Skip to content

Commit

Permalink
feat(dialog): Introduce a dedicated button to cancel a dialog (#4268)
Browse files Browse the repository at this point in the history
* feat(dialog): Introduce a dedicated button to cancel a dialog

* Create few-points-vanish.md

* Update few-points-vanish.md

* remnove unused imports

* udpate docs

* include feedback

* save

* eh?

* updated

* update changeset

* adjust tests

* fix demo

* make implementation more robust

* Update few-points-vanish.md
  • Loading branch information
sebald authored Nov 21, 2024
1 parent 8914fb0 commit 83ad341
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 60 deletions.
8 changes: 8 additions & 0 deletions .changeset/few-points-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@marigold/docs": minor
"@marigold/components": minor
---

feat(dialog): Introduce a dedicated button to close a dialog

Make it more convenient to have a button that closes the `<Dialog>`. With this, there is less need to use the child function to access the `close` method. Instead you can now use `<Button slot="close">` to render a close button.
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ export default (props: DialogProps) => (
details pre-filled, except for the date.
</Dialog.Content>
<Dialog.Actions>
<Button variant="secondary">Cancel</Button>
<Button variant="primary">Duplicate</Button>
<Button variant="secondary" slot="close">
Cancel
</Button>
<Button variant="primary" slot="close">
Duplicate
</Button>
</Dialog.Actions>
</Dialog>
</Dialog.Trigger>
Expand Down
32 changes: 15 additions & 17 deletions docs/content/components/overlay/dialog/dialog-content.demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,21 @@ export default () => (
<User /> Edit
</Button>
<Dialog>
{({ close }) => (
<FieldGroup labelWidth="50px">
<Dialog.Title level={2}>Edit user info</Dialog.Title>
<Dialog.Content>
<Stack space={3}>
<TextField label="Name" autoFocus />
<TextField label="Email" type="email" />
</Stack>
</Dialog.Content>
<Dialog.Actions>
<Button variant="ghost" onPress={close}>
Cancel
</Button>
<Button variant="primary">Update</Button>
</Dialog.Actions>
</FieldGroup>
)}
<FieldGroup labelWidth="50px">
<Dialog.Title level={2}>Edit user info</Dialog.Title>
<Dialog.Content>
<Stack space={3}>
<TextField label="Name" autoFocus />
<TextField label="Email" type="email" />
</Stack>
</Dialog.Content>
<Dialog.Actions>
<Button variant="secondary" slot="close">
Cancel
</Button>
<Button variant="primary">Update</Button>
</Dialog.Actions>
</FieldGroup>
</Dialog>
</Dialog.Trigger>
);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Button, Dialog } from '@marigold/components';

export default () => (
<Dialog.Trigger dismissable={false}>
<Dialog.Trigger dismissable>
<Button variant="primary">Duplicate</Button>
<Dialog closeButton size="small">
<Dialog.Title>Duplicate event</Dialog.Title>
Expand All @@ -10,7 +10,9 @@ export default () => (
details pre-filled, except for the date.
</Dialog.Content>
<Dialog.Actions>
<Button variant="secondary">Cancel</Button>
<Button variant="secondary" slot="close">
Cancel
</Button>
<Button variant="primary">Duplicate</Button>
</Dialog.Actions>
</Dialog>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ export default () => {
be undone.
</Dialog.Content>
<Dialog.Actions>
<Button size="small" variant="secondary" onPress={close}>
<Button variant="secondary" slot="close">
Cancel
</Button>
<Button size="small" variant="primary" onPress={close}>
<Button variant="primary" onPress={close}>
Delete
</Button>
</Dialog.Actions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ export default () => (
<Dialog aria-label="delete event">
<Dialog.Title>Are you sure you want to delete this event?</Dialog.Title>
<Dialog.Actions>
<Button variant="secondary">Cancel</Button>
<Button variant="secondary" slot="close">
Cancel
</Button>
<Button variant="primary">Delete</Button>
</Dialog.Actions>
</Dialog>
Expand Down
9 changes: 8 additions & 1 deletion docs/content/components/overlay/dialog/dialog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Lastly, avoid asking users to make decisions that require information not access

When a dialog is open, users cannot interact with the rest of the page until the dialog is closed. To accommodate both mouse and keyboard users, the `<Dialog>` provides multiple ways to close it:

- clicking the cancel button in the `<Dialog.Actions>`,
- pressing the close button (`slot="close"`) inside `<Dialog.Actions>`,
- using the close button (indicated by an "x"),
- pressing the "Esc" key, or
- clicking on the underlay (the dimmed background).
Expand All @@ -75,6 +75,13 @@ To prevent the dialog from closing when the underlay is (accidentally) clicked,

<ComponentDemo file="./dialog-dismiss.demo.tsx" />

<SectionMessage>
<SectionMessage.Title>Dedicated close button</SectionMessage.Title>
<SectionMessage.Content>
To conveniently create a close button for a dialog, set the `slot` prop to `"close"` on any `<Button>` within `<Dialog.Actions>` component. Pressing the button will then close the dialog.
</SectionMessage.Content>
</SectionMessage>

### Role

When a dialog requires the user's immediate attention, such as for an error or warning, set `role="alertdialog"`. This role ensures that assistive technologies, like screen readers, treat the dialog as high-priority, immediately notifying users of its content.
Expand Down
58 changes: 32 additions & 26 deletions packages/components/src/Dialog/Dialog.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { Meta, StoryObj } from '@storybook/react';
import { useState } from 'react';
import { Button } from '../Button';
import { Checkbox, CheckboxGroup } from '../Checkbox';
import { Inline } from '../Inline';
import { Menu } from '../Menu';
import { Modal, ModalProps } from '../Overlay/Modal';
import { Stack } from '../Stack';
Expand Down Expand Up @@ -67,7 +66,13 @@ export const Basic: Story = {
<Button variant="primary">Open</Button>
<Dialog size={size} closeButton>
<Dialog.Title>This is a headline!</Dialog.Title>
<Text>This is some not so very long text.</Text>
<Dialog.Content>This is some not so very long text.</Dialog.Content>
<Dialog.Actions>
<Button slot="close" variant="secondary">
Cancel
</Button>
<Button variant="primary">Ok</Button>
</Dialog.Actions>
</Dialog>
</Dialog.Trigger>
);
Expand All @@ -80,21 +85,17 @@ export const Form: Story = {
<Dialog.Trigger {...args}>
<Button variant="primary">Open</Button>
<Dialog size={size} closeButton>
{({ close }) => (
<>
<Dialog.Title>Please log into account </Dialog.Title>
<Dialog.Content>
<TextField label="Username" />
<TextField label="Password" type="password" />
</Dialog.Content>
<Dialog.Actions>
<Button variant="ghost" onPress={close}>
Cancel
</Button>
<Button variant="primary">Login</Button>
</Dialog.Actions>
</>
)}
<Dialog.Title>Please log into account </Dialog.Title>
<Dialog.Content>
<TextField label="Username" />
<TextField label="Password" type="password" />
</Dialog.Content>
<Dialog.Actions>
<Button slot="close" variant="secondary">
Cancel
</Button>
<Button variant="primary">Login</Button>
</Dialog.Actions>
</Dialog>
</Dialog.Trigger>
);
Expand Down Expand Up @@ -176,7 +177,9 @@ export const StickyFooter: Story = {
</Dialog.Content>
</div>
<Dialog.Actions>
<Button variant="primary">Ok</Button>
<Button variant="primary" slot="close">
close
</Button>
</Dialog.Actions>
</div>
</Dialog>
Expand Down Expand Up @@ -219,14 +222,17 @@ export const WithDialogController: Story = {
<Text>Do you really wanna delete this?</Text>
</Dialog.Content>
<Dialog.Actions>
<Inline space={5}>
<Button size="small" variant="ghost" onPress={close}>
Cancel
</Button>
<Button size="small" variant="primary" onPress={close}>
Delete
</Button>
</Inline>
<Button slot="close" variant="secondary">
Cancel
</Button>
<Button
slot="close"
variant="primary"
size="small"
onPress={close}
>
Delete
</Button>
</Dialog.Actions>
</>
)}
Expand Down
28 changes: 28 additions & 0 deletions packages/components/src/Dialog/Dialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -519,3 +519,31 @@ test('close state has a listener', async () => {

expect(spy.mock.calls).toMatchInlineSnapshot(`[]`);
});

test('cancel button closes dialog', async () => {
render(
<Dialog.Trigger>
<Button>Open</Button>

<Dialog closeButton>
<Dialog.Title>Headline</Dialog.Title>
<Dialog.Actions>
<Button slot="close">Cancel</Button>
</Dialog.Actions>
</Dialog>
</Dialog.Trigger>
);

const button = screen.getByText('Open');
await user.click(button);

const cancel = screen.getByText('Cancel');
await waitFor(() => {
expect(cancel).toBeInTheDocument();
});

await user.click(cancel);
await waitFor(() => {
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
});
30 changes: 29 additions & 1 deletion packages/components/src/Dialog/DialogActions.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { useContext } from 'react';
import type { ReactNode } from 'react';
import {
ButtonContext,
DEFAULT_SLOT,
OverlayTriggerStateContext,
Provider,
} from 'react-aria-components';
import { cn, useClassNames } from '@marigold/system';

export interface DialogActionsRenderProps {
close: () => void;
}

export interface DialogActions {
/**
* Children of the component.
Expand All @@ -12,9 +23,26 @@ export interface DialogActions {

export const DialogActions = ({ variant, size, children }: DialogActions) => {
const classNames = useClassNames({ component: 'Dialog', variant, size });
const overlayContext = useContext(OverlayTriggerStateContext);
const closeButtonProps = { onPress: overlayContext?.close };

return (
<div className={cn('[grid-area:actions]', classNames.actions)}>
{children}
<Provider
values={[
[
ButtonContext,
{
slots: {
[DEFAULT_SLOT]: {},
close: closeButtonProps,
},
},
],
]}
>
{children}
</Provider>
</div>
);
};
8 changes: 0 additions & 8 deletions packages/components/src/Select/intl.ts

This file was deleted.

0 comments on commit 83ad341

Please sign in to comment.