Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow ModalDialogs with variant='custom' #1442

Merged
merged 1 commit into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading