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

expose show()/close() methods via Dialog.useInstance() #1983

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e718677
add / methods to Dialog ref
mayank99 Apr 3, 2024
56100a8
add `show` and `close` methods to `Dialog`
mayank99 Apr 3, 2024
2bf4371
handle `onClose` implicitly
mayank99 Apr 3, 2024
26cbcad
Merge branch 'main' into mayank/dialog-ref
mayank99 Apr 3, 2024
e07d153
also add it to `Modal`
mayank99 Apr 3, 2024
80a5a23
update examples
mayank99 Apr 3, 2024
18ce887
docs
mayank99 Apr 3, 2024
35ec876
fix refs
mayank99 Apr 3, 2024
04e98c9
test
mayank99 Apr 3, 2024
97dab3d
typo
mayank99 Apr 3, 2024
2f267c1
cleanup
mayank99 Apr 3, 2024
b45ae79
whoops
mayank99 Apr 3, 2024
6785ea5
revert `Modal`
mayank99 Apr 3, 2024
ef7cb0d
Merge remote-tracking branch 'origin/main' into mayank/dialog-instance
mayank99 Apr 4, 2024
84b9a4d
wip
mayank99 Apr 4, 2024
e3defd8
cleanup
mayank99 Apr 4, 2024
d8a858c
fix types
mayank99 Apr 4, 2024
caf402d
fix test
mayank99 Apr 4, 2024
72c3f45
simplify
mayank99 Apr 4, 2024
4c88616
move helpers to separate module
mayank99 Apr 5, 2024
c2a511c
Merge branch 'main' into mayank/dialog-instance
mayank99 Apr 5, 2024
4f4d8fb
simplify even more
mayank99 Apr 5, 2024
9551838
changeset
mayank99 Apr 5, 2024
1a89963
consistency
mayank99 Apr 5, 2024
e75d73b
remove unnecessary export
mayank99 Apr 5, 2024
465a8d5
`@usage` → `@example`
mayank99 Apr 5, 2024
5077599
better example
mayank99 Apr 5, 2024
3542b00
cleanup
mayank99 Apr 5, 2024
b447d07
fix cleanup
mayank99 Apr 5, 2024
6a13b90
Update apps/website/src/content/docs/dialog.mdx
mayank99 Apr 8, 2024
57fed2d
Update examples/Dialog.draggable.jsx
mayank99 Apr 8, 2024
76c9556
update remaining instances of `dialog.show`
mayank99 Apr 9, 2024
b416563
Merge branch 'main' into mayank/dialog-instance
mayank99 Apr 10, 2024
a7c22dd
Merge branch 'main' into mayank/dialog-instance
mayank99 Apr 10, 2024
b685b37
fix tests
mayank99 Apr 10, 2024
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
14 changes: 14 additions & 0 deletions .changeset/eight-rocks-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@itwin/itwinui-react": minor
---

Added the ability to control `Dialog` imperatively using `show()` and `close()` methods from its instance.

```tsx
const dialog = Dialog.useInstance();

<Button onClick={() => dialog.show()}>Open dialog</Button>
<Dialog instance={dialog}>
<Button onClick={() => dialog.close()}>Close dialog</Button>
</Dialog>
```
115 changes: 18 additions & 97 deletions apps/react-workshop/src/Dialog.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,25 @@ export default {
title: 'Dialog',
};

export const Basic = () => {
const [isOpen, setIsOpen] = React.useState(false);

const closeDialog = () => {
setIsOpen(false);
};

const onClose = () => {
console.log('onClose');
closeDialog();
};

const primaryButtonHandle = () => {
console.log('Primary button');
closeDialog();
};
const lorem = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`;

const secondaryButtonHandle = () => {
console.log('Secondary button');
closeDialog();
};
export const Basic = () => {
const dialog = Dialog.useInstance();

return (
<>
<Button styleType='high-visibility' onClick={() => setIsOpen(true)}>
<Button styleType='high-visibility' onClick={() => dialog.show()}>
Open Dialog
</Button>
<Dialog isOpen={isOpen} onClose={onClose} closeOnEsc isDismissible>
<Dialog instance={dialog}>
<Dialog.Main>
<Dialog.TitleBar titleText='Best dialog ever' />
<Dialog.Content>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</Dialog.Content>
<Dialog.Content>{lorem}</Dialog.Content>
<Dialog.ButtonBar>
<Button styleType='high-visibility' onClick={primaryButtonHandle}>
<Button styleType='high-visibility' onClick={() => dialog.close()}>
Primary
</Button>
<Button onClick={secondaryButtonHandle}>Secondary</Button>
<Button onClick={() => dialog.close()}>Secondary</Button>
</Dialog.ButtonBar>
</Dialog.Main>
</Dialog>
Expand All @@ -61,59 +36,29 @@ export const Basic = () => {
};

export const Modal = () => {
const [isOpen, setIsOpen] = React.useState(false);

const closeDialog = () => {
setIsOpen(false);
};

const onClose = () => {
console.log('onClose');
closeDialog();
};

const primaryButtonHandle = () => {
console.log('Primary button');
closeDialog();
};

const secondaryButtonHandle = () => {
console.log('Secondary button');
closeDialog();
};
const dialog = Dialog.useInstance();

return (
<>
<Button styleType='high-visibility' onClick={() => setIsOpen(true)}>
<Button styleType='high-visibility' onClick={() => dialog.show()}>
Open Dialog
</Button>
<Dialog
isOpen={isOpen}
onClose={onClose}
closeOnEsc
instance={dialog}
closeOnExternalClick
preventDocumentScroll
trapFocus
setFocus
isDismissible
>
<Dialog.Backdrop onKeyDown={() => console.log('onKeyDown')} />
<Dialog.Backdrop />
<Dialog.Main>
<Dialog.TitleBar titleText='Best dialog ever' />
<Dialog.Content>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</Dialog.Content>
<Dialog.Content>{lorem}</Dialog.Content>
<Dialog.ButtonBar>
<Button styleType='high-visibility' onClick={primaryButtonHandle}>
<Button styleType='high-visibility' onClick={() => dialog.close()}>
Primary
</Button>
<Button onClick={secondaryButtonHandle}>Secondary</Button>
<Button onClick={() => dialog.close()}>Secondary</Button>
</Dialog.ButtonBar>
</Dialog.Main>
</Dialog>
Expand Down Expand Up @@ -158,15 +103,7 @@ export const DraggableAndResizable = () => {
>
<Dialog.Main>
<Dialog.TitleBar titleText='Best dialog ever' />
<Dialog.Content>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</Dialog.Content>
<Dialog.Content>{lorem}</Dialog.Content>
<Dialog.ButtonBar>
<Button styleType='high-visibility' onClick={primaryButtonHandle}>
Primary
Expand Down Expand Up @@ -230,15 +167,7 @@ export const DraggableRelativeToContainer = () => {
>
<Dialog.Main>
<Dialog.TitleBar titleText='Best dialog ever' />
<Dialog.Content>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</Dialog.Content>
<Dialog.Content>{lorem}</Dialog.Content>
<Dialog.ButtonBar>
<Button styleType='high-visibility' onClick={primaryButtonHandle}>
Primary
Expand Down Expand Up @@ -287,15 +216,7 @@ export const Placement = () => {
>
<Dialog.Main>
<Dialog.TitleBar titleText='Best dialog ever' />
<Dialog.Content>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</Dialog.Content>
<Dialog.Content>{lorem}</Dialog.Content>
<Dialog.ButtonBar>
<Button styleType='high-visibility' onClick={primaryButtonHandle}>
Primary
Expand Down
28 changes: 26 additions & 2 deletions apps/website/src/content/docs/dialog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ A dialog informs users about a task and can contain critical information, requir

Dialogs are purposefully interruptive, so they should be used sparingly.

## Dialog VS Modal
## Dialog vs Modal

The terms dialog and modal are often used interchangeably. Within iTwinUI we differentiate the two terms like so:

Expand All @@ -26,7 +26,31 @@ The terms dialog and modal are often used interchangeably. Within iTwinUI we dif
<AllExamples.DialogModalExample client:load />
</LiveExample>

## Variants
## Usage

The dialog can be opened and closed in two ways:

1. By using the `show()` and `close()` methods from its instance.

```tsx
const dialog = Dialog.useInstance();

<Button onClick={() => dialog.show()}>Open dialog</Button>
<Dialog instance={dialog}>
<Button onClick={() => dialog.close()}>Close dialog</Button>
</Dialog>
```

2. By using the `isOpen` prop, often paired with `onClose` and a state variable.

```tsx
const [isDialogOpen, setIsDialogOpen] = React.useState(false);

<Button onClick={() => setIsDialogOpen(true)}>Open dialog</Button>
<Dialog isOpen={isDialogOpen} onClose={() => setIsDialogOpen(false)}>
<Button onClick={() => setIsDialogOpen(false)}>Close dialog</Button>
</Dialog>
```

### Dismissible

Expand Down
23 changes: 5 additions & 18 deletions examples/Dialog.draggable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import * as React from 'react';
// import * as ReactDOM from 'react-dom';
import {
Dialog,
Button,
Expand All @@ -12,38 +11,26 @@ import {
} from '@itwin/itwinui-react';

export default () => {
const [isOpen, setIsOpen] = React.useState(false);
const dialog = Dialog.useInstance();

return (
<>
<Button styleType='high-visibility' onClick={() => setIsOpen(true)}>
<Button styleType='high-visibility' onClick={() => dialog.show()}>
Open draggable dialog
</Button>

<Dialog
isOpen={isOpen}
onClose={() => setIsOpen(false)}
setFocus={false}
closeOnEsc
isDismissible
isDraggable
isResizable
portal
>
<Dialog instance={dialog} isDraggable isResizable portal>
<Dialog.Main>
<Dialog.TitleBar titleText='New message' />
<Dialog.Content>
<LabeledInput label='Subject' />
<LabeledTextarea label='Message' />
</Dialog.Content>
<Dialog.ButtonBar>
<Button
styleType='high-visibility'
onClick={() => setIsOpen(false)}
>
<Button styleType='high-visibility' onClick={() => dialog.close()}>
Submit
</Button>
<Button onClick={() => setIsOpen(false)}>Save draft</Button>
<Button onClick={() => dialog.close()}>Save draft</Button>
</Dialog.ButtonBar>
</Dialog.Main>
</Dialog>
Expand Down
17 changes: 5 additions & 12 deletions examples/Dialog.main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,22 @@
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import * as React from 'react';
// import * as ReactDOM from 'react-dom';
import { Dialog, Button } from '@itwin/itwinui-react';

export default () => {
const [isOpen, setIsOpen] = React.useState(false);
const dialog = Dialog.useInstance();

return (
<>
<Button styleType='high-visibility' onClick={() => setIsOpen(true)}>
<Button styleType='high-visibility' onClick={() => dialog.show()}>
Open dialog
</Button>
<Dialog
isOpen={isOpen}
onClose={() => setIsOpen(false)}
closeOnEsc
instance={dialog}
closeOnExternalClick
preventDocumentScroll
trapFocus
setFocus
isDismissible
portal
>
<Dialog.Backdrop />
Expand All @@ -35,13 +31,10 @@ export default () => {
ask for a decision.
</Dialog.Content>
<Dialog.ButtonBar>
<Button
styleType='high-visibility'
onClick={() => setIsOpen(false)}
>
<Button styleType='high-visibility' onClick={() => dialog.close()}>
Primary
</Button>
<Button onClick={() => setIsOpen(false)}>Secondary</Button>
<Button onClick={() => dialog.close()}>Secondary</Button>
</Dialog.ButtonBar>
</Dialog.Main>
</Dialog>
Expand Down
20 changes: 5 additions & 15 deletions examples/Dialog.nondismissible.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,17 @@
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import * as React from 'react';
// import * as ReactDOM from 'react-dom';
import { Dialog, Button } from '@itwin/itwinui-react';

export default () => {
const [isOpen, setIsOpen] = React.useState(false);
const dialog = Dialog.useInstance();

return (
<>
<Button styleType='high-visibility' onClick={() => setIsOpen(true)}>
<Button styleType='high-visibility' onClick={() => dialog.show()}>
Open non-dismissible dialog
</Button>
<Dialog
isOpen={isOpen}
onClose={() => setIsOpen(false)}
setFocus={false}
isDismissible={false}
portal
>
<Dialog instance={dialog} setFocus={false} isDismissible={false} portal>
<Dialog.Backdrop />
<Dialog.Main>
<Dialog.TitleBar titleText='Empty trash' />
Expand All @@ -29,13 +22,10 @@ export default () => {
You can't undo this action.
</Dialog.Content>
<Dialog.ButtonBar>
<Button
styleType='high-visibility'
onClick={() => setIsOpen(false)}
>
<Button styleType='high-visibility' onClick={() => dialog.close()}>
Empty trash
</Button>
<Button onClick={() => setIsOpen(false)}>Cancel</Button>
<Button onClick={() => dialog.close()}>Cancel</Button>
</Dialog.ButtonBar>
</Dialog.Main>
</Dialog>
Expand Down
Loading
Loading