@wordpress/ui 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/README.md +4 -4
- package/build/alert-dialog/index.cjs +3 -0
- package/build/alert-dialog/index.cjs.map +2 -2
- package/build/alert-dialog/popup.cjs +120 -55
- package/build/alert-dialog/popup.cjs.map +3 -3
- package/build/alert-dialog/portal.cjs +38 -0
- package/build/alert-dialog/portal.cjs.map +7 -0
- package/build/alert-dialog/types.cjs.map +1 -1
- package/build/collapsible-card/content.cjs +9 -5
- package/build/collapsible-card/content.cjs.map +2 -2
- package/build/collapsible-card/header.cjs +14 -4
- package/build/collapsible-card/header.cjs.map +3 -3
- package/build/dialog/content.cjs +85 -0
- package/build/dialog/content.cjs.map +7 -0
- package/build/dialog/context.cjs +12 -44
- package/build/dialog/context.cjs.map +2 -2
- package/build/dialog/description.cjs +59 -0
- package/build/dialog/description.cjs.map +7 -0
- package/build/dialog/footer.cjs +5 -4
- package/build/dialog/footer.cjs.map +2 -2
- package/build/dialog/header.cjs +5 -4
- package/build/dialog/header.cjs.map +2 -2
- package/build/dialog/index.cjs +9 -0
- package/build/dialog/index.cjs.map +2 -2
- package/build/dialog/popup.cjs +21 -9
- package/build/dialog/popup.cjs.map +2 -2
- package/build/dialog/portal.cjs +38 -0
- package/build/dialog/portal.cjs.map +7 -0
- package/build/dialog/root.cjs +3 -2
- package/build/dialog/root.cjs.map +2 -2
- package/build/dialog/title.cjs +9 -6
- package/build/dialog/title.cjs.map +2 -2
- package/build/dialog/types.cjs.map +1 -1
- package/build/drawer/action.cjs +48 -0
- package/build/drawer/action.cjs.map +7 -0
- package/build/drawer/close-icon.cjs +58 -0
- package/build/drawer/close-icon.cjs.map +7 -0
- package/build/drawer/content.cjs +86 -0
- package/build/drawer/content.cjs.map +7 -0
- package/build/drawer/context.cjs +44 -0
- package/build/drawer/context.cjs.map +7 -0
- package/build/drawer/description.cjs +47 -0
- package/build/drawer/description.cjs.map +7 -0
- package/build/drawer/footer.cjs +65 -0
- package/build/drawer/footer.cjs.map +7 -0
- package/build/drawer/header.cjs +65 -0
- package/build/drawer/header.cjs.map +7 -0
- package/build/drawer/index.cjs +61 -0
- package/build/drawer/index.cjs.map +7 -0
- package/build/drawer/popup.cjs +103 -0
- package/build/drawer/popup.cjs.map +7 -0
- package/build/drawer/portal.cjs +38 -0
- package/build/drawer/portal.cjs.map +7 -0
- package/build/drawer/root.cjs +49 -0
- package/build/drawer/root.cjs.map +7 -0
- package/build/drawer/title.cjs +70 -0
- package/build/drawer/title.cjs.map +7 -0
- package/build/drawer/trigger.cjs +38 -0
- package/build/drawer/trigger.cjs.map +7 -0
- package/build/drawer/types.cjs +19 -0
- package/build/drawer/types.cjs.map +7 -0
- package/build/form/primitives/autocomplete/clear.cjs +62 -0
- package/build/form/primitives/autocomplete/clear.cjs.map +7 -0
- package/build/form/primitives/autocomplete/collection.cjs +38 -0
- package/build/form/primitives/autocomplete/collection.cjs.map +7 -0
- package/build/form/primitives/autocomplete/empty.cjs +67 -0
- package/build/form/primitives/autocomplete/empty.cjs.map +7 -0
- package/build/form/primitives/autocomplete/index.cjs +64 -0
- package/build/form/primitives/autocomplete/index.cjs.map +7 -0
- package/build/form/primitives/autocomplete/input-group.cjs +36 -0
- package/build/form/primitives/autocomplete/input-group.cjs.map +7 -0
- package/build/form/primitives/autocomplete/input.cjs +47 -0
- package/build/form/primitives/autocomplete/input.cjs.map +7 -0
- package/build/form/primitives/autocomplete/item.cjs +81 -0
- package/build/form/primitives/autocomplete/item.cjs.map +7 -0
- package/build/form/primitives/autocomplete/list-body.cjs +57 -0
- package/build/form/primitives/autocomplete/list-body.cjs.map +7 -0
- package/build/form/primitives/autocomplete/list.cjs +67 -0
- package/build/form/primitives/autocomplete/list.cjs.map +7 -0
- package/build/form/primitives/autocomplete/popup.cjs +102 -0
- package/build/form/primitives/autocomplete/popup.cjs.map +7 -0
- package/build/form/primitives/autocomplete/portal.cjs +38 -0
- package/build/form/primitives/autocomplete/portal.cjs.map +7 -0
- package/build/form/primitives/autocomplete/root.cjs +35 -0
- package/build/form/primitives/autocomplete/root.cjs.map +7 -0
- package/build/form/primitives/autocomplete/types.cjs +19 -0
- package/build/form/primitives/autocomplete/types.cjs.map +7 -0
- package/build/form/primitives/autocomplete/value.cjs +35 -0
- package/build/form/primitives/autocomplete/value.cjs.map +7 -0
- package/build/form/primitives/index.cjs +3 -0
- package/build/form/primitives/index.cjs.map +2 -2
- package/build/form/primitives/select/index.cjs +3 -0
- package/build/form/primitives/select/index.cjs.map +2 -2
- package/build/form/primitives/select/item.cjs +4 -5
- package/build/form/primitives/select/item.cjs.map +2 -2
- package/build/form/primitives/select/popup.cjs +12 -11
- package/build/form/primitives/select/popup.cjs.map +2 -2
- package/build/form/primitives/select/portal.cjs +38 -0
- package/build/form/primitives/select/portal.cjs.map +7 -0
- package/build/form/primitives/select/types.cjs.map +1 -1
- package/build/index.cjs +3 -0
- package/build/index.cjs.map +2 -2
- package/build/link/link.cjs +8 -18
- package/build/link/link.cjs.map +2 -2
- package/build/link/types.cjs.map +1 -1
- package/build/notice/action-button.cjs +3 -3
- package/build/notice/action-button.cjs.map +2 -2
- package/build/notice/action-link.cjs +8 -7
- package/build/notice/action-link.cjs.map +2 -2
- package/build/notice/actions.cjs +3 -3
- package/build/notice/actions.cjs.map +2 -2
- package/build/notice/close-icon.cjs +3 -3
- package/build/notice/close-icon.cjs.map +2 -2
- package/build/notice/description.cjs +3 -3
- package/build/notice/description.cjs.map +2 -2
- package/build/notice/root.cjs +3 -3
- package/build/notice/root.cjs.map +2 -2
- package/build/notice/title.cjs +3 -3
- package/build/notice/title.cjs.map +2 -2
- package/build/popover/arrow.cjs +4 -4
- package/build/popover/arrow.cjs.map +2 -2
- package/build/popover/context.cjs +4 -44
- package/build/popover/context.cjs.map +2 -2
- package/build/popover/description.cjs +1 -24
- package/build/popover/description.cjs.map +4 -4
- package/build/popover/index.cjs +3 -0
- package/build/popover/index.cjs.map +2 -2
- package/build/popover/popup.cjs +15 -15
- package/build/popover/popup.cjs.map +2 -2
- package/build/popover/portal.cjs +38 -0
- package/build/popover/portal.cjs.map +7 -0
- package/build/popover/root.cjs.map +1 -1
- package/build/popover/title.cjs +18 -4
- package/build/popover/title.cjs.map +3 -3
- package/build/popover/types.cjs.map +1 -1
- package/build/tabs/context.cjs +9 -22
- package/build/tabs/context.cjs.map +2 -2
- package/build/tabs/list.cjs +4 -4
- package/build/tabs/list.cjs.map +2 -2
- package/build/tabs/panel.cjs +19 -6
- package/build/tabs/panel.cjs.map +3 -3
- package/build/tabs/tab.cjs +4 -4
- package/build/tabs/tab.cjs.map +2 -2
- package/build/text/text.cjs +2 -2
- package/build/text/text.cjs.map +2 -2
- package/build/tooltip/index.cjs +3 -0
- package/build/tooltip/index.cjs.map +2 -2
- package/build/tooltip/popup.cjs +11 -14
- package/build/tooltip/popup.cjs.map +3 -3
- package/build/tooltip/portal.cjs +38 -0
- package/build/tooltip/portal.cjs.map +7 -0
- package/build/tooltip/provider.cjs +2 -2
- package/build/tooltip/provider.cjs.map +3 -3
- package/build/tooltip/root.cjs.map +3 -3
- package/build/tooltip/trigger.cjs +2 -2
- package/build/tooltip/trigger.cjs.map +3 -3
- package/build/tooltip/types.cjs.map +1 -1
- package/build/utils/create-overlay-modal-context.cjs +48 -0
- package/build/utils/create-overlay-modal-context.cjs.map +7 -0
- package/build/utils/create-overlay-title-validation.cjs +93 -0
- package/build/utils/create-overlay-title-validation.cjs.map +7 -0
- package/build/utils/render-portal-with-children.cjs +37 -0
- package/build/utils/render-portal-with-children.cjs.map +7 -0
- package/build/utils/use-deprioritized-initial-focus.cjs +8 -8
- package/build/utils/use-deprioritized-initial-focus.cjs.map +2 -2
- package/build/utils/use-overlay-scroll-state-attributes.cjs +140 -0
- package/build/utils/use-overlay-scroll-state-attributes.cjs.map +7 -0
- package/build/utils/use-schedule-validation.cjs +59 -0
- package/build/utils/use-schedule-validation.cjs.map +7 -0
- package/build/visually-hidden/visually-hidden.cjs +5 -1
- package/build/visually-hidden/visually-hidden.cjs.map +2 -2
- package/build-module/alert-dialog/index.mjs +2 -0
- package/build-module/alert-dialog/index.mjs.map +2 -2
- package/build-module/alert-dialog/popup.mjs +124 -56
- package/build-module/alert-dialog/popup.mjs.map +3 -3
- package/build-module/alert-dialog/portal.mjs +13 -0
- package/build-module/alert-dialog/portal.mjs.map +7 -0
- package/build-module/collapsible-card/content.mjs +9 -5
- package/build-module/collapsible-card/content.mjs.map +2 -2
- package/build-module/collapsible-card/header.mjs +14 -4
- package/build-module/collapsible-card/header.mjs.map +3 -3
- package/build-module/dialog/content.mjs +50 -0
- package/build-module/dialog/content.mjs.map +7 -0
- package/build-module/dialog/context.mjs +10 -51
- package/build-module/dialog/context.mjs.map +2 -2
- package/build-module/dialog/description.mjs +34 -0
- package/build-module/dialog/description.mjs.map +7 -0
- package/build-module/dialog/footer.mjs +5 -4
- package/build-module/dialog/footer.mjs.map +2 -2
- package/build-module/dialog/header.mjs +5 -4
- package/build-module/dialog/header.mjs.map +2 -2
- package/build-module/dialog/index.mjs +6 -0
- package/build-module/dialog/index.mjs.map +2 -2
- package/build-module/dialog/popup.mjs +23 -11
- package/build-module/dialog/popup.mjs.map +2 -2
- package/build-module/dialog/portal.mjs +13 -0
- package/build-module/dialog/portal.mjs.map +7 -0
- package/build-module/dialog/root.mjs +3 -2
- package/build-module/dialog/root.mjs.map +2 -2
- package/build-module/dialog/title.mjs +10 -7
- package/build-module/dialog/title.mjs.map +2 -2
- package/build-module/drawer/action.mjs +23 -0
- package/build-module/drawer/action.mjs.map +7 -0
- package/build-module/drawer/close-icon.mjs +33 -0
- package/build-module/drawer/close-icon.mjs.map +7 -0
- package/build-module/drawer/content.mjs +51 -0
- package/build-module/drawer/content.mjs.map +7 -0
- package/build-module/drawer/context.mjs +16 -0
- package/build-module/drawer/context.mjs.map +7 -0
- package/build-module/drawer/description.mjs +22 -0
- package/build-module/drawer/description.mjs.map +7 -0
- package/build-module/drawer/footer.mjs +30 -0
- package/build-module/drawer/footer.mjs.map +7 -0
- package/build-module/drawer/header.mjs +30 -0
- package/build-module/drawer/header.mjs.map +7 -0
- package/build-module/drawer/index.mjs +26 -0
- package/build-module/drawer/index.mjs.map +7 -0
- package/build-module/drawer/popup.mjs +70 -0
- package/build-module/drawer/popup.mjs.map +7 -0
- package/build-module/drawer/portal.mjs +13 -0
- package/build-module/drawer/portal.mjs.map +7 -0
- package/build-module/drawer/root.mjs +24 -0
- package/build-module/drawer/root.mjs.map +7 -0
- package/build-module/drawer/title.mjs +45 -0
- package/build-module/drawer/title.mjs.map +7 -0
- package/build-module/drawer/trigger.mjs +13 -0
- package/build-module/drawer/trigger.mjs.map +7 -0
- package/build-module/drawer/types.mjs +1 -0
- package/build-module/form/primitives/autocomplete/clear.mjs +37 -0
- package/build-module/form/primitives/autocomplete/clear.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/collection.mjs +13 -0
- package/build-module/form/primitives/autocomplete/collection.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/empty.mjs +32 -0
- package/build-module/form/primitives/autocomplete/empty.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/index.mjs +28 -0
- package/build-module/form/primitives/autocomplete/index.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/input-group.mjs +11 -0
- package/build-module/form/primitives/autocomplete/input-group.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/input.mjs +22 -0
- package/build-module/form/primitives/autocomplete/input.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/item.mjs +46 -0
- package/build-module/form/primitives/autocomplete/item.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/list-body.mjs +32 -0
- package/build-module/form/primitives/autocomplete/list-body.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/list.mjs +32 -0
- package/build-module/form/primitives/autocomplete/list.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/popup.mjs +69 -0
- package/build-module/form/primitives/autocomplete/popup.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/portal.mjs +13 -0
- package/build-module/form/primitives/autocomplete/portal.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/root.mjs +10 -0
- package/build-module/form/primitives/autocomplete/root.mjs.map +7 -0
- package/build-module/form/primitives/autocomplete/types.mjs +1 -0
- package/build-module/form/primitives/autocomplete/value.mjs +10 -0
- package/build-module/form/primitives/autocomplete/value.mjs.map +7 -0
- package/build-module/form/primitives/index.mjs +2 -0
- package/build-module/form/primitives/index.mjs.map +2 -2
- package/build-module/form/primitives/select/index.mjs +2 -0
- package/build-module/form/primitives/select/index.mjs.map +2 -2
- package/build-module/form/primitives/select/item.mjs +4 -5
- package/build-module/form/primitives/select/item.mjs.map +2 -2
- package/build-module/form/primitives/select/popup.mjs +12 -11
- package/build-module/form/primitives/select/popup.mjs.map +2 -2
- package/build-module/form/primitives/select/portal.mjs +13 -0
- package/build-module/form/primitives/select/portal.mjs.map +7 -0
- package/build-module/index.mjs +2 -0
- package/build-module/index.mjs.map +2 -2
- package/build-module/link/link.mjs +8 -18
- package/build-module/link/link.mjs.map +2 -2
- package/build-module/notice/action-button.mjs +3 -3
- package/build-module/notice/action-button.mjs.map +2 -2
- package/build-module/notice/action-link.mjs +8 -7
- package/build-module/notice/action-link.mjs.map +2 -2
- package/build-module/notice/actions.mjs +3 -3
- package/build-module/notice/actions.mjs.map +2 -2
- package/build-module/notice/close-icon.mjs +3 -3
- package/build-module/notice/close-icon.mjs.map +2 -2
- package/build-module/notice/description.mjs +3 -3
- package/build-module/notice/description.mjs.map +2 -2
- package/build-module/notice/root.mjs +3 -3
- package/build-module/notice/root.mjs.map +2 -2
- package/build-module/notice/title.mjs +3 -3
- package/build-module/notice/title.mjs.map +2 -2
- package/build-module/popover/arrow.mjs +4 -4
- package/build-module/popover/arrow.mjs.map +2 -2
- package/build-module/popover/context.mjs +4 -51
- package/build-module/popover/context.mjs.map +2 -2
- package/build-module/popover/description.mjs +1 -14
- package/build-module/popover/description.mjs.map +3 -3
- package/build-module/popover/index.mjs +2 -0
- package/build-module/popover/index.mjs.map +2 -2
- package/build-module/popover/popup.mjs +16 -16
- package/build-module/popover/popup.mjs.map +2 -2
- package/build-module/popover/portal.mjs +13 -0
- package/build-module/popover/portal.mjs.map +7 -0
- package/build-module/popover/root.mjs.map +1 -1
- package/build-module/popover/title.mjs +19 -5
- package/build-module/popover/title.mjs.map +3 -3
- package/build-module/tabs/context.mjs +11 -24
- package/build-module/tabs/context.mjs.map +2 -2
- package/build-module/tabs/list.mjs +4 -4
- package/build-module/tabs/list.mjs.map +2 -2
- package/build-module/tabs/panel.mjs +19 -6
- package/build-module/tabs/panel.mjs.map +3 -3
- package/build-module/tabs/tab.mjs +4 -4
- package/build-module/tabs/tab.mjs.map +2 -2
- package/build-module/text/text.mjs +2 -2
- package/build-module/text/text.mjs.map +2 -2
- package/build-module/tooltip/index.mjs +2 -0
- package/build-module/tooltip/index.mjs.map +2 -2
- package/build-module/tooltip/popup.mjs +14 -17
- package/build-module/tooltip/popup.mjs.map +2 -2
- package/build-module/tooltip/portal.mjs +13 -0
- package/build-module/tooltip/portal.mjs.map +7 -0
- package/build-module/tooltip/provider.mjs +3 -3
- package/build-module/tooltip/provider.mjs.map +2 -2
- package/build-module/tooltip/root.mjs +2 -2
- package/build-module/tooltip/root.mjs.map +2 -2
- package/build-module/tooltip/trigger.mjs +3 -3
- package/build-module/tooltip/trigger.mjs.map +2 -2
- package/build-module/utils/create-overlay-modal-context.mjs +23 -0
- package/build-module/utils/create-overlay-modal-context.mjs.map +7 -0
- package/build-module/utils/create-overlay-title-validation.mjs +75 -0
- package/build-module/utils/create-overlay-title-validation.mjs.map +7 -0
- package/build-module/utils/render-portal-with-children.mjs +12 -0
- package/build-module/utils/render-portal-with-children.mjs.map +7 -0
- package/build-module/utils/use-deprioritized-initial-focus.mjs +9 -9
- package/build-module/utils/use-deprioritized-initial-focus.mjs.map +2 -2
- package/build-module/utils/use-overlay-scroll-state-attributes.mjs +114 -0
- package/build-module/utils/use-overlay-scroll-state-attributes.mjs.map +7 -0
- package/build-module/utils/use-schedule-validation.mjs +34 -0
- package/build-module/utils/use-schedule-validation.mjs.map +7 -0
- package/build-module/visually-hidden/visually-hidden.mjs +5 -1
- package/build-module/visually-hidden/visually-hidden.mjs.map +2 -2
- package/build-types/alert-dialog/index.d.ts +1 -0
- package/build-types/alert-dialog/index.d.ts.map +1 -1
- package/build-types/alert-dialog/popup.d.ts.map +1 -1
- package/build-types/alert-dialog/portal.d.ts +9 -0
- package/build-types/alert-dialog/portal.d.ts.map +1 -0
- package/build-types/alert-dialog/stories/index.story.d.ts +29 -1
- package/build-types/alert-dialog/stories/index.story.d.ts.map +1 -1
- package/build-types/alert-dialog/types.d.ts +25 -3
- package/build-types/alert-dialog/types.d.ts.map +1 -1
- package/build-types/badge/stories/index.story.d.ts.map +1 -1
- package/build-types/card/stories/index.story.d.ts.map +1 -1
- package/build-types/collapsible/stories/index.story.d.ts.map +1 -1
- package/build-types/collapsible-card/content.d.ts.map +1 -1
- package/build-types/collapsible-card/header.d.ts.map +1 -1
- package/build-types/collapsible-card/stories/index.story.d.ts.map +1 -1
- package/build-types/dialog/content.d.ts +17 -0
- package/build-types/dialog/content.d.ts.map +1 -0
- package/build-types/dialog/context.d.ts +11 -16
- package/build-types/dialog/context.d.ts.map +1 -1
- package/build-types/dialog/description.d.ts +9 -0
- package/build-types/dialog/description.d.ts.map +1 -0
- package/build-types/dialog/footer.d.ts +8 -1
- package/build-types/dialog/footer.d.ts.map +1 -1
- package/build-types/dialog/header.d.ts +8 -1
- package/build-types/dialog/header.d.ts.map +1 -1
- package/build-types/dialog/index.d.ts +4 -1
- package/build-types/dialog/index.d.ts.map +1 -1
- package/build-types/dialog/popup.d.ts +3 -0
- package/build-types/dialog/popup.d.ts.map +1 -1
- package/build-types/dialog/portal.d.ts +10 -0
- package/build-types/dialog/portal.d.ts.map +1 -0
- package/build-types/dialog/root.d.ts +14 -4
- package/build-types/dialog/root.d.ts.map +1 -1
- package/build-types/dialog/stories/index.story.d.ts +29 -6
- package/build-types/dialog/stories/index.story.d.ts.map +1 -1
- package/build-types/dialog/title.d.ts.map +1 -1
- package/build-types/dialog/types.d.ts +60 -7
- package/build-types/dialog/types.d.ts.map +1 -1
- package/build-types/drawer/action.d.ts +8 -0
- package/build-types/drawer/action.d.ts.map +1 -0
- package/build-types/drawer/close-icon.d.ts +8 -0
- package/build-types/drawer/close-icon.d.ts.map +1 -0
- package/build-types/drawer/content.d.ts +21 -0
- package/build-types/drawer/content.d.ts.map +1 -0
- package/build-types/drawer/context.d.ts +20 -0
- package/build-types/drawer/context.d.ts.map +1 -0
- package/build-types/drawer/description.d.ts +9 -0
- package/build-types/drawer/description.d.ts.map +1 -0
- package/build-types/drawer/footer.d.ts +15 -0
- package/build-types/drawer/footer.d.ts.map +1 -0
- package/build-types/drawer/header.d.ts +15 -0
- package/build-types/drawer/header.d.ts.map +1 -0
- package/build-types/drawer/index.d.ts +13 -0
- package/build-types/drawer/index.d.ts.map +1 -0
- package/build-types/drawer/popup.d.ts +16 -0
- package/build-types/drawer/popup.d.ts.map +1 -0
- package/build-types/drawer/portal.d.ts +10 -0
- package/build-types/drawer/portal.d.ts.map +1 -0
- package/build-types/drawer/root.d.ts +21 -0
- package/build-types/drawer/root.d.ts.map +1 -0
- package/build-types/drawer/stories/index.story.d.ts +63 -0
- package/build-types/drawer/stories/index.story.d.ts.map +1 -0
- package/build-types/drawer/test/index.test.d.ts +2 -0
- package/build-types/drawer/test/index.test.d.ts.map +1 -0
- package/build-types/drawer/title.d.ts +22 -0
- package/build-types/drawer/title.d.ts.map +1 -0
- package/build-types/drawer/trigger.d.ts +7 -0
- package/build-types/drawer/trigger.d.ts.map +1 -0
- package/build-types/drawer/types.d.ts +146 -0
- package/build-types/drawer/types.d.ts.map +1 -0
- package/build-types/empty-state/stories/index.story.d.ts +1 -1
- package/build-types/empty-state/stories/index.story.d.ts.map +1 -1
- package/build-types/form/input-control/stories/index.story.d.ts +1 -1
- package/build-types/form/input-control/stories/index.story.d.ts.map +1 -1
- package/build-types/form/primitives/autocomplete/clear.d.ts +13 -0
- package/build-types/form/primitives/autocomplete/clear.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/collection.d.ts +3 -0
- package/build-types/form/primitives/autocomplete/collection.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/empty.d.ts +10 -0
- package/build-types/form/primitives/autocomplete/empty.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/index.d.ts +13 -0
- package/build-types/form/primitives/autocomplete/index.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/input-group.d.ts +16 -0
- package/build-types/form/primitives/autocomplete/input-group.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/input.d.ts +3 -0
- package/build-types/form/primitives/autocomplete/input.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/item.d.ts +10 -0
- package/build-types/form/primitives/autocomplete/item.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/list-body.d.ts +13 -0
- package/build-types/form/primitives/autocomplete/list-body.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/list.d.ts +11 -0
- package/build-types/form/primitives/autocomplete/list.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/popup.d.ts +11 -0
- package/build-types/form/primitives/autocomplete/popup.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/portal.d.ts +8 -0
- package/build-types/form/primitives/autocomplete/portal.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/root.d.ts +8 -0
- package/build-types/form/primitives/autocomplete/root.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/stories/fixtures.d.ts +8 -0
- package/build-types/form/primitives/autocomplete/stories/fixtures.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/stories/index.story.d.ts +41 -0
- package/build-types/form/primitives/autocomplete/stories/index.story.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/test/index.test.d.ts +2 -0
- package/build-types/form/primitives/autocomplete/test/index.test.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/types.d.ts +44 -0
- package/build-types/form/primitives/autocomplete/types.d.ts.map +1 -0
- package/build-types/form/primitives/autocomplete/value.d.ts +3 -0
- package/build-types/form/primitives/autocomplete/value.d.ts.map +1 -0
- package/build-types/form/primitives/field/stories/index.story.d.ts +1 -1
- package/build-types/form/primitives/field/stories/index.story.d.ts.map +1 -1
- package/build-types/form/primitives/fieldset/stories/index.story.d.ts +1 -1
- package/build-types/form/primitives/fieldset/stories/index.story.d.ts.map +1 -1
- package/build-types/form/primitives/index.d.ts +1 -0
- package/build-types/form/primitives/index.d.ts.map +1 -1
- package/build-types/form/primitives/input/stories/index.story.d.ts +1 -1
- package/build-types/form/primitives/input/stories/index.story.d.ts.map +1 -1
- package/build-types/form/primitives/input-layout/stories/index.story.d.ts +1 -1
- package/build-types/form/primitives/input-layout/stories/index.story.d.ts.map +1 -1
- package/build-types/form/primitives/select/index.d.ts +1 -0
- package/build-types/form/primitives/select/index.d.ts.map +1 -1
- package/build-types/form/primitives/select/item.d.ts.map +1 -1
- package/build-types/form/primitives/select/popup.d.ts +1 -2
- package/build-types/form/primitives/select/popup.d.ts.map +1 -1
- package/build-types/form/primitives/select/portal.d.ts +8 -0
- package/build-types/form/primitives/select/portal.d.ts.map +1 -0
- package/build-types/form/primitives/select/stories/index.story.d.ts +14 -6
- package/build-types/form/primitives/select/stories/index.story.d.ts.map +1 -1
- package/build-types/form/primitives/select/types.d.ts +7 -2
- package/build-types/form/primitives/select/types.d.ts.map +1 -1
- package/build-types/index.d.ts +1 -0
- package/build-types/index.d.ts.map +1 -1
- package/build-types/link/link.d.ts.map +1 -1
- package/build-types/link/stories/index.story.d.ts +2 -3
- package/build-types/link/stories/index.story.d.ts.map +1 -1
- package/build-types/link/types.d.ts +1 -2
- package/build-types/link/types.d.ts.map +1 -1
- package/build-types/notice/action-link.d.ts.map +1 -1
- package/build-types/popover/context.d.ts +6 -13
- package/build-types/popover/context.d.ts.map +1 -1
- package/build-types/popover/description.d.ts +0 -1
- package/build-types/popover/description.d.ts.map +1 -1
- package/build-types/popover/index.d.ts +2 -1
- package/build-types/popover/index.d.ts.map +1 -1
- package/build-types/popover/popup.d.ts +3 -2
- package/build-types/popover/popup.d.ts.map +1 -1
- package/build-types/popover/portal.d.ts +9 -0
- package/build-types/popover/portal.d.ts.map +1 -0
- package/build-types/popover/root.d.ts +2 -2
- package/build-types/popover/stories/index.story.d.ts +23 -15
- package/build-types/popover/stories/index.story.d.ts.map +1 -1
- package/build-types/popover/title.d.ts.map +1 -1
- package/build-types/popover/types.d.ts +8 -15
- package/build-types/popover/types.d.ts.map +1 -1
- package/build-types/stack/stories/index.story.d.ts.map +1 -1
- package/build-types/tabs/context.d.ts.map +1 -1
- package/build-types/tabs/panel.d.ts.map +1 -1
- package/build-types/tabs/stories/index.story.d.ts +1 -1
- package/build-types/tabs/stories/index.story.d.ts.map +1 -1
- package/build-types/text/stories/index.story.d.ts.map +1 -1
- package/build-types/tooltip/index.d.ts +2 -1
- package/build-types/tooltip/index.d.ts.map +1 -1
- package/build-types/tooltip/popup.d.ts.map +1 -1
- package/build-types/tooltip/portal.d.ts +8 -0
- package/build-types/tooltip/portal.d.ts.map +1 -0
- package/build-types/tooltip/provider.d.ts +1 -1
- package/build-types/tooltip/provider.d.ts.map +1 -1
- package/build-types/tooltip/stories/index.story.d.ts +18 -1
- package/build-types/tooltip/stories/index.story.d.ts.map +1 -1
- package/build-types/tooltip/stories/usage-guidelines.story.d.ts.map +1 -1
- package/build-types/tooltip/trigger.d.ts.map +1 -1
- package/build-types/tooltip/types.d.ts +11 -7
- package/build-types/tooltip/types.d.ts.map +1 -1
- package/build-types/utils/create-overlay-modal-context.d.ts +14 -0
- package/build-types/utils/create-overlay-modal-context.d.ts.map +1 -0
- package/build-types/utils/create-overlay-title-validation.d.ts +15 -0
- package/build-types/utils/create-overlay-title-validation.d.ts.map +1 -0
- package/build-types/utils/render-portal-with-children.d.ts +16 -0
- package/build-types/utils/render-portal-with-children.d.ts.map +1 -0
- package/build-types/utils/use-deprioritized-initial-focus.d.ts +9 -8
- package/build-types/utils/use-deprioritized-initial-focus.d.ts.map +1 -1
- package/build-types/utils/use-overlay-scroll-state-attributes.d.ts +85 -0
- package/build-types/utils/use-overlay-scroll-state-attributes.d.ts.map +1 -0
- package/build-types/utils/use-schedule-validation.d.ts +13 -0
- package/build-types/utils/use-schedule-validation.d.ts.map +1 -0
- package/build-types/visually-hidden/stories/index.story.d.ts.map +1 -1
- package/build-types/visually-hidden/visually-hidden.d.ts +4 -20
- package/build-types/visually-hidden/visually-hidden.d.ts.map +1 -1
- package/package.json +12 -12
- package/src/alert-dialog/index.ts +1 -0
- package/src/alert-dialog/popup.tsx +114 -45
- package/src/alert-dialog/portal.tsx +17 -0
- package/src/alert-dialog/stories/index.story.tsx +123 -3
- package/src/alert-dialog/style.module.css +13 -4
- package/src/alert-dialog/test/index.test.tsx +329 -3
- package/src/alert-dialog/types.ts +30 -3
- package/src/badge/stories/choosing-intent.story.tsx +1 -1
- package/src/badge/stories/index.story.tsx +1 -0
- package/src/card/stories/index.story.tsx +1 -0
- package/src/collapsible/stories/index.story.tsx +1 -0
- package/src/collapsible-card/content.tsx +12 -1
- package/src/collapsible-card/header.tsx +2 -0
- package/src/collapsible-card/stories/index.story.tsx +1 -0
- package/src/collapsible-card/style.module.css +16 -4
- package/src/dialog/content.tsx +47 -0
- package/src/dialog/context.tsx +14 -98
- package/src/dialog/description.tsx +27 -0
- package/src/dialog/footer.tsx +10 -2
- package/src/dialog/header.tsx +10 -2
- package/src/dialog/index.ts +16 -1
- package/src/dialog/popup.tsx +28 -8
- package/src/dialog/portal.tsx +18 -0
- package/src/dialog/root.tsx +22 -5
- package/src/dialog/stories/index.story.tsx +195 -51
- package/src/dialog/style.module.css +73 -23
- package/src/dialog/test/index.test.tsx +849 -149
- package/src/dialog/title.tsx +6 -4
- package/src/dialog/types.ts +64 -6
- package/src/drawer/action.tsx +28 -0
- package/src/drawer/close-icon.tsx +33 -0
- package/src/drawer/content.tsx +50 -0
- package/src/drawer/context.tsx +29 -0
- package/src/drawer/description.tsx +25 -0
- package/src/drawer/footer.tsx +34 -0
- package/src/drawer/header.tsx +34 -0
- package/src/drawer/index.ts +25 -0
- package/src/drawer/popup.tsx +100 -0
- package/src/drawer/portal.tsx +18 -0
- package/src/drawer/root.tsx +41 -0
- package/src/drawer/stories/index.story.tsx +543 -0
- package/src/drawer/style.module.css +324 -0
- package/src/drawer/test/index.test.tsx +1097 -0
- package/src/drawer/title.tsx +53 -0
- package/src/drawer/trigger.tsx +14 -0
- package/src/drawer/types.ts +174 -0
- package/src/empty-state/stories/index.story.tsx +2 -1
- package/src/form/input-control/stories/index.story.tsx +4 -1
- package/src/form/primitives/autocomplete/clear.tsx +35 -0
- package/src/form/primitives/autocomplete/collection.tsx +13 -0
- package/src/form/primitives/autocomplete/empty.tsx +17 -0
- package/src/form/primitives/autocomplete/index.ts +12 -0
- package/src/form/primitives/autocomplete/input-group.tsx +16 -0
- package/src/form/primitives/autocomplete/input.tsx +20 -0
- package/src/form/primitives/autocomplete/item.tsx +24 -0
- package/src/form/primitives/autocomplete/list-body.tsx +23 -0
- package/src/form/primitives/autocomplete/list.tsx +17 -0
- package/src/form/primitives/autocomplete/popup.tsx +42 -0
- package/src/form/primitives/autocomplete/portal.tsx +16 -0
- package/src/form/primitives/autocomplete/root.tsx +11 -0
- package/src/form/primitives/autocomplete/stories/fixtures.ts +35 -0
- package/src/form/primitives/autocomplete/stories/index.story.tsx +437 -0
- package/src/form/primitives/autocomplete/style.module.css +7 -0
- package/src/form/primitives/autocomplete/test/index.test.tsx +162 -0
- package/src/form/primitives/autocomplete/types.ts +74 -0
- package/src/form/primitives/autocomplete/value.tsx +6 -0
- package/src/form/primitives/field/stories/index.story.tsx +1 -1
- package/src/form/primitives/fieldset/stories/index.story.tsx +1 -1
- package/src/form/primitives/index.ts +1 -0
- package/src/form/primitives/input/stories/index.story.tsx +2 -1
- package/src/form/primitives/input-layout/stories/index.story.tsx +2 -1
- package/src/form/primitives/select/index.ts +1 -0
- package/src/form/primitives/select/item.tsx +0 -1
- package/src/form/primitives/select/popup.tsx +34 -37
- package/src/form/primitives/select/portal.tsx +16 -0
- package/src/form/primitives/select/stories/index.story.tsx +21 -7
- package/src/form/primitives/select/test/index.test.tsx +7 -3
- package/src/form/primitives/select/types.ts +9 -2
- package/src/index.ts +1 -0
- package/src/link/link.tsx +12 -26
- package/src/link/stories/index.story.tsx +6 -11
- package/src/link/style.module.css +5 -17
- package/src/link/test/index.test.tsx +31 -27
- package/src/link/types.ts +1 -2
- package/src/notice/action-link.tsx +7 -4
- package/src/notice/style.module.css +5 -5
- package/src/popover/context.tsx +6 -89
- package/src/popover/description.tsx +1 -5
- package/src/popover/index.ts +2 -1
- package/src/popover/popup.tsx +17 -15
- package/src/popover/portal.tsx +17 -0
- package/src/popover/root.tsx +2 -2
- package/src/popover/stories/index.story.tsx +56 -25
- package/src/popover/style.module.css +33 -4
- package/src/popover/test/index.test.tsx +189 -74
- package/src/popover/title.tsx +9 -5
- package/src/popover/types.ts +10 -15
- package/src/stack/stories/index.story.tsx +1 -0
- package/src/tabs/context.tsx +14 -34
- package/src/tabs/panel.tsx +7 -2
- package/src/tabs/stories/index.story.tsx +2 -1
- package/src/tabs/style.module.css +0 -17
- package/src/tabs/test/index.test.tsx +7 -3
- package/src/text/stories/index.story.tsx +1 -0
- package/src/text/text.tsx +2 -2
- package/src/tooltip/index.ts +2 -1
- package/src/tooltip/popup.tsx +24 -28
- package/src/tooltip/portal.tsx +16 -0
- package/src/tooltip/provider.tsx +3 -3
- package/src/tooltip/root.tsx +2 -2
- package/src/tooltip/stories/index.story.tsx +39 -1
- package/src/tooltip/stories/usage-guidelines.story.tsx +5 -1
- package/src/tooltip/style.module.css +12 -0
- package/src/tooltip/test/index.test.tsx +9 -3
- package/src/tooltip/trigger.tsx +3 -7
- package/src/tooltip/types.ts +13 -7
- package/src/utils/create-overlay-modal-context.tsx +34 -0
- package/src/utils/create-overlay-title-validation.tsx +116 -0
- package/src/utils/css/item-popup.module.css +9 -11
- package/src/utils/css/overlay-chrome.module.css +222 -0
- package/src/utils/render-portal-with-children.ts +27 -0
- package/src/utils/test/use-deprioritized-initial-focus.test.tsx +3 -3
- package/src/utils/use-deprioritized-initial-focus.ts +23 -17
- package/src/utils/use-overlay-scroll-state-attributes.ts +272 -0
- package/src/utils/use-schedule-validation.ts +45 -0
- package/src/visually-hidden/stories/index.story.tsx +1 -0
- package/src/visually-hidden/visually-hidden.tsx +9 -21
- package/build/types/css-modules.d.cjs +0 -2
- package/build/types/react.d.cjs +0 -5
- package/build/types/react.d.cjs.map +0 -7
- package/build-module/types/css-modules.d.mjs +0 -1
- package/build-module/types/react.d.mjs +0 -3
- package/build-module/types/react.d.mjs.map +0 -7
- package/src/types/css-modules.d.ts +0 -4
- package/src/types/react.d.ts +0 -7
- /package/build-module/{types/css-modules.d.mjs.map → drawer/types.mjs.map} +0 -0
- /package/{build/types/css-modules.d.cjs.map → build-module/form/primitives/autocomplete/types.mjs.map} +0 -0
|
@@ -1,36 +1,19 @@
|
|
|
1
|
-
import { render, screen, waitFor } from '@testing-library/react';
|
|
1
|
+
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
|
-
import {
|
|
4
|
-
import type { ReactNode } from 'react';
|
|
3
|
+
import { createRef, useState } from '@wordpress/element';
|
|
5
4
|
import * as Dialog from '../index';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
static getDerivedStateFromError() {
|
|
20
|
-
return { hasError: true };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
componentDidCatch( error: Error ) {
|
|
24
|
-
this.props.onError( error );
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
render() {
|
|
28
|
-
if ( this.state.hasError ) {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return this.props.children;
|
|
33
|
-
}
|
|
6
|
+
function collectUncaughtErrors() {
|
|
7
|
+
const errors: Error[] = [];
|
|
8
|
+
const handler = ( event: ErrorEvent ) => {
|
|
9
|
+
event.preventDefault();
|
|
10
|
+
errors.push( event.error );
|
|
11
|
+
};
|
|
12
|
+
window.addEventListener( 'error', handler );
|
|
13
|
+
return {
|
|
14
|
+
errors,
|
|
15
|
+
cleanup: () => window.removeEventListener( 'error', handler ),
|
|
16
|
+
};
|
|
34
17
|
}
|
|
35
18
|
|
|
36
19
|
describe( 'Dialog', () => {
|
|
@@ -39,10 +22,12 @@ describe( 'Dialog', () => {
|
|
|
39
22
|
const triggerRef = createRef< HTMLButtonElement >();
|
|
40
23
|
const popupRef = createRef< HTMLDivElement >();
|
|
41
24
|
const actionRef = createRef< HTMLButtonElement >();
|
|
42
|
-
const headerRef = createRef<
|
|
25
|
+
const headerRef = createRef< HTMLElement >();
|
|
43
26
|
const titleRef = createRef< HTMLHeadingElement >();
|
|
27
|
+
const descriptionRef = createRef< HTMLParagraphElement >();
|
|
44
28
|
const closeIconRef = createRef< HTMLButtonElement >();
|
|
45
|
-
const footerRef = createRef<
|
|
29
|
+
const footerRef = createRef< HTMLElement >();
|
|
30
|
+
const contentRef = createRef< HTMLDivElement >();
|
|
46
31
|
|
|
47
32
|
render(
|
|
48
33
|
<Dialog.Root>
|
|
@@ -54,6 +39,11 @@ describe( 'Dialog', () => {
|
|
|
54
39
|
</Dialog.Title>
|
|
55
40
|
<Dialog.CloseIcon ref={ closeIconRef } />
|
|
56
41
|
</Dialog.Header>
|
|
42
|
+
<Dialog.Content ref={ contentRef }>
|
|
43
|
+
<Dialog.Description ref={ descriptionRef }>
|
|
44
|
+
A test description
|
|
45
|
+
</Dialog.Description>
|
|
46
|
+
</Dialog.Content>
|
|
57
47
|
<Dialog.Footer ref={ footerRef }>
|
|
58
48
|
<Dialog.Action ref={ actionRef }>Close</Dialog.Action>
|
|
59
49
|
</Dialog.Footer>
|
|
@@ -73,15 +63,221 @@ describe( 'Dialog', () => {
|
|
|
73
63
|
} );
|
|
74
64
|
|
|
75
65
|
// Now that the dialog is open, verify all inner refs
|
|
76
|
-
expect( headerRef.current ).toBeInstanceOf(
|
|
66
|
+
expect( headerRef.current ).toBeInstanceOf( HTMLElement );
|
|
67
|
+
expect( headerRef.current?.tagName ).toBe( 'HEADER' );
|
|
77
68
|
expect( titleRef.current ).toBeInstanceOf( HTMLHeadingElement );
|
|
69
|
+
expect( descriptionRef.current ).toBeInstanceOf( HTMLParagraphElement );
|
|
78
70
|
expect( closeIconRef.current ).toBeInstanceOf( HTMLButtonElement );
|
|
79
71
|
expect( actionRef.current ).toBeInstanceOf( HTMLButtonElement );
|
|
80
|
-
expect( footerRef.current ).toBeInstanceOf(
|
|
72
|
+
expect( footerRef.current ).toBeInstanceOf( HTMLElement );
|
|
73
|
+
expect( footerRef.current?.tagName ).toBe( 'FOOTER' );
|
|
74
|
+
expect( contentRef.current ).toBeInstanceOf( HTMLDivElement );
|
|
75
|
+
} );
|
|
76
|
+
|
|
77
|
+
it( 'merges user `className` on Dialog.Title with the internal one', async () => {
|
|
78
|
+
// Regression test for the shared `useRender` class-name merge
|
|
79
|
+
// that also covers Popover.Title, Dialog.Description and
|
|
80
|
+
// Popover.Description.
|
|
81
|
+
const user = userEvent.setup();
|
|
82
|
+
|
|
83
|
+
render(
|
|
84
|
+
<Dialog.Root>
|
|
85
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
86
|
+
<Dialog.Popup>
|
|
87
|
+
<Dialog.Title className="custom-title">Title</Dialog.Title>
|
|
88
|
+
</Dialog.Popup>
|
|
89
|
+
</Dialog.Root>
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
93
|
+
|
|
94
|
+
const heading = await screen.findByRole( 'heading', { name: 'Title' } );
|
|
95
|
+
// The regression this guards against: `useRender` must still forward
|
|
96
|
+
// the user-supplied className to the underlying DOM node. CSS module
|
|
97
|
+
// classes are stubbed in the Jest environment, so we can only assert
|
|
98
|
+
// the user class end-to-end.
|
|
99
|
+
expect( heading ).toHaveClass( 'custom-title' );
|
|
100
|
+
} );
|
|
101
|
+
|
|
102
|
+
it( 'associates Dialog.Description with the popup via aria-describedby', async () => {
|
|
103
|
+
const user = userEvent.setup();
|
|
104
|
+
const popupRef = createRef< HTMLDivElement >();
|
|
105
|
+
|
|
106
|
+
render(
|
|
107
|
+
<Dialog.Root>
|
|
108
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
109
|
+
<Dialog.Popup ref={ popupRef }>
|
|
110
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
111
|
+
<Dialog.Description>My description</Dialog.Description>
|
|
112
|
+
</Dialog.Popup>
|
|
113
|
+
</Dialog.Root>
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
117
|
+
|
|
118
|
+
await waitFor( () => {
|
|
119
|
+
expect( popupRef.current ).toHaveAccessibleDescription(
|
|
120
|
+
'My description'
|
|
121
|
+
);
|
|
122
|
+
} );
|
|
123
|
+
} );
|
|
124
|
+
|
|
125
|
+
it( 'renders Dialog.Footer and supports render/className props', async () => {
|
|
126
|
+
const user = userEvent.setup();
|
|
127
|
+
|
|
128
|
+
render(
|
|
129
|
+
<Dialog.Root>
|
|
130
|
+
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
|
|
131
|
+
<Dialog.Popup>
|
|
132
|
+
<Dialog.Title>Test Dialog</Dialog.Title>
|
|
133
|
+
<Dialog.Footer
|
|
134
|
+
render={ <section data-testid="dialog-footer" /> }
|
|
135
|
+
className="custom-footer"
|
|
136
|
+
>
|
|
137
|
+
<Dialog.Action>Close</Dialog.Action>
|
|
138
|
+
</Dialog.Footer>
|
|
139
|
+
</Dialog.Popup>
|
|
140
|
+
</Dialog.Root>
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
await user.click(
|
|
144
|
+
screen.getByRole( 'button', { name: 'Open Dialog' } )
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const footer = await screen.findByTestId( 'dialog-footer' );
|
|
148
|
+
expect( footer.tagName ).toBe( 'SECTION' );
|
|
149
|
+
expect( footer ).toHaveClass( 'custom-footer' );
|
|
150
|
+
expect(
|
|
151
|
+
screen.getByRole( 'button', { name: 'Close' } )
|
|
152
|
+
).toBeInTheDocument();
|
|
153
|
+
} );
|
|
154
|
+
|
|
155
|
+
it( 'renders backdrop only when modal is true', async () => {
|
|
156
|
+
const getBackdrops = () => screen.queryAllByTestId( 'dialog-backdrop' );
|
|
157
|
+
|
|
158
|
+
const view = render(
|
|
159
|
+
<Dialog.Root open modal>
|
|
160
|
+
<Dialog.Popup>
|
|
161
|
+
<Dialog.Title>Modal dialog</Dialog.Title>
|
|
162
|
+
</Dialog.Popup>
|
|
163
|
+
</Dialog.Root>
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
expect( await screen.findByRole( 'dialog' ) ).toBeInTheDocument();
|
|
167
|
+
expect( getBackdrops() ).toHaveLength( 1 );
|
|
168
|
+
|
|
169
|
+
view.rerender(
|
|
170
|
+
<Dialog.Root open modal={ false }>
|
|
171
|
+
<Dialog.Popup>
|
|
172
|
+
<Dialog.Title>Non modal dialog</Dialog.Title>
|
|
173
|
+
</Dialog.Popup>
|
|
174
|
+
</Dialog.Root>
|
|
175
|
+
);
|
|
176
|
+
expect( await screen.findByRole( 'dialog' ) ).toBeInTheDocument();
|
|
177
|
+
expect( getBackdrops() ).toHaveLength( 0 );
|
|
178
|
+
|
|
179
|
+
view.rerender(
|
|
180
|
+
<Dialog.Root open modal="trap-focus">
|
|
181
|
+
<Dialog.Popup>
|
|
182
|
+
<Dialog.Title>Trap focus dialog</Dialog.Title>
|
|
183
|
+
</Dialog.Popup>
|
|
184
|
+
</Dialog.Root>
|
|
185
|
+
);
|
|
186
|
+
expect( await screen.findByRole( 'dialog' ) ).toBeInTheDocument();
|
|
187
|
+
expect( getBackdrops() ).toHaveLength( 0 );
|
|
188
|
+
} );
|
|
189
|
+
|
|
190
|
+
it( 'renders the popup across default and explicit size values', async () => {
|
|
191
|
+
const view = render(
|
|
192
|
+
<Dialog.Root open>
|
|
193
|
+
<Dialog.Popup>
|
|
194
|
+
<Dialog.Title>Default size dialog</Dialog.Title>
|
|
195
|
+
</Dialog.Popup>
|
|
196
|
+
</Dialog.Root>
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
expect( await screen.findByRole( 'dialog' ) ).toBeInTheDocument();
|
|
200
|
+
|
|
201
|
+
for ( const size of [
|
|
202
|
+
'small',
|
|
203
|
+
'medium',
|
|
204
|
+
'large',
|
|
205
|
+
'stretch',
|
|
206
|
+
'full',
|
|
207
|
+
] as const ) {
|
|
208
|
+
view.rerender(
|
|
209
|
+
<Dialog.Root open>
|
|
210
|
+
<Dialog.Popup size={ size }>
|
|
211
|
+
<Dialog.Title>{ size } dialog</Dialog.Title>
|
|
212
|
+
</Dialog.Popup>
|
|
213
|
+
</Dialog.Root>
|
|
214
|
+
);
|
|
215
|
+
expect( await screen.findByRole( 'dialog' ) ).toBeInTheDocument();
|
|
216
|
+
}
|
|
217
|
+
} );
|
|
218
|
+
|
|
219
|
+
it( 'marks Dialog.Action as disabled when loading is true', async () => {
|
|
220
|
+
render(
|
|
221
|
+
<Dialog.Root open>
|
|
222
|
+
<Dialog.Popup>
|
|
223
|
+
<Dialog.Title>Action states</Dialog.Title>
|
|
224
|
+
<Dialog.Footer>
|
|
225
|
+
<Dialog.Action loading>Loading action</Dialog.Action>
|
|
226
|
+
</Dialog.Footer>
|
|
227
|
+
</Dialog.Popup>
|
|
228
|
+
</Dialog.Root>
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const action = await screen.findByRole( 'button', {
|
|
232
|
+
name: 'Loading action',
|
|
233
|
+
} );
|
|
234
|
+
expect( action ).toHaveAttribute( 'aria-disabled', 'true' );
|
|
235
|
+
} );
|
|
236
|
+
|
|
237
|
+
it( 'marks Dialog.Action as disabled when disabled is true', async () => {
|
|
238
|
+
render(
|
|
239
|
+
<Dialog.Root open>
|
|
240
|
+
<Dialog.Popup>
|
|
241
|
+
<Dialog.Title>Action states</Dialog.Title>
|
|
242
|
+
<Dialog.Footer>
|
|
243
|
+
<Dialog.Action disabled>Disabled action</Dialog.Action>
|
|
244
|
+
</Dialog.Footer>
|
|
245
|
+
</Dialog.Popup>
|
|
246
|
+
</Dialog.Root>
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const action = await screen.findByRole( 'button', {
|
|
250
|
+
name: 'Disabled action',
|
|
251
|
+
} );
|
|
252
|
+
expect( action ).toHaveAttribute( 'aria-disabled', 'true' );
|
|
253
|
+
} );
|
|
254
|
+
|
|
255
|
+
it( 'lets explicit disabled={ false } override loading on Dialog.Action', async () => {
|
|
256
|
+
// `Dialog.Action` uses `disabled ?? loading`, so an explicit
|
|
257
|
+
// `disabled={ false }` wins over an active loading state.
|
|
258
|
+
render(
|
|
259
|
+
<Dialog.Root open>
|
|
260
|
+
<Dialog.Popup>
|
|
261
|
+
<Dialog.Title>Action states</Dialog.Title>
|
|
262
|
+
<Dialog.Footer>
|
|
263
|
+
<Dialog.Action disabled={ false } loading>
|
|
264
|
+
Explicit not-disabled
|
|
265
|
+
</Dialog.Action>
|
|
266
|
+
</Dialog.Footer>
|
|
267
|
+
</Dialog.Popup>
|
|
268
|
+
</Dialog.Root>
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const action = await screen.findByRole( 'button', {
|
|
272
|
+
name: 'Explicit not-disabled',
|
|
273
|
+
} );
|
|
274
|
+
expect( action ).not.toHaveAttribute( 'aria-disabled', 'true' );
|
|
81
275
|
} );
|
|
82
276
|
|
|
83
277
|
describe( 'Development mode validation', () => {
|
|
84
|
-
// Suppress
|
|
278
|
+
// Suppress console.error from React act() warnings and jsdom
|
|
279
|
+
// unhandled-error logging. Validation errors are caught via
|
|
280
|
+
// collectUncaughtErrors (window 'error' event) instead.
|
|
85
281
|
let originalConsoleError: typeof console.error;
|
|
86
282
|
|
|
87
283
|
beforeEach( () => {
|
|
@@ -98,210 +294,313 @@ describe( 'Dialog', () => {
|
|
|
98
294
|
|
|
99
295
|
it( 'should throw when Dialog.Title is missing', async () => {
|
|
100
296
|
const user = userEvent.setup();
|
|
101
|
-
const
|
|
297
|
+
const { errors, cleanup } = collectUncaughtErrors();
|
|
102
298
|
|
|
103
299
|
render(
|
|
104
|
-
<
|
|
105
|
-
<Dialog.
|
|
106
|
-
|
|
107
|
-
<Dialog.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
<Dialog.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
</Dialog.Root>
|
|
117
|
-
</TestErrorBoundary>
|
|
300
|
+
<Dialog.Root>
|
|
301
|
+
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
|
|
302
|
+
<Dialog.Popup>
|
|
303
|
+
<Dialog.Header>
|
|
304
|
+
{ /* Missing Dialog.Title */ }
|
|
305
|
+
</Dialog.Header>
|
|
306
|
+
<p>Content without a title</p>
|
|
307
|
+
<Dialog.Footer>
|
|
308
|
+
<Dialog.Action>Close</Dialog.Action>
|
|
309
|
+
</Dialog.Footer>
|
|
310
|
+
</Dialog.Popup>
|
|
311
|
+
</Dialog.Root>
|
|
118
312
|
);
|
|
119
313
|
|
|
120
|
-
// Open the dialog - this will trigger the error in useEffect
|
|
121
314
|
await user.click(
|
|
122
315
|
screen.getByRole( 'button', { name: 'Open Dialog' } )
|
|
123
316
|
);
|
|
124
317
|
|
|
125
318
|
await waitFor( () => {
|
|
126
|
-
expect(
|
|
319
|
+
expect( errors.length ).toBeGreaterThan( 0 );
|
|
127
320
|
} );
|
|
128
321
|
|
|
129
|
-
expect(
|
|
130
|
-
expect( ( onError.mock.calls[ 0 ][ 0 ] as Error ).message ).toBe(
|
|
322
|
+
expect( errors[ 0 ].message ).toBe(
|
|
131
323
|
'Dialog: Missing <Dialog.Title>. ' +
|
|
132
324
|
'For accessibility, every dialog requires a title. ' +
|
|
133
325
|
'If needed, the title can be visually hidden but must not be omitted.'
|
|
134
326
|
);
|
|
327
|
+
|
|
328
|
+
cleanup();
|
|
135
329
|
} );
|
|
136
330
|
|
|
137
331
|
it( 'should not throw before opening the dialog', async () => {
|
|
138
|
-
const
|
|
332
|
+
const { errors, cleanup } = collectUncaughtErrors();
|
|
139
333
|
|
|
140
334
|
render(
|
|
141
|
-
<
|
|
142
|
-
<Dialog.
|
|
143
|
-
|
|
144
|
-
<Dialog.
|
|
145
|
-
<Dialog.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
<Dialog.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
</Dialog.Root>
|
|
154
|
-
</TestErrorBoundary>
|
|
335
|
+
<Dialog.Root>
|
|
336
|
+
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
|
|
337
|
+
<Dialog.Popup>
|
|
338
|
+
<Dialog.Header>
|
|
339
|
+
<Dialog.Title>My Title</Dialog.Title>
|
|
340
|
+
</Dialog.Header>
|
|
341
|
+
<p>Content with a title</p>
|
|
342
|
+
<Dialog.Footer>
|
|
343
|
+
<Dialog.Action>Close</Dialog.Action>
|
|
344
|
+
</Dialog.Footer>
|
|
345
|
+
</Dialog.Popup>
|
|
346
|
+
</Dialog.Root>
|
|
155
347
|
);
|
|
156
348
|
|
|
157
|
-
// Check that the dialog itself hasn't been rendered in the DOM.
|
|
158
349
|
await expect( screen.findByRole( 'dialog' ) ).rejects.toThrow();
|
|
350
|
+
expect( errors ).toHaveLength( 0 );
|
|
159
351
|
|
|
160
|
-
|
|
352
|
+
cleanup();
|
|
161
353
|
} );
|
|
162
354
|
|
|
163
355
|
it( 'should not throw when Dialog.Title is present', async () => {
|
|
164
356
|
const user = userEvent.setup();
|
|
165
|
-
const
|
|
357
|
+
const { errors, cleanup } = collectUncaughtErrors();
|
|
166
358
|
|
|
167
359
|
render(
|
|
168
|
-
<
|
|
169
|
-
<Dialog.
|
|
170
|
-
|
|
171
|
-
<Dialog.
|
|
172
|
-
<Dialog.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
<Dialog.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
</Dialog.Root>
|
|
181
|
-
</TestErrorBoundary>
|
|
360
|
+
<Dialog.Root>
|
|
361
|
+
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
|
|
362
|
+
<Dialog.Popup>
|
|
363
|
+
<Dialog.Header>
|
|
364
|
+
<Dialog.Title>My Title</Dialog.Title>
|
|
365
|
+
</Dialog.Header>
|
|
366
|
+
<p>Content with a title</p>
|
|
367
|
+
<Dialog.Footer>
|
|
368
|
+
<Dialog.Action>Close</Dialog.Action>
|
|
369
|
+
</Dialog.Footer>
|
|
370
|
+
</Dialog.Popup>
|
|
371
|
+
</Dialog.Root>
|
|
182
372
|
);
|
|
183
373
|
|
|
184
|
-
// Open the dialog - should not throw
|
|
185
374
|
await user.click(
|
|
186
375
|
screen.getByRole( 'button', { name: 'Open Dialog' } )
|
|
187
376
|
);
|
|
188
377
|
|
|
189
|
-
// Wait for the dialog to appear and ensure validation does not trigger errors
|
|
190
378
|
await waitFor( () => {
|
|
191
379
|
expect( screen.getByRole( 'dialog' ) ).toBeInTheDocument();
|
|
192
380
|
} );
|
|
193
|
-
|
|
381
|
+
|
|
382
|
+
// Allow deferred validation to settle.
|
|
383
|
+
await act(
|
|
384
|
+
() => new Promise( ( resolve ) => setTimeout( resolve, 50 ) )
|
|
385
|
+
);
|
|
386
|
+
expect( errors ).toHaveLength( 0 );
|
|
387
|
+
|
|
388
|
+
cleanup();
|
|
194
389
|
} );
|
|
195
390
|
|
|
196
391
|
it( 'should throw when Dialog.Title is empty', async () => {
|
|
197
392
|
const user = userEvent.setup();
|
|
198
|
-
const
|
|
393
|
+
const { errors, cleanup } = collectUncaughtErrors();
|
|
199
394
|
|
|
200
395
|
render(
|
|
201
|
-
<
|
|
202
|
-
<Dialog.
|
|
203
|
-
|
|
204
|
-
<Dialog.
|
|
205
|
-
<Dialog.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
<
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
</Dialog.Popup>
|
|
214
|
-
</Dialog.Root>
|
|
215
|
-
</TestErrorBoundary>
|
|
396
|
+
<Dialog.Root>
|
|
397
|
+
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
|
|
398
|
+
<Dialog.Popup>
|
|
399
|
+
<Dialog.Header>
|
|
400
|
+
<Dialog.Title />
|
|
401
|
+
</Dialog.Header>
|
|
402
|
+
<p>Content with empty title</p>
|
|
403
|
+
<Dialog.Footer>
|
|
404
|
+
<Dialog.Action>Close</Dialog.Action>
|
|
405
|
+
</Dialog.Footer>
|
|
406
|
+
</Dialog.Popup>
|
|
407
|
+
</Dialog.Root>
|
|
216
408
|
);
|
|
217
409
|
|
|
218
|
-
// Open the dialog - this will trigger the error
|
|
219
410
|
await user.click(
|
|
220
411
|
screen.getByRole( 'button', { name: 'Open Dialog' } )
|
|
221
412
|
);
|
|
222
413
|
|
|
223
414
|
await waitFor( () => {
|
|
224
|
-
expect(
|
|
415
|
+
expect( errors.length ).toBeGreaterThan( 0 );
|
|
225
416
|
} );
|
|
226
417
|
|
|
227
|
-
expect(
|
|
228
|
-
expect( ( onError.mock.calls[ 0 ][ 0 ] as Error ).message ).toBe(
|
|
418
|
+
expect( errors[ 0 ].message ).toBe(
|
|
229
419
|
'Dialog: <Dialog.Title> cannot be empty. ' +
|
|
230
420
|
'Provide meaningful text content for the dialog title.'
|
|
231
421
|
);
|
|
422
|
+
|
|
423
|
+
cleanup();
|
|
232
424
|
} );
|
|
233
425
|
|
|
234
426
|
it( 'should throw when Dialog.Title contains only whitespace', async () => {
|
|
235
427
|
const user = userEvent.setup();
|
|
236
|
-
const
|
|
428
|
+
const { errors, cleanup } = collectUncaughtErrors();
|
|
237
429
|
|
|
238
430
|
render(
|
|
239
|
-
<
|
|
240
|
-
<Dialog.
|
|
241
|
-
|
|
242
|
-
<Dialog.
|
|
243
|
-
<Dialog.
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
<Dialog.
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
</Dialog.Root>
|
|
252
|
-
</TestErrorBoundary>
|
|
431
|
+
<Dialog.Root>
|
|
432
|
+
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
|
|
433
|
+
<Dialog.Popup>
|
|
434
|
+
<Dialog.Header>
|
|
435
|
+
<Dialog.Title> </Dialog.Title>
|
|
436
|
+
</Dialog.Header>
|
|
437
|
+
<p>Content with whitespace-only title</p>
|
|
438
|
+
<Dialog.Footer>
|
|
439
|
+
<Dialog.Action>Close</Dialog.Action>
|
|
440
|
+
</Dialog.Footer>
|
|
441
|
+
</Dialog.Popup>
|
|
442
|
+
</Dialog.Root>
|
|
253
443
|
);
|
|
254
444
|
|
|
255
|
-
// Open the dialog - this will trigger the error
|
|
256
445
|
await user.click(
|
|
257
446
|
screen.getByRole( 'button', { name: 'Open Dialog' } )
|
|
258
447
|
);
|
|
259
448
|
|
|
260
449
|
await waitFor( () => {
|
|
261
|
-
expect(
|
|
450
|
+
expect( errors.length ).toBeGreaterThan( 0 );
|
|
262
451
|
} );
|
|
263
452
|
|
|
264
|
-
expect(
|
|
265
|
-
expect( ( onError.mock.calls[ 0 ][ 0 ] as Error ).message ).toBe(
|
|
453
|
+
expect( errors[ 0 ].message ).toBe(
|
|
266
454
|
'Dialog: <Dialog.Title> cannot be empty. ' +
|
|
267
455
|
'Provide meaningful text content for the dialog title.'
|
|
268
456
|
);
|
|
457
|
+
|
|
458
|
+
cleanup();
|
|
269
459
|
} );
|
|
270
460
|
|
|
271
461
|
it( 'should not throw when Dialog.Title contains mixed content with text', async () => {
|
|
272
462
|
const user = userEvent.setup();
|
|
273
|
-
const
|
|
463
|
+
const { errors, cleanup } = collectUncaughtErrors();
|
|
274
464
|
|
|
275
465
|
render(
|
|
276
|
-
<
|
|
466
|
+
<Dialog.Root>
|
|
467
|
+
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
|
|
468
|
+
<Dialog.Popup>
|
|
469
|
+
<Dialog.Header>
|
|
470
|
+
<Dialog.Title>
|
|
471
|
+
<span aria-hidden="true">🎉</span>
|
|
472
|
+
Settings
|
|
473
|
+
</Dialog.Title>
|
|
474
|
+
</Dialog.Header>
|
|
475
|
+
<p>Content with icon and text title</p>
|
|
476
|
+
<Dialog.Footer>
|
|
477
|
+
<Dialog.Action>Close</Dialog.Action>
|
|
478
|
+
</Dialog.Footer>
|
|
479
|
+
</Dialog.Popup>
|
|
480
|
+
</Dialog.Root>
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
await user.click(
|
|
484
|
+
screen.getByRole( 'button', { name: 'Open Dialog' } )
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
await waitFor( () => {
|
|
488
|
+
expect( screen.getByRole( 'dialog' ) ).toBeInTheDocument();
|
|
489
|
+
} );
|
|
490
|
+
|
|
491
|
+
await act(
|
|
492
|
+
() => new Promise( ( resolve ) => setTimeout( resolve, 50 ) )
|
|
493
|
+
);
|
|
494
|
+
expect( errors ).toHaveLength( 0 );
|
|
495
|
+
|
|
496
|
+
cleanup();
|
|
497
|
+
} );
|
|
498
|
+
|
|
499
|
+
it( 'should throw when title is removed after mount', async () => {
|
|
500
|
+
const user = userEvent.setup();
|
|
501
|
+
const { errors, cleanup } = collectUncaughtErrors();
|
|
502
|
+
|
|
503
|
+
function Test() {
|
|
504
|
+
const [ showTitle, setShowTitle ] = useState( true );
|
|
505
|
+
return (
|
|
277
506
|
<Dialog.Root>
|
|
278
|
-
<Dialog.Trigger>Open
|
|
507
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
279
508
|
<Dialog.Popup>
|
|
280
|
-
|
|
281
|
-
<Dialog.Title>
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
</
|
|
286
|
-
<p>Content with icon and text title</p>
|
|
287
|
-
<Dialog.Footer>
|
|
288
|
-
<Dialog.Action>Close</Dialog.Action>
|
|
289
|
-
</Dialog.Footer>
|
|
509
|
+
{ showTitle && (
|
|
510
|
+
<Dialog.Title>My Title</Dialog.Title>
|
|
511
|
+
) }
|
|
512
|
+
<button onClick={ () => setShowTitle( false ) }>
|
|
513
|
+
Remove Title
|
|
514
|
+
</button>
|
|
290
515
|
</Dialog.Popup>
|
|
291
516
|
</Dialog.Root>
|
|
292
|
-
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
render( <Test /> );
|
|
521
|
+
|
|
522
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
523
|
+
|
|
524
|
+
await waitFor( () => {
|
|
525
|
+
expect( screen.getByRole( 'dialog' ) ).toBeInTheDocument();
|
|
526
|
+
} );
|
|
527
|
+
|
|
528
|
+
// Let initial validation settle — no errors expected.
|
|
529
|
+
await act(
|
|
530
|
+
() => new Promise( ( resolve ) => setTimeout( resolve, 50 ) )
|
|
293
531
|
);
|
|
532
|
+
expect( errors ).toHaveLength( 0 );
|
|
294
533
|
|
|
295
|
-
//
|
|
534
|
+
// Remove the title.
|
|
296
535
|
await user.click(
|
|
297
|
-
screen.getByRole( 'button', { name: '
|
|
536
|
+
screen.getByRole( 'button', { name: 'Remove Title' } )
|
|
298
537
|
);
|
|
299
538
|
|
|
300
|
-
|
|
539
|
+
await waitFor( () => {
|
|
540
|
+
expect( errors.length ).toBeGreaterThan( 0 );
|
|
541
|
+
} );
|
|
542
|
+
|
|
543
|
+
expect( errors[ 0 ].message ).toBe(
|
|
544
|
+
'Dialog: Missing <Dialog.Title>. ' +
|
|
545
|
+
'For accessibility, every dialog requires a title. ' +
|
|
546
|
+
'If needed, the title can be visually hidden but must not be omitted.'
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
cleanup();
|
|
550
|
+
} );
|
|
551
|
+
|
|
552
|
+
it( 'should recover when title is added back', async () => {
|
|
553
|
+
const user = userEvent.setup();
|
|
554
|
+
const { errors, cleanup } = collectUncaughtErrors();
|
|
555
|
+
|
|
556
|
+
function Test() {
|
|
557
|
+
const [ showTitle, setShowTitle ] = useState( false );
|
|
558
|
+
return (
|
|
559
|
+
<Dialog.Root>
|
|
560
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
561
|
+
<Dialog.Popup>
|
|
562
|
+
{ showTitle && (
|
|
563
|
+
<Dialog.Title>My Title</Dialog.Title>
|
|
564
|
+
) }
|
|
565
|
+
<button
|
|
566
|
+
onClick={ () => setShowTitle( ( s ) => ! s ) }
|
|
567
|
+
>
|
|
568
|
+
Toggle Title
|
|
569
|
+
</button>
|
|
570
|
+
</Dialog.Popup>
|
|
571
|
+
</Dialog.Root>
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
render( <Test /> );
|
|
576
|
+
|
|
577
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
578
|
+
|
|
301
579
|
await waitFor( () => {
|
|
302
580
|
expect( screen.getByRole( 'dialog' ) ).toBeInTheDocument();
|
|
303
581
|
} );
|
|
304
|
-
|
|
582
|
+
|
|
583
|
+
// Initially no title — should error.
|
|
584
|
+
await waitFor( () => {
|
|
585
|
+
expect( errors.length ).toBeGreaterThan( 0 );
|
|
586
|
+
} );
|
|
587
|
+
|
|
588
|
+
const errorCountAfterInitial = errors.length;
|
|
589
|
+
|
|
590
|
+
// Add the title back.
|
|
591
|
+
await user.click(
|
|
592
|
+
screen.getByRole( 'button', { name: 'Toggle Title' } )
|
|
593
|
+
);
|
|
594
|
+
|
|
595
|
+
// Wait for deferred validation to settle.
|
|
596
|
+
await act(
|
|
597
|
+
() => new Promise( ( resolve ) => setTimeout( resolve, 50 ) )
|
|
598
|
+
);
|
|
599
|
+
|
|
600
|
+
// No new errors should have been thrown.
|
|
601
|
+
expect( errors ).toHaveLength( errorCountAfterInitial );
|
|
602
|
+
|
|
603
|
+
cleanup();
|
|
305
604
|
} );
|
|
306
605
|
} );
|
|
307
606
|
|
|
@@ -422,8 +721,8 @@ describe( 'Dialog', () => {
|
|
|
422
721
|
} );
|
|
423
722
|
} );
|
|
424
723
|
|
|
425
|
-
describe( '
|
|
426
|
-
it( 'should render inside the container when provided', async () => {
|
|
724
|
+
describe( 'portal', () => {
|
|
725
|
+
it( 'should render inside the portal container when a custom target is provided', async () => {
|
|
427
726
|
const user = userEvent.setup();
|
|
428
727
|
const containerRef = createRef< HTMLDivElement >();
|
|
429
728
|
|
|
@@ -435,7 +734,11 @@ describe( 'Dialog', () => {
|
|
|
435
734
|
ref={ containerRef }
|
|
436
735
|
data-testid="custom-container"
|
|
437
736
|
/>
|
|
438
|
-
<Dialog.Popup
|
|
737
|
+
<Dialog.Popup
|
|
738
|
+
portal={
|
|
739
|
+
<Dialog.Portal container={ containerRef } />
|
|
740
|
+
}
|
|
741
|
+
>
|
|
439
742
|
<Dialog.Header>
|
|
440
743
|
<Dialog.Title>Title</Dialog.Title>
|
|
441
744
|
</Dialog.Header>
|
|
@@ -482,4 +785,401 @@ describe( 'Dialog', () => {
|
|
|
482
785
|
);
|
|
483
786
|
} );
|
|
484
787
|
} );
|
|
788
|
+
|
|
789
|
+
describe( 'overlay scroll container', () => {
|
|
790
|
+
it( 'marks Dialog.Content with data-wp-ui-overlay-scroll-container', async () => {
|
|
791
|
+
const user = userEvent.setup();
|
|
792
|
+
const contentRef = createRef< HTMLDivElement >();
|
|
793
|
+
|
|
794
|
+
render(
|
|
795
|
+
<Dialog.Root>
|
|
796
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
797
|
+
<Dialog.Popup>
|
|
798
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
799
|
+
<Dialog.Content ref={ contentRef }>
|
|
800
|
+
<p>Body</p>
|
|
801
|
+
</Dialog.Content>
|
|
802
|
+
</Dialog.Popup>
|
|
803
|
+
</Dialog.Root>
|
|
804
|
+
);
|
|
805
|
+
|
|
806
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
807
|
+
await waitFor( () => {
|
|
808
|
+
expect( contentRef.current ).toBeInstanceOf( HTMLDivElement );
|
|
809
|
+
} );
|
|
810
|
+
|
|
811
|
+
expect( contentRef.current ).toHaveAttribute(
|
|
812
|
+
'data-wp-ui-overlay-scroll-container'
|
|
813
|
+
);
|
|
814
|
+
} );
|
|
815
|
+
|
|
816
|
+
it( 'sets data-wp-ui-overlay-modal on the popup when modal is true', async () => {
|
|
817
|
+
const user = userEvent.setup();
|
|
818
|
+
const popupRef = createRef< HTMLDivElement >();
|
|
819
|
+
|
|
820
|
+
render(
|
|
821
|
+
<Dialog.Root modal>
|
|
822
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
823
|
+
<Dialog.Popup ref={ popupRef }>
|
|
824
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
825
|
+
</Dialog.Popup>
|
|
826
|
+
</Dialog.Root>
|
|
827
|
+
);
|
|
828
|
+
|
|
829
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
830
|
+
await waitFor( () => {
|
|
831
|
+
expect( popupRef.current ).toBeInstanceOf( HTMLDivElement );
|
|
832
|
+
} );
|
|
833
|
+
|
|
834
|
+
expect( popupRef.current ).toHaveAttribute(
|
|
835
|
+
'data-wp-ui-overlay-modal'
|
|
836
|
+
);
|
|
837
|
+
} );
|
|
838
|
+
|
|
839
|
+
it.each( [
|
|
840
|
+
[ 'false', false as const ],
|
|
841
|
+
[ 'trap-focus', 'trap-focus' as const ],
|
|
842
|
+
] )(
|
|
843
|
+
'omits data-wp-ui-overlay-modal on the popup when modal is %s',
|
|
844
|
+
async ( _label, modal ) => {
|
|
845
|
+
const user = userEvent.setup();
|
|
846
|
+
const popupRef = createRef< HTMLDivElement >();
|
|
847
|
+
|
|
848
|
+
render(
|
|
849
|
+
<Dialog.Root modal={ modal }>
|
|
850
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
851
|
+
<Dialog.Popup ref={ popupRef }>
|
|
852
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
853
|
+
</Dialog.Popup>
|
|
854
|
+
</Dialog.Root>
|
|
855
|
+
);
|
|
856
|
+
|
|
857
|
+
await user.click(
|
|
858
|
+
screen.getByRole( 'button', { name: 'Open' } )
|
|
859
|
+
);
|
|
860
|
+
await waitFor( () => {
|
|
861
|
+
expect( popupRef.current ).toBeInstanceOf( HTMLDivElement );
|
|
862
|
+
} );
|
|
863
|
+
|
|
864
|
+
expect( popupRef.current ).not.toHaveAttribute(
|
|
865
|
+
'data-wp-ui-overlay-modal'
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
);
|
|
869
|
+
|
|
870
|
+
it( 'pins Dialog.Header when rendered as a sibling of Dialog.Content', async () => {
|
|
871
|
+
const user = userEvent.setup();
|
|
872
|
+
const popupRef = createRef< HTMLDivElement >();
|
|
873
|
+
const headerRef = createRef< HTMLElement >();
|
|
874
|
+
const contentRef = createRef< HTMLDivElement >();
|
|
875
|
+
|
|
876
|
+
render(
|
|
877
|
+
<Dialog.Root>
|
|
878
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
879
|
+
<Dialog.Popup ref={ popupRef }>
|
|
880
|
+
<Dialog.Header ref={ headerRef }>
|
|
881
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
882
|
+
</Dialog.Header>
|
|
883
|
+
<Dialog.Content ref={ contentRef }>
|
|
884
|
+
<p>Body</p>
|
|
885
|
+
</Dialog.Content>
|
|
886
|
+
</Dialog.Popup>
|
|
887
|
+
</Dialog.Root>
|
|
888
|
+
);
|
|
889
|
+
|
|
890
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
891
|
+
await waitFor( () => {
|
|
892
|
+
expect( headerRef.current ).toBeInstanceOf( HTMLElement );
|
|
893
|
+
} );
|
|
894
|
+
|
|
895
|
+
// The header is inside the popup but NOT inside the scroll
|
|
896
|
+
// container — it sits outside the scrolling region as a
|
|
897
|
+
// pinned flex sibling of `Content`.
|
|
898
|
+
expect( popupRef.current ).toContainElement( headerRef.current );
|
|
899
|
+
expect( popupRef.current ).toContainElement( contentRef.current );
|
|
900
|
+
expect( contentRef.current ).not.toContainElement(
|
|
901
|
+
headerRef.current
|
|
902
|
+
);
|
|
903
|
+
// And it sits *before* the scroll container — the CSS
|
|
904
|
+
// sticky-separator selectors rely on that DOM order.
|
|
905
|
+
const position = headerRef.current!.compareDocumentPosition(
|
|
906
|
+
contentRef.current!
|
|
907
|
+
);
|
|
908
|
+
expect(
|
|
909
|
+
// eslint-disable-next-line no-bitwise
|
|
910
|
+
position & Node.DOCUMENT_POSITION_FOLLOWING
|
|
911
|
+
).toBeTruthy();
|
|
912
|
+
} );
|
|
913
|
+
|
|
914
|
+
it( 'scrolls Dialog.Header with the body when nested inside Dialog.Content', async () => {
|
|
915
|
+
const user = userEvent.setup();
|
|
916
|
+
const headerRef = createRef< HTMLElement >();
|
|
917
|
+
const contentRef = createRef< HTMLDivElement >();
|
|
918
|
+
|
|
919
|
+
render(
|
|
920
|
+
<Dialog.Root>
|
|
921
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
922
|
+
<Dialog.Popup>
|
|
923
|
+
<Dialog.Content ref={ contentRef }>
|
|
924
|
+
<Dialog.Header ref={ headerRef }>
|
|
925
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
926
|
+
</Dialog.Header>
|
|
927
|
+
<p>Body</p>
|
|
928
|
+
</Dialog.Content>
|
|
929
|
+
</Dialog.Popup>
|
|
930
|
+
</Dialog.Root>
|
|
931
|
+
);
|
|
932
|
+
|
|
933
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
934
|
+
await waitFor( () => {
|
|
935
|
+
expect( headerRef.current ).toBeInstanceOf( HTMLElement );
|
|
936
|
+
} );
|
|
937
|
+
|
|
938
|
+
expect( contentRef.current ).toContainElement( headerRef.current );
|
|
939
|
+
} );
|
|
940
|
+
|
|
941
|
+
it( 'invokes a consumer-supplied onScroll on Dialog.Content', async () => {
|
|
942
|
+
const user = userEvent.setup();
|
|
943
|
+
const onScroll = jest.fn();
|
|
944
|
+
const contentRef = createRef< HTMLDivElement >();
|
|
945
|
+
|
|
946
|
+
render(
|
|
947
|
+
<Dialog.Root>
|
|
948
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
949
|
+
<Dialog.Popup>
|
|
950
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
951
|
+
<Dialog.Content
|
|
952
|
+
ref={ contentRef }
|
|
953
|
+
onScroll={ onScroll }
|
|
954
|
+
>
|
|
955
|
+
<p>Body</p>
|
|
956
|
+
</Dialog.Content>
|
|
957
|
+
</Dialog.Popup>
|
|
958
|
+
</Dialog.Root>
|
|
959
|
+
);
|
|
960
|
+
|
|
961
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
962
|
+
await waitFor( () => {
|
|
963
|
+
expect( contentRef.current ).toBeInstanceOf( HTMLDivElement );
|
|
964
|
+
} );
|
|
965
|
+
|
|
966
|
+
act( () => {
|
|
967
|
+
contentRef.current?.dispatchEvent(
|
|
968
|
+
new Event( 'scroll', { bubbles: true } )
|
|
969
|
+
);
|
|
970
|
+
} );
|
|
971
|
+
|
|
972
|
+
expect( onScroll ).toHaveBeenCalledTimes( 1 );
|
|
973
|
+
} );
|
|
974
|
+
|
|
975
|
+
it( 'toggles tabindex="0" on Dialog.Content based on overflow', async () => {
|
|
976
|
+
const user = userEvent.setup();
|
|
977
|
+
const contentRef = createRef< HTMLDivElement >();
|
|
978
|
+
|
|
979
|
+
render(
|
|
980
|
+
<Dialog.Root>
|
|
981
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
982
|
+
<Dialog.Popup>
|
|
983
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
984
|
+
<Dialog.Content ref={ contentRef }>
|
|
985
|
+
<p>Body</p>
|
|
986
|
+
</Dialog.Content>
|
|
987
|
+
</Dialog.Popup>
|
|
988
|
+
</Dialog.Root>
|
|
989
|
+
);
|
|
990
|
+
|
|
991
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
992
|
+
await waitFor( () => {
|
|
993
|
+
expect( contentRef.current ).toBeInstanceOf( HTMLDivElement );
|
|
994
|
+
} );
|
|
995
|
+
|
|
996
|
+
// JSDOM reports 0/0 dimensions by default, so the initial
|
|
997
|
+
// mount sees no overflow and installs no tabindex. Stub
|
|
998
|
+
// layout metrics, dispatch a scroll to re-run the update,
|
|
999
|
+
// and verify the tabindex is installed.
|
|
1000
|
+
const content = contentRef.current!;
|
|
1001
|
+
Object.defineProperty( content, 'scrollHeight', {
|
|
1002
|
+
configurable: true,
|
|
1003
|
+
value: 500,
|
|
1004
|
+
} );
|
|
1005
|
+
Object.defineProperty( content, 'clientHeight', {
|
|
1006
|
+
configurable: true,
|
|
1007
|
+
value: 100,
|
|
1008
|
+
} );
|
|
1009
|
+
Object.defineProperty( content, 'scrollTop', {
|
|
1010
|
+
configurable: true,
|
|
1011
|
+
value: 0,
|
|
1012
|
+
} );
|
|
1013
|
+
|
|
1014
|
+
act( () => {
|
|
1015
|
+
content.dispatchEvent(
|
|
1016
|
+
new Event( 'scroll', { bubbles: true } )
|
|
1017
|
+
);
|
|
1018
|
+
} );
|
|
1019
|
+
|
|
1020
|
+
expect( content ).toHaveAttribute( 'tabindex', '0' );
|
|
1021
|
+
|
|
1022
|
+
// Shrink content so it no longer overflows and verify the
|
|
1023
|
+
// hook removes its managed tabindex.
|
|
1024
|
+
Object.defineProperty( content, 'scrollHeight', {
|
|
1025
|
+
configurable: true,
|
|
1026
|
+
value: 100,
|
|
1027
|
+
} );
|
|
1028
|
+
|
|
1029
|
+
act( () => {
|
|
1030
|
+
content.dispatchEvent(
|
|
1031
|
+
new Event( 'scroll', { bubbles: true } )
|
|
1032
|
+
);
|
|
1033
|
+
} );
|
|
1034
|
+
|
|
1035
|
+
expect( content ).not.toHaveAttribute( 'tabindex' );
|
|
1036
|
+
} );
|
|
1037
|
+
|
|
1038
|
+
// This test exercises the `updateScrollAttributes` path for
|
|
1039
|
+
// consumer takeover (overflow flips off while the override is
|
|
1040
|
+
// in place). The matching `cleanupScrollAttributes` path —
|
|
1041
|
+
// popup unmounts while the override is in place — is covered
|
|
1042
|
+
// transitively because both paths share a single
|
|
1043
|
+
// `reconcileTabbableFlag` helper inside the hook. If that
|
|
1044
|
+
// shared helper is ever inlined or split, add an explicit
|
|
1045
|
+
// unmount-after-takeover test to keep both paths regressions-
|
|
1046
|
+
// guarded.
|
|
1047
|
+
it( 'preserves a consumer-supplied tabindex set after the hook installed its own', async () => {
|
|
1048
|
+
const user = userEvent.setup();
|
|
1049
|
+
const contentRef = createRef< HTMLDivElement >();
|
|
1050
|
+
|
|
1051
|
+
render(
|
|
1052
|
+
<Dialog.Root>
|
|
1053
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
1054
|
+
<Dialog.Popup>
|
|
1055
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
1056
|
+
<Dialog.Content ref={ contentRef }>
|
|
1057
|
+
<p>Body</p>
|
|
1058
|
+
</Dialog.Content>
|
|
1059
|
+
</Dialog.Popup>
|
|
1060
|
+
</Dialog.Root>
|
|
1061
|
+
);
|
|
1062
|
+
|
|
1063
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
1064
|
+
await waitFor( () => {
|
|
1065
|
+
expect( contentRef.current ).toBeInstanceOf( HTMLDivElement );
|
|
1066
|
+
} );
|
|
1067
|
+
|
|
1068
|
+
const content = contentRef.current!;
|
|
1069
|
+
Object.defineProperty( content, 'scrollHeight', {
|
|
1070
|
+
configurable: true,
|
|
1071
|
+
value: 500,
|
|
1072
|
+
} );
|
|
1073
|
+
Object.defineProperty( content, 'clientHeight', {
|
|
1074
|
+
configurable: true,
|
|
1075
|
+
value: 100,
|
|
1076
|
+
} );
|
|
1077
|
+
Object.defineProperty( content, 'scrollTop', {
|
|
1078
|
+
configurable: true,
|
|
1079
|
+
value: 0,
|
|
1080
|
+
} );
|
|
1081
|
+
|
|
1082
|
+
act( () => {
|
|
1083
|
+
content.dispatchEvent(
|
|
1084
|
+
new Event( 'scroll', { bubbles: true } )
|
|
1085
|
+
);
|
|
1086
|
+
} );
|
|
1087
|
+
|
|
1088
|
+
expect( content ).toHaveAttribute( 'tabindex', '0' );
|
|
1089
|
+
|
|
1090
|
+
// Simulate the consumer taking over the tabindex after the
|
|
1091
|
+
// hook installed its own (e.g. a re-render with an explicit
|
|
1092
|
+
// `tabIndex={ -1 }` prop). The hook should detect the
|
|
1093
|
+
// consumer takeover and not clobber that value on the next
|
|
1094
|
+
// non-overflow tick.
|
|
1095
|
+
content.setAttribute( 'tabindex', '-1' );
|
|
1096
|
+
|
|
1097
|
+
Object.defineProperty( content, 'scrollHeight', {
|
|
1098
|
+
configurable: true,
|
|
1099
|
+
value: 100,
|
|
1100
|
+
} );
|
|
1101
|
+
|
|
1102
|
+
act( () => {
|
|
1103
|
+
content.dispatchEvent(
|
|
1104
|
+
new Event( 'scroll', { bubbles: true } )
|
|
1105
|
+
);
|
|
1106
|
+
} );
|
|
1107
|
+
|
|
1108
|
+
expect( content ).toHaveAttribute( 'tabindex', '-1' );
|
|
1109
|
+
} );
|
|
1110
|
+
|
|
1111
|
+
it( 'toggles data-wp-ui-overlay-scrolled-from-* based on scroll position', async () => {
|
|
1112
|
+
const user = userEvent.setup();
|
|
1113
|
+
const contentRef = createRef< HTMLDivElement >();
|
|
1114
|
+
|
|
1115
|
+
render(
|
|
1116
|
+
<Dialog.Root>
|
|
1117
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
1118
|
+
<Dialog.Popup>
|
|
1119
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
1120
|
+
<Dialog.Content ref={ contentRef }>
|
|
1121
|
+
<p>Body</p>
|
|
1122
|
+
</Dialog.Content>
|
|
1123
|
+
</Dialog.Popup>
|
|
1124
|
+
</Dialog.Root>
|
|
1125
|
+
);
|
|
1126
|
+
|
|
1127
|
+
await user.click( screen.getByRole( 'button', { name: 'Open' } ) );
|
|
1128
|
+
await waitFor( () => {
|
|
1129
|
+
expect( contentRef.current ).toBeInstanceOf( HTMLDivElement );
|
|
1130
|
+
} );
|
|
1131
|
+
|
|
1132
|
+
// JSDOM doesn't lay out elements, so we simulate an
|
|
1133
|
+
// overflowing scroll container by stubbing layout metrics
|
|
1134
|
+
// per scenario and dispatching a scroll event.
|
|
1135
|
+
const content = contentRef.current!;
|
|
1136
|
+
Object.defineProperty( content, 'scrollHeight', {
|
|
1137
|
+
configurable: true,
|
|
1138
|
+
value: 500,
|
|
1139
|
+
} );
|
|
1140
|
+
Object.defineProperty( content, 'clientHeight', {
|
|
1141
|
+
configurable: true,
|
|
1142
|
+
value: 100,
|
|
1143
|
+
} );
|
|
1144
|
+
|
|
1145
|
+
const setScrollTop = ( value: number ) => {
|
|
1146
|
+
Object.defineProperty( content, 'scrollTop', {
|
|
1147
|
+
configurable: true,
|
|
1148
|
+
value,
|
|
1149
|
+
} );
|
|
1150
|
+
act( () => {
|
|
1151
|
+
content.dispatchEvent(
|
|
1152
|
+
new Event( 'scroll', { bubbles: true } )
|
|
1153
|
+
);
|
|
1154
|
+
} );
|
|
1155
|
+
};
|
|
1156
|
+
|
|
1157
|
+
// At the top: only "from-bottom" is set (content below).
|
|
1158
|
+
setScrollTop( 0 );
|
|
1159
|
+
expect( content ).not.toHaveAttribute(
|
|
1160
|
+
'data-wp-ui-overlay-scrolled-from-top'
|
|
1161
|
+
);
|
|
1162
|
+
expect( content ).toHaveAttribute(
|
|
1163
|
+
'data-wp-ui-overlay-scrolled-from-bottom'
|
|
1164
|
+
);
|
|
1165
|
+
|
|
1166
|
+
// In the middle: both are set.
|
|
1167
|
+
setScrollTop( 200 );
|
|
1168
|
+
expect( content ).toHaveAttribute(
|
|
1169
|
+
'data-wp-ui-overlay-scrolled-from-top'
|
|
1170
|
+
);
|
|
1171
|
+
expect( content ).toHaveAttribute(
|
|
1172
|
+
'data-wp-ui-overlay-scrolled-from-bottom'
|
|
1173
|
+
);
|
|
1174
|
+
|
|
1175
|
+
// At the bottom: only "from-top" is set (content above).
|
|
1176
|
+
setScrollTop( 400 );
|
|
1177
|
+
expect( content ).toHaveAttribute(
|
|
1178
|
+
'data-wp-ui-overlay-scrolled-from-top'
|
|
1179
|
+
);
|
|
1180
|
+
expect( content ).not.toHaveAttribute(
|
|
1181
|
+
'data-wp-ui-overlay-scrolled-from-bottom'
|
|
1182
|
+
);
|
|
1183
|
+
} );
|
|
1184
|
+
} );
|
|
485
1185
|
} );
|