@atlaskit/top-layer 0.12.2 → 0.14.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 +31 -0
- package/README.md +61 -34
- package/dist/cjs/animations/presets.js +4 -4
- package/dist/cjs/entry-points/focus.js +6 -4
- package/dist/cjs/entry-points/get-aria-for-trigger.js +12 -0
- package/dist/cjs/entry-points/popover-surface.js +12 -0
- package/dist/cjs/entry-points/use-anchor-position-at-point.js +12 -0
- package/dist/cjs/entry-points/use-popover-id.js +21 -0
- package/dist/cjs/focus/get-first-focusable.js +19 -0
- package/dist/cjs/focus/get-focusables.js +30 -0
- package/dist/cjs/focus/get-last-focusable.js +19 -0
- package/dist/cjs/focus/get-next-focusable.js +43 -0
- package/dist/cjs/focus/is-in-same-layer.js +23 -0
- package/dist/cjs/focus/is-nested-layer-focused.js +32 -0
- package/dist/cjs/focus/selectors.js +19 -0
- package/dist/cjs/focus/types.js +1 -0
- package/dist/cjs/internal/get-aria-for-trigger.js +88 -0
- package/dist/cjs/internal/role-to-aria-has-popup.js +37 -0
- package/dist/cjs/internal/role-types.js +2 -35
- package/dist/cjs/internal/should-focus-into-popover.js +19 -0
- package/dist/cjs/internal/slot.js +1 -1
- package/dist/cjs/internal/use-anchor-position-at-point.js +127 -0
- package/dist/cjs/internal/use-anchor-position.js +36 -16
- package/dist/cjs/internal/use-focus-wrap.js +8 -5
- package/dist/cjs/internal/use-initial-focus.js +4 -4
- package/dist/cjs/placement-map/index.js +2 -2
- package/dist/cjs/placement-map/legacy-placements.js +2 -101
- package/dist/cjs/placement-map/placement-mapping.js +103 -0
- package/dist/cjs/popover/popover.js +79 -80
- package/dist/cjs/popover-surface/index.js +12 -0
- package/dist/cjs/{popup/popup-surface.js → popover-surface/popover-surface.js} +9 -12
- package/dist/cjs/testing/polyfill.js +9 -6
- package/dist/cjs/use-arrow-navigation/use-arrow-navigation.js +7 -5
- package/dist/es2019/animations/presets.js +4 -4
- package/dist/es2019/entry-points/focus.js +3 -1
- package/dist/es2019/entry-points/get-aria-for-trigger.js +1 -0
- package/dist/es2019/entry-points/popover-surface.js +1 -0
- package/dist/es2019/entry-points/use-anchor-position-at-point.js +1 -0
- package/dist/es2019/entry-points/use-popover-id.js +15 -0
- package/dist/es2019/focus/get-first-focusable.js +14 -0
- package/dist/es2019/focus/get-focusables.js +19 -0
- package/dist/es2019/focus/get-last-focusable.js +14 -0
- package/dist/es2019/focus/get-next-focusable.js +38 -0
- package/dist/es2019/focus/is-in-same-layer.js +18 -0
- package/dist/es2019/focus/is-nested-layer-focused.js +28 -0
- package/dist/es2019/focus/selectors.js +11 -0
- package/dist/es2019/focus/types.js +0 -0
- package/dist/es2019/internal/get-aria-for-trigger.js +84 -0
- package/dist/es2019/internal/role-to-aria-has-popup.js +32 -0
- package/dist/es2019/internal/role-types.js +0 -33
- package/dist/es2019/internal/should-focus-into-popover.js +14 -0
- package/dist/es2019/internal/slot.js +1 -1
- package/dist/es2019/internal/use-anchor-position-at-point.js +122 -0
- package/dist/es2019/internal/use-anchor-position.js +21 -14
- package/dist/es2019/internal/use-focus-wrap.js +4 -1
- package/dist/es2019/internal/use-initial-focus.js +1 -1
- package/dist/es2019/placement-map/index.js +1 -1
- package/dist/es2019/placement-map/legacy-placements.js +1 -100
- package/dist/es2019/placement-map/placement-mapping.js +97 -0
- package/dist/es2019/popover/popover.js +79 -80
- package/dist/es2019/popover-surface/index.js +1 -0
- package/dist/es2019/popover-surface/popover-surface.js +27 -0
- package/dist/es2019/testing/polyfill.js +9 -6
- package/dist/es2019/use-arrow-navigation/use-arrow-navigation.js +3 -1
- package/dist/esm/animations/presets.js +4 -4
- package/dist/esm/entry-points/focus.js +3 -1
- package/dist/esm/entry-points/get-aria-for-trigger.js +1 -0
- package/dist/esm/entry-points/popover-surface.js +1 -0
- package/dist/esm/entry-points/use-anchor-position-at-point.js +1 -0
- package/dist/esm/entry-points/use-popover-id.js +15 -0
- package/dist/esm/focus/get-first-focusable.js +13 -0
- package/dist/esm/focus/get-focusables.js +24 -0
- package/dist/esm/focus/get-last-focusable.js +13 -0
- package/dist/esm/focus/get-next-focusable.js +37 -0
- package/dist/esm/focus/is-in-same-layer.js +17 -0
- package/dist/esm/focus/is-nested-layer-focused.js +27 -0
- package/dist/esm/focus/selectors.js +13 -0
- package/dist/esm/focus/types.js +0 -0
- package/dist/esm/internal/get-aria-for-trigger.js +83 -0
- package/dist/esm/internal/role-to-aria-has-popup.js +31 -0
- package/dist/esm/internal/role-types.js +2 -34
- package/dist/esm/internal/should-focus-into-popover.js +13 -0
- package/dist/esm/internal/slot.js +1 -1
- package/dist/esm/internal/use-anchor-position-at-point.js +122 -0
- package/dist/esm/internal/use-anchor-position.js +36 -16
- package/dist/esm/internal/use-focus-wrap.js +4 -1
- package/dist/esm/internal/use-initial-focus.js +1 -1
- package/dist/esm/placement-map/index.js +1 -1
- package/dist/esm/placement-map/legacy-placements.js +1 -100
- package/dist/esm/placement-map/placement-mapping.js +97 -0
- package/dist/esm/popover/popover.js +79 -80
- package/dist/esm/popover-surface/index.js +1 -0
- package/dist/esm/popover-surface/popover-surface.js +26 -0
- package/dist/esm/testing/polyfill.js +9 -6
- package/dist/esm/use-arrow-navigation/use-arrow-navigation.js +3 -1
- package/dist/types/animations/presets.d.ts +4 -4
- package/dist/types/animations/types.d.ts +1 -1
- package/dist/types/dialog/types.d.ts +0 -8
- package/dist/types/entry-points/focus.d.ts +4 -2
- package/dist/types/entry-points/get-aria-for-trigger.d.ts +1 -0
- package/dist/types/entry-points/popover-surface.d.ts +2 -0
- package/dist/types/entry-points/popover.d.ts +1 -1
- package/dist/types/entry-points/use-anchor-position-at-point.d.ts +1 -0
- package/dist/types/entry-points/use-popover-id.d.ts +11 -0
- package/dist/types/focus/get-first-focusable.d.ts +8 -0
- package/dist/types/focus/get-focusables.d.ts +13 -0
- package/dist/types/focus/get-last-focusable.d.ts +8 -0
- package/dist/types/focus/get-next-focusable.d.ts +13 -0
- package/dist/types/focus/is-in-same-layer.d.ts +8 -0
- package/dist/types/focus/is-nested-layer-focused.d.ts +8 -0
- package/dist/types/focus/selectors.d.ts +4 -0
- package/dist/types/focus/types.d.ts +5 -0
- package/dist/types/internal/get-aria-for-trigger.d.ts +86 -0
- package/dist/types/internal/role-to-aria-has-popup.d.ts +13 -0
- package/dist/types/internal/role-types.d.ts +0 -12
- package/dist/types/internal/should-focus-into-popover.d.ts +8 -0
- package/dist/types/internal/slot.d.ts +2 -2
- package/dist/types/internal/use-anchor-position-at-point.d.ts +62 -0
- package/dist/types/internal/use-anchor-position.d.ts +6 -1
- package/dist/types/placement-map/index.d.ts +1 -1
- package/dist/types/placement-map/legacy-placements.d.ts +0 -12
- package/dist/types/placement-map/placement-mapping.d.ts +13 -0
- package/dist/types/popover/index.d.ts +1 -1
- package/dist/types/popover/popover.d.ts +6 -13
- package/dist/types/popover/types.d.ts +6 -5
- package/dist/types/popover-surface/index.d.ts +2 -0
- package/dist/types/popover-surface/popover-surface.d.ts +21 -0
- package/dist/types/use-arrow-navigation/use-arrow-navigation.d.ts +1 -1
- package/dist/types-ts4.5/animations/presets.d.ts +4 -4
- package/dist/types-ts4.5/animations/types.d.ts +1 -1
- package/dist/types-ts4.5/dialog/types.d.ts +0 -8
- package/dist/types-ts4.5/entry-points/focus.d.ts +4 -2
- package/dist/types-ts4.5/entry-points/get-aria-for-trigger.d.ts +1 -0
- package/dist/types-ts4.5/entry-points/popover-surface.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/popover.d.ts +1 -1
- package/dist/types-ts4.5/entry-points/use-anchor-position-at-point.d.ts +1 -0
- package/dist/types-ts4.5/entry-points/use-popover-id.d.ts +11 -0
- package/dist/types-ts4.5/focus/get-first-focusable.d.ts +8 -0
- package/dist/types-ts4.5/focus/get-focusables.d.ts +13 -0
- package/dist/types-ts4.5/focus/get-last-focusable.d.ts +8 -0
- package/dist/types-ts4.5/focus/get-next-focusable.d.ts +13 -0
- package/dist/types-ts4.5/focus/is-in-same-layer.d.ts +8 -0
- package/dist/types-ts4.5/focus/is-nested-layer-focused.d.ts +8 -0
- package/dist/types-ts4.5/focus/selectors.d.ts +4 -0
- package/dist/types-ts4.5/focus/types.d.ts +5 -0
- package/dist/types-ts4.5/internal/get-aria-for-trigger.d.ts +86 -0
- package/dist/types-ts4.5/internal/role-to-aria-has-popup.d.ts +13 -0
- package/dist/types-ts4.5/internal/role-types.d.ts +0 -12
- package/dist/types-ts4.5/internal/should-focus-into-popover.d.ts +8 -0
- package/dist/types-ts4.5/internal/slot.d.ts +2 -2
- package/dist/types-ts4.5/internal/use-anchor-position-at-point.d.ts +62 -0
- package/dist/types-ts4.5/internal/use-anchor-position.d.ts +6 -1
- package/dist/types-ts4.5/placement-map/index.d.ts +1 -1
- package/dist/types-ts4.5/placement-map/legacy-placements.d.ts +0 -12
- package/dist/types-ts4.5/placement-map/placement-mapping.d.ts +13 -0
- package/dist/types-ts4.5/popover/index.d.ts +1 -1
- package/dist/types-ts4.5/popover/popover.d.ts +6 -13
- package/dist/types-ts4.5/popover/types.d.ts +6 -5
- package/dist/types-ts4.5/popover-surface/index.d.ts +2 -0
- package/dist/types-ts4.5/popover-surface/popover-surface.d.ts +21 -0
- package/dist/types-ts4.5/use-arrow-navigation/use-arrow-navigation.d.ts +1 -1
- package/get-aria-for-trigger/package.json +17 -0
- package/package.json +3 -3
- package/popover-surface/package.json +17 -0
- package/use-anchor-position-at-point/package.json +17 -0
- package/use-popover-id/package.json +17 -0
- package/dist/cjs/entry-points/popup-surface.js +0 -12
- package/dist/cjs/entry-points/popup.js +0 -12
- package/dist/cjs/focus/focus.js +0 -169
- package/dist/cjs/focus/index.js +0 -24
- package/dist/cjs/popup/index.js +0 -37
- package/dist/cjs/popup/popup-content.js +0 -214
- package/dist/cjs/popup/popup-context.js +0 -25
- package/dist/cjs/popup/popup-provider.js +0 -15
- package/dist/cjs/popup/popup-trigger-function.js +0 -80
- package/dist/cjs/popup/popup-trigger.js +0 -66
- package/dist/cjs/popup/popup.js +0 -81
- package/dist/cjs/popup/types.js +0 -5
- package/dist/cjs/popup/use-maybe-popup-context.js +0 -17
- package/dist/cjs/popup/use-popup-context.js +0 -20
- package/dist/es2019/entry-points/popup-surface.js +0 -1
- package/dist/es2019/entry-points/popup.js +0 -1
- package/dist/es2019/focus/focus.js +0 -158
- package/dist/es2019/focus/index.js +0 -1
- package/dist/es2019/popup/index.js +0 -33
- package/dist/es2019/popup/popup-content.js +0 -206
- package/dist/es2019/popup/popup-context.js +0 -20
- package/dist/es2019/popup/popup-provider.js +0 -10
- package/dist/es2019/popup/popup-surface.js +0 -30
- package/dist/es2019/popup/popup-trigger-function.js +0 -75
- package/dist/es2019/popup/popup-trigger.js +0 -61
- package/dist/es2019/popup/popup.js +0 -67
- package/dist/es2019/popup/types.js +0 -1
- package/dist/es2019/popup/use-maybe-popup-context.js +0 -12
- package/dist/es2019/popup/use-popup-context.js +0 -15
- package/dist/esm/entry-points/popup-surface.js +0 -1
- package/dist/esm/entry-points/popup.js +0 -1
- package/dist/esm/focus/focus.js +0 -160
- package/dist/esm/focus/index.js +0 -1
- package/dist/esm/popup/index.js +0 -33
- package/dist/esm/popup/popup-content.js +0 -206
- package/dist/esm/popup/popup-context.js +0 -20
- package/dist/esm/popup/popup-provider.js +0 -10
- package/dist/esm/popup/popup-surface.js +0 -29
- package/dist/esm/popup/popup-trigger-function.js +0 -75
- package/dist/esm/popup/popup-trigger.js +0 -59
- package/dist/esm/popup/popup.js +0 -72
- package/dist/esm/popup/types.js +0 -1
- package/dist/esm/popup/use-maybe-popup-context.js +0 -12
- package/dist/esm/popup/use-popup-context.js +0 -15
- package/dist/types/entry-points/popup-surface.d.ts +0 -2
- package/dist/types/entry-points/popup.d.ts +0 -2
- package/dist/types/focus/focus.d.ts +0 -50
- package/dist/types/focus/index.d.ts +0 -2
- package/dist/types/popup/index.d.ts +0 -34
- package/dist/types/popup/popup-content.d.ts +0 -14
- package/dist/types/popup/popup-context.d.ts +0 -96
- package/dist/types/popup/popup-provider.d.ts +0 -10
- package/dist/types/popup/popup-surface.d.ts +0 -22
- package/dist/types/popup/popup-trigger-function.d.ts +0 -112
- package/dist/types/popup/popup-trigger.d.ts +0 -14
- package/dist/types/popup/popup.d.ts +0 -14
- package/dist/types/popup/types.d.ts +0 -321
- package/dist/types/popup/use-maybe-popup-context.d.ts +0 -8
- package/dist/types/popup/use-popup-context.d.ts +0 -7
- package/dist/types-ts4.5/entry-points/popup-surface.d.ts +0 -2
- package/dist/types-ts4.5/entry-points/popup.d.ts +0 -2
- package/dist/types-ts4.5/focus/focus.d.ts +0 -50
- package/dist/types-ts4.5/focus/index.d.ts +0 -2
- package/dist/types-ts4.5/popup/index.d.ts +0 -34
- package/dist/types-ts4.5/popup/popup-content.d.ts +0 -14
- package/dist/types-ts4.5/popup/popup-context.d.ts +0 -96
- package/dist/types-ts4.5/popup/popup-provider.d.ts +0 -10
- package/dist/types-ts4.5/popup/popup-surface.d.ts +0 -22
- package/dist/types-ts4.5/popup/popup-trigger-function.d.ts +0 -112
- package/dist/types-ts4.5/popup/popup-trigger.d.ts +0 -14
- package/dist/types-ts4.5/popup/popup.d.ts +0 -14
- package/dist/types-ts4.5/popup/types.d.ts +0 -321
- package/dist/types-ts4.5/popup/use-maybe-popup-context.d.ts +0 -8
- package/dist/types-ts4.5/popup/use-popup-context.d.ts +0 -7
- package/popup/package.json +0 -17
- package/popup-surface/package.json +0 -17
- /package/dist/cjs/{popup/popup-surface.compiled.css → popover-surface/popover-surface.compiled.css} +0 -0
- /package/dist/es2019/{popup/popup-surface.compiled.css → popover-surface/popover-surface.compiled.css} +0 -0
- /package/dist/esm/{popup/popup-surface.compiled.css → popover-surface/popover-surface.compiled.css} +0 -0
|
@@ -7,13 +7,12 @@ import { bind } from 'bind-event-listener';
|
|
|
7
7
|
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
8
8
|
import once from '@atlaskit/ds-lib/once';
|
|
9
9
|
import { useNotifyOpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer';
|
|
10
|
+
import { shouldFocusIntoPopover } from '../internal/role-types';
|
|
10
11
|
import { useAnimatedVisibility } from '../internal/use-animated-visibility';
|
|
11
12
|
import { useFocusWrap } from '../internal/use-focus-wrap';
|
|
12
13
|
import { useInitialFocus } from '../internal/use-initial-focus';
|
|
13
14
|
/**
|
|
14
|
-
* Detects
|
|
15
|
-
* Uses DOM reflection: unsupported browsers reflect the invalid value default ("manual").
|
|
16
|
-
* Safe for SSR. Result is cached via `once`.
|
|
15
|
+
* Detects `popover="hint"` support via DOM reflection. SSR-safe, cached.
|
|
17
16
|
*/
|
|
18
17
|
const supportsPopoverHint = once(() => {
|
|
19
18
|
if (typeof document === 'undefined') {
|
|
@@ -30,33 +29,20 @@ const styles = {
|
|
|
30
29
|
root: "_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _19pkidpf _2hwxidpf _otyridpf _18u0idpf _1r041wug _1reoewfl _18m9ewfl _bfhk1j28"
|
|
31
30
|
};
|
|
32
31
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* and dismissed when closeLayers() is called (e.g. when the side nav resizes).
|
|
36
|
-
*
|
|
37
|
-
* Note on open layer observer types not included here:
|
|
38
|
-
* - 'modal' only ever comes from the Dialog primitive, not Popover.
|
|
39
|
-
* - Other layer types (e.g. 'tooltip') do not yet exist in LayerType because
|
|
40
|
-
* there is no current use case for distinguishing them in the observer.
|
|
32
|
+
* Roles registered with the open layer observer as `popup`, so `closeLayers()`
|
|
33
|
+
* dismisses them. `modal` comes from Dialog only; other layer types are unused.
|
|
41
34
|
*/
|
|
42
35
|
const POPUP_ROLES = new Set(['menu', 'listbox', 'dialog', 'alertdialog', 'tree', 'grid']);
|
|
43
36
|
|
|
44
37
|
/**
|
|
45
|
-
* Unopinionated top-layer primitive.
|
|
46
|
-
*
|
|
47
|
-
* Manages only visibility (isOpen) and animation (animate). Has no knowledge
|
|
48
|
-
* of positioning - compose with `useAnchorPosition` for anchor positioning
|
|
49
|
-
* and optionally `useWidthFromAnchor` for setting the width of a popover element
|
|
50
|
-
* relative to its anchor trigger.
|
|
38
|
+
* Unopinionated top-layer primitive. Manages visibility and animation only;
|
|
39
|
+
* compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
|
|
51
40
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* - `isOpen={false}` → `hidePopover()`, exit animation via `allow-discrete`
|
|
41
|
+
* `isOpen={true}` calls `showPopover()` (entry via `@starting-style`);
|
|
42
|
+
* `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
|
|
55
43
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* consumer must set `isOpen` to `false`. The DOM owns the dismiss; React
|
|
59
|
-
* must follow.
|
|
44
|
+
* In `mode="auto"`, the browser can light-dismiss (Escape, click outside).
|
|
45
|
+
* `onClose` fires; the consumer must then set `isOpen` to `false`.
|
|
60
46
|
*/
|
|
61
47
|
export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
62
48
|
children,
|
|
@@ -79,11 +65,9 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
79
65
|
const autoId = useId();
|
|
80
66
|
const ownRef = useRef(null);
|
|
81
67
|
const combinedRef = mergeRefs([ownRef, ref].filter(Boolean));
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
// (
|
|
85
|
-
// attributes. React 19.2.0 replaced colons with underscores, making this
|
|
86
|
-
// stripping unnecessary once React 18 support is dropped.
|
|
68
|
+
// React 18 `useId()` returns IDs with colons (invalid in CSS selectors
|
|
69
|
+
// and popover target attributes). Strip them; remove once React 18 is
|
|
70
|
+
// dropped (React 19.2 uses underscores).
|
|
87
71
|
const popoverId = idProp !== null && idProp !== void 0 ? idProp : `popover-${autoId.replace(/:/g, '')}`;
|
|
88
72
|
const {
|
|
89
73
|
showChildren,
|
|
@@ -96,12 +80,10 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
96
80
|
onExitFinish
|
|
97
81
|
});
|
|
98
82
|
|
|
99
|
-
// Focus management
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
// tracks `previouslyFocusedElement` on show and restores it on hide.
|
|
104
|
-
// No custom restoration hook is needed. See: notes/architecture/focus-restoration.md
|
|
83
|
+
// Focus management: initial focus on open (role-dependent), Tab cycling
|
|
84
|
+
// for dialog roles. Restoration is native for outermost popovers; nested
|
|
85
|
+
// focus-capturing roles are handled below via `beforetoggle` snapshot.
|
|
86
|
+
// See: notes/architecture/focus-restoration.md
|
|
105
87
|
useFocusWrap({
|
|
106
88
|
elementRef: ownRef,
|
|
107
89
|
role
|
|
@@ -112,13 +94,9 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
112
94
|
role
|
|
113
95
|
});
|
|
114
96
|
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
// (
|
|
118
|
-
//
|
|
119
|
-
// Only set type: 'popup' for roles that are interactive overlay popups.
|
|
120
|
-
// Passive/informational roles (tooltip, note, status, alert, log) and
|
|
121
|
-
// no-role cases do not map to LayerType 'popup', so type is left undefined.
|
|
97
|
+
// Register with open layer observer so `closeLayers()` and open-count
|
|
98
|
+
// subscriptions work. Only popup-like roles register as `popup`; passive
|
|
99
|
+
// roles (tooltip, status, etc.) leave `type` undefined.
|
|
122
100
|
const handleObserverClose = useCallback(() => {
|
|
123
101
|
onClose === null || onClose === void 0 ? void 0 : onClose({
|
|
124
102
|
reason: 'programmatic'
|
|
@@ -130,25 +108,29 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
130
108
|
onClose: handleObserverClose
|
|
131
109
|
});
|
|
132
110
|
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
// However, there is a behavioral difference: "auto" participates in the
|
|
138
|
-
// auto-dismiss stack and WILL close other "auto" popovers when it opens
|
|
139
|
-
// (e.g. a tooltip opening will close an open dropdown). "hint" does not
|
|
140
|
-
// have this side effect. This difference only affects browsers without
|
|
141
|
-
// popover="hint" support, and that set is shrinking rapidly.
|
|
111
|
+
// `hint` falls back to `auto` when unsupported: closest behavior (light
|
|
112
|
+
// dismiss works), but `auto` participates in the auto-dismiss stack so it
|
|
113
|
+
// will close other `auto` popovers when opened. Acceptable trade-off given
|
|
114
|
+
// shrinking browser set without `hint` support.
|
|
142
115
|
const mode = modeProp === 'hint' && !supportsPopoverHint() ? 'auto' : modeProp;
|
|
143
116
|
|
|
144
|
-
//
|
|
145
|
-
// When we call hidePopover() ourselves the beforetoggle event fires synchronously,
|
|
146
|
-
// so this ref prevents the toggle handler from calling onClose redundantly.
|
|
117
|
+
// Prevents toggle handler from calling onClose for our own hidePopover() calls.
|
|
147
118
|
const programmaticCloseRef = useRef(false);
|
|
148
119
|
|
|
149
|
-
//
|
|
150
|
-
// the browser processes light dismiss), read in the toggle handler.
|
|
120
|
+
// Set in capture-phase keydown so the toggle handler knows close reason.
|
|
151
121
|
const closeReasonRef = useRef('light-dismiss');
|
|
122
|
+
|
|
123
|
+
// Snapshot of pre-open focus, used to restore focus for nested popovers
|
|
124
|
+
// with focus-capturing roles (browser only restores the outermost).
|
|
125
|
+
const previouslyFocusedElementRef = useRef(null);
|
|
126
|
+
const handleBeforeToggle = useCallback(event => {
|
|
127
|
+
if (event.newState !== 'open') {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- need active element snapshot
|
|
131
|
+
const active = document.activeElement;
|
|
132
|
+
previouslyFocusedElementRef.current = active instanceof HTMLElement ? active : null;
|
|
133
|
+
}, []);
|
|
152
134
|
const handleToggle = useCallback(event => {
|
|
153
135
|
const element = ownRef.current;
|
|
154
136
|
if (event.newState === 'open') {
|
|
@@ -166,32 +148,52 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
166
148
|
isOpen: false,
|
|
167
149
|
element: element
|
|
168
150
|
});
|
|
151
|
+
|
|
152
|
+
// Nested-popover focus restoration fallback (browser only
|
|
153
|
+
// restores outermost; Firefox skips nested entirely).
|
|
154
|
+
// Restore only when the role moved focus in on open AND the
|
|
155
|
+
// close was Escape/programmatic. For light dismiss, the
|
|
156
|
+
// click target keeps focus per HTML spec
|
|
157
|
+
// (`focusPreviousElement=false`).
|
|
158
|
+
const previouslyFocused = previouslyFocusedElementRef.current;
|
|
159
|
+
const reason = closeReasonRef.current;
|
|
160
|
+
const isProgrammatic = programmaticCloseRef.current;
|
|
161
|
+
const shouldRestore = previouslyFocused !== null && previouslyFocused.isConnected && shouldFocusIntoPopover({
|
|
162
|
+
role
|
|
163
|
+
}) && (reason === 'escape' || isProgrammatic);
|
|
164
|
+
if (shouldRestore && previouslyFocused) {
|
|
165
|
+
previouslyFocused.focus({
|
|
166
|
+
preventScroll: true
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
previouslyFocusedElementRef.current = null;
|
|
169
170
|
}
|
|
170
171
|
|
|
171
|
-
// Programmatic close
|
|
172
|
+
// Programmatic close: consumer already knows.
|
|
172
173
|
if (programmaticCloseRef.current) {
|
|
174
|
+
// Reset reason so a stale 'escape' from a race with Escape keydown
|
|
175
|
+
// does not corrupt the next browser-dismiss cycle.
|
|
176
|
+
closeReasonRef.current = 'light-dismiss';
|
|
173
177
|
return;
|
|
174
178
|
}
|
|
175
179
|
|
|
176
|
-
// Browser dismiss (Escape
|
|
180
|
+
// Browser dismiss (Escape/click-outside).
|
|
177
181
|
const reason = closeReasonRef.current;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// `manual
|
|
181
|
-
// internally by `PopupContent` - the optional check guards
|
|
182
|
-
// the manual-mode forwarded path where the field is undefined.
|
|
182
|
+
// reset for next dismiss
|
|
183
|
+
closeReasonRef.current = 'light-dismiss';
|
|
184
|
+
// Optional: `manual` mode has no `onClose` in the forwarded type.
|
|
183
185
|
onClose === null || onClose === void 0 ? void 0 : onClose({
|
|
184
186
|
reason
|
|
185
187
|
});
|
|
186
188
|
}
|
|
187
|
-
}, [onClose, onOpenChange]);
|
|
189
|
+
}, [onClose, onOpenChange, role]);
|
|
188
190
|
useEffect(() => {
|
|
189
191
|
const element = ownRef.current;
|
|
190
192
|
if (!element) {
|
|
191
193
|
return;
|
|
192
194
|
}
|
|
193
195
|
|
|
194
|
-
//
|
|
196
|
+
// Tag Escape before the browser processes light dismiss.
|
|
195
197
|
const unbindEscape = bind(element, {
|
|
196
198
|
type: 'keydown',
|
|
197
199
|
listener: event => {
|
|
@@ -207,15 +209,20 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
207
209
|
type: 'toggle',
|
|
208
210
|
listener: handleToggle
|
|
209
211
|
});
|
|
212
|
+
// Snapshot `document.activeElement` before `useInitialFocus` moves it.
|
|
213
|
+
const unbindBeforeToggle = bind(element, {
|
|
214
|
+
type: 'beforetoggle',
|
|
215
|
+
listener: handleBeforeToggle
|
|
216
|
+
});
|
|
210
217
|
return () => {
|
|
211
218
|
unbindEscape();
|
|
212
219
|
unbindToggle();
|
|
220
|
+
unbindBeforeToggle();
|
|
213
221
|
};
|
|
214
|
-
}, [handleToggle]);
|
|
222
|
+
}, [handleToggle, handleBeforeToggle]);
|
|
215
223
|
|
|
216
|
-
// Placement-dependent animation CSS vars
|
|
217
|
-
//
|
|
218
|
-
// (e.g. inline `animate={slideAndFade()}`) do not re-trigger visibility.
|
|
224
|
+
// Placement-dependent animation CSS vars. Kept separate from show/hide
|
|
225
|
+
// so preset reference changes do not re-trigger visibility.
|
|
219
226
|
useLayoutEffect(() => {
|
|
220
227
|
const el = ownRef.current;
|
|
221
228
|
if (!el || !(preset !== null && preset !== void 0 && preset.getProperties) || !placement) {
|
|
@@ -229,14 +236,9 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
229
236
|
});
|
|
230
237
|
}, [preset, placement]);
|
|
231
238
|
|
|
232
|
-
// Show/hide based on isOpen.
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
// effect ran).
|
|
236
|
-
// Defensive try/catch: these APIs throw InvalidStateError if the element
|
|
237
|
-
// is disconnected or missing the popover attribute. While we do not expect
|
|
238
|
-
// that to happen in normal usage, it can occur in edge cases (e.g. React
|
|
239
|
-
// concurrent mode, StrictMode double-effects, or unmount races).
|
|
239
|
+
// Show/hide based on isOpen. `showPopover`/`hidePopover` are no-ops when
|
|
240
|
+
// already in the target state. Try/catch guards `InvalidStateError` on
|
|
241
|
+
// disconnected elements (StrictMode/concurrent/unmount edge cases).
|
|
240
242
|
useLayoutEffect(() => {
|
|
241
243
|
const el = ownRef.current;
|
|
242
244
|
if (!el) {
|
|
@@ -244,20 +246,17 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
244
246
|
}
|
|
245
247
|
if (isOpen) {
|
|
246
248
|
programmaticCloseRef.current = false;
|
|
247
|
-
// Defensive: element may be disconnected or in an unexpected state.
|
|
248
249
|
try {
|
|
249
250
|
el.showPopover();
|
|
250
251
|
} catch {}
|
|
251
252
|
return () => {
|
|
252
253
|
programmaticCloseRef.current = true;
|
|
253
|
-
// Defensive: element may be disconnected or in an unexpected state.
|
|
254
254
|
try {
|
|
255
255
|
el.hidePopover();
|
|
256
256
|
} catch {}
|
|
257
257
|
};
|
|
258
258
|
}
|
|
259
259
|
programmaticCloseRef.current = true;
|
|
260
|
-
// Defensive: element may be disconnected or in an unexpected state.
|
|
261
260
|
try {
|
|
262
261
|
el.hidePopover();
|
|
263
262
|
} catch {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PopoverSurface } from './popover-surface';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* popover-surface.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
|
+
import "./popover-surface.compiled.css";
|
|
3
|
+
import { ax, ix } from "@compiled/react/runtime";
|
|
4
|
+
import React from 'react';
|
|
5
|
+
const styles = {
|
|
6
|
+
root: "_2rkofajl _1reo1wug _18m91wug _bfhk1bhr _16qs130s"
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Optional styled wrapper for popover content.
|
|
11
|
+
*
|
|
12
|
+
* Adds default visual styling (background, border-radius, box-shadow)
|
|
13
|
+
* using design tokens.
|
|
14
|
+
*
|
|
15
|
+
* Presentational primitive - `children`-only by design. This component
|
|
16
|
+
* intentionally exposes no `style`, `className`, `xcss`, `id`, or `ref`
|
|
17
|
+
* props. If you need any of those, render your own wrapper element inside
|
|
18
|
+
* `Popover` instead. `PopoverSurface` is the no-config "give me the default
|
|
19
|
+
* ADS overlay look" surface, nothing more.
|
|
20
|
+
*/
|
|
21
|
+
export function PopoverSurface({
|
|
22
|
+
children
|
|
23
|
+
}) {
|
|
24
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
25
|
+
className: ax([styles.root])
|
|
26
|
+
}, children);
|
|
27
|
+
}
|
|
@@ -107,7 +107,7 @@ function createToggleScheduler() {
|
|
|
107
107
|
newState
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
-
// Task queue (setTimeout)
|
|
110
|
+
// Task queue (setTimeout): browser fires toggle after microtasks drain, not during
|
|
111
111
|
setTimeout(() => {
|
|
112
112
|
const entry = pending.get(element);
|
|
113
113
|
if (!entry) {
|
|
@@ -552,10 +552,11 @@ if (typeof HTMLElement !== 'undefined') {
|
|
|
552
552
|
element: this
|
|
553
553
|
})} is not connected to the document. Ensure the element has been added to the DOM (e.g. via render() or document.body.appendChild()) before calling showPopover().`, 'InvalidStateError');
|
|
554
554
|
}
|
|
555
|
+
// No-op: already showing.
|
|
555
556
|
if (isPopoverOpen({
|
|
556
557
|
element: this
|
|
557
558
|
})) {
|
|
558
|
-
return;
|
|
559
|
+
return;
|
|
559
560
|
}
|
|
560
561
|
|
|
561
562
|
// sync, cancelable on show only
|
|
@@ -745,8 +746,9 @@ if (typeof HTMLDialogElement !== 'undefined') {
|
|
|
745
746
|
})} is not connected to the document. Ensure the element has been added to the DOM (e.g. via render() or document.body.appendChild()) before calling showModal().`, 'InvalidStateError');
|
|
746
747
|
}
|
|
747
748
|
if (this.hasAttribute('open')) {
|
|
749
|
+
// No-op: already modal.
|
|
748
750
|
if (this._isModal) {
|
|
749
|
-
return;
|
|
751
|
+
return;
|
|
750
752
|
}
|
|
751
753
|
throw new DOMException(`Failed to execute 'showModal' on 'HTMLDialogElement': ${describeElement({
|
|
752
754
|
element: this
|
|
@@ -770,7 +772,7 @@ if (typeof HTMLDialogElement !== 'undefined') {
|
|
|
770
772
|
}
|
|
771
773
|
if (typeof proto.show !== 'function') {
|
|
772
774
|
proto.show = function show() {
|
|
773
|
-
// Browser does not throw for disconnected elements on show
|
|
775
|
+
// Browser does not throw for disconnected elements on show; no-op.
|
|
774
776
|
if (!this.isConnected || this.hasAttribute('open')) {
|
|
775
777
|
return;
|
|
776
778
|
}
|
|
@@ -792,11 +794,12 @@ if (typeof HTMLDialogElement !== 'undefined') {
|
|
|
792
794
|
}
|
|
793
795
|
if (typeof proto.close !== 'function') {
|
|
794
796
|
proto.close = function close(returnValue) {
|
|
797
|
+
// No-op: already closed.
|
|
795
798
|
if (!this.hasAttribute('open')) {
|
|
796
|
-
return;
|
|
799
|
+
return;
|
|
797
800
|
}
|
|
798
801
|
|
|
799
|
-
// Sync beforetoggle (not cancelable)
|
|
802
|
+
// Sync beforetoggle (not cancelable); matches browser behavior.
|
|
800
803
|
fireToggleEvent({
|
|
801
804
|
element: this,
|
|
802
805
|
type: 'beforetoggle',
|
|
@@ -2,7 +2,9 @@ import { useCallback, useEffect } from 'react';
|
|
|
2
2
|
import { bind } from 'bind-event-listener';
|
|
3
3
|
import { getDocument } from '@atlaskit/browser-apis';
|
|
4
4
|
import { KEY_DOWN, KEY_END, KEY_HOME, KEY_TAB, KEY_UP } from '@atlaskit/ds-lib/keycodes';
|
|
5
|
-
import { getFirstFocusable
|
|
5
|
+
import { getFirstFocusable } from '../focus/get-first-focusable';
|
|
6
|
+
import { getLastFocusable } from '../focus/get-last-focusable';
|
|
7
|
+
import { getNextFocusable } from '../focus/get-next-focusable';
|
|
6
8
|
const menuScope = '[role="menu"]';
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -58,10 +58,10 @@ var SLIDE_AND_FADE_CSS = "\n[data-ds-popover-slide-and-fade] {\n opacity: 0;\n
|
|
|
58
58
|
* import { slideAndFade } from '@atlaskit/top-layer/animations';
|
|
59
59
|
*
|
|
60
60
|
* // Default 4px slide (tooltip)
|
|
61
|
-
* <
|
|
61
|
+
* <Popover animate={slideAndFade()} />
|
|
62
62
|
*
|
|
63
63
|
* // Custom 8px slide (popup / dropdown)
|
|
64
|
-
* <
|
|
64
|
+
* <Popover animate={slideAndFade({ distance: 8 })} />
|
|
65
65
|
* ```
|
|
66
66
|
*/
|
|
67
67
|
export function slideAndFade(options) {
|
|
@@ -95,7 +95,7 @@ var FADE_CSS = "\n[data-ds-popover-fade] {\n opacity: 0;\n transition:\n op
|
|
|
95
95
|
* ```tsx
|
|
96
96
|
* import { fade } from '@atlaskit/top-layer/animations';
|
|
97
97
|
*
|
|
98
|
-
* <
|
|
98
|
+
* <Popover animate={fade()} />
|
|
99
99
|
* ```
|
|
100
100
|
*/
|
|
101
101
|
// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
|
|
@@ -121,7 +121,7 @@ var SCALE_AND_FADE_CSS = "\n[data-ds-popover-scale-and-fade] {\n opacity: 0;\n
|
|
|
121
121
|
* ```tsx
|
|
122
122
|
* import { scaleAndFade } from '@atlaskit/top-layer/animations';
|
|
123
123
|
*
|
|
124
|
-
* <
|
|
124
|
+
* <Popover animate={scaleAndFade()} />
|
|
125
125
|
* ```
|
|
126
126
|
*/
|
|
127
127
|
// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
export { getFirstFocusable
|
|
1
|
+
export { getFirstFocusable } from '../focus/get-first-focusable';
|
|
2
|
+
export { getLastFocusable } from '../focus/get-last-focusable';
|
|
3
|
+
export { getNextFocusable } from '../focus/get-next-focusable';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getAriaForTrigger } from '../internal/get-aria-for-trigger';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PopoverSurface } from '../popover-surface';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useAnchorPositionAtPoint } from '../internal/use-anchor-position-at-point';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useId } from '@atlaskit/ds-lib/use-id';
|
|
2
|
+
/**
|
|
3
|
+
* Returns a stable HTML `id` used to wire a trigger element to its popover
|
|
4
|
+
* via ARIA (`aria-controls`) and the Popover API (`popovertarget`).
|
|
5
|
+
*
|
|
6
|
+
* The returned value is intended for the `id` attribute on the popover and
|
|
7
|
+
* for the matching `aria-controls` / `popovertarget` references on the
|
|
8
|
+
* trigger. It is NOT a CSS `anchor-name` value: CSS anchor positioning is
|
|
9
|
+
* handled internally by `useAnchorPosition`, which mints and applies its
|
|
10
|
+
* own `anchor-name` on the trigger element.
|
|
11
|
+
*/
|
|
12
|
+
export function usePopoverId() {
|
|
13
|
+
// prefixing for debug clarity in the DOM
|
|
14
|
+
return "popover-".concat(useId());
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { getFocusables } from './get-focusables';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the first focusable element within the container.
|
|
4
|
+
*/
|
|
5
|
+
export function getFirstFocusable(_ref) {
|
|
6
|
+
var container = _ref.container,
|
|
7
|
+
filter = _ref.filter;
|
|
8
|
+
var items = getFocusables({
|
|
9
|
+
container: container,
|
|
10
|
+
filter: filter
|
|
11
|
+
});
|
|
12
|
+
return items.length > 0 ? items[0] : null;
|
|
13
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { isInSameLayer } from './is-in-same-layer';
|
|
2
|
+
import { selectors } from './selectors';
|
|
3
|
+
/**
|
|
4
|
+
* Returns all focusable HTMLElements within the container, optionally filtered.
|
|
5
|
+
*
|
|
6
|
+
* Focusables that belong to a nested top-layer scope (a `[popover]` or
|
|
7
|
+
* `<dialog>` descendant of the container) are excluded - those elements
|
|
8
|
+
* are owned by the inner layer's focus management. The container itself
|
|
9
|
+
* is allowed to be a popover/dialog; only nested ones are filtered.
|
|
10
|
+
*/
|
|
11
|
+
export function getFocusables(_ref) {
|
|
12
|
+
var container = _ref.container,
|
|
13
|
+
filter = _ref.filter;
|
|
14
|
+
return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (element) {
|
|
15
|
+
return element instanceof HTMLElement;
|
|
16
|
+
}).filter(function (element) {
|
|
17
|
+
return isInSameLayer({
|
|
18
|
+
element: element,
|
|
19
|
+
container: container
|
|
20
|
+
});
|
|
21
|
+
}).filter(function (element) {
|
|
22
|
+
return !filter || filter(element, container);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { getFocusables } from './get-focusables';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the last focusable element within the container.
|
|
4
|
+
*/
|
|
5
|
+
export function getLastFocusable(_ref) {
|
|
6
|
+
var container = _ref.container,
|
|
7
|
+
filter = _ref.filter;
|
|
8
|
+
var items = getFocusables({
|
|
9
|
+
container: container,
|
|
10
|
+
filter: filter
|
|
11
|
+
});
|
|
12
|
+
return items.length > 0 ? items[items.length - 1] : null;
|
|
13
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the next focusable element in the given direction relative to the
|
|
3
|
+
* currently focused element within the container. Wraps around at both ends.
|
|
4
|
+
*
|
|
5
|
+
* Returns `null` if there is no focused element within the container or if
|
|
6
|
+
* the focused element is not in the list of focusable elements.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { getFocusables } from './get-focusables';
|
|
10
|
+
import { selectors } from './selectors';
|
|
11
|
+
export function getNextFocusable(_ref) {
|
|
12
|
+
var _all$nextIndex;
|
|
13
|
+
var container = _ref.container,
|
|
14
|
+
direction = _ref.direction,
|
|
15
|
+
filter = _ref.filter;
|
|
16
|
+
var all = getFocusables({
|
|
17
|
+
container: container,
|
|
18
|
+
filter: filter
|
|
19
|
+
});
|
|
20
|
+
var current = container.querySelector(selectors.focused);
|
|
21
|
+
if (!(current instanceof HTMLElement)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
var index = all.indexOf(current);
|
|
25
|
+
if (index === -1) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
var nextIndex = function () {
|
|
29
|
+
if (direction === 'forwards') {
|
|
30
|
+
return (index + 1) % all.length;
|
|
31
|
+
}
|
|
32
|
+
var proposed = index - 1;
|
|
33
|
+
// if going into negative numbers, loop back to the last item
|
|
34
|
+
return proposed < 0 ? all.length - 1 : proposed;
|
|
35
|
+
}();
|
|
36
|
+
return (_all$nextIndex = all[nextIndex]) !== null && _all$nextIndex !== void 0 ? _all$nextIndex : null;
|
|
37
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
var topLayerSelector = '[popover], dialog, [role="dialog"], [role="alertdialog"]';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns true when `element` and `container` resolve to the same nearest
|
|
5
|
+
* top-layer host (or both resolve to `null`, meaning the document layer).
|
|
6
|
+
*/
|
|
7
|
+
export function isInSameLayer(_ref) {
|
|
8
|
+
var element = _ref.element,
|
|
9
|
+
container = _ref.container;
|
|
10
|
+
var elementLayer = element.closest(topLayerSelector);
|
|
11
|
+
var containerLayer = container.closest(topLayerSelector);
|
|
12
|
+
// Both elements are in the "document" layer
|
|
13
|
+
if (!elementLayer && !containerLayer) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
return elementLayer === containerLayer;
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { getDocument } from '@atlaskit/browser-apis';
|
|
2
|
+
import { isInSameLayer } from './is-in-same-layer';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns `true` when `document.activeElement` is inside a nested top-layer
|
|
6
|
+
* descendant of `container` (a `[popover]`, `<dialog>`, `[role="dialog"]` or
|
|
7
|
+
* `[role="alertdialog"]` that is itself a descendant of `container`).
|
|
8
|
+
*/
|
|
9
|
+
export function isNestedLayerFocused(_ref) {
|
|
10
|
+
var _getDocument;
|
|
11
|
+
var container = _ref.container;
|
|
12
|
+
var focused = (_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.activeElement;
|
|
13
|
+
if (!(focused instanceof HTMLElement)) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Cannot be in a nested layer if it is not in the container
|
|
18
|
+
if (!container.contains(focused)) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// If not in the same layer, must be in a nested layer
|
|
23
|
+
return !isInSameLayer({
|
|
24
|
+
element: focused,
|
|
25
|
+
container: container
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export var selectors = function () {
|
|
2
|
+
// Common exclusion filter applied to every selector.
|
|
3
|
+
var not = ':not([tabindex="-1"]):not([aria-disabled="true"]):not([aria-hidden="true"])';
|
|
4
|
+
var notDisabled = ":not([disabled])".concat(not);
|
|
5
|
+
var focusable = ["a[href]".concat(not), "area[href]".concat(not), "input".concat(notDisabled, ":not([type=\"hidden\"])"), "select".concat(notDisabled), "textarea".concat(notDisabled), "button".concat(notDisabled), "iframe".concat(not), "audio[controls]".concat(not), "video[controls]".concat(not), "[contenteditable]:not([contenteditable=\"false\"])".concat(not), "[tabindex]".concat(notDisabled).concat(not)];
|
|
6
|
+
return {
|
|
7
|
+
focusable: focusable.join(','),
|
|
8
|
+
// Build the `:focus` selector
|
|
9
|
+
focused: focusable.map(function (selector) {
|
|
10
|
+
return "".concat(selector, ":focus");
|
|
11
|
+
}).join(',')
|
|
12
|
+
};
|
|
13
|
+
}();
|
|
File without changes
|