@atlaskit/top-layer 0.16.0 → 0.18.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.
Files changed (141) hide show
  1. package/AGENTS.md +113 -0
  2. package/CHANGELOG.md +14 -0
  3. package/README.md +4 -4
  4. package/animations/package.json +1 -8
  5. package/dialog/package.json +1 -8
  6. package/dialog-scroll-lock/package.json +1 -8
  7. package/dist/cjs/animations/presets.js +96 -9
  8. package/dist/cjs/dialog/dialog-content.js +12 -30
  9. package/dist/cjs/entry-points/animations.js +12 -0
  10. package/dist/cjs/internal/set-style.js +5 -5
  11. package/dist/cjs/internal/slot.js +1 -1
  12. package/dist/cjs/internal/use-anchor-position-at-point.js +8 -8
  13. package/dist/cjs/internal/use-anchor-position.js +19 -40
  14. package/dist/cjs/internal/use-animated-visibility.js +31 -61
  15. package/dist/cjs/internal/use-initial-focus.js +9 -13
  16. package/dist/cjs/internal/use-width-from-anchor.js +6 -6
  17. package/dist/cjs/popover/popover.js +30 -58
  18. package/dist/cjs/popover-surface/popover-surface.js +4 -3
  19. package/dist/cjs/testing/polyfill.js +9 -9
  20. package/dist/cjs/use-simple-light-dismiss/index.js +3 -3
  21. package/dist/es2019/animations/presets.js +145 -2
  22. package/dist/es2019/dialog/dialog-content.js +12 -30
  23. package/dist/es2019/entry-points/animations.js +1 -1
  24. package/dist/es2019/internal/set-style.js +5 -5
  25. package/dist/es2019/internal/slot.js +1 -1
  26. package/dist/es2019/internal/use-anchor-position-at-point.js +8 -8
  27. package/dist/es2019/internal/use-anchor-position.js +19 -40
  28. package/dist/es2019/internal/use-animated-visibility.js +31 -61
  29. package/dist/es2019/internal/use-initial-focus.js +9 -13
  30. package/dist/es2019/internal/use-width-from-anchor.js +6 -6
  31. package/dist/es2019/popover/popover.js +30 -58
  32. package/dist/es2019/popover-surface/popover-surface.js +1 -1
  33. package/dist/es2019/testing/polyfill.js +7 -11
  34. package/dist/es2019/use-simple-light-dismiss/index.js +3 -3
  35. package/dist/esm/animations/presets.js +93 -9
  36. package/dist/esm/dialog/dialog-content.js +12 -30
  37. package/dist/esm/entry-points/animations.js +1 -1
  38. package/dist/esm/internal/set-style.js +5 -5
  39. package/dist/esm/internal/slot.js +1 -1
  40. package/dist/esm/internal/use-anchor-position-at-point.js +8 -8
  41. package/dist/esm/internal/use-anchor-position.js +19 -40
  42. package/dist/esm/internal/use-animated-visibility.js +31 -61
  43. package/dist/esm/internal/use-initial-focus.js +9 -13
  44. package/dist/esm/internal/use-width-from-anchor.js +6 -6
  45. package/dist/esm/popover/popover.js +30 -58
  46. package/dist/esm/popover-surface/popover-surface.js +1 -1
  47. package/dist/esm/testing/polyfill.js +9 -9
  48. package/dist/esm/use-simple-light-dismiss/index.js +3 -3
  49. package/dist/types/animations/presets.d.ts +16 -0
  50. package/dist/types/entry-points/animations.d.ts +1 -1
  51. package/dist/types/internal/set-style.d.ts +2 -2
  52. package/dist/types/internal/slot.d.ts +2 -2
  53. package/dist/types/internal/use-anchor-position-at-point.d.ts +2 -2
  54. package/dist/types/internal/use-anchor-position.d.ts +0 -4
  55. package/dist/types/internal/use-initial-focus.d.ts +1 -1
  56. package/dist/types/popover/types.d.ts +5 -7
  57. package/dist/types/popover-surface/popover-surface.d.ts +2 -2
  58. package/focus/package.json +1 -8
  59. package/get-aria-for-trigger/package.json +1 -8
  60. package/open-layer-observer/package.json +1 -8
  61. package/package.json +3 -3
  62. package/placement-map/package.json +1 -8
  63. package/popover/package.json +1 -8
  64. package/popover-surface/package.json +1 -8
  65. package/testing/polyfill/package.json +1 -8
  66. package/testing/to-be-visible/package.json +1 -8
  67. package/use-anchor-position/package.json +1 -8
  68. package/use-anchor-position-at-point/package.json +1 -8
  69. package/use-arrow-navigation/package.json +1 -8
  70. package/use-popover-id/package.json +1 -8
  71. package/use-simple-light-dismiss/package.json +1 -8
  72. package/use-width-from-anchor/package.json +1 -8
  73. package/dist/types-ts4.5/animations/presets.d.ts +0 -94
  74. package/dist/types-ts4.5/animations/types.d.ts +0 -38
  75. package/dist/types-ts4.5/dialog/create-close-event.d.ts +0 -23
  76. package/dist/types-ts4.5/dialog/dialog-content.d.ts +0 -24
  77. package/dist/types-ts4.5/dialog/index.d.ts +0 -3
  78. package/dist/types-ts4.5/dialog/types.d.ts +0 -126
  79. package/dist/types-ts4.5/dialog-scroll-lock/index.d.ts +0 -40
  80. package/dist/types-ts4.5/entry-points/animations.d.ts +0 -2
  81. package/dist/types-ts4.5/entry-points/dialog-scroll-lock.d.ts +0 -1
  82. package/dist/types-ts4.5/entry-points/dialog.d.ts +0 -2
  83. package/dist/types-ts4.5/entry-points/focus.d.ts +0 -4
  84. package/dist/types-ts4.5/entry-points/get-aria-for-trigger.d.ts +0 -1
  85. package/dist/types-ts4.5/entry-points/open-layer-observer.d.ts +0 -5
  86. package/dist/types-ts4.5/entry-points/placement-map.d.ts +0 -3
  87. package/dist/types-ts4.5/entry-points/popover-surface.d.ts +0 -2
  88. package/dist/types-ts4.5/entry-points/popover.d.ts +0 -2
  89. package/dist/types-ts4.5/entry-points/use-anchor-position-at-point.d.ts +0 -1
  90. package/dist/types-ts4.5/entry-points/use-anchor-position.d.ts +0 -1
  91. package/dist/types-ts4.5/entry-points/use-arrow-navigation.d.ts +0 -3
  92. package/dist/types-ts4.5/entry-points/use-popover-id.d.ts +0 -11
  93. package/dist/types-ts4.5/entry-points/use-simple-light-dismiss.d.ts +0 -2
  94. package/dist/types-ts4.5/entry-points/use-width-from-anchor.d.ts +0 -1
  95. package/dist/types-ts4.5/focus/get-first-focusable.d.ts +0 -8
  96. package/dist/types-ts4.5/focus/get-focusables.d.ts +0 -13
  97. package/dist/types-ts4.5/focus/get-last-focusable.d.ts +0 -8
  98. package/dist/types-ts4.5/focus/get-next-focusable.d.ts +0 -13
  99. package/dist/types-ts4.5/focus/is-in-same-layer.d.ts +0 -8
  100. package/dist/types-ts4.5/focus/is-nested-layer-focused.d.ts +0 -8
  101. package/dist/types-ts4.5/focus/selectors.d.ts +0 -4
  102. package/dist/types-ts4.5/focus/types.d.ts +0 -5
  103. package/dist/types-ts4.5/index.d.ts +0 -0
  104. package/dist/types-ts4.5/internal/anchor-positioning-fallback.d.ts +0 -26
  105. package/dist/types-ts4.5/internal/combine.d.ts +0 -14
  106. package/dist/types-ts4.5/internal/ensure-preset-styles.d.ts +0 -6
  107. package/dist/types-ts4.5/internal/get-aria-for-trigger.d.ts +0 -93
  108. package/dist/types-ts4.5/internal/placement-to-position-area.d.ts +0 -21
  109. package/dist/types-ts4.5/internal/placement-to-try-fallbacks.d.ts +0 -36
  110. package/dist/types-ts4.5/internal/reduced-motion.d.ts +0 -14
  111. package/dist/types-ts4.5/internal/resolve-css-length-to-pixels.d.ts +0 -20
  112. package/dist/types-ts4.5/internal/resolve-css-length.d.ts +0 -8
  113. package/dist/types-ts4.5/internal/resolve-placement.d.ts +0 -58
  114. package/dist/types-ts4.5/internal/role-to-aria-has-popup.d.ts +0 -13
  115. package/dist/types-ts4.5/internal/role-types.d.ts +0 -71
  116. package/dist/types-ts4.5/internal/set-style.d.ts +0 -11
  117. package/dist/types-ts4.5/internal/should-focus-into-popover.d.ts +0 -8
  118. package/dist/types-ts4.5/internal/slot.d.ts +0 -29
  119. package/dist/types-ts4.5/internal/use-anchor-position-at-point.d.ts +0 -67
  120. package/dist/types-ts4.5/internal/use-anchor-position.d.ts +0 -91
  121. package/dist/types-ts4.5/internal/use-animated-visibility.d.ts +0 -109
  122. package/dist/types-ts4.5/internal/use-animation-preset.d.ts +0 -11
  123. package/dist/types-ts4.5/internal/use-focus-wrap.d.ts +0 -25
  124. package/dist/types-ts4.5/internal/use-initial-focus.d.ts +0 -73
  125. package/dist/types-ts4.5/internal/use-preset-styles.d.ts +0 -15
  126. package/dist/types-ts4.5/internal/use-width-from-anchor.d.ts +0 -21
  127. package/dist/types-ts4.5/placement-map/index.d.ts +0 -51
  128. package/dist/types-ts4.5/placement-map/legacy-placements.d.ts +0 -27
  129. package/dist/types-ts4.5/placement-map/placement-mapping.d.ts +0 -13
  130. package/dist/types-ts4.5/popover/create-close-event.d.ts +0 -25
  131. package/dist/types-ts4.5/popover/index.d.ts +0 -3
  132. package/dist/types-ts4.5/popover/popover.d.ts +0 -17
  133. package/dist/types-ts4.5/popover/types.d.ts +0 -193
  134. package/dist/types-ts4.5/popover-surface/index.d.ts +0 -2
  135. package/dist/types-ts4.5/popover-surface/popover-surface.d.ts +0 -21
  136. package/dist/types-ts4.5/testing/polyfill.d.ts +0 -25
  137. package/dist/types-ts4.5/testing/to-be-visible.d.ts +0 -23
  138. package/dist/types-ts4.5/use-arrow-navigation/index.d.ts +0 -3
  139. package/dist/types-ts4.5/use-arrow-navigation/is-at-current-menu-level.d.ts +0 -48
  140. package/dist/types-ts4.5/use-arrow-navigation/use-arrow-navigation.d.ts +0 -102
  141. package/dist/types-ts4.5/use-simple-light-dismiss/index.d.ts +0 -45
@@ -1,17 +0,0 @@
1
- /**
2
- * @jsxRuntime classic
3
- * @jsx jsx
4
- */
5
- import React from 'react';
6
- import { type TPopoverForwardedProps } from './types';
7
- /**
8
- * Unopinionated top-layer primitive. Manages visibility and animation only;
9
- * compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
10
- *
11
- * `isOpen={true}` calls `showPopover()` (entry via `@starting-style`);
12
- * `isOpen={false}` calls `hidePopover()` (exit via `allow-discrete`).
13
- *
14
- * In `mode="auto"`, the browser can light-dismiss (Escape, click outside).
15
- * `onClose` fires; the consumer must then set `isOpen` to `false`.
16
- */
17
- export declare const Popover: React.ForwardRefExoticComponent<TPopoverForwardedProps & React.RefAttributes<HTMLDivElement>>;
@@ -1,193 +0,0 @@
1
- import { type ReactNode } from 'react';
2
- import { type StrictXCSSProp } from '@atlaskit/css';
3
- import { type TAnimationPreset } from '../animations/types';
4
- import { type TPlacementOptions } from '../internal/resolve-placement';
5
- import { type TAriaRoleRequired, type TRoleRequiringAccessibleName, type TRoleWithImplicitName } from '../internal/role-types';
6
- /**
7
- * The reason a popover was closed.
8
- *
9
- * - `'escape'`: The user pressed the Escape key.
10
- * - `'light-dismiss'`: The user clicked outside the popover (or the browser
11
- * dismissed it for another auto-mode reason).
12
- * - `'programmatic'`: The popover was closed programmatically.
13
- */
14
- export type TPopoverCloseReason = 'escape' | 'light-dismiss' | 'programmatic';
15
- /**
16
- * Flat (non-discriminated) props accepted by the Popover component internally.
17
- *
18
- * TypeScript limitation: when PopupContent destructures props from a
19
- * discriminated union (role, label, labelledBy) and re-passes them individually
20
- * to Popover, TypeScript cannot prove the individual fields still satisfy the
21
- * union constraint. This flat type accepts all role/label combinations without
22
- * the union, since ARIA correctness is enforced at the TPopupContentProps
23
- * boundary where consumers interact.
24
- */
25
- export type TPopoverForwardedProps = TPopoverBaseProps & {
26
- mode?: 'auto' | 'hint' | 'manual';
27
- onClose?: (args: {
28
- reason: TPopoverCloseReason;
29
- }) => void;
30
- role?: TRoleRequiringAccessibleName | TRoleWithImplicitName;
31
- label?: string;
32
- labelledBy?: string;
33
- };
34
- export type { TPlacementOptions };
35
- type TPopoverBaseProps = {
36
- children: ReactNode;
37
- /**
38
- * Additional CSS styles applied to the popover root element.
39
- * Use to set `backgroundColor` to match the popup surface colour.
40
- */
41
- xcss?: StrictXCSSProp<'backgroundColor', never>;
42
- /**
43
- * Animation preset for entry/exit transitions.
44
- *
45
- * Animations use `@starting-style` and `allow-discrete` for progressive
46
- * enhancement: browsers without support show/hide instantly.
47
- */
48
- animate?: false | TAnimationPreset;
49
- /**
50
- * Test ID applied to the popover element.
51
- */
52
- testId?: string;
53
- /**
54
- * HTML `id` attribute for the popover element. When omitted, a unique ID
55
- * is generated automatically. Pair the trigger with this ID via `aria-controls`
56
- * and the popover with `popovertarget`. Use `usePopoverId()` to generate a
57
- * stable, CSS-safe id.
58
- */
59
- id?: string;
60
- /**
61
- * Whether the popover is open.
62
- *
63
- * - **`true`:** show the popover (calls `showPopover()`, entry animation plays via `@starting-style`).
64
- * - **`false`:** hide the popover. When an `animate` preset is provided, the exit
65
- * animation plays (via `allow-discrete`) before the popover becomes logically closed.
66
- * Otherwise hides instantly.
67
- *
68
- * The consumer does not conditionally render the `Popover` — visibility is driven
69
- * by this prop.
70
- *
71
- * **Lifecycle observable to consumers:**
72
- *
73
- * - The host element is in the DOM only while the popover is open or its exit
74
- * animation is playing. After exit completes the element is unmounted so it
75
- * does not leave an empty `role` / `popover` element in the accessibility tree.
76
- * The exact unmount timing is private and may change.
77
- * - The `id` (supplied or generated via `usePopoverId()`) is stable across opens.
78
- * - The `ref` is populated only while the host element is rendered. Consumers
79
- * that read from the ref outside of `onOpenChange` / `onEnterFinish` should
80
- * gate the read on `isOpen` being `true`.
81
- *
82
- * **Important:** For `mode="auto"` popovers, the browser can dismiss the popover
83
- * via light dismiss (Escape, click outside) independently of this prop. When that
84
- * happens, `onClose` is called and the consumer should respond by setting `isOpen`
85
- * to `false`. If `isOpen` remains `true` after a browser dismiss, the DOM and
86
- * React state will be out of sync (the popover will be hidden despite `isOpen={true}`).
87
- */
88
- isOpen: boolean;
89
- /**
90
- * Called when the popover's open state changes via browser toggle events.
91
- *
92
- * Receives the new open state and a reference to the popover element,
93
- * which is useful for focus management (e.g. focusing the first interactive
94
- * child on open via `getFirstFocusable` from `@atlaskit/top-layer/focus`).
95
- *
96
- * @example
97
- * ```tsx
98
- * <Popover
99
- * onOpenChange={({ isOpen, element }) => {
100
- * if (isOpen) {
101
- * getFirstFocusable({ container: element })?.focus();
102
- * }
103
- * }}
104
- * />
105
- * ```
106
- */
107
- onOpenChange?: (args: {
108
- isOpen: boolean;
109
- element: HTMLDivElement;
110
- }) => void;
111
- /**
112
- * Placement hint for directional animations (e.g. `slideAndFade`).
113
- *
114
- * When `animate` is provided, the preset's `getProperties(placement)` is
115
- * called to set CSS custom properties (like `--ds-popover-tx`, `--ds-popover-ty`)
116
- * that control the slide direction. Has no effect without `animate`.
117
- *
118
- * This does NOT control positioning. Use `useAnchorPosition` for that.
119
- */
120
- placement?: TPlacementOptions;
121
- /**
122
- * Called after the entry animation completes (or immediately on open when
123
- * there is no animation or reduced motion is active).
124
- *
125
- * Use this for external lifecycle coordination - e.g. notifying a manager
126
- * that the show sequence is finished.
127
- */
128
- onEnterFinish?: () => void;
129
- /**
130
- * Called after the exit animation completes (or immediately on close when
131
- * there is no animation or reduced motion is active).
132
- *
133
- * Use this for external lifecycle coordination, e.g. notifying a manager
134
- * that the hide sequence is finished, or firing an `onCloseComplete` callback.
135
- */
136
- onExitFinish?: () => void;
137
- };
138
- /**
139
- * Unopinionated top-layer primitive.
140
- *
141
- * `Popover` manages only top-layer visibility and animation. It has no
142
- * knowledge of positioning. For anchor positioning, compose with the
143
- * `useAnchorPosition` hook separately.
144
- *
145
- * Use `Popover` directly for custom trigger lifecycles (hover, timers,
146
- * external state) or trigger-less UI (flags, toasts). For the common
147
- * button-opens-content pattern, use the `Popup` compound instead.
148
- *
149
- * Dismiss behavior:
150
- * - `'auto'` (default): Escape to close, click-outside to close, focus restoration,
151
- * automatic nesting, mutual exclusivity.
152
- * - `'hint'`: ephemeral UI (e.g. tooltips) that does not close other `auto`
153
- * popovers. Falls back silently to `auto` semantics in browsers without
154
- * `popover='hint'` support, meaning the hint will close any other `auto`
155
- * popovers in those browsers. If cross-browser uniformity matters more
156
- * than the no-close behaviour, pass `auto` explicitly.
157
- * - `'manual'`: no light dismiss. Consumer controls show/hide entirely. Only
158
- * appropriate for persistent UI (e.g. flags, banners).
159
- */
160
- export type TPopoverProps = TPopoverBaseProps & TAriaRoleRequired & ({
161
- mode?: 'auto' | 'hint';
162
- /**
163
- * Called when the popover is dismissed via light dismiss
164
- * (Escape, click outside).
165
- *
166
- * Required for `auto` and `hint` modes - without it, browser
167
- * dismissals leave the consumer's `isOpen` stuck at `true` while
168
- * the DOM is hidden, producing a stale-open state.
169
- *
170
- * The `reason` field indicates how the dismiss occurred:
171
- * - `'escape'`: the user pressed the Escape key.
172
- * - `'light-dismiss'`: the user clicked outside (or another auto-dismiss).
173
- */
174
- onClose: (args: {
175
- reason: TPopoverCloseReason;
176
- }) => void;
177
- } | {
178
- mode: 'manual';
179
- onClose?: never;
180
- });
181
- /**
182
- * The width mode of the popover relative to its anchor element.
183
- *
184
- * - `'none'` (default): popover sizes to its content, ignoring the anchor width.
185
- * - `'match-anchor'`: popover matches the anchor element's width exactly
186
- * via CSS `anchor-size(width)`. Falls back to a one-off measurement
187
- * of `anchorRef.current.offsetWidth` when CSS Anchor Positioning
188
- * is not supported.
189
- * - `'min-anchor'`: popover is at least as wide as the anchor, but
190
- * can grow wider if content requires it. Uses `min-width: anchor-size(width)`.
191
- * Falls back to a one-off measurement of the anchor's width.
192
- */
193
- export type TWidthFromAnchorMode = 'none' | 'match-anchor' | 'min-anchor';
@@ -1,2 +0,0 @@
1
- export { PopoverSurface } from './popover-surface';
2
- export type { TPopoverSurfaceProps } from './popover-surface';
@@ -1,21 +0,0 @@
1
- /**
2
- * @jsxRuntime classic
3
- * @jsx jsx
4
- */
5
- import React, { type ReactNode } from 'react';
6
- export type TPopoverSurfaceProps = {
7
- children: ReactNode;
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 declare function PopoverSurface({ children }: TPopoverSurfaceProps): React.ReactElement;
@@ -1,25 +0,0 @@
1
- /**
2
- * Popover API & HTMLDialogElement polyfills for jsdom.
3
- *
4
- * jsdom does not implement the Popover API or the HTMLDialogElement methods
5
- * (showModal, show, close). This polyfill provides faithful implementations,
6
- * including timing semantics validated against Chromium via Playwright.
7
- *
8
- * Behaviour:
9
- * - beforetoggle: sync, cancelable on popover show only. toggle: async task, never cancelable.
10
- * - Rapid show/hide coalesces into one toggle event (originalOldState to finalNewState).
11
- * - Dialog: showModal/show fire beforetoggle+toggle. close fires toggle then close event.
12
- * - Popover open state tracked via `data-popover-open` (no `:popover-open` in jsdom).
13
- * - Auto popovers: maintain an open stack, perform light-dismiss on document mousedown
14
- * outside the open chain, and dismiss the topmost on Escape.
15
- * - On open, removes any inline `opacity: 0` from the popover element so callers that
16
- * rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-position`) become
17
- * visible in jsdom, where layout-driven RO callbacks never fire.
18
- *
19
- * Companion `toBeVisible` patch lives at `./to-be-visible`.
20
- *
21
- * Importing this module has the side-effect of patching the relevant
22
- * prototypes. It is safe to import multiple times; each branch is guarded
23
- * to avoid overwriting native implementations or re-patching.
24
- */
25
- export {};
@@ -1,23 +0,0 @@
1
- /**
2
- * Patches `toBeVisible()` to understand popover and dialog visibility.
3
- *
4
- * jest-dom's `toBeVisible()` does not know about the Popover API. In real
5
- * browsers the UA stylesheet hides `[popover]` with `display: none`, but
6
- * jsdom has no such stylesheet - so closed popovers incorrectly appear visible.
7
- *
8
- * Raw jest-dom results in jsdom:
9
- *
10
- * closed popover / child → true (WRONG - should be false)
11
- * open popover / child → true (correct)
12
- * closed dialog / child → false (correct - jsdom natively hides <dialog>)
13
- * open dialog / child → true (correct)
14
- *
15
- * We correct both false positives and false negatives:
16
- * 1. Delegate to the original first.
17
- * 2. If it says "visible" → check for closed top-layer hosts (false positive).
18
- * 3. If it says "not visible" → check for open top-layer hosts (false negative).
19
- *
20
- * Must load via `setupFilesAfterEnv` (after jest-dom registers its matchers).
21
- * Polyfills live in `./polyfill` (loaded via `setupFiles`).
22
- */
23
- export {};
@@ -1,3 +0,0 @@
1
- export { useArrowNavigation } from './use-arrow-navigation';
2
- export type { TUseArrowNavigationArgs } from './use-arrow-navigation';
3
- export { isAtCurrentMenuLevel } from './is-at-current-menu-level';
@@ -1,48 +0,0 @@
1
- /**
2
- * Returns true if the element belongs to the current menu level of the
3
- * container, i.e. it is NOT inside a nested `role="menu"` sub-container.
4
- *
5
- * Uses `element.closest('[role="menu"]')` to determine the nearest menu
6
- * scope. If the nearest scope is the container's own `role="menu"` element,
7
- * the element belongs to this level. If it is a different (nested) menu,
8
- * the element belongs to a child level and should be excluded.
9
- *
10
- * Supports two container patterns:
11
- *
12
- * **1. Container has `role="menu"` directly** (preferred, used by avatar-group):
13
- * ```
14
- * <div ref={containerRef} role="menu">
15
- * <button role="menuitem" /> ← isAtCurrentMenuLevel → true
16
- * <div role="menu"> ← nested sub-menu
17
- * <button role="menuitem" /> ← isAtCurrentMenuLevel → false
18
- * </div>
19
- * </div>
20
- * ```
21
- * Uses the simple check: `element.closest('[role="menu"]') === container`
22
- *
23
- * **2. Container is a wrapper without `role="menu"`** (used by dropdown-menu,
24
- * where `MenuGroup` owns `role="menu"` but does not accept a ref):
25
- * ```
26
- * <div ref={containerRef}> ← wrapper (no role="menu")
27
- * <MenuGroup role="menu">
28
- * <button role="menuitem" /> ← isAtCurrentMenuLevel → true
29
- * <div role="menu"> ← nested sub-menu
30
- * <button role="menuitem" /> ← isAtCurrentMenuLevel → false
31
- * </div>
32
- * </MenuGroup>
33
- * </div>
34
- * ```
35
- * Falls back to walking the DOM to check that the element's closest
36
- * `role="menu"` is the container's own menu (not doubly nested).
37
- *
38
- * Ideally all consumers should use pattern 1 (place the ref directly on the
39
- * `role="menu"` element). Pattern 2 exists because `@atlaskit/menu`'s
40
- * `MenuGroup` does not currently accept a ref. If `MenuGroup` gains ref
41
- * support in the future, dropdown-menu should switch to pattern 1 and the
42
- * fallback path can be removed.
43
- *
44
- * Used both as a `TFocusableFilter` (to scope getNextFocusable etc.) and as
45
- * a guard to prevent parent menu handlers from acting on events that
46
- * belong to a nested menu.
47
- */
48
- export declare function isAtCurrentMenuLevel(element: Element, container: HTMLElement): boolean;
@@ -1,102 +0,0 @@
1
- import { type RefObject } from 'react';
2
- import { type TFocusableFilter } from '../focus/types';
3
- /**
4
- * Args for `useArrowNavigation`.
5
- *
6
- * Keyboard contract:
7
- * - `ArrowDown` / `ArrowUp` move within the current menu level.
8
- * - `Home` / `End` jump to first / last.
9
- * - `ArrowRight` / `ArrowLeft` opens / closes nested submenus.
10
- * - `Tab` / `Shift+Tab` dismiss the menu (matching the ARIA APG menu pattern,
11
- * plus Radix UI / Headless UI / React Aria / Floating UI conventions).
12
- * Symmetric in both directions: there is no special-case for the last
13
- * item that lets Tab leave the menu without dismissing it.
14
- * - `Page Up` / `Page Down`: NOT handled - extend via your own listener if
15
- * your menu needs page-style scrolling.
16
- */
17
- export type TUseArrowNavigationArgs = {
18
- /**
19
- * Ref to the container element that holds the focusable items.
20
- */
21
- containerRef: RefObject<HTMLElement | null>;
22
- /**
23
- * Called when ArrowRight is pressed on a focused element with `aria-haspopup`.
24
- *
25
- * This follows the WAI-ARIA menu pattern: ArrowRight on a menu item that
26
- * controls a submenu should open that submenu. The consumer decides *how*
27
- * to open it (e.g. `trigger.click()`, imperative state update, etc.).
28
- *
29
- * Only fires when `filter` (if provided) confirms the focused element
30
- * belongs to the current menu level.
31
- */
32
- onNestedOpen?: ({ trigger }: {
33
- trigger: HTMLElement;
34
- }) => void;
35
- /**
36
- * Called when ArrowLeft is pressed and the current menu is nested
37
- * (i.e. the container is inside another `role="menu"`).
38
- *
39
- * This follows the WAI-ARIA menu pattern: ArrowLeft in a submenu
40
- * should close it and return to the parent menu. The consumer
41
- * decides *how* to close (e.g. calling their close handler).
42
- */
43
- onNestedClose?: () => void;
44
- /**
45
- * Called when the user presses Tab to exit the menu.
46
- */
47
- onClose: () => void;
48
- /**
49
- * When false, the keydown listener is not attached.
50
- * Defaults to true.
51
- */
52
- isEnabled?: boolean;
53
- /**
54
- * Optional filter to restrict which focusable elements are navigated.
55
- * When provided, only elements that pass the filter will be focused.
56
- *
57
- * The filter is also used as a guard on the currently focused element:
58
- * if the focused element does not pass the filter, the handler bails out.
59
- * This prevents parent menu handlers from acting on events that belong
60
- * to a nested menu.
61
- *
62
- * A common filter is `isAtCurrentMenuLevel` which excludes items inside
63
- * nested `role="menu"` sub-containers.
64
- */
65
- filter?: TFocusableFilter;
66
- };
67
- /**
68
- * Provides arrow key navigation for menu containers.
69
- *
70
- * Uses the focusable helpers from `@atlaskit/top-layer/focus` to manage
71
- * DOM-based focus movement within a container.
72
- *
73
- * - **ArrowDown / ArrowUp**: Move focus to the next/previous item (wraps).
74
- * - **Home / End**: Move focus to the first/last item.
75
- * - **Tab**: Calls `onClose` to exit the menu.
76
- *
77
- * When a `filter` is provided, it is used both for scoping focusable
78
- * elements and as a guard to prevent parent menu handlers from acting
79
- * on events that belong to a nested menu.
80
- *
81
- * @example Basic usage
82
- * ```tsx
83
- * useArrowNavigation({
84
- * containerRef: menuRef,
85
- * onClose: () => setIsOpen(false),
86
- * isEnabled: isOpen,
87
- * });
88
- * ```
89
- *
90
- * @example With nested menu filter
91
- * ```tsx
92
- * import { useArrowNavigation, isAtCurrentMenuLevel } from '@atlaskit/top-layer/use-arrow-navigation';
93
- *
94
- * useArrowNavigation({
95
- * containerRef: menuRef,
96
- * onClose: () => setIsOpen(false),
97
- * isEnabled: isOpen,
98
- * filter: isAtCurrentMenuLevel,
99
- * });
100
- * ```
101
- */
102
- export declare function useArrowNavigation({ containerRef, onClose, onNestedOpen, onNestedClose, isEnabled, filter, }: TUseArrowNavigationArgs): void;
@@ -1,45 +0,0 @@
1
- import { type RefObject } from 'react';
2
- import { type TPopoverCloseReason } from '../popover/types';
3
- type TUseSimpleLightDismissOptions = {
4
- /**
5
- * Ref to the popover element. Clicks inside this element will not trigger dismiss.
6
- */
7
- popoverRef: RefObject<HTMLElement | null>;
8
- /**
9
- * Whether the popover is currently open.
10
- * Listeners are only bound when `isOpen` is `true`.
11
- */
12
- isOpen: boolean;
13
- /**
14
- * Called when a light-dismiss event occurs.
15
- *
16
- * - `reason: 'escape'` - the user pressed the Escape key.
17
- * - `reason: 'light-dismiss'` - the user clicked outside the popover.
18
- *
19
- * **Note:** This hook provides simple, standalone light dismiss that does not
20
- * participate in the browser's `popover="auto"` dismiss stack. Every active
21
- * instance will fire independently - if multiple popovers use this hook,
22
- * they will all receive dismiss events.
23
- */
24
- onClose: (args: {
25
- reason: TPopoverCloseReason;
26
- }) => void;
27
- };
28
- /**
29
- * Simple light-dismiss hook for `popover="manual"` elements.
30
- *
31
- * Provides Escape-to-close and click-outside-to-close behavior without
32
- * relying on the browser's `popover="auto"` light-dismiss stack.
33
- *
34
- * **No stacking awareness:** This hook does not track a popover stack.
35
- * If multiple manual popovers are open and all use this hook, a single
36
- * Escape press or outside click will dismiss **all of them simultaneously**.
37
- * This is by design - the hook is intentionally simple for cases where
38
- * only one manual popover is open at a time.
39
- *
40
- * For stacked/nested popovers that should dismiss one-at-a-time, use
41
- * `popover="auto"` mode instead, which provides native stack-aware
42
- * light dismiss via the browser's top-layer stack.
43
- */
44
- export declare function useSimpleLightDismiss({ popoverRef, isOpen, onClose, }: TUseSimpleLightDismissOptions): void;
45
- export type { TUseSimpleLightDismissOptions };