This repository was archived by the owner on Mar 4, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 51
fix(Dialog): support nested Dialogs and Popups #1706
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
d3e398e
add nesting registry
layershifter 42079b4
wip
layershifter b1f30d6
add prototype
layershifter 358f3d3
add E2E tests
layershifter 78a6b0d
remove console.log
layershifter a2de2d6
add changelog entry
layershifter 4d0ca8c
fix dangerjs issue
layershifter a5c0e84
Update e2e/tests/dialogInPopup-test.ts
layershifter c0e19d6
Update e2e/tests/dialogInDialog-test.ts
layershifter ecd632d
Merge branches 'fix/dialog-nesting' and 'master' of https://github.co…
layershifter 9611389
update test header
layershifter 3d71049
use boundingBox
layershifter c0023ed
update method
layershifter 5614eb8
Merge branch 'master' into fix/dialog-nesting
layershifter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| import { Button, Dialog, Popup } from '@stardust-ui/react' | ||
| import * as React from 'react' | ||
|
|
||
| import { ComponentPrototype, PrototypeSection } from 'docs/src/prototypes/Prototypes' | ||
|
|
||
| const PopupAndDialog: React.FC = () => ( | ||
| <Popup | ||
| content={ | ||
| <> | ||
| <p> | ||
| This <code>Popup</code> will be kept open after <code>Dialog</code> will be opened. | ||
| </p> | ||
| <Dialog | ||
| cancelButton="Close" | ||
| header="A dialog" | ||
| trigger={<Button content="Open a dialog" />} | ||
| /> | ||
| </> | ||
| } | ||
| trigger={<Button content="Open a popup" />} | ||
| /> | ||
| ) | ||
|
|
||
| const ControlledPopupAndDialog: React.FC = () => { | ||
| const [dialogOpen, setDialogOpen] = React.useState(false) | ||
| const [popupOpen, setPopupOpen] = React.useState(false) | ||
|
|
||
| return ( | ||
| <> | ||
| <Popup | ||
| content={ | ||
| <> | ||
| <p> | ||
| This <code>Popup</code> will be close after <code>Dialog</code> will be opened. | ||
| </p> | ||
| <Button | ||
| content="Open a dialog & close popup" | ||
| onClick={() => { | ||
| setPopupOpen(false) | ||
| setDialogOpen(true) | ||
| }} | ||
| /> | ||
| </> | ||
| } | ||
| onOpenChange={(e, data) => setPopupOpen(data.open)} | ||
| open={popupOpen} | ||
| trigger={<Button content="Open a popup" />} | ||
| /> | ||
| <Dialog | ||
| cancelButton="Close" | ||
| header="A dialog" | ||
| onCancel={() => setDialogOpen(false)} | ||
| open={dialogOpen} | ||
| /> | ||
| </> | ||
| ) | ||
| } | ||
|
|
||
| const NestedDialogs: React.FC = () => ( | ||
| <Dialog | ||
| cancelButton="Close" | ||
| header="An outer dialog" | ||
| content={ | ||
| <> | ||
| <p> | ||
| This <code>Dialog</code> contains another <code>Dialog</code> inside. | ||
| </p> | ||
| <blockquote> | ||
| 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. | ||
| </blockquote> | ||
|
|
||
| <Dialog | ||
| cancelButton="Close" | ||
| header="An inner dialog" | ||
| content={ | ||
| <> | ||
| <p> | ||
| This <code>Dialog</code> is nested ヽ(^o^)ノ, if you will on an overlay only this{' '} | ||
| <code>Dialog</code> will be closed. | ||
| </p> | ||
|
|
||
| <Popup | ||
| content="You can have also Popups inside dialogs!" | ||
| trigger={<Button content="Open a popup" />} | ||
| /> | ||
| </> | ||
| } | ||
| trigger={<Button content="Open a dialog" />} | ||
| /> | ||
| </> | ||
| } | ||
| trigger={<Button content="Open a dialog" />} | ||
| /> | ||
| ) | ||
|
|
||
| const NestedPopupsAndDialogs: React.FC = () => { | ||
| return ( | ||
| <PrototypeSection title="Nested Popups & Dialogs"> | ||
| <ComponentPrototype | ||
| title="A popup with dialog" | ||
| description="Popup will be kept open after Dialog" | ||
| > | ||
| <PopupAndDialog /> | ||
| </ComponentPrototype> | ||
| <ComponentPrototype | ||
| title="A closable popup with dialog" | ||
| description="Popup will be closed once Dialog will be opened" | ||
| > | ||
| <ControlledPopupAndDialog /> | ||
| </ComponentPrototype> | ||
| <ComponentPrototype title="Nested dialogs" description="An example with nested dialogs"> | ||
| <NestedDialogs /> | ||
| </ComponentPrototype> | ||
| </PrototypeSection> | ||
| ) | ||
| } | ||
|
|
||
| export default NestedPopupsAndDialogs |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import * as React from 'react' | ||
| import { Button, Dialog } from '@stardust-ui/react' | ||
|
|
||
| export const selectors = { | ||
| outerClose: 'outer-close', | ||
| outerHeader: 'outer-header', | ||
| outerTrigger: 'outer-trigger', | ||
| outerOverlay: 'outer-overlay', | ||
|
|
||
| innerClose: 'inner-close', | ||
| innerHeader: 'inner-header', | ||
| innerTrigger: 'inner-trigger', | ||
| innerOverlay: 'inner-overlay', | ||
| } | ||
|
|
||
| const DialogInPopupExample = () => ( | ||
| <Dialog | ||
| cancelButton={{ content: 'Close', id: selectors.outerClose }} | ||
| content={ | ||
| <Dialog | ||
| cancelButton={{ content: 'Close', id: selectors.innerClose }} | ||
| header={{ content: 'An inner', id: selectors.innerHeader }} | ||
| overlay={{ id: selectors.innerOverlay }} | ||
| trigger={<Button id={selectors.innerTrigger} content="Open a dialog" />} | ||
| /> | ||
| } | ||
| header={{ content: 'An outer', id: selectors.outerHeader }} | ||
| overlay={{ id: selectors.outerOverlay }} | ||
| trigger={<Button id={selectors.outerTrigger} content="Open a dialog" />} | ||
| /> | ||
| ) | ||
|
|
||
| export default DialogInPopupExample |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| import { selectors } from './dialogInDialog-example' | ||
|
|
||
| const outerClose = `#${selectors.outerClose}` | ||
| const outerHeader = `#${selectors.outerHeader}` | ||
| const outerOverlay = `#${selectors.outerOverlay}` | ||
| const outerTrigger = `#${selectors.outerTrigger}` | ||
| const innerClose = `#${selectors.innerClose}` | ||
| const innerHeader = `#${selectors.innerHeader}` | ||
| const innerTrigger = `#${selectors.innerTrigger}` | ||
| const innerOverlay = `#${selectors.innerOverlay}` | ||
|
|
||
| // https://github.com/stardust-ui/react/issues/1674 | ||
| describe('Dialog in Dialog', () => { | ||
| beforeEach(async () => { | ||
| await e2e.gotoTestCase(__filename, outerTrigger) | ||
| }) | ||
|
|
||
| it('An outer "Dialog" should be open after inner "Dialog" will be opened', async () => { | ||
| await e2e.clickOn(outerTrigger) | ||
| expect(await e2e.exists(outerHeader)).toBe(true) | ||
|
|
||
| await e2e.clickOn(innerTrigger) | ||
| expect(await e2e.exists(outerHeader)).toBe(true) | ||
| expect(await e2e.exists(innerHeader)).toBe(true) | ||
| }) | ||
|
|
||
| it('A click inside inner "Dialog" should not close dialogs', async () => { | ||
| await e2e.clickOn(outerTrigger) | ||
| await e2e.clickOn(innerTrigger) | ||
| await e2e.clickOn(innerHeader) | ||
|
|
||
| expect(await e2e.exists(outerHeader)).toBe(true) | ||
| expect(await e2e.exists(innerHeader)).toBe(true) | ||
| }) | ||
|
|
||
| it('A click on overlay should close only the last opened "Dialog"', async () => { | ||
| await e2e.clickOn(outerTrigger) | ||
| await e2e.clickOn(innerTrigger) | ||
|
|
||
| await e2e.clickOnPosition(innerOverlay, 0, 0) | ||
|
|
||
| expect(await e2e.exists(outerHeader)).toBe(true) | ||
| expect(await e2e.exists(innerHeader)).toBe(false) | ||
|
|
||
| await e2e.clickOnPosition(outerOverlay, 0, 0) | ||
| expect(await e2e.exists(outerHeader)).toBe(false) | ||
| expect(await e2e.exists(innerHeader)).toBe(false) | ||
| }) | ||
|
|
||
| it('A click on cancel button should close only matching "Dialog"', async () => { | ||
| await e2e.clickOn(outerTrigger) | ||
| await e2e.clickOn(innerTrigger) | ||
|
|
||
| await e2e.clickOn(innerClose) | ||
| expect(await e2e.exists(outerHeader)).toBe(true) | ||
| expect(await e2e.exists(innerHeader)).toBe(false) | ||
|
|
||
| await e2e.clickOn(outerClose) | ||
| expect(await e2e.exists(outerHeader)).toBe(false) | ||
| expect(await e2e.exists(innerHeader)).toBe(false) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import * as React from 'react' | ||
| import { Button, Dialog, Popup } from '@stardust-ui/react' | ||
|
|
||
| export const selectors = { | ||
| dialogCancel: 'dialog-cancel', | ||
| dialogHeader: Dialog.slotClassNames.header, | ||
| dialogOverlay: Dialog.slotClassNames.overlay, | ||
| dialogTrigger: 'dialog-trigger', | ||
| popupContent: Popup.Content.className, | ||
| popupTrigger: 'popup-trigger', | ||
| } | ||
|
|
||
| const DialogInPopupExample = () => ( | ||
| <Popup | ||
| content={ | ||
| <Dialog | ||
| cancelButton={{ content: 'Close', id: selectors.dialogCancel }} | ||
| header="A dialog" | ||
| trigger={<Button id={selectors.dialogTrigger} content="Open a dialog" />} | ||
| /> | ||
| } | ||
| trigger={<Button id={selectors.popupTrigger} content="Open a popup" />} | ||
| /> | ||
| ) | ||
|
|
||
| export default DialogInPopupExample |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import { selectors } from './dialogInPopup-example' | ||
|
|
||
| const dialogCancel = `#${selectors.dialogCancel}` | ||
| const dialogHeader = `.${selectors.dialogHeader}` | ||
| const dialogOverlay = `.${selectors.dialogOverlay}` | ||
| const dialogTrigger = `#${selectors.dialogTrigger}` | ||
| const popupContent = `.${selectors.popupContent}` | ||
| const popupTrigger = `#${selectors.popupTrigger}` | ||
|
|
||
| // https://github.com/stardust-ui/react/issues/1674 | ||
| describe('Dialog in Popup', () => { | ||
| beforeEach(async () => { | ||
| await e2e.gotoTestCase(__filename, popupTrigger) | ||
| }) | ||
|
|
||
| it('"Popup" should be open after "Dialog" will be opened', async () => { | ||
| await e2e.clickOn(popupTrigger) | ||
| expect(await e2e.exists(popupContent)).toBe(true) | ||
|
|
||
| await e2e.clickOn(dialogTrigger) | ||
| expect(await e2e.exists(popupContent)).toBe(true) | ||
| expect(await e2e.exists(dialogHeader)).toBe(true) | ||
| }) | ||
|
|
||
| it('"Popup" should be open after "Dialog" will be closed', async () => { | ||
| await e2e.clickOn(popupTrigger) | ||
| await e2e.clickOn(dialogTrigger) | ||
| await e2e.clickOn(dialogCancel) | ||
|
|
||
| expect(await e2e.exists(popupContent)).toBe(true) | ||
| expect(await e2e.exists(dialogHeader)).toBe(false) | ||
| }) | ||
|
|
||
| it('"Popup" and "Dialog" will be kept open on a click inside "Dialog"', async () => { | ||
| await e2e.clickOn(popupTrigger) | ||
| await e2e.clickOn(dialogTrigger) | ||
| await e2e.clickOn(dialogHeader) | ||
|
|
||
| expect(await e2e.exists(popupContent)).toBe(true) | ||
| expect(await e2e.exists(dialogHeader)).toBe(true) | ||
| }) | ||
|
|
||
| it('"Popup" will be kept open on a click inside "Dialog" overlay', async () => { | ||
| await e2e.clickOn(popupTrigger) | ||
| await e2e.clickOn(dialogTrigger) | ||
| await e2e.clickOnPosition(dialogOverlay, 0, 0) | ||
|
|
||
| expect(await e2e.exists(popupContent)).toBe(true) | ||
| expect(await e2e.exists(dialogHeader)).toBe(false) | ||
| }) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "extends": "../build/tsconfig.common.json", | ||
| "compilerOptions": { | ||
| "module": "esnext" | ||
| }, | ||
| "include": ["../packages/react/src", "../e2e", "../types"] | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ import * as React from 'react' | |
|
|
||
| export type GetContextRefs = (needleRef: NodeRef) => NodeRef[] | ||
| export type GetRefs = () => NodeRef[] | ||
| export type NodeRef<T extends Node = Node> = React.RefObject<T> | ||
| export type NodeRef<T extends Node = Node> = React.MutableRefObject<T> | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There refs are mutable, it allows to avoid usage of |
||
|
|
||
| export type NestingContextValue = { | ||
| getContextRefs: GetContextRefs | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add
tsconfig.jsonto get proper autocomplete