Skip to content

Commit

Permalink
Allow ModalDialogs with variant='custom'
Browse files Browse the repository at this point in the history
  • Loading branch information
acelaya committed Jan 31, 2024
1 parent 5ffcf1b commit 97130ff
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/components/feedback/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export type PanelDialogProps = PresentationalProps &
variant?: 'panel';
};

type CustomDialogProps = PresentationalProps &
export type CustomDialogProps = PresentationalProps &
ComponentProps & {
/** `custom` allows any layout of Dialog children */
variant: 'custom';
Expand Down
28 changes: 16 additions & 12 deletions src/components/feedback/ModalDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useTabKeyNavigation } from '../../hooks/use-tab-key-navigation';
import { downcastRef } from '../../util/typing';
import Overlay from '../layout/Overlay';
import Dialog from './Dialog';
import type { PanelDialogProps } from './Dialog';
import type { CustomDialogProps, PanelDialogProps } from './Dialog';

type ModalSize = 'sm' | 'md' | 'lg' | 'custom';

Expand Down Expand Up @@ -33,12 +33,20 @@ type ComponentProps = {
size?: ModalSize;
};

export type ModalDialogProps = Omit<
export type PanelModalDialogProps = Omit<
PanelDialogProps,
'restoreFocus' | 'closeOnEscape'
> &
ComponentProps;

export type CustomModalDialogProps = Omit<
CustomDialogProps,
'restoreFocus' | 'closeOnEscape'
> &
ComponentProps;

export type ModalDialogProps = PanelModalDialogProps | CustomModalDialogProps;

/**
* Show a modal dialog
*/
Expand All @@ -47,7 +55,7 @@ export default function ModalDialog({
disableCloseOnEscape = false,
disableFocusTrap = false,
disableRestoreFocus = false,
size,
size = 'md',

classes,
elementRef,
Expand All @@ -59,8 +67,6 @@ export default function ModalDialog({

...htmlAndPanelAttributes
}: ModalDialogProps) {
// Prefer `size` prop but support deprecated `width` if present
const modalSize = size ?? 'md';
const modalRef = useSyncedRef(elementRef);

useTabKeyNavigation(modalRef, { enabled: !disableFocusTrap });
Expand Down Expand Up @@ -90,17 +96,15 @@ export default function ModalDialog({
'tall:fixed tall:max-h-[80vh] tall:top-[10vh]',
{
// Max-width rules will ensure actual width never exceeds 90vw
'w-[30rem]': modalSize === 'sm',
'w-[36rem]': modalSize === 'md', // default
'w-[42rem]': modalSize === 'lg',
// No width classes are added if width is 'custom'
'w-[30rem]': size === 'sm',
'w-[36rem]': size === 'md', // default
'w-[42rem]': size === 'lg',
// No width classes are added if `size` is 'custom'
},
classes,
)}
elementRef={downcastRef(modalRef)}
// Testing affordance. TODO: Remove once deprecated `width` prop
// no longer supported.
data-modal-size={modalSize}
data-modal-size={size}
>
{children}
</Dialog>
Expand Down
8 changes: 1 addition & 7 deletions src/components/feedback/test/ModalDialog-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe('ModalDialog', () => {
.getAttribute('data-modal-size');
}

it('sets a default size if neither `size` nor `width` provided', () => {
it('sets a default size if `size` is not provided', () => {
const wrapper = mount(
<ModalDialog title="Test modal dialog">This is my dialog</ModalDialog>,
);
Expand All @@ -129,11 +129,5 @@ describe('ModalDialog', () => {

assert.equal(modalSize(wrapper), 'lg');
});

it('prefers `size` over `width` to set size', () => {
const wrapper = sizedModal({ size: 'lg', width: 'sm' });

assert.equal(modalSize(wrapper), 'lg');
});
});
});
36 changes: 34 additions & 2 deletions src/pattern-library/components/patterns/feedback/DialogPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import {
TabList,
} from '../../../../';
import { ModalDialog } from '../../../../components/feedback';
import type { ModalDialogProps } from '../../../../components/feedback/ModalDialog';
import type {
CustomModalDialogProps,
PanelModalDialogProps,
} from '../../../../components/feedback/ModalDialog';
import { confirm } from '../../../../util/prompts';
import Library from '../../Library';
import { LoremIpsum, nabokovNovels } from '../samples';
Expand Down Expand Up @@ -120,7 +123,7 @@ function Confirm() {
);
}

type ModalDialog_Props = ModalDialogProps & {
type ModalDialog_Props = PanelModalDialogProps & {
/** Pattern-wrapping prop. Not visible in source view */
_nonCloseable?: boolean;
_alwaysShowButton?: boolean;
Expand Down Expand Up @@ -169,6 +172,25 @@ function ModalDialog_({
);
}

function CustomModalDialog_(dialogProps: CustomModalDialogProps) {
const [dialogOpen, setDialogOpen] = useState(false);

return (
<>
<Button onClick={() => setDialogOpen(prev => !prev)} variant="primary">
{dialogOpen ? 'Hide' : 'Show'} dialog
</Button>
{dialogOpen && (
<ModalDialog
{...dialogProps}
onClose={() => setDialogOpen(false)}
closeOnClickAway
/>
)}
</>
);
}

export default function DialogPage() {
const inputRef = useRef(null);

Expand Down Expand Up @@ -728,6 +750,16 @@ export default function DialogPage() {
</ModalDialog_>
</Library.Demo>
</Library.Example>
<Library.Example title="Custom layout">
<Library.Demo title="Modal dialog with custom layout" withSource>
<CustomModalDialog_ variant="custom">
<div className="flex gap-x-3 items-center border p-3 bg-white">
<div className="grow">Custom dialog content</div>
<CloseButton />
</div>
</CustomModalDialog_>
</Library.Demo>
</Library.Example>
</Library.Pattern>
<Library.Pattern title="ComponentAPI">
<Library.Example title="title">
Expand Down

0 comments on commit 97130ff

Please sign in to comment.