@atlaskit/top-layer 0.1.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 +44 -0
- package/README.md +151 -0
- package/animations/package.json +17 -0
- package/arrow/package.json +17 -0
- package/create-close-event/package.json +17 -0
- package/dialog/package.json +17 -0
- package/dialog-scroll-lock/package.json +17 -0
- package/dist/cjs/animations/presets.js +199 -0
- package/dist/cjs/animations/types.js +5 -0
- package/dist/cjs/arrow/index.js +130 -0
- package/dist/cjs/arrow/types.js +5 -0
- package/dist/cjs/dialog/create-close-event.js +39 -0
- package/dist/cjs/dialog/dialog-content.compiled.css +14 -0
- package/dist/cjs/dialog/dialog-content.js +144 -0
- package/dist/cjs/dialog/index.js +19 -0
- package/dist/cjs/dialog/types.js +5 -0
- package/dist/cjs/dialog-scroll-lock/index.js +46 -0
- package/dist/cjs/entry-points/animations.js +36 -0
- package/dist/cjs/entry-points/arrow.js +12 -0
- package/dist/cjs/entry-points/create-close-event.js +19 -0
- package/dist/cjs/entry-points/dialog-scroll-lock.js +12 -0
- package/dist/cjs/entry-points/dialog.js +12 -0
- package/dist/cjs/entry-points/focus.js +24 -0
- package/dist/cjs/entry-points/placement-map.js +18 -0
- package/dist/cjs/entry-points/popover.js +12 -0
- package/dist/cjs/entry-points/popup-surface.js +12 -0
- package/dist/cjs/entry-points/popup.js +12 -0
- package/dist/cjs/entry-points/use-anchor-position.js +12 -0
- package/dist/cjs/entry-points/use-arrow-navigation.js +18 -0
- package/dist/cjs/entry-points/use-simple-light-dismiss.js +12 -0
- package/dist/cjs/focus/focus.js +115 -0
- package/dist/cjs/focus/index.js +24 -0
- package/dist/cjs/index.js +8 -0
- package/dist/cjs/internal/anchor-positioning-fallback.js +154 -0
- package/dist/cjs/internal/combine.js +29 -0
- package/dist/cjs/internal/ensure-preset-styles.js +34 -0
- package/dist/cjs/internal/reduced-motion.js +27 -0
- package/dist/cjs/internal/resolve-placement.js +24 -0
- package/dist/cjs/internal/role-types.js +66 -0
- package/dist/cjs/internal/set-style.js +42 -0
- package/dist/cjs/internal/slot.js +65 -0
- package/dist/cjs/internal/use-anchor-positioning.js +336 -0
- package/dist/cjs/internal/use-animated-visibility.js +169 -0
- package/dist/cjs/internal/use-animation-preset.js +24 -0
- package/dist/cjs/internal/use-focus-wrap.js +94 -0
- package/dist/cjs/internal/use-initial-focus.js +112 -0
- package/dist/cjs/internal/use-preset-styles.js +27 -0
- package/dist/cjs/placement-map/index.js +147 -0
- package/dist/cjs/popover/create-close-event.js +44 -0
- package/dist/cjs/popover/index.js +19 -0
- package/dist/cjs/popover/popover.compiled.css +13 -0
- package/dist/cjs/popover/popover.js +251 -0
- package/dist/cjs/popover/types.js +5 -0
- package/dist/cjs/popup/index.js +37 -0
- package/dist/cjs/popup/popup-content.js +201 -0
- package/dist/cjs/popup/popup-context.js +42 -0
- package/dist/cjs/popup/popup-surface.compiled.css +5 -0
- package/dist/cjs/popup/popup-surface.js +30 -0
- package/dist/cjs/popup/popup-trigger-function.js +74 -0
- package/dist/cjs/popup/popup-trigger.js +82 -0
- package/dist/cjs/popup/popup.js +70 -0
- package/dist/cjs/popup/types.js +5 -0
- package/dist/cjs/use-arrow-navigation/index.js +18 -0
- package/dist/cjs/use-arrow-navigation/use-arrow-navigation.js +245 -0
- package/dist/cjs/use-simple-light-dismiss/index.js +84 -0
- package/dist/es2019/animations/presets.js +375 -0
- package/dist/es2019/animations/types.js +1 -0
- package/dist/es2019/arrow/index.js +249 -0
- package/dist/es2019/arrow/types.js +1 -0
- package/dist/es2019/dialog/create-close-event.js +34 -0
- package/dist/es2019/dialog/dialog-content.compiled.css +14 -0
- package/dist/es2019/dialog/dialog-content.js +138 -0
- package/dist/es2019/dialog/index.js +2 -0
- package/dist/es2019/dialog/types.js +1 -0
- package/dist/es2019/dialog-scroll-lock/index.js +41 -0
- package/dist/es2019/entry-points/animations.js +1 -0
- package/dist/es2019/entry-points/arrow.js +1 -0
- package/dist/es2019/entry-points/create-close-event.js +2 -0
- package/dist/es2019/entry-points/dialog-scroll-lock.js +1 -0
- package/dist/es2019/entry-points/dialog.js +1 -0
- package/dist/es2019/entry-points/focus.js +1 -0
- package/dist/es2019/entry-points/placement-map.js +1 -0
- package/dist/es2019/entry-points/popover.js +1 -0
- package/dist/es2019/entry-points/popup-surface.js +1 -0
- package/dist/es2019/entry-points/popup.js +1 -0
- package/dist/es2019/entry-points/use-anchor-position.js +1 -0
- package/dist/es2019/entry-points/use-arrow-navigation.js +1 -0
- package/dist/es2019/entry-points/use-simple-light-dismiss.js +1 -0
- package/dist/es2019/focus/focus.js +107 -0
- package/dist/es2019/focus/index.js +1 -0
- package/dist/es2019/index.js +7 -0
- package/dist/es2019/internal/anchor-positioning-fallback.js +153 -0
- package/dist/es2019/internal/combine.js +18 -0
- package/dist/es2019/internal/ensure-preset-styles.js +29 -0
- package/dist/es2019/internal/reduced-motion.js +21 -0
- package/dist/es2019/internal/resolve-placement.js +19 -0
- package/dist/es2019/internal/role-types.js +61 -0
- package/dist/es2019/internal/set-style.js +39 -0
- package/dist/es2019/internal/slot.js +57 -0
- package/dist/es2019/internal/use-anchor-positioning.js +330 -0
- package/dist/es2019/internal/use-animated-visibility.js +159 -0
- package/dist/es2019/internal/use-animation-preset.js +18 -0
- package/dist/es2019/internal/use-focus-wrap.js +90 -0
- package/dist/es2019/internal/use-initial-focus.js +109 -0
- package/dist/es2019/internal/use-preset-styles.js +22 -0
- package/dist/es2019/placement-map/index.js +142 -0
- package/dist/es2019/popover/create-close-event.js +39 -0
- package/dist/es2019/popover/index.js +2 -0
- package/dist/es2019/popover/popover.compiled.css +13 -0
- package/dist/es2019/popover/popover.js +240 -0
- package/dist/es2019/popover/types.js +1 -0
- package/dist/es2019/popup/index.js +33 -0
- package/dist/es2019/popup/popup-content.js +192 -0
- package/dist/es2019/popup/popup-context.js +34 -0
- package/dist/es2019/popup/popup-surface.compiled.css +5 -0
- package/dist/es2019/popup/popup-surface.js +24 -0
- package/dist/es2019/popup/popup-trigger-function.js +69 -0
- package/dist/es2019/popup/popup-trigger.js +76 -0
- package/dist/es2019/popup/popup.js +56 -0
- package/dist/es2019/popup/types.js +1 -0
- package/dist/es2019/use-arrow-navigation/index.js +1 -0
- package/dist/es2019/use-arrow-navigation/use-arrow-navigation.js +238 -0
- package/dist/es2019/use-simple-light-dismiss/index.js +79 -0
- package/dist/esm/animations/presets.js +190 -0
- package/dist/esm/animations/types.js +1 -0
- package/dist/esm/arrow/index.js +123 -0
- package/dist/esm/arrow/types.js +1 -0
- package/dist/esm/dialog/create-close-event.js +33 -0
- package/dist/esm/dialog/dialog-content.compiled.css +14 -0
- package/dist/esm/dialog/dialog-content.js +135 -0
- package/dist/esm/dialog/index.js +2 -0
- package/dist/esm/dialog/types.js +1 -0
- package/dist/esm/dialog-scroll-lock/index.js +41 -0
- package/dist/esm/entry-points/animations.js +1 -0
- package/dist/esm/entry-points/arrow.js +1 -0
- package/dist/esm/entry-points/create-close-event.js +2 -0
- package/dist/esm/entry-points/dialog-scroll-lock.js +1 -0
- package/dist/esm/entry-points/dialog.js +1 -0
- package/dist/esm/entry-points/focus.js +1 -0
- package/dist/esm/entry-points/placement-map.js +1 -0
- package/dist/esm/entry-points/popover.js +1 -0
- package/dist/esm/entry-points/popup-surface.js +1 -0
- package/dist/esm/entry-points/popup.js +1 -0
- package/dist/esm/entry-points/use-anchor-position.js +1 -0
- package/dist/esm/entry-points/use-arrow-navigation.js +1 -0
- package/dist/esm/entry-points/use-simple-light-dismiss.js +1 -0
- package/dist/esm/focus/focus.js +107 -0
- package/dist/esm/focus/index.js +1 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/internal/anchor-positioning-fallback.js +147 -0
- package/dist/esm/internal/combine.js +23 -0
- package/dist/esm/internal/ensure-preset-styles.js +28 -0
- package/dist/esm/internal/reduced-motion.js +21 -0
- package/dist/esm/internal/resolve-placement.js +18 -0
- package/dist/esm/internal/role-types.js +60 -0
- package/dist/esm/internal/set-style.js +36 -0
- package/dist/esm/internal/slot.js +59 -0
- package/dist/esm/internal/use-anchor-positioning.js +323 -0
- package/dist/esm/internal/use-animated-visibility.js +162 -0
- package/dist/esm/internal/use-animation-preset.js +18 -0
- package/dist/esm/internal/use-focus-wrap.js +89 -0
- package/dist/esm/internal/use-initial-focus.js +107 -0
- package/dist/esm/internal/use-preset-styles.js +21 -0
- package/dist/esm/placement-map/index.js +141 -0
- package/dist/esm/popover/create-close-event.js +38 -0
- package/dist/esm/popover/index.js +2 -0
- package/dist/esm/popover/popover.compiled.css +13 -0
- package/dist/esm/popover/popover.js +242 -0
- package/dist/esm/popover/types.js +1 -0
- package/dist/esm/popup/index.js +33 -0
- package/dist/esm/popup/popup-content.js +192 -0
- package/dist/esm/popup/popup-context.js +34 -0
- package/dist/esm/popup/popup-surface.compiled.css +5 -0
- package/dist/esm/popup/popup-surface.js +23 -0
- package/dist/esm/popup/popup-trigger-function.js +69 -0
- package/dist/esm/popup/popup-trigger.js +74 -0
- package/dist/esm/popup/popup.js +61 -0
- package/dist/esm/popup/types.js +1 -0
- package/dist/esm/use-arrow-navigation/index.js +1 -0
- package/dist/esm/use-arrow-navigation/use-arrow-navigation.js +238 -0
- package/dist/esm/use-simple-light-dismiss/index.js +78 -0
- package/dist/types/animations/presets.d.ts +94 -0
- package/dist/types/animations/types.d.ts +42 -0
- package/dist/types/arrow/index.d.ts +24 -0
- package/dist/types/arrow/types.d.ts +29 -0
- package/dist/types/dialog/create-close-event.d.ts +24 -0
- package/dist/types/dialog/dialog-content.d.ts +20 -0
- package/dist/types/dialog/index.d.ts +3 -0
- package/dist/types/dialog/types.d.ts +92 -0
- package/dist/types/dialog-scroll-lock/index.d.ts +24 -0
- package/dist/types/entry-points/animations.d.ts +2 -0
- package/dist/types/entry-points/arrow.d.ts +2 -0
- package/dist/types/entry-points/create-close-event.d.ts +4 -0
- package/dist/types/entry-points/dialog-scroll-lock.d.ts +1 -0
- package/dist/types/entry-points/dialog.d.ts +2 -0
- package/dist/types/entry-points/focus.d.ts +2 -0
- package/dist/types/entry-points/placement-map.d.ts +2 -0
- package/dist/types/entry-points/popover.d.ts +2 -0
- package/dist/types/entry-points/popup-surface.d.ts +2 -0
- package/dist/types/entry-points/popup.d.ts +2 -0
- package/dist/types/entry-points/use-anchor-position.d.ts +1 -0
- package/dist/types/entry-points/use-arrow-navigation.d.ts +2 -0
- package/dist/types/entry-points/use-simple-light-dismiss.d.ts +2 -0
- package/dist/types/focus/focus.d.ts +42 -0
- package/dist/types/focus/index.d.ts +2 -0
- package/dist/types/index.d.ts +0 -0
- package/dist/types/internal/anchor-positioning-fallback.d.ts +24 -0
- package/dist/types/internal/combine.d.ts +14 -0
- package/dist/types/internal/ensure-preset-styles.d.ts +6 -0
- package/dist/types/internal/reduced-motion.d.ts +14 -0
- package/dist/types/internal/resolve-placement.d.ts +16 -0
- package/dist/types/internal/role-types.d.ts +62 -0
- package/dist/types/internal/set-style.d.ts +28 -0
- package/dist/types/internal/slot.d.ts +29 -0
- package/dist/types/internal/use-anchor-positioning.d.ts +95 -0
- package/dist/types/internal/use-animated-visibility.d.ts +74 -0
- package/dist/types/internal/use-animation-preset.d.ts +11 -0
- package/dist/types/internal/use-focus-wrap.d.ts +20 -0
- package/dist/types/internal/use-initial-focus.d.ts +21 -0
- package/dist/types/internal/use-preset-styles.d.ts +15 -0
- package/dist/types/placement-map/index.d.ts +55 -0
- package/dist/types/popover/create-close-event.d.ts +26 -0
- package/dist/types/popover/index.d.ts +3 -0
- package/dist/types/popover/popover.d.ts +22 -0
- package/dist/types/popover/types.d.ts +153 -0
- package/dist/types/popup/index.d.ts +34 -0
- package/dist/types/popup/popup-content.d.ts +14 -0
- package/dist/types/popup/popup-context.d.ts +96 -0
- package/dist/types/popup/popup-surface.d.ts +16 -0
- package/dist/types/popup/popup-trigger-function.d.ts +108 -0
- package/dist/types/popup/popup-trigger.d.ts +23 -0
- package/dist/types/popup/popup.d.ts +14 -0
- package/dist/types/popup/types.d.ts +289 -0
- package/dist/types/use-arrow-navigation/index.d.ts +2 -0
- package/dist/types/use-arrow-navigation/use-arrow-navigation.d.ts +136 -0
- package/dist/types/use-simple-light-dismiss/index.d.ts +45 -0
- package/dist/types-ts4.5/animations/presets.d.ts +94 -0
- package/dist/types-ts4.5/animations/types.d.ts +42 -0
- package/dist/types-ts4.5/arrow/index.d.ts +24 -0
- package/dist/types-ts4.5/arrow/types.d.ts +29 -0
- package/dist/types-ts4.5/dialog/create-close-event.d.ts +24 -0
- package/dist/types-ts4.5/dialog/dialog-content.d.ts +20 -0
- package/dist/types-ts4.5/dialog/index.d.ts +3 -0
- package/dist/types-ts4.5/dialog/types.d.ts +92 -0
- package/dist/types-ts4.5/dialog-scroll-lock/index.d.ts +24 -0
- package/dist/types-ts4.5/entry-points/animations.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/arrow.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/create-close-event.d.ts +4 -0
- package/dist/types-ts4.5/entry-points/dialog-scroll-lock.d.ts +1 -0
- package/dist/types-ts4.5/entry-points/dialog.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/focus.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/placement-map.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/popover.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/popup-surface.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/popup.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/use-anchor-position.d.ts +1 -0
- package/dist/types-ts4.5/entry-points/use-arrow-navigation.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/use-simple-light-dismiss.d.ts +2 -0
- package/dist/types-ts4.5/focus/focus.d.ts +42 -0
- package/dist/types-ts4.5/focus/index.d.ts +2 -0
- package/dist/types-ts4.5/index.d.ts +0 -0
- package/dist/types-ts4.5/internal/anchor-positioning-fallback.d.ts +24 -0
- package/dist/types-ts4.5/internal/combine.d.ts +14 -0
- package/dist/types-ts4.5/internal/ensure-preset-styles.d.ts +6 -0
- package/dist/types-ts4.5/internal/reduced-motion.d.ts +14 -0
- package/dist/types-ts4.5/internal/resolve-placement.d.ts +16 -0
- package/dist/types-ts4.5/internal/role-types.d.ts +62 -0
- package/dist/types-ts4.5/internal/set-style.d.ts +28 -0
- package/dist/types-ts4.5/internal/slot.d.ts +29 -0
- package/dist/types-ts4.5/internal/use-anchor-positioning.d.ts +95 -0
- package/dist/types-ts4.5/internal/use-animated-visibility.d.ts +74 -0
- package/dist/types-ts4.5/internal/use-animation-preset.d.ts +11 -0
- package/dist/types-ts4.5/internal/use-focus-wrap.d.ts +20 -0
- package/dist/types-ts4.5/internal/use-initial-focus.d.ts +21 -0
- package/dist/types-ts4.5/internal/use-preset-styles.d.ts +15 -0
- package/dist/types-ts4.5/placement-map/index.d.ts +55 -0
- package/dist/types-ts4.5/popover/create-close-event.d.ts +26 -0
- package/dist/types-ts4.5/popover/index.d.ts +3 -0
- package/dist/types-ts4.5/popover/popover.d.ts +22 -0
- package/dist/types-ts4.5/popover/types.d.ts +153 -0
- package/dist/types-ts4.5/popup/index.d.ts +34 -0
- package/dist/types-ts4.5/popup/popup-content.d.ts +14 -0
- package/dist/types-ts4.5/popup/popup-context.d.ts +96 -0
- package/dist/types-ts4.5/popup/popup-surface.d.ts +16 -0
- package/dist/types-ts4.5/popup/popup-trigger-function.d.ts +108 -0
- package/dist/types-ts4.5/popup/popup-trigger.d.ts +23 -0
- package/dist/types-ts4.5/popup/popup.d.ts +14 -0
- package/dist/types-ts4.5/popup/types.d.ts +289 -0
- package/dist/types-ts4.5/use-arrow-navigation/index.d.ts +2 -0
- package/dist/types-ts4.5/use-arrow-navigation/use-arrow-navigation.d.ts +136 -0
- package/dist/types-ts4.5/use-simple-light-dismiss/index.d.ts +45 -0
- package/focus/package.json +17 -0
- package/package.json +95 -0
- package/placement-map/package.json +17 -0
- package/popover/package.json +17 -0
- package/popup/package.json +17 -0
- package/popup-surface/package.json +17 -0
- package/use-anchor-position/package.json +17 -0
- package/use-arrow-navigation/package.json +17 -0
- package/use-simple-light-dismiss/package.json +17 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { getFirstFocusable } from '../focus/focus';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Determines the correct element to receive initial focus within a popover,
|
|
6
|
+
* based on its ARIA role.
|
|
7
|
+
*
|
|
8
|
+
* Focus rules by role (per WAI-ARIA APG):
|
|
9
|
+
* - `dialog` / `alertdialog`: first element with `[autofocus]`, or first focusable element
|
|
10
|
+
* - `menu`: first menu item (`[role="menuitem|menuitemcheckbox|menuitemradio"]`)
|
|
11
|
+
* - `listbox`: first selected option (`[aria-selected="true"]`), or first option (`[role="option"]`)
|
|
12
|
+
* - `tooltip`: no focus movement (tooltips are informational)
|
|
13
|
+
* - no role / other roles: no focus movement
|
|
14
|
+
*
|
|
15
|
+
* Note: React 18's `autoFocus` JSX prop does NOT set the HTML `autofocus`
|
|
16
|
+
* attribute — it only calls `.focus()` imperatively during commit, which
|
|
17
|
+
* has no effect on hidden popover content. Consumers must set the native
|
|
18
|
+
* attribute via a ref callback (e.g. `node.setAttribute('autofocus', '')`).
|
|
19
|
+
* React 19+ reflects the JSX prop as the HTML attribute automatically.
|
|
20
|
+
*/
|
|
21
|
+
function getInitialFocusTarget({
|
|
22
|
+
container
|
|
23
|
+
}) {
|
|
24
|
+
const role = container.getAttribute('role');
|
|
25
|
+
if (role === 'dialog' || role === 'alertdialog') {
|
|
26
|
+
// Prefer element with the native HTML autofocus attribute.
|
|
27
|
+
const autofocusEl = container.querySelector('[autofocus]');
|
|
28
|
+
if (autofocusEl) {
|
|
29
|
+
return autofocusEl;
|
|
30
|
+
}
|
|
31
|
+
// Fall back to first focusable element
|
|
32
|
+
return getFirstFocusable({
|
|
33
|
+
container
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (role === 'menu') {
|
|
37
|
+
// Initial focus placement is the extent of what top-layer provides
|
|
38
|
+
// for menus. All subsequent keyboard navigation (arrow keys, Home/End,
|
|
39
|
+
// type-ahead, Enter/Space, submenu coordination) is the responsibility
|
|
40
|
+
// of the consumer component (e.g. dropdown-menu), because menu keyboard
|
|
41
|
+
// behavior varies by context (orientation, nesting, item type, control
|
|
42
|
+
// pattern). See: notes/outputs/menu-keyboard-decision.md
|
|
43
|
+
return getFirstFocusable({
|
|
44
|
+
container
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (role === 'listbox') {
|
|
48
|
+
// Prefer selected option, fall back to first focusable
|
|
49
|
+
const selectedOption = container.querySelector('[role="option"][aria-selected="true"]');
|
|
50
|
+
if (selectedOption) {
|
|
51
|
+
return selectedOption;
|
|
52
|
+
}
|
|
53
|
+
return getFirstFocusable({
|
|
54
|
+
container
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// tooltip, no role, or other roles: no focus movement
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Moves focus into a popover element when it opens, based on its ARIA role.
|
|
64
|
+
*
|
|
65
|
+
* This implements WCAG 2.4.3 (Focus Order) initial focus placement:
|
|
66
|
+
* - `dialog` / `alertdialog` → focus first focusable (or `[autofocus]`)
|
|
67
|
+
* - `menu` → focus first menu item
|
|
68
|
+
* - `listbox` → focus selected or first option
|
|
69
|
+
* - `tooltip` / no role → no focus movement
|
|
70
|
+
*
|
|
71
|
+
* The role is read from the element's `role` attribute (not passed as a prop),
|
|
72
|
+
* following the same pattern as `useFocusWrap`.
|
|
73
|
+
*
|
|
74
|
+
* Always call this hook unconditionally. Focus is only moved when `isOpen`
|
|
75
|
+
* transitions to `true` and the role requires it.
|
|
76
|
+
*/
|
|
77
|
+
export function useInitialFocus({
|
|
78
|
+
elementRef,
|
|
79
|
+
isOpen,
|
|
80
|
+
role
|
|
81
|
+
}) {
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (!isOpen) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const el = elementRef.current;
|
|
87
|
+
if (!el) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Use requestAnimationFrame to ensure the popover is fully rendered
|
|
92
|
+
// and visible in the top layer before attempting to move focus.
|
|
93
|
+
// showPopover() is called in useLayoutEffect (which runs before this
|
|
94
|
+
// useEffect), so by the time the RAF fires after the next paint the
|
|
95
|
+
// element is guaranteed to be in the top layer.
|
|
96
|
+
const rafId = requestAnimationFrame(() => {
|
|
97
|
+
var _getInitialFocusTarge;
|
|
98
|
+
(_getInitialFocusTarge = getInitialFocusTarget({
|
|
99
|
+
container: el
|
|
100
|
+
})) === null || _getInitialFocusTarge === void 0 ? void 0 : _getInitialFocusTarge.focus();
|
|
101
|
+
});
|
|
102
|
+
return () => {
|
|
103
|
+
cancelAnimationFrame(rafId);
|
|
104
|
+
};
|
|
105
|
+
// We intentionally depend on `role` even though `getInitialFocusTarget`
|
|
106
|
+
// reads from the DOM attribute. This ensures the effect re-runs if
|
|
107
|
+
// the role prop changes while the popover is open.
|
|
108
|
+
}, [elementRef, isOpen, role]);
|
|
109
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useInsertionEffect } from 'react';
|
|
2
|
+
import { ensurePresetStyles } from './ensure-preset-styles';
|
|
3
|
+
/**
|
|
4
|
+
* Normalizes a preset prop to a value (or null) and ensures its CSS
|
|
5
|
+
* is injected once into `document.head`.
|
|
6
|
+
*
|
|
7
|
+
* Works with any preset that has `{ css, name }` — animation presets
|
|
8
|
+
* (TAnimationPreset) and arrow presets (TArrowPreset) both satisfy this shape.
|
|
9
|
+
*/
|
|
10
|
+
export function usePresetStyles({
|
|
11
|
+
preset
|
|
12
|
+
}) {
|
|
13
|
+
const resolved = preset != null && preset !== false ? preset : null;
|
|
14
|
+
useInsertionEffect(() => {
|
|
15
|
+
if (resolved) {
|
|
16
|
+
ensurePresetStyles({
|
|
17
|
+
preset: resolved
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}, [resolved]);
|
|
21
|
+
return resolved;
|
|
22
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy Popper.js placement values (used by `@atlaskit/popper`, `@atlaskit/popup`,
|
|
3
|
+
* `@atlaskit/tooltip`, etc.).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Maps legacy Popper.js placement values to the new object-based
|
|
8
|
+
* `Placement` values used by `@atlaskit/top-layer/popover`.
|
|
9
|
+
*
|
|
10
|
+
* **Mapping logic:**
|
|
11
|
+
*
|
|
12
|
+
* | Legacy (Popper.js) | New (Placement object) |
|
|
13
|
+
* | ------------------- | --------------------------------------------------- |
|
|
14
|
+
* | `top` | `{ axis: 'block', edge: 'start', align: 'center' }` |
|
|
15
|
+
* | `top-start` | `{ axis: 'block', edge: 'start', align: 'start' }` |
|
|
16
|
+
* | `top-end` | `{ axis: 'block', edge: 'start', align: 'end' }` |
|
|
17
|
+
* | `bottom` | `{ axis: 'block', edge: 'end', align: 'center' }` |
|
|
18
|
+
* | `bottom-start` | `{ axis: 'block', edge: 'end', align: 'start' }` |
|
|
19
|
+
* | `bottom-end` | `{ axis: 'block', edge: 'end', align: 'end' }` |
|
|
20
|
+
* | `right` | `{ axis: 'inline', edge: 'end', align: 'center' }` |
|
|
21
|
+
* | `right-start` | `{ axis: 'inline', edge: 'end', align: 'start' }` |
|
|
22
|
+
* | `right-end` | `{ axis: 'inline', edge: 'end', align: 'end' }` |
|
|
23
|
+
* | `left` | `{ axis: 'inline', edge: 'start', align: 'center' }` |
|
|
24
|
+
* | `left-start` | `{ axis: 'inline', edge: 'start', align: 'start' }` |
|
|
25
|
+
* | `left-end` | `{ axis: 'inline', edge: 'start', align: 'end' }` |
|
|
26
|
+
* | `auto` | `{ axis: 'block', edge: 'end', align: 'center' }` |
|
|
27
|
+
* | `auto-start` | `{ axis: 'block', edge: 'end', align: 'start' }` |
|
|
28
|
+
* | `auto-end` | `{ axis: 'block', edge: 'end', align: 'end' }` |
|
|
29
|
+
*
|
|
30
|
+
* The `position-try-fallbacks` CSS property handles flipping automatically.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map';
|
|
35
|
+
*
|
|
36
|
+
* // In a migration from @atlaskit/popup:
|
|
37
|
+
* const oldPlacement: TLegacyPlacement = 'bottom-start';
|
|
38
|
+
* const newPlacement: TPlacementOptions = fromLegacyPlacement({ legacy: oldPlacement });
|
|
39
|
+
* // newPlacement === { axis: 'block', edge: 'end', align: 'start' }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
const placementMapping = {
|
|
43
|
+
top: {
|
|
44
|
+
axis: 'block',
|
|
45
|
+
edge: 'start',
|
|
46
|
+
align: 'center'
|
|
47
|
+
},
|
|
48
|
+
'top-start': {
|
|
49
|
+
axis: 'block',
|
|
50
|
+
edge: 'start',
|
|
51
|
+
align: 'start'
|
|
52
|
+
},
|
|
53
|
+
'top-center': {
|
|
54
|
+
axis: 'block',
|
|
55
|
+
edge: 'start',
|
|
56
|
+
align: 'center'
|
|
57
|
+
},
|
|
58
|
+
'top-end': {
|
|
59
|
+
axis: 'block',
|
|
60
|
+
edge: 'start',
|
|
61
|
+
align: 'end'
|
|
62
|
+
},
|
|
63
|
+
bottom: {
|
|
64
|
+
axis: 'block',
|
|
65
|
+
edge: 'end',
|
|
66
|
+
align: 'center'
|
|
67
|
+
},
|
|
68
|
+
'bottom-start': {
|
|
69
|
+
axis: 'block',
|
|
70
|
+
edge: 'end',
|
|
71
|
+
align: 'start'
|
|
72
|
+
},
|
|
73
|
+
'bottom-center': {
|
|
74
|
+
axis: 'block',
|
|
75
|
+
edge: 'end',
|
|
76
|
+
align: 'center'
|
|
77
|
+
},
|
|
78
|
+
'bottom-end': {
|
|
79
|
+
axis: 'block',
|
|
80
|
+
edge: 'end',
|
|
81
|
+
align: 'end'
|
|
82
|
+
},
|
|
83
|
+
right: {
|
|
84
|
+
axis: 'inline',
|
|
85
|
+
edge: 'end',
|
|
86
|
+
align: 'center'
|
|
87
|
+
},
|
|
88
|
+
'right-start': {
|
|
89
|
+
axis: 'inline',
|
|
90
|
+
edge: 'end',
|
|
91
|
+
align: 'start'
|
|
92
|
+
},
|
|
93
|
+
'right-end': {
|
|
94
|
+
axis: 'inline',
|
|
95
|
+
edge: 'end',
|
|
96
|
+
align: 'end'
|
|
97
|
+
},
|
|
98
|
+
left: {
|
|
99
|
+
axis: 'inline',
|
|
100
|
+
edge: 'start',
|
|
101
|
+
align: 'center'
|
|
102
|
+
},
|
|
103
|
+
'left-start': {
|
|
104
|
+
axis: 'inline',
|
|
105
|
+
edge: 'start',
|
|
106
|
+
align: 'start'
|
|
107
|
+
},
|
|
108
|
+
'left-end': {
|
|
109
|
+
axis: 'inline',
|
|
110
|
+
edge: 'start',
|
|
111
|
+
align: 'end'
|
|
112
|
+
},
|
|
113
|
+
auto: {
|
|
114
|
+
axis: 'block',
|
|
115
|
+
edge: 'end',
|
|
116
|
+
align: 'center'
|
|
117
|
+
},
|
|
118
|
+
'auto-start': {
|
|
119
|
+
axis: 'block',
|
|
120
|
+
edge: 'end',
|
|
121
|
+
align: 'start'
|
|
122
|
+
},
|
|
123
|
+
'auto-end': {
|
|
124
|
+
axis: 'block',
|
|
125
|
+
edge: 'end',
|
|
126
|
+
align: 'end'
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Convert a legacy Popper.js placement to the new CSS `position-area`-based Placement.
|
|
132
|
+
*/
|
|
133
|
+
export function fromLegacyPlacement({
|
|
134
|
+
legacy
|
|
135
|
+
}) {
|
|
136
|
+
return placementMapping[legacy];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The full mapping record, exposed for consumers that need to iterate or introspect.
|
|
141
|
+
*/
|
|
142
|
+
export { placementMapping };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a synthetic DOM event from a `TPopoverCloseReason`.
|
|
3
|
+
*
|
|
4
|
+
* Useful when bridging the Popover primitive's `onClose({ reason })` callback
|
|
5
|
+
* to a legacy API that expects a native DOM event — for example,
|
|
6
|
+
* `@atlaskit/inline-dialog`'s `onClose(event)` contract.
|
|
7
|
+
*
|
|
8
|
+
* - `'escape'` → `KeyboardEvent('keydown', { key: 'Escape' })`
|
|
9
|
+
* - `'light-dismiss'` → `MouseEvent('click')`
|
|
10
|
+
*
|
|
11
|
+
* For any other reason, a generic `Event('close')` is returned as a fallback.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* import { createPopoverCloseEvent } from '@atlaskit/top-layer/create-close-event';
|
|
16
|
+
* import { type TPopoverCloseReason } from '@atlaskit/top-layer/popover';
|
|
17
|
+
*
|
|
18
|
+
* function onPopoverClose({ reason }: { reason: TPopoverCloseReason }) {
|
|
19
|
+
* legacyOnClose(createPopoverCloseEvent({ reason }));
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function createPopoverCloseEvent({
|
|
24
|
+
reason
|
|
25
|
+
}) {
|
|
26
|
+
if (reason === 'escape') {
|
|
27
|
+
return new KeyboardEvent('keydown', {
|
|
28
|
+
key: 'Escape',
|
|
29
|
+
bubbles: true
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (reason === 'light-dismiss') {
|
|
33
|
+
return new MouseEvent('click', {
|
|
34
|
+
bubbles: true,
|
|
35
|
+
cancelable: true
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return new Event('close');
|
|
39
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
._19itglyw{border:none}
|
|
3
|
+
._1r041wug{inset:auto}._18m9ewfl{overflow-y:visible}
|
|
4
|
+
._18u0idpf{margin-left:0}
|
|
5
|
+
._19bvidpf{padding-left:0}
|
|
6
|
+
._19pkidpf{margin-top:0}
|
|
7
|
+
._1reoewfl{overflow-x:visible}
|
|
8
|
+
._2hwxidpf{margin-right:0}
|
|
9
|
+
._bfhk1j28{background-color:transparent}
|
|
10
|
+
._ca0qidpf{padding-top:0}
|
|
11
|
+
._n3tdidpf{padding-bottom:0}
|
|
12
|
+
._otyridpf{margin-bottom:0}
|
|
13
|
+
._u5f3idpf{padding-right:0}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/* popover.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
3
|
+
import "./popover.compiled.css";
|
|
4
|
+
import { ax, ix } from "@compiled/react/runtime";
|
|
5
|
+
import React, { forwardRef, useCallback, useEffect, useId, useLayoutEffect, useRef } from 'react';
|
|
6
|
+
import { bind } from 'bind-event-listener';
|
|
7
|
+
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
8
|
+
import noop from '@atlaskit/ds-lib/noop';
|
|
9
|
+
import once from '@atlaskit/ds-lib/once';
|
|
10
|
+
import { useAnimatedVisibility } from '../internal/use-animated-visibility';
|
|
11
|
+
import { useFocusWrap } from '../internal/use-focus-wrap';
|
|
12
|
+
import { useInitialFocus } from '../internal/use-initial-focus';
|
|
13
|
+
/**
|
|
14
|
+
* Detects whether the browser supports the `popover="hint"` attribute value.
|
|
15
|
+
* Uses DOM reflection: unsupported browsers reflect the invalid value default ("manual").
|
|
16
|
+
* Safe for SSR. Result is cached via `once`.
|
|
17
|
+
*/
|
|
18
|
+
const supportsPopoverHint = once(() => {
|
|
19
|
+
if (typeof document === 'undefined') {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
// eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- feature detection
|
|
23
|
+
const el = document.createElement('div');
|
|
24
|
+
el.setAttribute('popover', 'hint');
|
|
25
|
+
return el.popover === 'hint';
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- popover UA reset requires values not in cssMap's type union
|
|
29
|
+
const styles = {
|
|
30
|
+
root: "_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _19pkidpf _2hwxidpf _otyridpf _18u0idpf _1r041wug _1reoewfl _18m9ewfl _bfhk1j28"
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Unopinionated top-layer primitive.
|
|
34
|
+
*
|
|
35
|
+
* Manages only visibility (isOpen) and animation (animate). Has no knowledge
|
|
36
|
+
* of positioning — compose with `useAnchorPosition` for anchor positioning.
|
|
37
|
+
*
|
|
38
|
+
* Visibility is driven by the `isOpen` prop:
|
|
39
|
+
* - `isOpen={true}` → `showPopover()`, entry animation via `@starting-style`
|
|
40
|
+
* - `isOpen={false}` → `hidePopover()`, exit animation via `allow-discrete`
|
|
41
|
+
*
|
|
42
|
+
* For `mode="auto"`, the browser can dismiss the popover via light dismiss
|
|
43
|
+
* (Escape, click outside). When that happens, `onClose` is called and the
|
|
44
|
+
* consumer must set `isOpen` to `false`. The DOM owns the dismiss — React
|
|
45
|
+
* must follow.
|
|
46
|
+
*/
|
|
47
|
+
export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
48
|
+
children,
|
|
49
|
+
mode: modeProp = 'auto',
|
|
50
|
+
onClose = noop,
|
|
51
|
+
onOpenChange,
|
|
52
|
+
onExitFinish,
|
|
53
|
+
animate,
|
|
54
|
+
placement,
|
|
55
|
+
testId,
|
|
56
|
+
isOpen,
|
|
57
|
+
// ARIA
|
|
58
|
+
role,
|
|
59
|
+
label,
|
|
60
|
+
labelledBy,
|
|
61
|
+
id: idProp
|
|
62
|
+
}, ref) {
|
|
63
|
+
const autoId = useId();
|
|
64
|
+
const ownRef = useRef(null);
|
|
65
|
+
const combinedRef = mergeRefs([ownRef, ref].filter(Boolean));
|
|
66
|
+
// Regex is intentional — `replaceAll` is not available in our supported
|
|
67
|
+
// browser matrix. In React 18, `useId()` returns IDs containing colons
|
|
68
|
+
// (e.g. `:r1:`) which are invalid in CSS selectors and `popover` target
|
|
69
|
+
// attributes. React 19.2.0 replaced colons with underscores, making this
|
|
70
|
+
// stripping unnecessary once React 18 support is dropped.
|
|
71
|
+
const popoverId = idProp !== null && idProp !== void 0 ? idProp : `popover-${autoId.replace(/:/g, '')}`;
|
|
72
|
+
const {
|
|
73
|
+
showChildren,
|
|
74
|
+
preset
|
|
75
|
+
} = useAnimatedVisibility({
|
|
76
|
+
isOpen,
|
|
77
|
+
animate,
|
|
78
|
+
elementRef: ownRef,
|
|
79
|
+
onExitFinish
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// ── Focus management ──
|
|
83
|
+
// Initial focus: on open, moves focus into the popover (role-dependent).
|
|
84
|
+
// Focus wrap: Tab/Shift+Tab cycle within the popover for dialog roles.
|
|
85
|
+
// Focus restoration: handled natively by the Popover API — the browser
|
|
86
|
+
// tracks `previouslyFocusedElement` on show and restores it on hide.
|
|
87
|
+
// No custom restoration hook is needed. See: notes/architecture/focus-restoration.md
|
|
88
|
+
useFocusWrap({
|
|
89
|
+
elementRef: ownRef,
|
|
90
|
+
role
|
|
91
|
+
});
|
|
92
|
+
useInitialFocus({
|
|
93
|
+
elementRef: ownRef,
|
|
94
|
+
isOpen,
|
|
95
|
+
role
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Hint mode fallback: "hint" downgrades to "auto" if unsupported.
|
|
99
|
+
//
|
|
100
|
+
// Decision (2026-03-17 audit): We keep "auto" as the fallback (not "manual")
|
|
101
|
+
// because it provides the closest behavior to "hint" (light dismiss works).
|
|
102
|
+
// However, there is a behavioral difference: "auto" participates in the
|
|
103
|
+
// auto-dismiss stack and WILL close other "auto" popovers when it opens
|
|
104
|
+
// (e.g. a tooltip opening will close an open dropdown). "hint" does not
|
|
105
|
+
// have this side effect. This difference only affects browsers without
|
|
106
|
+
// popover="hint" support, and that set is shrinking rapidly.
|
|
107
|
+
const mode = modeProp === 'hint' && !supportsPopoverHint() ? 'auto' : modeProp;
|
|
108
|
+
|
|
109
|
+
// Distinguishes programmatic hidePopover() from browser-initiated dismiss.
|
|
110
|
+
// When we call hidePopover() ourselves the toggle event fires synchronously —
|
|
111
|
+
// this ref prevents the toggle handler from calling onClose redundantly.
|
|
112
|
+
const programmaticCloseRef = useRef(false);
|
|
113
|
+
|
|
114
|
+
// Escape key tracking: set in a capture-phase keydown listener (fires before
|
|
115
|
+
// the browser processes light dismiss), read in the toggle handler.
|
|
116
|
+
const closeReasonRef = useRef('light-dismiss');
|
|
117
|
+
const handleToggle = useCallback(event => {
|
|
118
|
+
const el = ownRef.current;
|
|
119
|
+
if (event.newState === 'open') {
|
|
120
|
+
if (el) {
|
|
121
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
|
|
122
|
+
isOpen: true,
|
|
123
|
+
element: el
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (event.newState === 'closed') {
|
|
129
|
+
if (el) {
|
|
130
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
|
|
131
|
+
isOpen: false,
|
|
132
|
+
element: el
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Programmatic close (unmount or isOpen→false). Consumer already knows.
|
|
137
|
+
if (programmaticCloseRef.current) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Browser dismiss (Escape or click-outside). Notify consumer.
|
|
142
|
+
const reason = closeReasonRef.current;
|
|
143
|
+
closeReasonRef.current = 'light-dismiss'; // reset for next dismiss
|
|
144
|
+
onClose({
|
|
145
|
+
reason
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}, [onClose, onOpenChange]);
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
const el = ownRef.current;
|
|
151
|
+
if (!el) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Capture-phase: tag Escape before the browser processes light dismiss.
|
|
156
|
+
const unbindEscape = bind(el, {
|
|
157
|
+
type: 'keydown',
|
|
158
|
+
listener: event => {
|
|
159
|
+
if (event.key === 'Escape') {
|
|
160
|
+
closeReasonRef.current = 'escape';
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
options: {
|
|
164
|
+
capture: true
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
const unbindToggle = bind(el, {
|
|
168
|
+
type: 'toggle',
|
|
169
|
+
listener: handleToggle
|
|
170
|
+
});
|
|
171
|
+
return () => {
|
|
172
|
+
unbindEscape();
|
|
173
|
+
unbindToggle();
|
|
174
|
+
};
|
|
175
|
+
}, [handleToggle]);
|
|
176
|
+
|
|
177
|
+
// Placement-dependent animation CSS vars (e.g. slide direction).
|
|
178
|
+
// Separate from show/hide so that preset reference changes
|
|
179
|
+
// (e.g. inline `animate={slideAndFade()}`) don't re-trigger visibility.
|
|
180
|
+
useLayoutEffect(() => {
|
|
181
|
+
const el = ownRef.current;
|
|
182
|
+
if (!el || !(preset !== null && preset !== void 0 && preset.getProperties) || !placement) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const props = preset.getProperties({
|
|
186
|
+
placement
|
|
187
|
+
});
|
|
188
|
+
Object.entries(props).forEach(([key, value]) => {
|
|
189
|
+
el.style.setProperty(key, String(value));
|
|
190
|
+
});
|
|
191
|
+
}, [preset, placement]);
|
|
192
|
+
|
|
193
|
+
// Show/hide based on isOpen. try/catch because show/hide throw if the
|
|
194
|
+
// element is already in the target state (e.g. browser dismissed via
|
|
195
|
+
// light-dismiss before our effect ran).
|
|
196
|
+
useLayoutEffect(() => {
|
|
197
|
+
const el = ownRef.current;
|
|
198
|
+
if (!el) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (isOpen) {
|
|
202
|
+
programmaticCloseRef.current = false;
|
|
203
|
+
try {
|
|
204
|
+
el.showPopover();
|
|
205
|
+
} catch {
|
|
206
|
+
// Already showing or unsupported — DOM matches intent.
|
|
207
|
+
}
|
|
208
|
+
return () => {
|
|
209
|
+
programmaticCloseRef.current = true;
|
|
210
|
+
try {
|
|
211
|
+
el.hidePopover();
|
|
212
|
+
} catch {
|
|
213
|
+
// Already hidden — DOM matches intent.
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
programmaticCloseRef.current = true;
|
|
218
|
+
try {
|
|
219
|
+
el.hidePopover();
|
|
220
|
+
} catch {
|
|
221
|
+
// Already hidden — DOM matches intent.
|
|
222
|
+
}
|
|
223
|
+
}, [isOpen]);
|
|
224
|
+
return /*#__PURE__*/React.createElement("div", _extends({
|
|
225
|
+
ref: combinedRef,
|
|
226
|
+
id: popoverId
|
|
227
|
+
// @ts-expect-error -- popover attribute not yet in React types
|
|
228
|
+
// eslint-disable-next-line react/no-unknown-property -- popover attribute not yet in React types
|
|
229
|
+
,
|
|
230
|
+
popover: mode,
|
|
231
|
+
role: role,
|
|
232
|
+
"aria-label": label,
|
|
233
|
+
"aria-labelledby": labelledBy,
|
|
234
|
+
"data-testid": testId
|
|
235
|
+
}, preset ? {
|
|
236
|
+
[`data-ds-popover-${preset.name}`]: ''
|
|
237
|
+
} : undefined, {
|
|
238
|
+
className: ax([styles.root])
|
|
239
|
+
}), showChildren ? children : null);
|
|
240
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { PopupRoot } from './popup';
|
|
2
|
+
import { PopupContent } from './popup-content';
|
|
3
|
+
import { PopupSurface } from './popup-surface';
|
|
4
|
+
import { PopupTrigger } from './popup-trigger';
|
|
5
|
+
import { PopupTriggerFunction } from './popup-trigger-function';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Compound component for rendering content in the browser's top layer
|
|
9
|
+
* using the native Popover API (`popover="auto"`).
|
|
10
|
+
* Placement is owned by this compound: root provides it via context, Content applies it
|
|
11
|
+
* (CSS Anchor Positioning or JS fallback).
|
|
12
|
+
*
|
|
13
|
+
* For default overlay styling (background, shadow, border-radius), see `PopupSurface` in the package examples.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <Popup placement={{ edge: 'end' }} onClose={handleClose}>
|
|
18
|
+
* <Popup.Trigger>
|
|
19
|
+
* <button>Open</button>
|
|
20
|
+
* </Popup.Trigger>
|
|
21
|
+
* <Popup.Content role="dialog" label="My popup">
|
|
22
|
+
* Content goes here
|
|
23
|
+
* </Popup.Content>
|
|
24
|
+
* </Popup>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
const Popup = Object.assign(PopupRoot, {
|
|
28
|
+
Trigger: PopupTrigger,
|
|
29
|
+
TriggerFunction: PopupTriggerFunction,
|
|
30
|
+
Content: PopupContent,
|
|
31
|
+
Surface: PopupSurface
|
|
32
|
+
});
|
|
33
|
+
export { Popup };
|