@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,249 @@
|
|
|
1
|
+
import once from '@atlaskit/ds-lib/once';
|
|
2
|
+
import { getPlacement, placementToPositionArea } from '../internal/use-anchor-positioning';
|
|
3
|
+
/**
|
|
4
|
+
* CSS for popover arrows using the `clip-path: inset() margin-box` technique.
|
|
5
|
+
*
|
|
6
|
+
* How it works:
|
|
7
|
+
* 1. Four arrow shapes exist simultaneously as `::before` (top/bottom) and
|
|
8
|
+
* `::after` (left/right) hexagonal pseudo-elements.
|
|
9
|
+
* 2. `clip-path: inset(1px) margin-box` clips the popover to its margin-box.
|
|
10
|
+
* 3. Margin on the anchor-facing side pushes the popover away, creating space
|
|
11
|
+
* where one arrow "escapes" the clip boundary and becomes visible.
|
|
12
|
+
* 4. `@position-try` rules change both `position-area` and `margin` when
|
|
13
|
+
* flipping, ensuring the correct arrow is always shown.
|
|
14
|
+
*
|
|
15
|
+
* Constraints:
|
|
16
|
+
* - `box-shadow` must be `none` (interferes with `clip-path: inset() margin-box`)
|
|
17
|
+
* - `::before` and `::after` are consumed — consumers cannot use them
|
|
18
|
+
* - Arrow pseudo-elements use `background: inherit` from the popover element
|
|
19
|
+
*
|
|
20
|
+
* @see https://goulet.dev/posts/tooltip-with-popover-and-anchor-positioning/
|
|
21
|
+
*/
|
|
22
|
+
const ARROW_CSS = `
|
|
23
|
+
[data-ds-popover-arrow] {
|
|
24
|
+
clip-path: inset(var(--ds-arrow-offset, 1px)) margin-box;
|
|
25
|
+
box-shadow: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Top and Bottom arrows (vertical hexagon) */
|
|
29
|
+
[data-ds-popover-arrow]::before {
|
|
30
|
+
content: "";
|
|
31
|
+
position: absolute;
|
|
32
|
+
z-index: -1;
|
|
33
|
+
background: inherit;
|
|
34
|
+
left: 50%;
|
|
35
|
+
transform: translateX(-50%);
|
|
36
|
+
width: calc(var(--ds-arrow-size, 8px) * 2);
|
|
37
|
+
height: calc(100% + var(--ds-arrow-size, 8px) * 2);
|
|
38
|
+
top: calc(var(--ds-arrow-size, 8px) * -1);
|
|
39
|
+
clip-path: polygon(
|
|
40
|
+
0 var(--ds-arrow-size, 8px),
|
|
41
|
+
50% 0,
|
|
42
|
+
100% var(--ds-arrow-size, 8px),
|
|
43
|
+
100% calc(100% - var(--ds-arrow-size, 8px)),
|
|
44
|
+
50% 100%,
|
|
45
|
+
0 calc(100% - var(--ds-arrow-size, 8px))
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Left and Right arrows (horizontal hexagon) */
|
|
50
|
+
[data-ds-popover-arrow]::after {
|
|
51
|
+
content: "";
|
|
52
|
+
position: absolute;
|
|
53
|
+
z-index: -1;
|
|
54
|
+
background: inherit;
|
|
55
|
+
top: 50%;
|
|
56
|
+
transform: translateY(-50%);
|
|
57
|
+
height: calc(var(--ds-arrow-size, 8px) * 2);
|
|
58
|
+
width: calc(100% + var(--ds-arrow-size, 8px) * 2);
|
|
59
|
+
left: calc(var(--ds-arrow-size, 8px) * -1);
|
|
60
|
+
clip-path: polygon(
|
|
61
|
+
var(--ds-arrow-size, 8px) 0,
|
|
62
|
+
calc(100% - var(--ds-arrow-size, 8px)) 0,
|
|
63
|
+
100% 50%,
|
|
64
|
+
calc(100% - var(--ds-arrow-size, 8px)) 100%,
|
|
65
|
+
var(--ds-arrow-size, 8px) 100%,
|
|
66
|
+
0 50%
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* ── @position-try rules ──
|
|
71
|
+
* One rule per possible position-area value.
|
|
72
|
+
* Each sets the position-area and the correct margin direction
|
|
73
|
+
* so the arrow on the anchor-facing side is revealed.
|
|
74
|
+
*
|
|
75
|
+
* Margin direction per edge:
|
|
76
|
+
* block-start (above anchor) → margin-block-end (bottom, facing anchor)
|
|
77
|
+
* block-end (below anchor) → margin-block-start (top, facing anchor)
|
|
78
|
+
* inline-start (left of anchor) → margin-inline-end (right, facing anchor)
|
|
79
|
+
* inline-end (right of anchor) → margin-inline-start (left, facing anchor)
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
/* Single-axis centered */
|
|
83
|
+
@position-try --ds-arrow-block-start {
|
|
84
|
+
position-area: block-start;
|
|
85
|
+
margin: 0;
|
|
86
|
+
margin-block-end: var(--ds-arrow-size, 8px);
|
|
87
|
+
}
|
|
88
|
+
@position-try --ds-arrow-block-end {
|
|
89
|
+
position-area: block-end;
|
|
90
|
+
margin: 0;
|
|
91
|
+
margin-block-start: var(--ds-arrow-size, 8px);
|
|
92
|
+
}
|
|
93
|
+
@position-try --ds-arrow-inline-start {
|
|
94
|
+
position-area: inline-start;
|
|
95
|
+
margin: 0;
|
|
96
|
+
margin-inline-end: var(--ds-arrow-size, 8px);
|
|
97
|
+
}
|
|
98
|
+
@position-try --ds-arrow-inline-end {
|
|
99
|
+
position-area: inline-end;
|
|
100
|
+
margin: 0;
|
|
101
|
+
margin-inline-start: var(--ds-arrow-size, 8px);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Block edge + inline span */
|
|
105
|
+
@position-try --ds-arrow-block-start-span-inline-start {
|
|
106
|
+
position-area: block-start span-inline-start;
|
|
107
|
+
margin: 0;
|
|
108
|
+
margin-block-end: var(--ds-arrow-size, 8px);
|
|
109
|
+
}
|
|
110
|
+
@position-try --ds-arrow-block-start-span-inline-end {
|
|
111
|
+
position-area: block-start span-inline-end;
|
|
112
|
+
margin: 0;
|
|
113
|
+
margin-block-end: var(--ds-arrow-size, 8px);
|
|
114
|
+
}
|
|
115
|
+
@position-try --ds-arrow-block-end-span-inline-start {
|
|
116
|
+
position-area: block-end span-inline-start;
|
|
117
|
+
margin: 0;
|
|
118
|
+
margin-block-start: var(--ds-arrow-size, 8px);
|
|
119
|
+
}
|
|
120
|
+
@position-try --ds-arrow-block-end-span-inline-end {
|
|
121
|
+
position-area: block-end span-inline-end;
|
|
122
|
+
margin: 0;
|
|
123
|
+
margin-block-start: var(--ds-arrow-size, 8px);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Inline edge + block span */
|
|
127
|
+
@position-try --ds-arrow-inline-start-span-block-start {
|
|
128
|
+
position-area: inline-start span-block-start;
|
|
129
|
+
margin: 0;
|
|
130
|
+
margin-inline-end: var(--ds-arrow-size, 8px);
|
|
131
|
+
}
|
|
132
|
+
@position-try --ds-arrow-inline-start-span-block-end {
|
|
133
|
+
position-area: inline-start span-block-end;
|
|
134
|
+
margin: 0;
|
|
135
|
+
margin-inline-end: var(--ds-arrow-size, 8px);
|
|
136
|
+
}
|
|
137
|
+
@position-try --ds-arrow-inline-end-span-block-start {
|
|
138
|
+
position-area: inline-end span-block-start;
|
|
139
|
+
margin: 0;
|
|
140
|
+
margin-inline-start: var(--ds-arrow-size, 8px);
|
|
141
|
+
}
|
|
142
|
+
@position-try --ds-arrow-inline-end-span-block-end {
|
|
143
|
+
position-area: inline-end span-block-end;
|
|
144
|
+
margin: 0;
|
|
145
|
+
margin-inline-start: var(--ds-arrow-size, 8px);
|
|
146
|
+
}
|
|
147
|
+
`;
|
|
148
|
+
|
|
149
|
+
// ── Placement utilities ──
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Converts a `position-area` value to a CSS rule name by replacing spaces with hyphens
|
|
153
|
+
* and prepending `--ds-arrow-`.
|
|
154
|
+
*
|
|
155
|
+
* @example positionAreaToRuleName('block-end span-inline-start') → '--ds-arrow-block-end-span-inline-start'
|
|
156
|
+
*/
|
|
157
|
+
function positionAreaToRuleName({
|
|
158
|
+
positionArea
|
|
159
|
+
}) {
|
|
160
|
+
return `--ds-arrow-${positionArea.replace(/ /g, '-')}`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Returns `position-try-fallbacks` using named `@position-try` rules
|
|
165
|
+
* that change both `position-area` and `margin` when flipping.
|
|
166
|
+
*
|
|
167
|
+
* This is required for the arrow technique because built-in keywords
|
|
168
|
+
* (`flip-block`, `flip-inline`) only flip `position-area` — they do
|
|
169
|
+
* not update the margin direction needed to reveal the correct arrow.
|
|
170
|
+
*/
|
|
171
|
+
function getTryFallbacks({
|
|
172
|
+
placement
|
|
173
|
+
}) {
|
|
174
|
+
const {
|
|
175
|
+
axis,
|
|
176
|
+
edge,
|
|
177
|
+
align
|
|
178
|
+
} = getPlacement({
|
|
179
|
+
placement
|
|
180
|
+
});
|
|
181
|
+
if (align === 'center') {
|
|
182
|
+
// Single-axis: only flip the edge
|
|
183
|
+
const flippedEdge = edge === 'start' ? 'end' : 'start';
|
|
184
|
+
return positionAreaToRuleName({
|
|
185
|
+
positionArea: placementToPositionArea({
|
|
186
|
+
placement: {
|
|
187
|
+
axis,
|
|
188
|
+
edge: flippedEdge
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Compound placement: try flipping edge, alignment, and both
|
|
195
|
+
const flippedEdge = edge === 'start' ? 'end' : 'start';
|
|
196
|
+
const flippedAlign = align === 'start' ? 'end' : 'start';
|
|
197
|
+
return [positionAreaToRuleName({
|
|
198
|
+
positionArea: placementToPositionArea({
|
|
199
|
+
placement: {
|
|
200
|
+
axis,
|
|
201
|
+
edge: flippedEdge,
|
|
202
|
+
align
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
}), positionAreaToRuleName({
|
|
206
|
+
positionArea: placementToPositionArea({
|
|
207
|
+
placement: {
|
|
208
|
+
axis,
|
|
209
|
+
edge,
|
|
210
|
+
align: flippedAlign
|
|
211
|
+
}
|
|
212
|
+
})
|
|
213
|
+
}), positionAreaToRuleName({
|
|
214
|
+
positionArea: placementToPositionArea({
|
|
215
|
+
placement: {
|
|
216
|
+
axis,
|
|
217
|
+
edge: flippedEdge,
|
|
218
|
+
align: flippedAlign
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
})].join(', ');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Creates an arrow preset for popover content.
|
|
226
|
+
*
|
|
227
|
+
* The returned object is passed to `PopoverContent`'s `arrow` prop.
|
|
228
|
+
* It carries the CSS string and fallback logic so that consumers who
|
|
229
|
+
* don't use arrows pay no bundle cost.
|
|
230
|
+
*
|
|
231
|
+
* The arrows inherit their background from the popover element.
|
|
232
|
+
* When `arrow` is active, `PopoverContent` does not reset `background`
|
|
233
|
+
* to `transparent`, allowing the UA default (`canvas`) or a consumer-set
|
|
234
|
+
* background to show through.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```tsx
|
|
238
|
+
* import { arrow } from '@atlaskit/top-layer/arrow';
|
|
239
|
+
*
|
|
240
|
+
* const myArrow = arrow();
|
|
241
|
+
*
|
|
242
|
+
* <Popup.Content arrow={myArrow} />
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
export const arrow = once(() => ({
|
|
246
|
+
name: 'arrow',
|
|
247
|
+
css: ARROW_CSS,
|
|
248
|
+
getTryFallbacks
|
|
249
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a synthetic DOM event from a `TDialogCloseReason`.
|
|
3
|
+
*
|
|
4
|
+
* Useful when bridging the Dialog primitive's `onClose({ reason })` callback
|
|
5
|
+
* to a legacy API that expects a `KeyboardEvent` or `MouseEvent` — for example,
|
|
6
|
+
* `@atlaskit/modal-dialog`'s `onClose(event, analyticsEvent)` contract.
|
|
7
|
+
*
|
|
8
|
+
* - `'escape'` → `KeyboardEvent('keydown', { key: 'Escape' })`
|
|
9
|
+
* - `'overlay-click'` → `MouseEvent('click')`
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import { createCloseEvent } from '@atlaskit/top-layer/create-close-event';
|
|
14
|
+
* import { type TDialogCloseReason } from '@atlaskit/top-layer/dialog';
|
|
15
|
+
*
|
|
16
|
+
* function onDialogClose({ reason }: { reason: TDialogCloseReason }) {
|
|
17
|
+
* legacyOnClose(createCloseEvent({ reason }));
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function createCloseEvent({
|
|
22
|
+
reason
|
|
23
|
+
}) {
|
|
24
|
+
if (reason === 'escape') {
|
|
25
|
+
return new KeyboardEvent('keydown', {
|
|
26
|
+
key: 'Escape',
|
|
27
|
+
bubbles: true
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return new MouseEvent('click', {
|
|
31
|
+
bubbles: true,
|
|
32
|
+
cancelable: true
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
._19itglyw{border:none}._18u01wug{margin-left:auto}
|
|
3
|
+
._19pk1wug{margin-top:auto}
|
|
4
|
+
._1ltk1i5c::-ms-backdrop{background-color:var(--ds-blanket,#050c1f75)}
|
|
5
|
+
._1ltk1i5c::backdrop{background-color:var(--ds-blanket,#050c1f75)}
|
|
6
|
+
._1q51ze3t{padding-block-start:var(--ds-space-0,0)}
|
|
7
|
+
._2hwx1wug{margin-right:auto}
|
|
8
|
+
._85i5ze3t{padding-block-end:var(--ds-space-0,0)}
|
|
9
|
+
._bfhk1j28{background-color:transparent}
|
|
10
|
+
._bozgze3t{padding-inline-start:var(--ds-space-0,0)}
|
|
11
|
+
._c71lglyw{max-height:none}
|
|
12
|
+
._otyr1wug{margin-bottom:auto}
|
|
13
|
+
._p12fglyw{max-width:none}
|
|
14
|
+
._y4tize3t{padding-inline-end:var(--ds-space-0,0)}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/* dialog-content.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
3
|
+
import "./dialog-content.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 { useAnimatedVisibility } from '../internal/use-animated-visibility';
|
|
9
|
+
import { useFocusWrap } from '../internal/use-focus-wrap';
|
|
10
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- dialog reset requires values not in cssMap's type union
|
|
11
|
+
const styles = {
|
|
12
|
+
dialog: "_19itglyw _19pk1wug _2hwx1wug _otyr1wug _18u01wug _1q51ze3t _y4tize3t _85i5ze3t _bozgze3t _p12fglyw _c71lglyw _bfhk1j28 _1ltk1i5c"
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Low-level `<dialog>` primitive. No visual opinions — no width, height,
|
|
17
|
+
* background, border-radius, or layout. Consumers provide their own styling.
|
|
18
|
+
*
|
|
19
|
+
* Visibility is controlled declaratively via `isOpen`:
|
|
20
|
+
* - `isOpen={true}` calls `.showModal()` (entry animation via `@starting-style`)
|
|
21
|
+
* - `isOpen={false}` calls `.close()` (exit animation via `allow-discrete`)
|
|
22
|
+
*
|
|
23
|
+
* Handles native `cancel` event (Escape) and backdrop click detection.
|
|
24
|
+
*
|
|
25
|
+
* Close flow: we never call `dialog.close()` from event handlers. We always call
|
|
26
|
+
* `onClose`; the consumer decides whether to set `isOpen={false}`.
|
|
27
|
+
*/
|
|
28
|
+
export const Dialog = /*#__PURE__*/forwardRef(function Dialog({
|
|
29
|
+
children,
|
|
30
|
+
isOpen,
|
|
31
|
+
onClose,
|
|
32
|
+
onExitFinish,
|
|
33
|
+
animate,
|
|
34
|
+
style,
|
|
35
|
+
testId,
|
|
36
|
+
id: providedId,
|
|
37
|
+
label,
|
|
38
|
+
labelledBy,
|
|
39
|
+
shouldHideBackdrop
|
|
40
|
+
}, ref) {
|
|
41
|
+
const generatedId = useId();
|
|
42
|
+
const dialogId = providedId !== null && providedId !== void 0 ? providedId : generatedId;
|
|
43
|
+
const ownRef = useRef(null);
|
|
44
|
+
const combinedRef = mergeRefs([ownRef, ref]);
|
|
45
|
+
|
|
46
|
+
// ── Animation lifecycle ──
|
|
47
|
+
const {
|
|
48
|
+
showChildren,
|
|
49
|
+
preset
|
|
50
|
+
} = useAnimatedVisibility({
|
|
51
|
+
isOpen,
|
|
52
|
+
animate,
|
|
53
|
+
elementRef: ownRef,
|
|
54
|
+
onExitFinish
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// ── Focus wrap ──
|
|
58
|
+
// Native <dialog>.showModal() traps focus but wraps through <body> at
|
|
59
|
+
// the boundary (A → B → C → body → A). This hook intercepts Tab to
|
|
60
|
+
// wrap directly (A → B → C → A), matching the WAI-ARIA APG pattern.
|
|
61
|
+
useFocusWrap({
|
|
62
|
+
elementRef: ownRef,
|
|
63
|
+
role: 'dialog'
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Show/hide the dialog in response to isOpen changes.
|
|
67
|
+
useLayoutEffect(() => {
|
|
68
|
+
const dialog = ownRef.current;
|
|
69
|
+
if (!dialog) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (isOpen) {
|
|
73
|
+
if (!dialog.open) {
|
|
74
|
+
dialog.showModal();
|
|
75
|
+
}
|
|
76
|
+
return () => {
|
|
77
|
+
if (dialog.open) {
|
|
78
|
+
dialog.close();
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (dialog.open) {
|
|
83
|
+
dialog.close();
|
|
84
|
+
}
|
|
85
|
+
}, [isOpen]);
|
|
86
|
+
|
|
87
|
+
// ── Handle native Escape (cancel event) ──
|
|
88
|
+
const handleCancel = useCallback(event => {
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
onClose({
|
|
91
|
+
reason: 'escape'
|
|
92
|
+
});
|
|
93
|
+
}, [onClose]);
|
|
94
|
+
|
|
95
|
+
// ── Handle backdrop click ──
|
|
96
|
+
// Attached via bind-event-listener rather than a React prop so we avoid
|
|
97
|
+
// a11y lint suppressions on the <dialog> element.
|
|
98
|
+
// Keyboard dismiss is already handled natively (Escape → onCancel above).
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
const dialog = ownRef.current;
|
|
101
|
+
if (!dialog) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
return bind(dialog, {
|
|
105
|
+
type: 'click',
|
|
106
|
+
listener(event) {
|
|
107
|
+
if (event.target === event.currentTarget) {
|
|
108
|
+
onClose({
|
|
109
|
+
reason: 'overlay-click'
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}, [onClose]);
|
|
115
|
+
|
|
116
|
+
// Atomic CSS (Compiled) deduplicates ::backdrop { background-color }
|
|
117
|
+
// into a single class, making it impossible to toggle between two values
|
|
118
|
+
// via cssMap entries. An ID-scoped <style> has higher specificity than
|
|
119
|
+
// any atomic class, so the override always wins.
|
|
120
|
+
const escapedId = CSS.escape(dialogId);
|
|
121
|
+
return /*#__PURE__*/React.createElement("dialog", _extends({
|
|
122
|
+
ref: combinedRef,
|
|
123
|
+
id: dialogId,
|
|
124
|
+
"aria-label": label,
|
|
125
|
+
"aria-labelledby": label ? undefined : labelledBy,
|
|
126
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
|
|
127
|
+
style: style,
|
|
128
|
+
onCancel: handleCancel,
|
|
129
|
+
"data-testid": testId
|
|
130
|
+
}, preset ? {
|
|
131
|
+
[`data-ds-${preset.name}`]: ''
|
|
132
|
+
} : undefined, {
|
|
133
|
+
className: ax([styles.dialog])
|
|
134
|
+
}), shouldHideBackdrop &&
|
|
135
|
+
/*#__PURE__*/
|
|
136
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-global-styles
|
|
137
|
+
React.createElement("style", null, `#${escapedId}::backdrop{background-color:transparent}`), showChildren ? children : null);
|
|
138
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useLayoutEffect } from 'react';
|
|
2
|
+
import { getDocument } from '@atlaskit/browser-apis';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* __DialogScrollLock__
|
|
6
|
+
*
|
|
7
|
+
* Prevents background page scrolling while mounted. Designed to be rendered
|
|
8
|
+
* inside a `Dialog` so that the scroll lock is automatically removed when the
|
|
9
|
+
* dialog closes (unmounts its children).
|
|
10
|
+
*
|
|
11
|
+
* Native `<dialog>.showModal()` makes background content _inert_ (not
|
|
12
|
+
* focusable/clickable), but does **not** prevent scroll events from reaching
|
|
13
|
+
* the document body. This component fills that gap by setting
|
|
14
|
+
* `overflow: hidden` on `document.body`.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* import { Dialog } from '@atlaskit/top-layer/dialog';
|
|
19
|
+
* import { DialogScrollLock } from '@atlaskit/top-layer/dialog-scroll-lock';
|
|
20
|
+
*
|
|
21
|
+
* <Dialog isOpen={isOpen} onClose={onClose}>
|
|
22
|
+
* <DialogScrollLock />
|
|
23
|
+
* {children}
|
|
24
|
+
* </Dialog>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function DialogScrollLock() {
|
|
28
|
+
useLayoutEffect(() => {
|
|
29
|
+
var _getDocument;
|
|
30
|
+
const body = (_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.body;
|
|
31
|
+
if (!body) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const previousOverflow = body.style.overflow;
|
|
35
|
+
body.style.overflow = 'hidden';
|
|
36
|
+
return () => {
|
|
37
|
+
body.style.overflow = previousOverflow;
|
|
38
|
+
};
|
|
39
|
+
}, []);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { slideAndFade, fade, scaleAndFade, dialogSlideUpAndFade, dialogFade } from '../animations/presets';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { arrow } from '../arrow';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DialogScrollLock } from '../dialog-scroll-lock';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Dialog } from '../dialog';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getFirstFocusable, getLastFocusable, getNextFocusable } from '../focus';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { fromLegacyPlacement, placementMapping } from '../placement-map';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Popover } from '../popover';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PopupSurface } from '../popup/popup-surface';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Popup } from '../popup';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useAnchorPosition } from '../internal/use-anchor-positioning';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useArrowNavigation, isAtCurrentMenuLevel } from '../use-arrow-navigation';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useSimpleLightDismiss } from '../use-simple-light-dismiss';
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focusable element selectors and navigation helpers.
|
|
3
|
+
*
|
|
4
|
+
* Uses CSS selectors to discover focusable elements within a container,
|
|
5
|
+
* avoiding the need for a manual registration system. Disabled elements
|
|
6
|
+
* (both HTML `disabled` attribute and `aria-disabled="true"`) and elements
|
|
7
|
+
* with `tabindex="-1"` are excluded automatically.
|
|
8
|
+
*
|
|
9
|
+
* All public functions accept an optional `filter` callback to further
|
|
10
|
+
* restrict which focusable elements are included.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const selectors = (() => {
|
|
14
|
+
// Common exclusion filter applied to every selector.
|
|
15
|
+
const not = ':not([tabindex="-1"]):not([aria-disabled="true"]):not([aria-hidden="true"])';
|
|
16
|
+
const notDisabled = `:not([disabled])${not}`;
|
|
17
|
+
const focusable = [`a[href]${not}`, `area[href]${not}`, `input${notDisabled}:not([type="hidden"])`, `select${notDisabled}`, `textarea${notDisabled}`, `button${notDisabled}`, `iframe${not}`, `audio[controls]${not}`, `video[controls]${not}`, `[contenteditable]:not([contenteditable="false"])${not}`, `[tabindex]${notDisabled}${not}`];
|
|
18
|
+
return {
|
|
19
|
+
focusable: focusable.join(','),
|
|
20
|
+
focused: focusable.join(':focus,') + ':focus'
|
|
21
|
+
};
|
|
22
|
+
})();
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* An optional callback to restrict which focusable elements are included.
|
|
26
|
+
* Return `true` to include the element, `false` to skip it.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns all focusable HTMLElements within the container, optionally filtered.
|
|
31
|
+
*
|
|
32
|
+
* Note: this searches the full subtree and does not stop at nested
|
|
33
|
+
* popover/dialog boundaries. In practice this is fine because nested
|
|
34
|
+
* popovers are not rendered until they are opened, so their content
|
|
35
|
+
* is not in the DOM when the parent's initial focus runs. If that
|
|
36
|
+
* assumption changes, this would need to be scoped to the current layer.
|
|
37
|
+
*/
|
|
38
|
+
function getFocusables({
|
|
39
|
+
container,
|
|
40
|
+
filter
|
|
41
|
+
}) {
|
|
42
|
+
return Array.from(container.querySelectorAll(selectors.focusable)).filter(el => el instanceof HTMLElement).filter(el => !filter || filter(el, container));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Returns the first focusable element within the container.
|
|
47
|
+
*/
|
|
48
|
+
export function getFirstFocusable({
|
|
49
|
+
container,
|
|
50
|
+
filter
|
|
51
|
+
}) {
|
|
52
|
+
const items = getFocusables({
|
|
53
|
+
container,
|
|
54
|
+
filter
|
|
55
|
+
});
|
|
56
|
+
return items.length > 0 ? items[0] : null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Returns the last focusable element within the container.
|
|
61
|
+
*/
|
|
62
|
+
export function getLastFocusable({
|
|
63
|
+
container,
|
|
64
|
+
filter
|
|
65
|
+
}) {
|
|
66
|
+
const items = getFocusables({
|
|
67
|
+
container,
|
|
68
|
+
filter
|
|
69
|
+
});
|
|
70
|
+
return items.length > 0 ? items[items.length - 1] : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Returns the next focusable element in the given direction relative to the
|
|
75
|
+
* currently focused element within the container. Wraps around at both ends.
|
|
76
|
+
*
|
|
77
|
+
* Returns `null` if there is no focused element within the container or if
|
|
78
|
+
* the focused element is not in the list of focusable elements.
|
|
79
|
+
*/
|
|
80
|
+
export function getNextFocusable({
|
|
81
|
+
container,
|
|
82
|
+
direction,
|
|
83
|
+
filter
|
|
84
|
+
}) {
|
|
85
|
+
var _all$nextIndex;
|
|
86
|
+
const all = getFocusables({
|
|
87
|
+
container,
|
|
88
|
+
filter
|
|
89
|
+
});
|
|
90
|
+
const current = container.querySelector(selectors.focused);
|
|
91
|
+
if (!(current instanceof HTMLElement)) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const index = all.indexOf(current);
|
|
95
|
+
if (index === -1) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const nextIndex = (() => {
|
|
99
|
+
if (direction === 'forwards') {
|
|
100
|
+
return (index + 1) % all.length;
|
|
101
|
+
}
|
|
102
|
+
const proposed = index - 1;
|
|
103
|
+
// if going into negative numbers, loop back to the last item
|
|
104
|
+
return proposed < 0 ? all.length - 1 : proposed;
|
|
105
|
+
})();
|
|
106
|
+
return (_all$nextIndex = all[nextIndex]) !== null && _all$nextIndex !== void 0 ? _all$nextIndex : null;
|
|
107
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getFirstFocusable, getLastFocusable, getNextFocusable } from './focus';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// This file exists for module resolution purposes.
|
|
2
|
+
// Not exporting anything from the root entry point.
|
|
3
|
+
// Please use individual entry points for minimum bundle size:
|
|
4
|
+
//
|
|
5
|
+
// import { Popup } from '@atlaskit/top-layer/popup';
|
|
6
|
+
// import { Dialog } from '@atlaskit/top-layer/dialog';
|
|
7
|
+
// import { Popover } from '@atlaskit/top-layer/popover';
|