@atlaskit/top-layer 0.13.0 → 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 +15 -0
- package/README.md +61 -34
- package/dist/cjs/animations/presets.js +4 -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-popover-id.js +21 -0
- package/dist/cjs/internal/get-aria-for-trigger.js +88 -0
- package/dist/cjs/internal/role-types.js +64 -1
- package/dist/cjs/internal/slot.js +1 -1
- package/dist/cjs/internal/use-anchor-position.js +30 -14
- 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/es2019/animations/presets.js +4 -4
- 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-popover-id.js +15 -0
- package/dist/es2019/internal/get-aria-for-trigger.js +84 -0
- package/dist/es2019/internal/role-types.js +59 -0
- package/dist/es2019/internal/slot.js +1 -1
- package/dist/es2019/internal/use-anchor-position.js +16 -12
- 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/esm/animations/presets.js +4 -4
- 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-popover-id.js +15 -0
- package/dist/esm/internal/get-aria-for-trigger.js +83 -0
- package/dist/esm/internal/role-types.js +58 -0
- package/dist/esm/internal/slot.js +1 -1
- package/dist/esm/internal/use-anchor-position.js +30 -14
- 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/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/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-popover-id.d.ts +11 -0
- package/dist/types/internal/get-aria-for-trigger.d.ts +86 -0
- package/dist/types/internal/role-types.d.ts +7 -0
- package/dist/types/internal/slot.d.ts +2 -2
- 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-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/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-popover-id.d.ts +11 -0
- package/dist/types-ts4.5/internal/get-aria-for-trigger.d.ts +86 -0
- package/dist/types-ts4.5/internal/role-types.d.ts +7 -0
- package/dist/types-ts4.5/internal/slot.d.ts +2 -2
- 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/get-aria-for-trigger/package.json +17 -0
- package/package.json +3 -3
- package/popover-surface/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/popup/index.js +0 -37
- package/dist/cjs/popup/popup-content.js +0 -215
- 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/popup/index.js +0 -33
- package/dist/es2019/popup/popup-content.js +0 -207
- 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/popup/index.js +0 -33
- package/dist/esm/popup/popup-content.js +0 -207
- 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/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/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
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
1
3
|
/**
|
|
2
4
|
* Anchor positioning for top-layer popovers. See
|
|
3
5
|
* `notes/architecture/positioning.md` for the full model.
|
|
@@ -28,15 +30,25 @@ import { setStyle } from './set-style';
|
|
|
28
30
|
// from `./resolve-placement` so search-and-jump lands at the source of truth.
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
|
-
* Module-scope no-op `ResizeObserver`
|
|
33
|
+
* Module-scope no-op `ResizeObserver` used in non-DOM jest environments where
|
|
32
34
|
* `ResizeObserver` is `undefined`. Hoisted out of the effect to avoid
|
|
33
|
-
*
|
|
35
|
+
* allocating a new class declaration on every run.
|
|
34
36
|
*/
|
|
35
|
-
var
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
var NoopResizeObserver = /*#__PURE__*/function () {
|
|
38
|
+
function NoopResizeObserver() {
|
|
39
|
+
_classCallCheck(this, NoopResizeObserver);
|
|
40
|
+
}
|
|
41
|
+
return _createClass(NoopResizeObserver, [{
|
|
42
|
+
key: "observe",
|
|
43
|
+
value: function observe() {}
|
|
44
|
+
}, {
|
|
45
|
+
key: "unobserve",
|
|
46
|
+
value: function unobserve() {}
|
|
47
|
+
}, {
|
|
48
|
+
key: "disconnect",
|
|
49
|
+
value: function disconnect() {}
|
|
50
|
+
}]);
|
|
51
|
+
}();
|
|
40
52
|
|
|
41
53
|
/**
|
|
42
54
|
* Returns true when the popover is currently open. Wrapped because the
|
|
@@ -193,6 +205,7 @@ function useStablePlacement(placement) {
|
|
|
193
205
|
* comparison is used internally so re-runs are skipped when the resolved
|
|
194
206
|
* placement shape is unchanged.
|
|
195
207
|
*/
|
|
208
|
+
// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
|
|
196
209
|
export function useAnchorPosition(_ref3) {
|
|
197
210
|
var anchorRef = _ref3.anchorRef,
|
|
198
211
|
popoverRef = _ref3.popoverRef,
|
|
@@ -399,17 +412,20 @@ export function useAnchorPosition(_ref3) {
|
|
|
399
412
|
// Self-disconnects after one valid measurement; ongoing
|
|
400
413
|
// scroll/resize is handled by the window listeners below.
|
|
401
414
|
// `ResizeObserver` is missing in some non-DOM jest environments
|
|
402
|
-
// (e.g. post-office's `node` environment). Fall back to
|
|
403
|
-
//
|
|
404
|
-
//
|
|
405
|
-
//
|
|
406
|
-
//
|
|
407
|
-
|
|
415
|
+
// (e.g. post-office's `node` environment). Fall back to a no-op
|
|
416
|
+
// observer there. The scroll/resize listeners below still keep
|
|
417
|
+
// the popover positioned in the rare case the consumer also
|
|
418
|
+
// polyfilled `showPopover` but not `ResizeObserver`. Real
|
|
419
|
+
// browsers always have it. The `NoopResizeObserver` class is
|
|
420
|
+
// hoisted to module scope (see top of file) so we do not allocate
|
|
421
|
+
// a new constructor on every effect run.
|
|
422
|
+
var ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
|
|
423
|
+
var resizeObserver = new ResizeObserverImpl(function () {
|
|
408
424
|
if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
|
|
409
425
|
update();
|
|
410
426
|
resizeObserver.disconnect();
|
|
411
427
|
}
|
|
412
|
-
})
|
|
428
|
+
});
|
|
413
429
|
|
|
414
430
|
// If the popover is already open by the time this effect runs (for
|
|
415
431
|
// example, the parent `useAnchorPosition` effect runs after the child
|
|
@@ -9,13 +9,12 @@ import { bind } from 'bind-event-listener';
|
|
|
9
9
|
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
10
10
|
import once from '@atlaskit/ds-lib/once';
|
|
11
11
|
import { useNotifyOpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer';
|
|
12
|
+
import { shouldFocusIntoPopover } from '../internal/role-types';
|
|
12
13
|
import { useAnimatedVisibility } from '../internal/use-animated-visibility';
|
|
13
14
|
import { useFocusWrap } from '../internal/use-focus-wrap';
|
|
14
15
|
import { useInitialFocus } from '../internal/use-initial-focus';
|
|
15
16
|
/**
|
|
16
|
-
* Detects
|
|
17
|
-
* Uses DOM reflection: unsupported browsers reflect the invalid value default ("manual").
|
|
18
|
-
* Safe for SSR. Result is cached via `once`.
|
|
17
|
+
* Detects `popover="hint"` support via DOM reflection. SSR-safe, cached.
|
|
19
18
|
*/
|
|
20
19
|
var supportsPopoverHint = once(function () {
|
|
21
20
|
if (typeof document === 'undefined') {
|
|
@@ -32,33 +31,20 @@ var styles = {
|
|
|
32
31
|
root: "_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _19pkidpf _2hwxidpf _otyridpf _18u0idpf _1r041wug _1reoewfl _18m9ewfl _bfhk1j28"
|
|
33
32
|
};
|
|
34
33
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* and dismissed when closeLayers() is called (e.g. when the side nav resizes).
|
|
38
|
-
*
|
|
39
|
-
* Note on open layer observer types not included here:
|
|
40
|
-
* - 'modal' only ever comes from the Dialog primitive, not Popover.
|
|
41
|
-
* - Other layer types (e.g. 'tooltip') do not yet exist in LayerType because
|
|
42
|
-
* there is no current use case for distinguishing them in the observer.
|
|
34
|
+
* Roles registered with the open layer observer as `popup`, so `closeLayers()`
|
|
35
|
+
* dismisses them. `modal` comes from Dialog only; other layer types are unused.
|
|
43
36
|
*/
|
|
44
37
|
var POPUP_ROLES = new Set(['menu', 'listbox', 'dialog', 'alertdialog', 'tree', 'grid']);
|
|
45
38
|
|
|
46
39
|
/**
|
|
47
|
-
* Unopinionated top-layer primitive.
|
|
48
|
-
*
|
|
49
|
-
* Manages only visibility (isOpen) and animation (animate). Has no knowledge
|
|
50
|
-
* of positioning - compose with `useAnchorPosition` for anchor positioning
|
|
51
|
-
* and optionally `useWidthFromAnchor` for setting the width of a popover element
|
|
52
|
-
* relative to its anchor trigger.
|
|
40
|
+
* Unopinionated top-layer primitive. Manages visibility and animation only;
|
|
41
|
+
* compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
|
|
53
42
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* - `isOpen={false}` → `hidePopover()`, exit animation via `allow-discrete`
|
|
43
|
+
* `isOpen={true}` calls `showPopover()` (entry via `@starting-style`);
|
|
44
|
+
* `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
|
|
57
45
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* consumer must set `isOpen` to `false`. The DOM owns the dismiss; React
|
|
61
|
-
* must follow.
|
|
46
|
+
* In `mode="auto"`, the browser can light-dismiss (Escape, click outside).
|
|
47
|
+
* `onClose` fires; the consumer must then set `isOpen` to `false`.
|
|
62
48
|
*/
|
|
63
49
|
export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
64
50
|
var children = _ref.children,
|
|
@@ -80,11 +66,9 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
80
66
|
var autoId = useId();
|
|
81
67
|
var ownRef = useRef(null);
|
|
82
68
|
var combinedRef = mergeRefs([ownRef, ref].filter(Boolean));
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
// (
|
|
86
|
-
// attributes. React 19.2.0 replaced colons with underscores, making this
|
|
87
|
-
// stripping unnecessary once React 18 support is dropped.
|
|
69
|
+
// React 18 `useId()` returns IDs with colons (invalid in CSS selectors
|
|
70
|
+
// and popover target attributes). Strip them; remove once React 18 is
|
|
71
|
+
// dropped (React 19.2 uses underscores).
|
|
88
72
|
var popoverId = idProp !== null && idProp !== void 0 ? idProp : "popover-".concat(autoId.replace(/:/g, ''));
|
|
89
73
|
var _useAnimatedVisibilit = useAnimatedVisibility({
|
|
90
74
|
isOpen: isOpen,
|
|
@@ -96,12 +80,10 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
96
80
|
showChildren = _useAnimatedVisibilit.showChildren,
|
|
97
81
|
preset = _useAnimatedVisibilit.preset;
|
|
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: role
|
|
@@ -112,13 +94,9 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
112
94
|
role: 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
|
var handleObserverClose = useCallback(function () {
|
|
123
101
|
onClose === null || onClose === void 0 || onClose({
|
|
124
102
|
reason: 'programmatic'
|
|
@@ -130,25 +108,29 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
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
|
var 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
|
var 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
|
var 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
|
+
var previouslyFocusedElementRef = useRef(null);
|
|
126
|
+
var handleBeforeToggle = useCallback(function (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
|
+
var active = document.activeElement;
|
|
132
|
+
previouslyFocusedElementRef.current = active instanceof HTMLElement ? active : null;
|
|
133
|
+
}, []);
|
|
152
134
|
var handleToggle = useCallback(function (event) {
|
|
153
135
|
var element = ownRef.current;
|
|
154
136
|
if (event.newState === 'open') {
|
|
@@ -166,32 +148,52 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
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
|
+
var previouslyFocused = previouslyFocusedElementRef.current;
|
|
159
|
+
var _reason = closeReasonRef.current;
|
|
160
|
+
var isProgrammatic = programmaticCloseRef.current;
|
|
161
|
+
var shouldRestore = previouslyFocused !== null && previouslyFocused.isConnected && shouldFocusIntoPopover({
|
|
162
|
+
role: 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
|
var 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 || onClose({
|
|
184
186
|
reason: reason
|
|
185
187
|
});
|
|
186
188
|
}
|
|
187
|
-
}, [onClose, onOpenChange]);
|
|
189
|
+
}, [onClose, onOpenChange, role]);
|
|
188
190
|
useEffect(function () {
|
|
189
191
|
var 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
|
var unbindEscape = bind(element, {
|
|
196
198
|
type: 'keydown',
|
|
197
199
|
listener: function listener(event) {
|
|
@@ -207,15 +209,20 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
207
209
|
type: 'toggle',
|
|
208
210
|
listener: handleToggle
|
|
209
211
|
});
|
|
212
|
+
// Snapshot `document.activeElement` before `useInitialFocus` moves it.
|
|
213
|
+
var unbindBeforeToggle = bind(element, {
|
|
214
|
+
type: 'beforetoggle',
|
|
215
|
+
listener: handleBeforeToggle
|
|
216
|
+
});
|
|
210
217
|
return function () {
|
|
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(function () {
|
|
220
227
|
var el = ownRef.current;
|
|
221
228
|
if (!el || !(preset !== null && preset !== void 0 && preset.getProperties) || !placement) {
|
|
@@ -232,14 +239,9 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
232
239
|
});
|
|
233
240
|
}, [preset, placement]);
|
|
234
241
|
|
|
235
|
-
// Show/hide based on isOpen.
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
// effect ran).
|
|
239
|
-
// Defensive try/catch: these APIs throw InvalidStateError if the element
|
|
240
|
-
// is disconnected or missing the popover attribute. While we do not expect
|
|
241
|
-
// that to happen in normal usage, it can occur in edge cases (e.g. React
|
|
242
|
-
// concurrent mode, StrictMode double-effects, or unmount races).
|
|
242
|
+
// Show/hide based on isOpen. `showPopover`/`hidePopover` are no-ops when
|
|
243
|
+
// already in the target state. Try/catch guards `InvalidStateError` on
|
|
244
|
+
// disconnected elements (StrictMode/concurrent/unmount edge cases).
|
|
243
245
|
useLayoutEffect(function () {
|
|
244
246
|
var el = ownRef.current;
|
|
245
247
|
if (!el) {
|
|
@@ -247,20 +249,17 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
247
249
|
}
|
|
248
250
|
if (isOpen) {
|
|
249
251
|
programmaticCloseRef.current = false;
|
|
250
|
-
// Defensive: element may be disconnected or in an unexpected state.
|
|
251
252
|
try {
|
|
252
253
|
el.showPopover();
|
|
253
254
|
} catch (_unused) {}
|
|
254
255
|
return function () {
|
|
255
256
|
programmaticCloseRef.current = true;
|
|
256
|
-
// Defensive: element may be disconnected or in an unexpected state.
|
|
257
257
|
try {
|
|
258
258
|
el.hidePopover();
|
|
259
259
|
} catch (_unused2) {}
|
|
260
260
|
};
|
|
261
261
|
}
|
|
262
262
|
programmaticCloseRef.current = true;
|
|
263
|
-
// Defensive: element may be disconnected or in an unexpected state.
|
|
264
263
|
try {
|
|
265
264
|
el.hidePopover();
|
|
266
265
|
} catch (_unused3) {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PopoverSurface } from './popover-surface';
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
var 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(_ref) {
|
|
22
|
+
var children = _ref.children;
|
|
23
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
24
|
+
className: ax([styles.root])
|
|
25
|
+
}, children);
|
|
26
|
+
}
|
|
@@ -102,7 +102,7 @@ function createToggleScheduler() {
|
|
|
102
102
|
newState: newState
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
// Task queue (setTimeout)
|
|
105
|
+
// Task queue (setTimeout): browser fires toggle after microtasks drain, not during
|
|
106
106
|
setTimeout(function () {
|
|
107
107
|
var entry = pending.get(element);
|
|
108
108
|
if (!entry) {
|
|
@@ -532,10 +532,11 @@ if (typeof HTMLElement !== 'undefined') {
|
|
|
532
532
|
element: this
|
|
533
533
|
}), " 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');
|
|
534
534
|
}
|
|
535
|
+
// No-op: already showing.
|
|
535
536
|
if (isPopoverOpen({
|
|
536
537
|
element: this
|
|
537
538
|
})) {
|
|
538
|
-
return;
|
|
539
|
+
return;
|
|
539
540
|
}
|
|
540
541
|
|
|
541
542
|
// sync, cancelable on show only
|
|
@@ -729,8 +730,9 @@ if (typeof HTMLDialogElement !== 'undefined') {
|
|
|
729
730
|
}), " 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');
|
|
730
731
|
}
|
|
731
732
|
if (this.hasAttribute('open')) {
|
|
733
|
+
// No-op: already modal.
|
|
732
734
|
if (this._isModal) {
|
|
733
|
-
return;
|
|
735
|
+
return;
|
|
734
736
|
}
|
|
735
737
|
throw new DOMException("Failed to execute 'showModal' on 'HTMLDialogElement': ".concat(describeElement({
|
|
736
738
|
element: this
|
|
@@ -754,7 +756,7 @@ if (typeof HTMLDialogElement !== 'undefined') {
|
|
|
754
756
|
}
|
|
755
757
|
if (typeof proto.show !== 'function') {
|
|
756
758
|
proto.show = function show() {
|
|
757
|
-
// Browser does not throw for disconnected elements on show
|
|
759
|
+
// Browser does not throw for disconnected elements on show; no-op.
|
|
758
760
|
if (!this.isConnected || this.hasAttribute('open')) {
|
|
759
761
|
return;
|
|
760
762
|
}
|
|
@@ -776,11 +778,12 @@ if (typeof HTMLDialogElement !== 'undefined') {
|
|
|
776
778
|
}
|
|
777
779
|
if (typeof proto.close !== 'function') {
|
|
778
780
|
proto.close = function close(returnValue) {
|
|
781
|
+
// No-op: already closed.
|
|
779
782
|
if (!this.hasAttribute('open')) {
|
|
780
|
-
return;
|
|
783
|
+
return;
|
|
781
784
|
}
|
|
782
785
|
|
|
783
|
-
// Sync beforetoggle (not cancelable)
|
|
786
|
+
// Sync beforetoggle (not cancelable); matches browser behavior.
|
|
784
787
|
fireToggleEvent({
|
|
785
788
|
element: this,
|
|
786
789
|
type: 'beforetoggle',
|
|
@@ -18,10 +18,10 @@ type TSlideAndFadeOptions = {
|
|
|
18
18
|
* import { slideAndFade } from '@atlaskit/top-layer/animations';
|
|
19
19
|
*
|
|
20
20
|
* // Default 4px slide (tooltip)
|
|
21
|
-
* <
|
|
21
|
+
* <Popover animate={slideAndFade()} />
|
|
22
22
|
*
|
|
23
23
|
* // Custom 8px slide (popup / dropdown)
|
|
24
|
-
* <
|
|
24
|
+
* <Popover animate={slideAndFade({ distance: 8 })} />
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
27
|
export declare function slideAndFade(options?: TSlideAndFadeOptions): TAnimationPreset;
|
|
@@ -34,7 +34,7 @@ export declare function slideAndFade(options?: TSlideAndFadeOptions): TAnimation
|
|
|
34
34
|
* ```tsx
|
|
35
35
|
* import { fade } from '@atlaskit/top-layer/animations';
|
|
36
36
|
*
|
|
37
|
-
* <
|
|
37
|
+
* <Popover animate={fade()} />
|
|
38
38
|
* ```
|
|
39
39
|
*/
|
|
40
40
|
export declare function fade(): TAnimationPreset;
|
|
@@ -47,7 +47,7 @@ export declare function fade(): TAnimationPreset;
|
|
|
47
47
|
* ```tsx
|
|
48
48
|
* import { scaleAndFade } from '@atlaskit/top-layer/animations';
|
|
49
49
|
*
|
|
50
|
-
* <
|
|
50
|
+
* <Popover animate={scaleAndFade()} />
|
|
51
51
|
* ```
|
|
52
52
|
*/
|
|
53
53
|
export declare function scaleAndFade(): TAnimationPreset;
|
|
@@ -49,14 +49,6 @@ type TDialogBaseProps = {
|
|
|
49
49
|
* Additional inline styles applied to the `<dialog>` element.
|
|
50
50
|
*
|
|
51
51
|
* Use for custom width, height, transform, or other overrides.
|
|
52
|
-
*
|
|
53
|
-
* Rule deviation: the house rules ban unbounded `style` props on
|
|
54
|
-
* components. `Dialog` is a low-level primitive that intentionally has
|
|
55
|
-
* no visual opinions of its own; consumers such as `@atlaskit/modal-dialog`
|
|
56
|
-
* must be able to set width, height, and transforms on the native
|
|
57
|
-
* `<dialog>` element. Removing this prop would be a breaking change
|
|
58
|
-
* and is tracked separately. Keep until an xcss-based replacement
|
|
59
|
-
* exists on the primitive.
|
|
60
52
|
*/
|
|
61
53
|
style?: CSSProperties;
|
|
62
54
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getAriaForTrigger } from '../internal/get-aria-for-trigger';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Popover } from '../popover';
|
|
2
|
-
export type { TPopoverProps, TPopoverCloseReason } from '../popover';
|
|
2
|
+
export type { TPopoverProps, TPopoverCloseReason, TPlacementOptions } from '../popover';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a stable HTML `id` used to wire a trigger element to its popover
|
|
3
|
+
* via ARIA (`aria-controls`) and the Popover API (`popovertarget`).
|
|
4
|
+
*
|
|
5
|
+
* The returned value is intended for the `id` attribute on the popover and
|
|
6
|
+
* for the matching `aria-controls` / `popovertarget` references on the
|
|
7
|
+
* trigger. It is NOT a CSS `anchor-name` value: CSS anchor positioning is
|
|
8
|
+
* handled internally by `useAnchorPosition`, which mints and applies its
|
|
9
|
+
* own `anchor-name` on the trigger element.
|
|
10
|
+
*/
|
|
11
|
+
export declare function usePopoverId(): string;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type TAriaHasPopupValue, type TRoleRequiringAccessibleName } from './role-types';
|
|
2
|
+
/**
|
|
3
|
+
* Roles accepted by `getAriaForTrigger`.
|
|
4
|
+
*
|
|
5
|
+
* Excludes tooltip-family roles (`tooltip`, `note`, `status`, `alert`, `log`)
|
|
6
|
+
* because the correct trigger wiring for those is `aria-describedby`, not
|
|
7
|
+
* `aria-haspopup` / `aria-expanded` / `aria-controls`. Use `aria-describedby`
|
|
8
|
+
* manually for tooltip triggers.
|
|
9
|
+
*/
|
|
10
|
+
type TAriaForTriggerRole = TRoleRequiringAccessibleName | 'listbox' | 'tree' | 'grid';
|
|
11
|
+
type TGetAriaForTriggerOptions = {
|
|
12
|
+
/**
|
|
13
|
+
* The `role` that will be set on the `<Popover>` element. Used to derive
|
|
14
|
+
* the correct `aria-haspopup` value for the trigger.
|
|
15
|
+
*/
|
|
16
|
+
role: TAriaForTriggerRole;
|
|
17
|
+
/**
|
|
18
|
+
* Whether the popover is currently open. Drives `aria-expanded`.
|
|
19
|
+
*/
|
|
20
|
+
isOpen: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The popover identifier - the value returned by `usePopoverId()`,
|
|
23
|
+
* passed as `id` to `<Popover>` and referenced here via `aria-controls`.
|
|
24
|
+
*/
|
|
25
|
+
popoverId: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Non-undefined subset of `TAriaHasPopupValue`. Every role accepted by
|
|
29
|
+
* `getAriaForTrigger` maps to a concrete `aria-haspopup` string, so the
|
|
30
|
+
* trigger always receives a defined attribute value.
|
|
31
|
+
*/
|
|
32
|
+
type TAriaHasPopupForTrigger = Exclude<TAriaHasPopupValue, undefined>;
|
|
33
|
+
type TAriaForTrigger = {
|
|
34
|
+
'aria-haspopup': TAriaHasPopupForTrigger;
|
|
35
|
+
'aria-expanded': boolean;
|
|
36
|
+
'aria-controls': string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Returns the ARIA attributes to spread onto a click-activated popover trigger.
|
|
40
|
+
*
|
|
41
|
+
* Centralises three attributes that are easy to forget or get wrong individually:
|
|
42
|
+
*
|
|
43
|
+
* - `aria-haspopup` - derived from the popover's role (e.g. `dialog → "dialog"`,
|
|
44
|
+
* `menu → "menu"`, `tooltip → undefined`). React omits the attribute when
|
|
45
|
+
* the value is `undefined`.
|
|
46
|
+
* - `aria-expanded` - reflects the current open state.
|
|
47
|
+
* - `aria-controls` - references the popover element by its id, even
|
|
48
|
+
* while the popover is closed. The relationship is stable; `aria-expanded`
|
|
49
|
+
* carries the current visibility state.
|
|
50
|
+
*
|
|
51
|
+
* **This function is for click/keyboard-activated popovers only.** For
|
|
52
|
+
* hover-driven tooltips, the trigger should use `aria-describedby` instead.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* import { getAriaForTrigger } from '@atlaskit/top-layer/get-aria-for-trigger';
|
|
57
|
+
* import { usePopoverId } from '@atlaskit/top-layer/use-popover-id';
|
|
58
|
+
*
|
|
59
|
+
* const popoverId = usePopoverId();
|
|
60
|
+
* const [isOpen, setIsOpen] = useState(false);
|
|
61
|
+
*
|
|
62
|
+
* return (
|
|
63
|
+
* <>
|
|
64
|
+
* <button
|
|
65
|
+
* ref={triggerRef}
|
|
66
|
+
* onClick={() => setIsOpen((previous) => !previous)}
|
|
67
|
+
* {...getAriaForTrigger({ role: 'dialog', isOpen, popoverId })}
|
|
68
|
+
* >
|
|
69
|
+
* Open
|
|
70
|
+
* </button>
|
|
71
|
+
* <Popover
|
|
72
|
+
* id={popoverId}
|
|
73
|
+
* role="dialog"
|
|
74
|
+
* label="My dialog"
|
|
75
|
+
* isOpen={isOpen}
|
|
76
|
+
* triggerRef={triggerRef}
|
|
77
|
+
* onClose={() => setIsOpen(false)}
|
|
78
|
+
* >
|
|
79
|
+
* …
|
|
80
|
+
* </Popover>
|
|
81
|
+
* </>
|
|
82
|
+
* );
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function getAriaForTrigger({ role, isOpen, popoverId, }: TGetAriaForTriggerOptions): TAriaForTrigger;
|
|
86
|
+
export {};
|
|
@@ -61,4 +61,11 @@ export type TAriaRoleOptional = ({
|
|
|
61
61
|
} & TAccessibleNameRequired) | ({
|
|
62
62
|
role?: TRoleWithImplicitName;
|
|
63
63
|
} & TAccessibleNameOptional);
|
|
64
|
+
/**
|
|
65
|
+
* Returns `true` when the given popover role moves focus into the popover
|
|
66
|
+
* on open, and `false` otherwise (including when `role` is `undefined`).
|
|
67
|
+
*/
|
|
68
|
+
export declare function shouldFocusIntoPopover({ role, }: {
|
|
69
|
+
role: TRoleRequiringAccessibleName | TRoleWithImplicitName | undefined;
|
|
70
|
+
}): boolean;
|
|
64
71
|
export {};
|
|
@@ -2,7 +2,7 @@ import { type ForwardRefExoticComponent, type ReactNode, type RefAttributes } fr
|
|
|
2
2
|
/**
|
|
3
3
|
* Extra DOM/event props are passed through to the cloned child.
|
|
4
4
|
*/
|
|
5
|
-
export type
|
|
5
|
+
export type SlotProps = {
|
|
6
6
|
children: ReactNode;
|
|
7
7
|
} & Record<string, unknown>;
|
|
8
8
|
/**
|
|
@@ -26,4 +26,4 @@ export type TSlotProps = {
|
|
|
26
26
|
* </Slot>
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
|
-
export declare const Slot: ForwardRefExoticComponent<
|
|
29
|
+
export declare const Slot: ForwardRefExoticComponent<SlotProps & RefAttributes<HTMLElement>>;
|