@atlaskit/top-layer 0.6.2 → 0.7.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 (66) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/README.md +4 -2
  3. package/dist/cjs/arrow/index.js +2 -2
  4. package/dist/cjs/dialog/dialog-content.js +6 -1
  5. package/dist/cjs/entry-points/use-width-from-anchor.js +12 -0
  6. package/dist/cjs/focus/focus.js +4 -4
  7. package/dist/cjs/internal/combine.js +2 -2
  8. package/dist/cjs/internal/use-anchor-position.js +25 -7
  9. package/dist/cjs/internal/use-animated-visibility.js +3 -3
  10. package/dist/cjs/internal/use-focus-wrap.js +7 -7
  11. package/dist/cjs/internal/use-initial-focus.js +1 -1
  12. package/dist/cjs/internal/use-width-from-anchor.js +107 -0
  13. package/dist/cjs/popover/popover.js +12 -10
  14. package/dist/cjs/popup/popup-content.js +10 -37
  15. package/dist/cjs/popup/popup-trigger.js +2 -2
  16. package/dist/cjs/use-simple-light-dismiss/index.js +1 -1
  17. package/dist/es2019/arrow/index.js +2 -2
  18. package/dist/es2019/dialog/dialog-content.js +6 -1
  19. package/dist/es2019/entry-points/use-width-from-anchor.js +1 -0
  20. package/dist/es2019/focus/focus.js +1 -1
  21. package/dist/es2019/internal/combine.js +1 -1
  22. package/dist/es2019/internal/use-anchor-position.js +13 -7
  23. package/dist/es2019/internal/use-animated-visibility.js +3 -3
  24. package/dist/es2019/internal/use-focus-wrap.js +7 -7
  25. package/dist/es2019/internal/use-initial-focus.js +1 -1
  26. package/dist/es2019/internal/use-width-from-anchor.js +103 -0
  27. package/dist/es2019/popover/popover.js +12 -10
  28. package/dist/es2019/popup/popup-content.js +9 -36
  29. package/dist/es2019/popup/popup-trigger.js +2 -2
  30. package/dist/es2019/use-simple-light-dismiss/index.js +1 -1
  31. package/dist/esm/arrow/index.js +2 -2
  32. package/dist/esm/dialog/dialog-content.js +6 -1
  33. package/dist/esm/entry-points/use-width-from-anchor.js +1 -0
  34. package/dist/esm/focus/focus.js +4 -4
  35. package/dist/esm/internal/combine.js +2 -2
  36. package/dist/esm/internal/use-anchor-position.js +25 -7
  37. package/dist/esm/internal/use-animated-visibility.js +3 -3
  38. package/dist/esm/internal/use-focus-wrap.js +7 -7
  39. package/dist/esm/internal/use-initial-focus.js +1 -1
  40. package/dist/esm/internal/use-width-from-anchor.js +102 -0
  41. package/dist/esm/popover/popover.js +12 -10
  42. package/dist/esm/popup/popup-content.js +10 -37
  43. package/dist/esm/popup/popup-trigger.js +2 -2
  44. package/dist/esm/use-simple-light-dismiss/index.js +1 -1
  45. package/dist/types/entry-points/use-width-from-anchor.d.ts +1 -0
  46. package/dist/types/internal/use-anchor-position.d.ts +1 -1
  47. package/dist/types/internal/use-focus-wrap.d.ts +1 -1
  48. package/dist/types/internal/use-width-from-anchor.d.ts +20 -0
  49. package/dist/types/popover/popover.d.ts +3 -1
  50. package/dist/types/popover/types.d.ts +13 -0
  51. package/dist/types/popup/popup-content.d.ts +1 -1
  52. package/dist/types/popup/popup-trigger.d.ts +1 -1
  53. package/dist/types/popup/types.d.ts +8 -8
  54. package/dist/types/use-simple-light-dismiss/index.d.ts +3 -3
  55. package/dist/types-ts4.5/entry-points/use-width-from-anchor.d.ts +1 -0
  56. package/dist/types-ts4.5/internal/use-anchor-position.d.ts +1 -1
  57. package/dist/types-ts4.5/internal/use-focus-wrap.d.ts +1 -1
  58. package/dist/types-ts4.5/internal/use-width-from-anchor.d.ts +20 -0
  59. package/dist/types-ts4.5/popover/popover.d.ts +3 -1
  60. package/dist/types-ts4.5/popover/types.d.ts +13 -0
  61. package/dist/types-ts4.5/popup/popup-content.d.ts +1 -1
  62. package/dist/types-ts4.5/popup/popup-trigger.d.ts +1 -1
  63. package/dist/types-ts4.5/popup/types.d.ts +8 -8
  64. package/dist/types-ts4.5/use-simple-light-dismiss/index.d.ts +3 -3
  65. package/package.json +2 -2
  66. package/use-width-from-anchor/package.json +17 -0
@@ -0,0 +1 @@
1
+ export { useWidthFromAnchor } from '../internal/use-width-from-anchor';
@@ -39,7 +39,7 @@ function getFocusables({
39
39
  container,
40
40
  filter
41
41
  }) {
42
- return Array.from(container.querySelectorAll(selectors.focusable)).filter(el => el instanceof HTMLElement).filter(el => !filter || filter(el, container));
42
+ return Array.from(container.querySelectorAll(selectors.focusable)).filter(element => element instanceof HTMLElement).filter(element => !filter || filter(element, container));
43
43
  }
44
44
 
45
45
  /**
@@ -13,6 +13,6 @@
13
13
  */
14
14
  export function combine(...cleanupFns) {
15
15
  return function cleanup() {
16
- cleanupFns.forEach(fn => fn === null || fn === void 0 ? void 0 : fn());
16
+ cleanupFns.forEach(callback => callback === null || callback === void 0 ? void 0 : callback());
17
17
  };
18
18
  }
@@ -323,12 +323,6 @@ export function useAnchorPosition({
323
323
  property: 'inset',
324
324
  value: 'auto'
325
325
  },
326
- // Ensures the popup's margin box overflows the viewport when its span region is too
327
- // narrow, triggering position-try-fallbacks correctly rather than wrapping content.
328
- {
329
- property: 'min-inline-size',
330
- value: 'max-content'
331
- },
332
326
  // Main-axis gap between the popover and its trigger
333
327
  {
334
328
  property: gap.property,
@@ -488,7 +482,19 @@ export function useAnchorPosition({
488
482
  // ResizeObserver fires once the browser has real dimensions.
489
483
  // Self-disconnects after one valid measurement; ongoing
490
484
  // scroll/resize is handled by the window listeners below.
491
- const resizeObserver = new ResizeObserver(() => {
485
+ // `ResizeObserver` is missing in some non-DOM jest environments
486
+ // (e.g. post-office's `node` environment). Fall back to a no-op
487
+ // observer there — the scroll/resize listeners below still keep
488
+ // the popover positioned in the rare case the consumer also
489
+ // polyfilled `showPopover` but not `ResizeObserver`. Real
490
+ // browsers always have it.
491
+ const NoopResizeObserver = class {
492
+ observe() {}
493
+ unobserve() {}
494
+ disconnect() {}
495
+ };
496
+ const ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
497
+ const resizeObserver = new ResizeObserverImpl(() => {
492
498
  if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
493
499
  update();
494
500
  resizeObserver.disconnect();
@@ -104,8 +104,8 @@ export function useAnimatedVisibility({
104
104
  if (isOpen || !showChildren || !willAnimate) {
105
105
  return;
106
106
  }
107
- const el = elementRef.current;
108
- if (!el) {
107
+ const element = elementRef.current;
108
+ if (!element) {
109
109
  return;
110
110
  }
111
111
  function finish() {
@@ -119,7 +119,7 @@ export function useAnimatedVisibility({
119
119
  const fallbackId = setTimeout(finish, ((_preset$exitDurationM = preset === null || preset === void 0 ? void 0 : preset.exitDurationMs) !== null && _preset$exitDurationM !== void 0 ? _preset$exitDurationM : 0) + 50);
120
120
 
121
121
  // Primary: listen for the CSS transition to complete
122
- const unbind = bind(el, {
122
+ const unbind = bind(element, {
123
123
  type: 'transitionend',
124
124
  listener: finish,
125
125
  options: {
@@ -34,7 +34,7 @@ function roleRequiresFocusWrap(role) {
34
34
  * elements within the container using wrapping navigation.
35
35
  *
36
36
  * Light dismiss (Escape, click outside) continues to work natively
37
- * via `popover="auto"` — this hook only intercepts Tab.
37
+ * via `popover="auto"` - this hook only intercepts Tab.
38
38
  *
39
39
  * Always call this hook unconditionally. The listener is only
40
40
  * attached when the role requires focus wrapping, and is cleaned
@@ -45,11 +45,11 @@ export function useFocusWrap({
45
45
  role
46
46
  }) {
47
47
  useEffect(() => {
48
- const el = elementRef.current;
49
- if (!el || !roleRequiresFocusWrap(role)) {
48
+ const element = elementRef.current;
49
+ if (!element || !roleRequiresFocusWrap(role)) {
50
50
  return;
51
51
  }
52
- const unbind = bind(el, {
52
+ const unbind = bind(element, {
53
53
  type: 'keydown',
54
54
  listener: event => {
55
55
  if (event.key !== 'Tab') {
@@ -61,7 +61,7 @@ export function useFocusWrap({
61
61
  // Try to move to the next/previous focusable element relative
62
62
  // to the currently focused element within the container.
63
63
  const next = getNextFocusable({
64
- container: el,
64
+ container: element,
65
65
  direction
66
66
  });
67
67
  if (next) {
@@ -73,9 +73,9 @@ export function useFocusWrap({
73
73
  // focused element isn't in the focusable list). Fall back to
74
74
  // the first or last focusable element depending on direction.
75
75
  const fallback = direction === 'forwards' ? getFirstFocusable({
76
- container: el
76
+ container: element
77
77
  }) : getLastFocusable({
78
- container: el
78
+ container: element
79
79
  });
80
80
  if (fallback) {
81
81
  fallback.focus();
@@ -13,7 +13,7 @@ import { getFirstFocusable } from '../focus/focus';
13
13
  * - no role / other roles: no focus movement
14
14
  *
15
15
  * Note: React 18's `autoFocus` JSX prop does NOT set the HTML `autofocus`
16
- * attribute — it only calls `.focus()` imperatively during commit, which
16
+ * attribute - it only calls `.focus()` imperatively during commit, which
17
17
  * has no effect on hidden popover content. Consumers must set the native
18
18
  * attribute via a ref callback (e.g. `node.setAttribute('autofocus', '')`).
19
19
  * React 19+ reflects the JSX prop as the HTML attribute automatically.
@@ -0,0 +1,103 @@
1
+ import { useLayoutEffect } from 'react';
2
+ import { setStyle } from './set-style';
3
+
4
+ /**
5
+ * Sets the width of a popover element relative to its anchor element.
6
+ *
7
+ * - `'match-anchor'` → `width: anchor-size(width)` — popover matches anchor width exactly.
8
+ * - `'min-anchor'` → `min-width: anchor-size(width)` — popover is at least as wide as anchor,
9
+ * but can grow wider.
10
+ * - `'none'` → no explicit width is set (default behaviour)
11
+ *
12
+ * Uses CSS `anchor-size(width)` when the browser supports it, falling back to a
13
+ * one-off measurement of `anchor.offsetWidth`.
14
+ *
15
+ * Designed to be composed alongside `useAnchorPosition` for top-layer popovers.
16
+ */
17
+ export function useWidthFromAnchor({
18
+ mode,
19
+ popoverRef,
20
+ anchorRef
21
+ }) {
22
+ useLayoutEffect(() => {
23
+ const node = popoverRef.current;
24
+ if (!node) {
25
+ return;
26
+ }
27
+
28
+ // Feature-detect `anchor-size()` specifically (not just `anchor-name`)
29
+ // so the JS fallback fires correctly in browsers that support anchor
30
+ // positioning but not anchor sizing.
31
+ const supportsAnchorSize = typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('width', 'anchor-size(width)');
32
+ if (mode === 'match-anchor') {
33
+ // Set an exact width matching the anchor.
34
+ // `min-inline-size` is intentionally NOT set here — it would override the
35
+ // explicit width constraint, allowing the popover to grow past the anchor's width.
36
+ if (supportsAnchorSize) {
37
+ return setStyle({
38
+ el: node,
39
+ styles: [{
40
+ property: 'width',
41
+ value: 'anchor-size(width)'
42
+ }]
43
+ });
44
+ }
45
+
46
+ // JS fallback: one-off read of the anchor's width.
47
+ const anchor = anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.current;
48
+ if (anchor) {
49
+ return setStyle({
50
+ el: node,
51
+ styles: [{
52
+ property: 'width',
53
+ value: `${anchor.offsetWidth}px`
54
+ }]
55
+ });
56
+ }
57
+ return;
58
+ }
59
+
60
+ // For 'min-anchor' and 'none', apply `min-inline-size: max-content` to ensure
61
+ // correct position-try-fallbacks behaviour (popover margin box overflows the
62
+ // viewport when its span region is too narrow, rather than wrapping content).
63
+ const minInlineSizeStyle = {
64
+ property: 'min-inline-size',
65
+ value: 'max-content'
66
+ };
67
+ if (mode === 'min-anchor') {
68
+ // Set a minimum width matching the anchor. The popover can grow wider
69
+ // if its content requires it.
70
+ if (supportsAnchorSize) {
71
+ return setStyle({
72
+ el: node,
73
+ styles: [minInlineSizeStyle, {
74
+ property: 'min-width',
75
+ value: 'anchor-size(width)'
76
+ }]
77
+ });
78
+ }
79
+ const anchor = anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.current;
80
+ if (anchor) {
81
+ return setStyle({
82
+ el: node,
83
+ styles: [minInlineSizeStyle, {
84
+ property: 'min-width',
85
+ value: `${anchor.offsetWidth}px`
86
+ }]
87
+ });
88
+ }
89
+
90
+ // No anchor available in JS fallback — still apply min-inline-size.
91
+ return setStyle({
92
+ el: node,
93
+ styles: [minInlineSizeStyle]
94
+ });
95
+ }
96
+
97
+ // 'none' mode: no explicit width, but still apply `min-inline-size: max-content`.
98
+ return setStyle({
99
+ el: node,
100
+ styles: [minInlineSizeStyle]
101
+ });
102
+ }, [mode, popoverRef, anchorRef]);
103
+ }
@@ -33,7 +33,9 @@ const styles = {
33
33
  * Unopinionated top-layer primitive.
34
34
  *
35
35
  * Manages only visibility (isOpen) and animation (animate). Has no knowledge
36
- * of positioning — compose with `useAnchorPosition` for anchor positioning.
36
+ * of positioning — compose with `useAnchorPosition` for anchor positioning
37
+ * and optionally `useWidthFromAnchor` for setting the width of a popover element
38
+ * relative to its anchor trigger.
37
39
  *
38
40
  * Visibility is driven by the `isOpen` prop:
39
41
  * - `isOpen={true}` → `showPopover()`, entry animation via `@starting-style`
@@ -116,21 +118,21 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
116
118
  // the browser processes light dismiss), read in the toggle handler.
117
119
  const closeReasonRef = useRef('light-dismiss');
118
120
  const handleToggle = useCallback(event => {
119
- const el = ownRef.current;
121
+ const element = ownRef.current;
120
122
  if (event.newState === 'open') {
121
- if (el) {
123
+ if (element) {
122
124
  onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
123
125
  isOpen: true,
124
- element: el
126
+ element: element
125
127
  });
126
128
  }
127
129
  return;
128
130
  }
129
131
  if (event.newState === 'closed') {
130
- if (el) {
132
+ if (element) {
131
133
  onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
132
134
  isOpen: false,
133
- element: el
135
+ element: element
134
136
  });
135
137
  }
136
138
 
@@ -148,13 +150,13 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
148
150
  }
149
151
  }, [onClose, onOpenChange]);
150
152
  useEffect(() => {
151
- const el = ownRef.current;
152
- if (!el) {
153
+ const element = ownRef.current;
154
+ if (!element) {
153
155
  return;
154
156
  }
155
157
 
156
158
  // Capture-phase: tag Escape before the browser processes light dismiss.
157
- const unbindEscape = bind(el, {
159
+ const unbindEscape = bind(element, {
158
160
  type: 'keydown',
159
161
  listener: event => {
160
162
  if (event.key === 'Escape') {
@@ -165,7 +167,7 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
165
167
  capture: true
166
168
  }
167
169
  });
168
- const unbindToggle = bind(el, {
170
+ const unbindToggle = bind(element, {
169
171
  type: 'toggle',
170
172
  listener: handleToggle
171
173
  });
@@ -6,12 +6,13 @@ import mergeRefs from '@atlaskit/ds-lib/merge-refs';
6
6
  import { roleToAriaHasPopup } from '../internal/role-types';
7
7
  import { useAnchorPosition } from '../internal/use-anchor-position';
8
8
  import { usePresetStyles } from '../internal/use-preset-styles';
9
+ import { useWidthFromAnchor } from '../internal/use-width-from-anchor';
9
10
  import { Popover } from '../popover/popover';
10
11
  import { useMaybePopupContext } from './popup-context';
11
12
  /**
12
13
  * Thin context wrapper that composes `Popover` + `useAnchorPosition`.
13
14
  *
14
- * Used inside the `<Popup>` compound — reads triggerRef, placement, isOpen,
15
+ * Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
15
16
  * and onClose from context. For standalone usage (tooltip, spotlight, flag),
16
17
  * use `Popover` + `useAnchorPosition` directly.
17
18
  */
@@ -23,7 +24,7 @@ export const PopupContent = /*#__PURE__*/forwardRef(function PopupContent({
23
24
  animate,
24
25
  arrow,
25
26
  mode,
26
- width = 'content',
27
+ widthFromAnchor = 'none',
27
28
  xcss,
28
29
  isOpen: isOpenProp,
29
30
  triggerRef: triggerRefProp,
@@ -88,7 +89,7 @@ export const PopupContent = /*#__PURE__*/forwardRef(function PopupContent({
88
89
  // ── Nested popover focus restoration fallback ──
89
90
  // The browser only captures `previouslyFocusedElement` for the
90
91
  // outermost popover="auto" in the stack. Inner (nested) popovers
91
- // have shouldRestoreFocus=false, so the browser won't restore
92
+ // have shouldRestoreFocus=false, so the browser will not restore
92
93
  // focus when they close.
93
94
  //
94
95
  // We detect this case by checking if focus is still inside the
@@ -131,39 +132,11 @@ export const PopupContent = /*#__PURE__*/forwardRef(function PopupContent({
131
132
  forceFallbackPositioning,
132
133
  arrow: arrowPreset !== null && arrowPreset !== void 0 ? arrowPreset : undefined
133
134
  });
134
-
135
- // ── Width: match trigger ──
136
- // When width="trigger" or width="min-trigger", size the popover relative
137
- // to the trigger element. Uses CSS `anchor-size(width)` when supported,
138
- // falling back to a one-off measurement of the trigger's offsetWidth.
139
- useLayoutEffect(() => {
140
- if (width === 'content') {
141
- return;
142
- }
143
- const node = popoverRef.current;
144
- if (!node) {
145
- return;
146
- }
147
- const cssProperty = width === 'trigger' ? 'width' : 'min-width';
148
- const anchorValue = 'anchor-size(width)';
149
-
150
- // Feature-detect `anchor-size()` specifically (not just `anchor-name`)
151
- // so the JS fallback fires correctly in browsers that support anchor
152
- // positioning but not anchor sizing.
153
- const supportsAnchorSize = typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('width', 'anchor-size(width)');
154
- if (supportsAnchorSize) {
155
- node.style.setProperty(cssProperty, anchorValue);
156
- } else {
157
- // JS fallback: one-off read of the trigger's width.
158
- const trigger = triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current;
159
- if (trigger) {
160
- node.style.setProperty(cssProperty, `${trigger.offsetWidth}px`);
161
- }
162
- }
163
- return () => {
164
- node.style.removeProperty(cssProperty);
165
- };
166
- }, [width, popoverRef, triggerRef]);
135
+ useWidthFromAnchor({
136
+ mode: widthFromAnchor,
137
+ popoverRef,
138
+ anchorRef: triggerRef
139
+ });
167
140
 
168
141
  // Merge: the popoverRef (shared with trigger + positioning) and the forwarded ref.
169
142
  const combinedRef = mergeRefs([popoverRef, ref]);
@@ -18,7 +18,7 @@ import { usePopupContext } from './popup-context';
18
18
  * from opening.
19
19
  *
20
20
  * If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
21
- * instead — it hands you raw props via a render-prop and avoids
21
+ * instead - it hands you raw props via a render-prop and avoids
22
22
  * `cloneElement` entirely.
23
23
  */
24
24
  export function PopupTrigger({
@@ -34,7 +34,7 @@ export function PopupTrigger({
34
34
  const childOnClick = /*#__PURE__*/isValidElement(children) ? children.props.onClick : undefined;
35
35
 
36
36
  // Use a ref to track the latest isOpen value so the click handler
37
- // doesn't need isOpen in its dependency array (which would recreate
37
+ // does not need isOpen in its dependency array (which would recreate
38
38
  // the handler on every open/close, breaking cloneElement identity).
39
39
  const isOpenRef = React.useRef(isOpen);
40
40
  isOpenRef.current = isOpen;
@@ -21,7 +21,7 @@ export function useSimpleLightDismiss({
21
21
  isOpen,
22
22
  onClose
23
23
  }) {
24
- // Keep a stable ref to onClose so the effect doesn't re-bind on every render.
24
+ // Keep a stable ref to onClose so the effect does not re-bind on every render.
25
25
  const onCloseRef = useRef(onClose);
26
26
  onCloseRef.current = onClose;
27
27
  useEffect(() => {
@@ -14,7 +14,7 @@ import { getPlacement, placementToPositionArea } from '../internal/use-anchor-po
14
14
  *
15
15
  * Constraints:
16
16
  * - `box-shadow` must be `none` (interferes with `clip-path: inset() margin-box`)
17
- * - `::before` and `::after` are consumed — consumers cannot use them
17
+ * - `::before` and `::after` are consumed - consumers cannot use them
18
18
  * - Arrow pseudo-elements use `background: inherit` from the popover element
19
19
  *
20
20
  * @see https://goulet.dev/posts/tooltip-with-popover-and-anchor-positioning/
@@ -39,7 +39,7 @@ function positionAreaToRuleName(_ref) {
39
39
  * that change both `position-area` and `margin` when flipping.
40
40
  *
41
41
  * This is required for the arrow technique because built-in keywords
42
- * (`flip-block`, `flip-inline`) only flip `position-area` — they do
42
+ * (`flip-block`, `flip-inline`) only flip `position-area` - they do
43
43
  * not update the margin direction needed to reveal the correct arrow.
44
44
  */
45
45
  function getTryFallbacks(_ref2) {
@@ -119,7 +119,12 @@ export var Dialog = /*#__PURE__*/forwardRef(function Dialog(_ref, ref) {
119
119
  var escapedId = CSS.escape(dialogId);
120
120
  return /*#__PURE__*/React.createElement("dialog", _extends({
121
121
  ref: combinedRef,
122
- id: dialogId,
122
+ id: dialogId
123
+ // Modern browsers infer modal semantics from `.showModal()` but
124
+ // some assistive tech still keys off `aria-modal="true"`. Setting
125
+ // it explicitly is recommended by WAI-ARIA APG dialog pattern.
126
+ ,
127
+ "aria-modal": "true",
123
128
  "aria-label": label,
124
129
  "aria-labelledby": label ? undefined : labelledBy,
125
130
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
@@ -0,0 +1 @@
1
+ export { useWidthFromAnchor } from '../internal/use-width-from-anchor';
@@ -38,10 +38,10 @@ var selectors = function () {
38
38
  function getFocusables(_ref) {
39
39
  var container = _ref.container,
40
40
  filter = _ref.filter;
41
- return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (el) {
42
- return el instanceof HTMLElement;
43
- }).filter(function (el) {
44
- return !filter || filter(el, container);
41
+ return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (element) {
42
+ return element instanceof HTMLElement;
43
+ }).filter(function (element) {
44
+ return !filter || filter(element, container);
45
45
  });
46
46
  }
47
47
 
@@ -16,8 +16,8 @@ export function combine() {
16
16
  cleanupFns[_key] = arguments[_key];
17
17
  }
18
18
  return function cleanup() {
19
- cleanupFns.forEach(function (fn) {
20
- return fn === null || fn === void 0 ? void 0 : fn();
19
+ cleanupFns.forEach(function (callback) {
20
+ return callback === null || callback === void 0 ? void 0 : callback();
21
21
  });
22
22
  };
23
23
  }
@@ -1,3 +1,5 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
+ import _createClass from "@babel/runtime/helpers/createClass";
1
3
  /**
2
4
  * Anchor positioning for top-layer popovers. See
3
5
  * `notes/architecture/positioning.md` for the full model.
@@ -314,12 +316,6 @@ export function useAnchorPosition(_ref5) {
314
316
  property: 'inset',
315
317
  value: 'auto'
316
318
  },
317
- // Ensures the popup's margin box overflows the viewport when its span region is too
318
- // narrow, triggering position-try-fallbacks correctly rather than wrapping content.
319
- {
320
- property: 'min-inline-size',
321
- value: 'max-content'
322
- },
323
319
  // Main-axis gap between the popover and its trigger
324
320
  {
325
321
  property: gap.property,
@@ -480,7 +476,29 @@ export function useAnchorPosition(_ref5) {
480
476
  // ResizeObserver fires once the browser has real dimensions.
481
477
  // Self-disconnects after one valid measurement; ongoing
482
478
  // scroll/resize is handled by the window listeners below.
483
- var resizeObserver = new ResizeObserver(function () {
479
+ // `ResizeObserver` is missing in some non-DOM jest environments
480
+ // (e.g. post-office's `node` environment). Fall back to a no-op
481
+ // observer there — the scroll/resize listeners below still keep
482
+ // the popover positioned in the rare case the consumer also
483
+ // polyfilled `showPopover` but not `ResizeObserver`. Real
484
+ // browsers always have it.
485
+ var NoopResizeObserver = /*#__PURE__*/function () {
486
+ function NoopResizeObserver() {
487
+ _classCallCheck(this, NoopResizeObserver);
488
+ }
489
+ return _createClass(NoopResizeObserver, [{
490
+ key: "observe",
491
+ value: function observe() {}
492
+ }, {
493
+ key: "unobserve",
494
+ value: function unobserve() {}
495
+ }, {
496
+ key: "disconnect",
497
+ value: function disconnect() {}
498
+ }]);
499
+ }();
500
+ var ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
501
+ var resizeObserver = new ResizeObserverImpl(function () {
484
502
  if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
485
503
  update();
486
504
  resizeObserver.disconnect();
@@ -107,8 +107,8 @@ export function useAnimatedVisibility(_ref) {
107
107
  if (isOpen || !showChildren || !willAnimate) {
108
108
  return;
109
109
  }
110
- var el = elementRef.current;
111
- if (!el) {
110
+ var element = elementRef.current;
111
+ if (!element) {
112
112
  return;
113
113
  }
114
114
  function finish() {
@@ -122,7 +122,7 @@ export function useAnimatedVisibility(_ref) {
122
122
  var fallbackId = setTimeout(finish, ((_preset$exitDurationM = preset === null || preset === void 0 ? void 0 : preset.exitDurationMs) !== null && _preset$exitDurationM !== void 0 ? _preset$exitDurationM : 0) + 50);
123
123
 
124
124
  // Primary: listen for the CSS transition to complete
125
- var unbind = bind(el, {
125
+ var unbind = bind(element, {
126
126
  type: 'transitionend',
127
127
  listener: finish,
128
128
  options: {
@@ -34,7 +34,7 @@ function roleRequiresFocusWrap(role) {
34
34
  * elements within the container using wrapping navigation.
35
35
  *
36
36
  * Light dismiss (Escape, click outside) continues to work natively
37
- * via `popover="auto"` — this hook only intercepts Tab.
37
+ * via `popover="auto"` - this hook only intercepts Tab.
38
38
  *
39
39
  * Always call this hook unconditionally. The listener is only
40
40
  * attached when the role requires focus wrapping, and is cleaned
@@ -44,11 +44,11 @@ export function useFocusWrap(_ref) {
44
44
  var elementRef = _ref.elementRef,
45
45
  role = _ref.role;
46
46
  useEffect(function () {
47
- var el = elementRef.current;
48
- if (!el || !roleRequiresFocusWrap(role)) {
47
+ var element = elementRef.current;
48
+ if (!element || !roleRequiresFocusWrap(role)) {
49
49
  return;
50
50
  }
51
- var unbind = bind(el, {
51
+ var unbind = bind(element, {
52
52
  type: 'keydown',
53
53
  listener: function listener(event) {
54
54
  if (event.key !== 'Tab') {
@@ -60,7 +60,7 @@ export function useFocusWrap(_ref) {
60
60
  // Try to move to the next/previous focusable element relative
61
61
  // to the currently focused element within the container.
62
62
  var next = getNextFocusable({
63
- container: el,
63
+ container: element,
64
64
  direction: direction
65
65
  });
66
66
  if (next) {
@@ -72,9 +72,9 @@ export function useFocusWrap(_ref) {
72
72
  // focused element isn't in the focusable list). Fall back to
73
73
  // the first or last focusable element depending on direction.
74
74
  var fallback = direction === 'forwards' ? getFirstFocusable({
75
- container: el
75
+ container: element
76
76
  }) : getLastFocusable({
77
- container: el
77
+ container: element
78
78
  });
79
79
  if (fallback) {
80
80
  fallback.focus();
@@ -13,7 +13,7 @@ import { getFirstFocusable } from '../focus/focus';
13
13
  * - no role / other roles: no focus movement
14
14
  *
15
15
  * Note: React 18's `autoFocus` JSX prop does NOT set the HTML `autofocus`
16
- * attribute — it only calls `.focus()` imperatively during commit, which
16
+ * attribute - it only calls `.focus()` imperatively during commit, which
17
17
  * has no effect on hidden popover content. Consumers must set the native
18
18
  * attribute via a ref callback (e.g. `node.setAttribute('autofocus', '')`).
19
19
  * React 19+ reflects the JSX prop as the HTML attribute automatically.