Fix <Modal> footers with long-text or lots of buttons

This commit is contained in:
Evan Hahn 2021-05-27 11:43:39 -04:00 committed by GitHub
parent 6664315e3a
commit 7038a3f3ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 48 additions and 20 deletions

View file

@ -91,13 +91,15 @@
padding: 16px; padding: 16px;
} }
&__footer { &__button-footer {
display: flex; display: flex;
flex-wrap: wrap;
justify-content: flex-end; justify-content: flex-end;
margin-top: 16px; margin-top: 8px;
.module-Button { .module-Button {
margin-left: 8px; margin-left: 8px;
margin-top: 8px;
} }
} }

View file

@ -22,8 +22,8 @@ export const Alert: FunctionComponent<PropsType> = ({
}) => ( }) => (
<Modal i18n={i18n} onClose={onClose} title={title}> <Modal i18n={i18n} onClose={onClose} title={title}>
{body} {body}
<Modal.Footer> <Modal.ButtonFooter>
<Button onClick={onClose}>{i18n('Confirmation--confirm')}</Button> <Button onClick={onClose}>{i18n('Confirmation--confirm')}</Button>
</Modal.Footer> </Modal.ButtonFooter>
</Modal> </Modal>
); );

View file

@ -118,7 +118,7 @@ export const CallingSelectPresentingSourcesModal = ({
/> />
))} ))}
</div> </div>
<Modal.Footer moduleClassName="module-CallingSelectPresentingSourcesModal"> <Modal.ButtonFooter moduleClassName="module-CallingSelectPresentingSourcesModal">
<Button <Button
onClick={() => setPresenting()} onClick={() => setPresenting()}
variant={ButtonVariant.Secondary} variant={ButtonVariant.Secondary}
@ -131,7 +131,7 @@ export const CallingSelectPresentingSourcesModal = ({
> >
{i18n('calling__SelectPresentingSourcesModal--confirm')} {i18n('calling__SelectPresentingSourcesModal--confirm')}
</Button> </Button>
</Modal.Footer> </Modal.ButtonFooter>
</Modal> </Modal>
); );
}; };

View file

@ -43,14 +43,14 @@ export function CaptchaDialog(props: Readonly<PropsType>): JSX.Element {
<section> <section>
<p>{i18n('CaptchaDialog--can-close__body')}</p> <p>{i18n('CaptchaDialog--can-close__body')}</p>
</section> </section>
<Modal.Footer> <Modal.ButtonFooter>
<Button onClick={onCancelClick} variant={ButtonVariant.Secondary}> <Button onClick={onCancelClick} variant={ButtonVariant.Secondary}>
{i18n('cancel')} {i18n('cancel')}
</Button> </Button>
<Button onClick={onSkipClick} variant={ButtonVariant.Destructive}> <Button onClick={onSkipClick} variant={ButtonVariant.Destructive}>
{i18n('CaptchaDialog--can_close__skip-verification')} {i18n('CaptchaDialog--can_close__skip-verification')}
</Button> </Button>
</Modal.Footer> </Modal.ButtonFooter>
</Modal> </Modal>
); );
} }
@ -80,7 +80,7 @@ export function CaptchaDialog(props: Readonly<PropsType>): JSX.Element {
<p>{i18n('CaptchaDialog__first-paragraph')}</p> <p>{i18n('CaptchaDialog__first-paragraph')}</p>
<p>{i18n('CaptchaDialog__second-paragraph')}</p> <p>{i18n('CaptchaDialog__second-paragraph')}</p>
</section> </section>
<Modal.Footer> <Modal.ButtonFooter>
<Button <Button
disabled={isPending} disabled={isPending}
onClick={onContinueClick} onClick={onContinueClick}
@ -93,7 +93,7 @@ export function CaptchaDialog(props: Readonly<PropsType>): JSX.Element {
'Continue' 'Continue'
)} )}
</Button> </Button>
</Modal.Footer> </Modal.ButtonFooter>
</Modal> </Modal>
); );
} }

View file

@ -78,7 +78,7 @@ export const ConfirmationDialog = React.memo(
return ( return (
<Modal i18n={i18n} onClose={cancelAndClose} title={title} theme={theme}> <Modal i18n={i18n} onClose={cancelAndClose} title={title} theme={theme}>
{children} {children}
<Modal.Footer> <Modal.ButtonFooter>
<Button <Button
onClick={handleCancel} onClick={handleCancel}
ref={focusRef} ref={focusRef}
@ -101,7 +101,7 @@ export const ConfirmationDialog = React.memo(
{action.text} {action.text}
</Button> </Button>
))} ))}
</Modal.Footer> </Modal.ButtonFooter>
</Modal> </Modal>
); );
} }

View file

@ -35,7 +35,7 @@ export const ErrorModal = (props: PropsType): JSX.Element => {
<div className="module-error-modal__description"> <div className="module-error-modal__description">
{description || i18n('ErrorModal--description')} {description || i18n('ErrorModal--description')}
</div> </div>
<Modal.Footer> <Modal.ButtonFooter>
<Button <Button
onClick={onClose} onClick={onClose}
ref={focusRef} ref={focusRef}
@ -43,7 +43,7 @@ export const ErrorModal = (props: PropsType): JSX.Element => {
> >
{buttonText || i18n('Confirmation--confirm')} {buttonText || i18n('Confirmation--confirm')}
</Button> </Button>
</Modal.Footer> </Modal.ButtonFooter>
</> </>
</Modal> </Modal>
); );

View file

@ -2,12 +2,14 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import React from 'react'; import React from 'react';
import { noop } from 'lodash';
import { storiesOf } from '@storybook/react'; import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { setup as setupI18n } from '../../js/modules/i18n'; import { setup as setupI18n } from '../../js/modules/i18n';
import enMessages from '../../_locales/en/messages.json'; import enMessages from '../../_locales/en/messages.json';
import { Button } from './Button';
import { Modal } from './Modal'; import { Modal } from './Modal';
const i18n = setupI18n('en', enMessages); const i18n = setupI18n('en', enMessages);
@ -30,10 +32,31 @@ story.add('Bare bones, long', () => (
</Modal> </Modal>
)); ));
story.add('Title, X button, body, and footer', () => ( story.add('Title, X button, body, and button footer', () => (
<Modal i18n={i18n} title="Hello world" onClose={onClose} hasXButton> <Modal i18n={i18n} title="Hello world" onClose={onClose} hasXButton>
{LOREM_IPSUM} {LOREM_IPSUM}
<Modal.Footer>Footer</Modal.Footer> <Modal.ButtonFooter>
<Button onClick={noop}>Okay</Button>
</Modal.ButtonFooter>
</Modal>
));
story.add('Lots of buttons in the footer', () => (
<Modal i18n={i18n} onClose={onClose}>
Hello world!
<Modal.ButtonFooter>
<Button onClick={noop}>Okay</Button>
<Button onClick={noop}>Okay</Button>
<Button onClick={noop}>Okay</Button>
<Button onClick={noop}>
This is a button with a fairly large amount of text
</Button>
<Button onClick={noop}>Okay</Button>
<Button onClick={noop}>
This is a button with a fairly large amount of text
</Button>
<Button onClick={noop}>Okay</Button>
</Modal.ButtonFooter>
</Modal> </Modal>
)); ));

View file

@ -85,7 +85,7 @@ export function Modal({
); );
} }
Modal.Footer = ({ Modal.ButtonFooter = ({
children, children,
moduleClassName, moduleClassName,
}: Readonly<{ }: Readonly<{
@ -93,7 +93,10 @@ Modal.Footer = ({
moduleClassName?: string; moduleClassName?: string;
}>): ReactElement => ( }>): ReactElement => (
<div <div
className={getClassNamesFor(BASE_CLASS_NAME, moduleClassName)('__footer')} className={getClassNamesFor(
BASE_CLASS_NAME,
moduleClassName
)('__button-footer')}
> >
{children} {children}
</div> </div>

View file

@ -37,7 +37,7 @@ export const NeedsScreenRecordingPermissionsModal = ({
<li>{i18n('calling__presenting--permission-instruction-step3')}</li> <li>{i18n('calling__presenting--permission-instruction-step3')}</li>
<li>{i18n('calling__presenting--permission-instruction-step4')}</li> <li>{i18n('calling__presenting--permission-instruction-step4')}</li>
</ol> </ol>
<Modal.Footer> <Modal.ButtonFooter>
<Button <Button
onClick={toggleScreenRecordingPermissionsDialog} onClick={toggleScreenRecordingPermissionsDialog}
ref={focusRef} ref={focusRef}
@ -54,7 +54,7 @@ export const NeedsScreenRecordingPermissionsModal = ({
> >
{i18n('calling__presenting--permission-open')} {i18n('calling__presenting--permission-open')}
</Button> </Button>
</Modal.Footer> </Modal.ButtonFooter>
</Modal> </Modal>
); );
}; };