Skip to content
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
6 changes: 6 additions & 0 deletions .changeset/fifty-jokes-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@frontify/fondue-components": minor
"@frontify/fondue": patch
---

feat: adjust dialog component styling
25 changes: 25 additions & 0 deletions packages/components/src/components/Dialog/Dialog.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,31 @@ export const WithFocusableContent: Story = {
},
};

export const Fullscreen: Story = {
args: {
size: 'fullscreen',
},
render: (args) => {
return (
<Dialog.Root>
<Dialog.Trigger>
<Button>Open dialog</Button>
</Dialog.Trigger>
<Dialog.Content {...args}>
<Dialog.Header>
<Dialog.Title>Header</Dialog.Title>
</Dialog.Header>
<Dialog.Body>None</Dialog.Body>
<Dialog.Footer>
<Button emphasis="default">Cancel</Button>
<Button>Submit</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
);
},
};

export const WithNoPadding: Story = {
render: (args) => {
return (
Expand Down
13 changes: 11 additions & 2 deletions packages/components/src/components/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { useSyncRefs } from '#/hooks/useSyncRefs';
import { useTranslation } from '#/hooks/useTranslation';
import { addAutoFocusAttribute, addShowFocusRing } from '#/utilities/domUtilities';

import { Button } from '../Button/Button';
import { ThemeProvider, useFondueTheme } from '../ThemeProvider/ThemeProvider';

import styles from './styles/dialog.module.scss';
Expand Down Expand Up @@ -62,7 +63,11 @@ export type DialogContentProps = {
* @default "center"
*/
verticalAlign?: 'top' | 'center';

/**
* Whether the dialog should be fit or fullscreen
* @default "fit"
*/
size?: 'fit' | 'fullscreen';
/**
* Define a maximum width for the dialog
* @default "800px"
Expand Down Expand Up @@ -221,6 +226,7 @@ export const DialogContent = (
minHeight = '200px',
padding = 'compact',
verticalAlign = 'center',
size = 'fit',
'data-test-id': dataTestId = 'fondue-dialog-content',
showUnderlay = false,
rounded = true,
Expand Down Expand Up @@ -290,6 +296,7 @@ export const DialogContent = (
data-dialog-padding={padding}
data-dialog-rounded={rounded}
data-test-id={dataTestId}
data-dialog-size={size}
data-dialog-vertical-align={verticalAlign}
dir={dir}
>
Expand Down Expand Up @@ -332,7 +339,9 @@ export const DialogHeader = (
aria-label={t('Dialog_close')}
{...closeProps}
>
<IconCross size={20} />
<Button emphasis="weak" size="small" aspect="square">
<IconCross size={16} />
</Button>
</RadixDialog.Close>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,14 @@ test('should render borders on footer and header by default', async ({ mount, pa
);
const headerElement = page.getByTestId(DIALOG_HEADER_TEST_ID);
const footerElement = page.getByTestId(DIALOG_FOOTER_TEST_ID);
await expect(headerElement).toHaveCSS('border-bottom-width', '1px');
await expect(footerElement).toHaveCSS('border-top-width', '1px');
const headerBorderWidth = await headerElement.evaluate(
(element) => getComputedStyle(element, '::after').borderTopWidth,
);
const footerBorderWidth = await footerElement.evaluate(
(element) => getComputedStyle(element, '::before').borderTopWidth,
);
expect(headerBorderWidth).toBe('1px');
expect(footerBorderWidth).toBe('1px');
});

test('should not render borders when showBorder is false', async ({ mount, page }) => {
Expand Down Expand Up @@ -472,6 +478,46 @@ test('should have its content to expand to max width set by user', async ({ moun
await expect(contentElement).toHaveCSS('width', '810px');
});

test('should render fit size by default', async ({ mount, page }) => {
await mount(
<Dialog.Root open>
<Dialog.Trigger>
<Button>{DIALOG_TRIGGER_TEXT}</Button>
</Dialog.Trigger>
<Dialog.Content data-test-id={DIALOG_CONTENT_TEST_ID}>
<Dialog.Header data-test-id={DIALOG_HEADER_TEST_ID}>{DIALOG_HEADER_TEXT}</Dialog.Header>
<Dialog.Body data-test-id={DIALOG_BODY_TEST_ID}>{DIALOG_BODY_TEXT}</Dialog.Body>
</Dialog.Content>
</Dialog.Root>,
);
const contentElement = page.getByTestId(DIALOG_CONTENT_TEST_ID);
await expect(contentElement).toHaveAttribute('data-dialog-size', 'fit');
});

test('should render fullscreen size', async ({ mount, page }) => {
await mount(
<Dialog.Root open>
<Dialog.Trigger>
<Button>{DIALOG_TRIGGER_TEXT}</Button>
</Dialog.Trigger>
<Dialog.Content size="fullscreen" data-test-id={DIALOG_CONTENT_TEST_ID}>
<Dialog.Header data-test-id={DIALOG_HEADER_TEST_ID}>{DIALOG_HEADER_TEXT}</Dialog.Header>
<Dialog.Body data-test-id={DIALOG_BODY_TEST_ID}>{DIALOG_BODY_TEXT}</Dialog.Body>
</Dialog.Content>
</Dialog.Root>,
);
const contentElement = page.getByTestId(DIALOG_CONTENT_TEST_ID);
await expect(contentElement).toHaveAttribute('data-dialog-size', 'fullscreen');

// Fullscreen expands the dialog to the viewport minus a 2rem (32px) inset.
const viewport = page.viewportSize();
expect(viewport).not.toBeNull();
if (viewport) {
await expect(contentElement).toHaveCSS('width', `${viewport.width - 32}px`);
await expect(contentElement).toHaveCSS('height', `${viewport.height - 32}px`);
}
});

test('should focus first input in body when dialog opens', async ({ mount, page }) => {
const component = await mount(
<Dialog.Root>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
transform: translateX(-50%) translateY(-50%);
background-color: var(--color-surface-default);
box-shadow: var(--shadow-default);
border: var(--border-width-default) solid var(--color-line-subtle);
z-index: 1;
width: calc(100vw - 2rem);
max-width: var(--dialog-max-width);
Expand All @@ -34,6 +33,13 @@
}
}

&[data-dialog-size='fullscreen'] {
max-height: calc(100vh - 2rem);
height: calc(100vh - 2rem);
max-width: calc(100vw - 2rem);
width: calc(100vw - 2rem);
}

&:has([data-dialog-layout-component]) {
display: grid;
}
Expand All @@ -44,10 +50,14 @@
}

&[data-dialog-rounded='true'] {
border-radius: var(--border-radius-large);
border-radius: var(--border-radius-x-large);
}
--header-divider-padding: #{sizeToken.get(0)};
--footer-divider-padding: #{sizeToken.get(0)};

&[data-dialog-padding='tight'] {
--header-divider-padding: #{sizeToken.get(2)};
--footer-divider-padding: #{sizeToken.get(2)};
.header,
.footer,
.body {
Expand All @@ -56,6 +66,8 @@
}

&[data-dialog-padding='compact'] {
--header-divider-padding: #{sizeToken.get(4)};
--footer-divider-padding: #{sizeToken.get(4)};
.header,
.footer {
padding: sizeToken.get(4);
Expand All @@ -68,6 +80,8 @@
}

&[data-dialog-padding='comfortable'] {
--header-divider-padding: #{sizeToken.get(6)};
--footer-divider-padding: #{sizeToken.get(6)};
.header,
.footer {
padding: sizeToken.get(6);
Expand All @@ -80,6 +94,9 @@
}

&[data-dialog-padding='spacious'] {
--header-divider-padding: #{sizeToken.get(10)};
--footer-divider-padding: #{sizeToken.get(10)};

.header,
.footer {
padding: sizeToken.get(10);
Expand All @@ -99,29 +116,42 @@
font-weight: var(--typography-font-weight-medium);
grid-row: 2;
grid-column: 1;

&[data-show-border='true'] {
border-block-end: var(--border-width-default) solid var(--color-line-subtle);
position: relative;

&[data-show-border='true']::after {
content: '';
display: block;
position: absolute;
height: 0;
bottom: 0;
left: var(--header-divider-padding);
right: var(--header-divider-padding);
border-top: var(--border-width-default) solid var(--color-line-subtle);
}

&[data-dialog-header-padding='none'] {
padding: sizeToken.get(0);
--header-divider-padding: #{sizeToken.get(0)};
}

&[data-dialog-header-padding='tight'] {
padding: sizeToken.get(2);
--header-divider-padding: #{sizeToken.get(2)};
}

&[data-dialog-header-padding='compact'] {
padding: sizeToken.get(4);
--header-divider-padding: #{sizeToken.get(4)};
}

&[data-dialog-header-padding='comfortable'] {
padding: sizeToken.get(6);
--header-divider-padding: #{sizeToken.get(6)};
}

&[data-dialog-header-padding='spacious'] {
padding: sizeToken.get(10);
--header-divider-padding: #{sizeToken.get(10)};
}

& {
Expand Down Expand Up @@ -190,29 +220,42 @@
font-weight: var(--font-weight-medium);
grid-row: 4;
grid-column: 1;
position: relative;

&[data-dialog-footer-padding='none'] {
padding: sizeToken.get(0);
--footer-divider-padding: #{sizeToken.get(0)};
}

&[data-dialog-footer-padding='tight'] {
padding: sizeToken.get(2);
--footer-divider-padding: #{sizeToken.get(2)};
}

&[data-dialog-footer-padding='compact'] {
padding: sizeToken.get(4);
--footer-divider-padding: #{sizeToken.get(4)};
}

&[data-dialog-footer-padding='comfortable'] {
padding: sizeToken.get(6);
--footer-divider-padding: #{sizeToken.get(6)};
}

&[data-dialog-footer-padding='spacious'] {
padding: sizeToken.get(10);
--footer-divider-padding: #{sizeToken.get(10)};
}

&[data-show-border='true'] {
border-block-start: var(--border-width-default) solid var(--color-line-subtle);
&[data-show-border='true']::before {
content: '';
display: block;
position: absolute;
height: 0;
top: 0;
left: var(--footer-divider-padding);
right: var(--footer-divider-padding);
border-top: var(--border-width-default) solid var(--color-line-subtle);
}

& {
Expand Down