@atlaskit/top-layer 4.4.5 → 5.0.1

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 (137) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +13 -4
  3. package/dist/cjs/dialog/dialog-content.js +2 -0
  4. package/dist/cjs/entry-points/use-popover-id.js +5 -10
  5. package/dist/cjs/internal/anchor-positioning/apply-anchor-positioning.js +86 -0
  6. package/dist/cjs/internal/anchor-positioning/cross-axis-shift-margins.js +34 -0
  7. package/dist/cjs/internal/anchor-positioning/edge-margin.js +21 -0
  8. package/dist/cjs/internal/anchor-positioning/fit-margins.js +77 -0
  9. package/dist/cjs/internal/anchor-positioning/get-existing-anchor-name.js +18 -0
  10. package/dist/cjs/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +11 -11
  11. package/dist/cjs/internal/anchor-positioning/placement-to-try-fallbacks.js +95 -0
  12. package/dist/cjs/internal/anchored-popover-size.js +345 -0
  13. package/dist/cjs/internal/get-aria-for-trigger.js +7 -13
  14. package/dist/cjs/internal/is-native-element-open.js +19 -0
  15. package/dist/cjs/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
  16. package/dist/cjs/internal/javascript-fallback/apply-javascript-fallback-positioning.js +297 -0
  17. package/dist/cjs/internal/javascript-fallback/resolve-css-length-to-pixels.js +90 -0
  18. package/dist/cjs/internal/javascript-fallback/warn-fallback-failure.js +19 -0
  19. package/dist/cjs/internal/resolve-placement.js +14 -6
  20. package/dist/cjs/internal/supports-anchor-positioning.js +17 -0
  21. package/dist/cjs/internal/supports-anchor-size.js +17 -0
  22. package/dist/cjs/internal/supports-css-declaration.js +25 -0
  23. package/dist/cjs/internal/surface-reset.js +5 -0
  24. package/dist/cjs/internal/use-anchored-popover-at-point.js +124 -0
  25. package/dist/cjs/internal/use-anchored-popover.js +277 -0
  26. package/dist/cjs/internal/use-animated-visibility.js +11 -23
  27. package/dist/cjs/popover/popover.compiled.css +4 -0
  28. package/dist/cjs/popover/popover.js +63 -61
  29. package/dist/cjs/testing/polyfill.js +6 -7
  30. package/dist/es2019/dialog/dialog-content.js +2 -0
  31. package/dist/es2019/entry-points/use-popover-id.js +6 -10
  32. package/dist/es2019/internal/anchor-positioning/apply-anchor-positioning.js +83 -0
  33. package/dist/es2019/internal/anchor-positioning/cross-axis-shift-margins.js +29 -0
  34. package/dist/es2019/internal/anchor-positioning/edge-margin.js +18 -0
  35. package/dist/es2019/internal/anchor-positioning/fit-margins.js +69 -0
  36. package/dist/es2019/internal/anchor-positioning/get-existing-anchor-name.js +12 -0
  37. package/dist/es2019/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +9 -9
  38. package/dist/es2019/internal/anchor-positioning/placement-to-try-fallbacks.js +94 -0
  39. package/dist/es2019/internal/anchored-popover-size.js +343 -0
  40. package/dist/es2019/internal/get-aria-for-trigger.js +7 -13
  41. package/dist/es2019/internal/is-native-element-open.js +14 -0
  42. package/dist/es2019/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
  43. package/dist/es2019/internal/javascript-fallback/apply-javascript-fallback-positioning.js +291 -0
  44. package/dist/es2019/internal/javascript-fallback/resolve-css-length-to-pixels.js +87 -0
  45. package/dist/es2019/internal/javascript-fallback/warn-fallback-failure.js +14 -0
  46. package/dist/es2019/internal/resolve-placement.js +14 -6
  47. package/dist/es2019/internal/supports-anchor-positioning.js +12 -0
  48. package/dist/es2019/internal/supports-anchor-size.js +12 -0
  49. package/dist/es2019/internal/supports-css-declaration.js +20 -0
  50. package/dist/es2019/internal/surface-reset.js +1 -0
  51. package/dist/es2019/internal/use-anchored-popover-at-point.js +116 -0
  52. package/dist/es2019/internal/use-anchored-popover.js +265 -0
  53. package/dist/es2019/internal/use-animated-visibility.js +1 -14
  54. package/dist/es2019/popover/popover.compiled.css +4 -0
  55. package/dist/es2019/popover/popover.js +69 -61
  56. package/dist/es2019/testing/polyfill.js +6 -7
  57. package/dist/esm/dialog/dialog-content.js +2 -0
  58. package/dist/esm/entry-points/use-popover-id.js +6 -10
  59. package/dist/esm/internal/anchor-positioning/apply-anchor-positioning.js +80 -0
  60. package/dist/esm/internal/anchor-positioning/cross-axis-shift-margins.js +28 -0
  61. package/dist/esm/internal/anchor-positioning/edge-margin.js +15 -0
  62. package/dist/esm/internal/anchor-positioning/fit-margins.js +71 -0
  63. package/dist/esm/internal/anchor-positioning/get-existing-anchor-name.js +12 -0
  64. package/dist/esm/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +11 -12
  65. package/dist/esm/internal/anchor-positioning/placement-to-try-fallbacks.js +89 -0
  66. package/dist/esm/internal/anchored-popover-size.js +338 -0
  67. package/dist/esm/internal/get-aria-for-trigger.js +7 -13
  68. package/dist/esm/internal/is-native-element-open.js +13 -0
  69. package/dist/esm/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
  70. package/dist/esm/internal/javascript-fallback/apply-javascript-fallback-positioning.js +290 -0
  71. package/dist/esm/internal/javascript-fallback/resolve-css-length-to-pixels.js +85 -0
  72. package/dist/esm/internal/javascript-fallback/warn-fallback-failure.js +13 -0
  73. package/dist/esm/internal/resolve-placement.js +14 -6
  74. package/dist/esm/internal/supports-anchor-positioning.js +12 -0
  75. package/dist/esm/internal/supports-anchor-size.js +12 -0
  76. package/dist/esm/internal/supports-css-declaration.js +19 -0
  77. package/dist/esm/internal/surface-reset.js +1 -0
  78. package/dist/esm/internal/use-anchored-popover-at-point.js +118 -0
  79. package/dist/esm/internal/use-anchored-popover.js +271 -0
  80. package/dist/esm/internal/use-animated-visibility.js +10 -22
  81. package/dist/esm/popover/popover.compiled.css +4 -0
  82. package/dist/esm/popover/popover.js +63 -61
  83. package/dist/esm/testing/polyfill.js +6 -7
  84. package/dist/types/entry-points/placement-map.d.ts +2 -2
  85. package/dist/types/entry-points/use-popover-id.d.ts +3 -7
  86. package/dist/types/internal/anchor-positioning/apply-anchor-positioning.d.ts +26 -0
  87. package/dist/types/internal/anchor-positioning/cross-axis-shift-margins.d.ts +19 -0
  88. package/dist/types/internal/anchor-positioning/edge-margin.d.ts +10 -0
  89. package/dist/types/internal/anchor-positioning/fit-margins.d.ts +30 -0
  90. package/dist/types/internal/anchor-positioning/get-existing-anchor-name.d.ts +8 -0
  91. package/dist/types/internal/{placement-to-position-area.d.ts → anchor-positioning/placement-to-position-area.d.ts} +10 -6
  92. package/dist/types/internal/anchor-positioning/placement-to-try-fallbacks.d.ts +30 -0
  93. package/dist/types/internal/anchored-popover-size.d.ts +126 -0
  94. package/dist/types/internal/get-aria-for-trigger.d.ts +13 -25
  95. package/dist/types/internal/is-native-element-open.d.ts +3 -0
  96. package/dist/types/internal/javascript-fallback/anchor-positioning-fallback.d.ts +36 -0
  97. package/dist/types/internal/javascript-fallback/apply-javascript-fallback-positioning.d.ts +15 -0
  98. package/dist/types/internal/javascript-fallback/resolve-css-length-to-pixels.d.ts +20 -0
  99. package/dist/types/internal/javascript-fallback/warn-fallback-failure.d.ts +7 -0
  100. package/dist/types/internal/resolve-placement.d.ts +18 -2
  101. package/dist/types/internal/supports-anchor-positioning.d.ts +5 -0
  102. package/dist/types/internal/supports-anchor-size.d.ts +5 -0
  103. package/dist/types/internal/supports-css-declaration.d.ts +11 -0
  104. package/dist/types/internal/surface-reset.d.ts +25 -0
  105. package/dist/types/internal/use-anchored-popover-at-point.d.ts +48 -0
  106. package/dist/types/internal/use-anchored-popover.d.ts +143 -0
  107. package/dist/types/popover/index.d.ts +2 -1
  108. package/dist/types/popover/popover.d.ts +1 -1
  109. package/dist/types/popover/types.d.ts +15 -17
  110. package/dist/types/testing/polyfill.d.ts +3 -3
  111. package/package.json +2 -2
  112. package/use-anchored-popover/package.json +10 -0
  113. package/use-anchored-popover-at-point/package.json +10 -0
  114. package/dist/cjs/internal/placement-to-try-fallbacks.js +0 -108
  115. package/dist/cjs/internal/resolve-css-length-to-pixels.js +0 -104
  116. package/dist/cjs/internal/use-anchor-position-at-point.js +0 -129
  117. package/dist/cjs/internal/use-anchor-position.js +0 -501
  118. package/dist/cjs/internal/use-width-from-anchor.js +0 -124
  119. package/dist/es2019/internal/placement-to-try-fallbacks.js +0 -108
  120. package/dist/es2019/internal/resolve-css-length-to-pixels.js +0 -101
  121. package/dist/es2019/internal/use-anchor-position-at-point.js +0 -124
  122. package/dist/es2019/internal/use-anchor-position.js +0 -480
  123. package/dist/es2019/internal/use-width-from-anchor.js +0 -120
  124. package/dist/esm/internal/placement-to-try-fallbacks.js +0 -103
  125. package/dist/esm/internal/resolve-css-length-to-pixels.js +0 -98
  126. package/dist/esm/internal/use-anchor-position-at-point.js +0 -124
  127. package/dist/esm/internal/use-anchor-position.js +0 -494
  128. package/dist/esm/internal/use-width-from-anchor.js +0 -118
  129. package/dist/types/internal/anchor-positioning-fallback.d.ts +0 -51
  130. package/dist/types/internal/placement-to-try-fallbacks.d.ts +0 -13
  131. package/dist/types/internal/resolve-css-length-to-pixels.d.ts +0 -20
  132. package/dist/types/internal/use-anchor-position-at-point.d.ts +0 -67
  133. package/dist/types/internal/use-anchor-position.d.ts +0 -87
  134. package/dist/types/internal/use-width-from-anchor.d.ts +0 -19
  135. package/use-anchor-position/package.json +0 -10
  136. package/use-anchor-position-at-point/package.json +0 -10
  137. package/use-width-from-anchor/package.json +0 -10
@@ -1,501 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports.useAnchorPosition = useAnchorPosition;
8
- var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
- var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
10
- var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
11
- var _react = require("react");
12
- var _bindEventListener = require("bind-event-listener");
13
- var _rafSchd = _interopRequireDefault(require("raf-schd"));
14
- var _once = _interopRequireDefault(require("@atlaskit/ds-lib/once"));
15
- var _anchorPositioningFallback = require("./anchor-positioning-fallback");
16
- var _combine = require("./combine");
17
- var _placementToPositionArea = require("./placement-to-position-area");
18
- var _placementToTryFallbacks = require("./placement-to-try-fallbacks");
19
- var _resolveCssLengthToPixels = require("./resolve-css-length-to-pixels");
20
- var _resolvePlacement = require("./resolve-placement");
21
- var _setStyle = require("./set-style");
22
- /**
23
- * Anchor positioning for top-layer popovers. See
24
- * `notes/architecture/positioning.md` for the full model.
25
- *
26
- * Two runtime paths: CSS Anchor Positioning (modern browsers) and a JS
27
- * fallback that measures the trigger and writes `top`/`left`.
28
- *
29
- * Both paths honour `offset.gap` and `offset.crossAxisShift`. The
30
- * CSS path passes the values through as strings; the JS fallback resolves
31
- * them to pixels via a hidden DOM probe (see `resolveCssLengthToPixels`)
32
- * so tokens, `calc()`, `var()`, etc all work. The JS fallback hides the
33
- * popover with `opacity: 0` until the first measurement completes, so it
34
- * is never painted at the wrong location.
35
- */
36
-
37
- // `resolvePlacement` is intentionally NOT re-exported here - import it directly
38
- // from `./resolve-placement` so search-and-jump lands at the source of truth.
39
-
40
- /**
41
- * Module-scope no-op `ResizeObserver` used in non-DOM jest environments where
42
- * `ResizeObserver` is `undefined`. Hoisted out of the effect to avoid
43
- * allocating a new class declaration on every run.
44
- */
45
- var NoopResizeObserver = /*#__PURE__*/function () {
46
- function NoopResizeObserver() {
47
- (0, _classCallCheck2.default)(this, NoopResizeObserver);
48
- }
49
- return (0, _createClass2.default)(NoopResizeObserver, [{
50
- key: "observe",
51
- value: function observe() {}
52
- }, {
53
- key: "unobserve",
54
- value: function unobserve() {}
55
- }, {
56
- key: "disconnect",
57
- value: function disconnect() {}
58
- }]);
59
- }();
60
-
61
- /**
62
- * Returns true when the popover is currently open. Wrapped because the
63
- * `:popover-open` pseudo-class is not implemented in some test environments
64
- * (e.g. jsdom), where `matches` throws on unknown selectors.
65
- */
66
- function isPopoverOpen(popover) {
67
- try {
68
- return popover.matches(':popover-open');
69
- } catch (_unused) {
70
- return false;
71
- }
72
- }
73
-
74
- /**
75
- * Detects whether the browser supports CSS Anchor Positioning.
76
- * Uses `once()` for lazy evaluation: safe for SSR and avoids hydration mismatches.
77
- */
78
- var supportsAnchorPositioning = (0, _once.default)(function () {
79
- if (typeof window === 'undefined' || typeof CSS === 'undefined' || typeof CSS.supports !== 'function') {
80
- return false;
81
- }
82
- return CSS.supports('anchor-name', '--a');
83
- });
84
-
85
- /**
86
- * Every logical margin property this module can write: one per axis, per side.
87
- *
88
- * Deriving the union from `TPlacementAxis` and `TPlacementEdge` rather than
89
- * writing the four names out keeps it in step with the placement model, and
90
- * makes `CROSS_AXIS_SHIFT_CUSTOM_PROPERTY` below exhaustive by construction.
91
- */
92
-
93
- /**
94
- * The custom property mirroring each cross-axis shift margin.
95
- *
96
- * These are written for the planned named arrow `@position-try` rules. Nothing
97
- * reads them yet, and the shift no longer depends on them: the antisymmetric
98
- * margins written by `crossAxisShiftMargins` survive a cross-axis slide on
99
- * their own.
100
- *
101
- * Keyed on `TLogicalMarginProperty` and not on `string`, so a margin property
102
- * that has no custom property (or a custom property whose margin no longer
103
- * exists) is a compile error rather than an `undefined` lookup that reaches
104
- * `setStyle` as `{ property: undefined, value }`.
105
- */
106
- var CROSS_AXIS_SHIFT_CUSTOM_PROPERTY = {
107
- 'margin-inline-start': '--ds-cross-axis-shift-margin-start',
108
- 'margin-inline-end': '--ds-cross-axis-shift-margin-end',
109
- 'margin-block-start': '--ds-cross-axis-shift-margin-block-start',
110
- 'margin-block-end': '--ds-cross-axis-shift-margin-block-end'
111
- };
112
- var ZEROED_CROSS_AXIS_SHIFT_CUSTOM_PROPERTIES = Object.values(CROSS_AXIS_SHIFT_CUSTOM_PROPERTY).map(function (property) {
113
- return {
114
- property: property,
115
- value: '0px'
116
- };
117
- });
118
-
119
- /**
120
- * Returns the CSS margin declaration that creates a gap between the
121
- * popover and its trigger on the side facing the anchor.
122
- *
123
- * For example, a `block-end` placement (popover below) gets
124
- * `margin-block-start: 8px` to push it away from the trigger's bottom edge.
125
- */
126
- function edgeMargin(_ref) {
127
- var placement = _ref.placement,
128
- offset = _ref.offset;
129
- var axis = placement.axis,
130
- edge = placement.edge;
131
- // The gap sits on the side FACING the anchor, which is always the side
132
- // opposite the placement edge.
133
- var anchorFacingEdge = edge === 'end' ? 'start' : 'end';
134
- return {
135
- property: "margin-".concat(axis, "-").concat(anchorFacingEdge),
136
- value: offset
137
- };
138
- }
139
-
140
- /**
141
- * **The cross-axis shift margins.**
142
- *
143
- * The shift is written antisymmetrically on BOTH cross-axis sides
144
- * (`start: +value`, `end: -value`) rather than as a single margin on the side
145
- * picked from `align`. Two separate behaviours require it:
146
- *
147
- * 1. **`align: 'center'` is centered with `anchor-center`, which centers the
148
- * popover's MARGIN box on the anchor.** A single-sided margin widens the
149
- * margin box, so it displaces the border box by only half its value. An
150
- * antisymmetric pair leaves the margin box width unchanged (`+value` and
151
- * `-value` sum to zero) while moving its center by the full value.
152
- * 2. **`position-try-fallbacks` can slide the popover onto the opposite
153
- * cross-axis side.** A `<position-area>` fallback keeps the base style's
154
- * margins, and margin on the un-anchored side has no effect, so a
155
- * single-sided margin is silently dropped once the browser slides across the
156
- * cross axis. With both sides written, whichever side ends up anchored moves
157
- * the popover the same physical direction.
158
- *
159
- * Leaving the margin box width unchanged also means the shift does not move
160
- * the point at which `position-try-fallbacks` decides the popover overflows.
161
- *
162
- * A `<try-tactic>` fallback (`flip-block`, `flip-inline`) behaves differently to
163
- * a `<position-area>` one: it SWAPS the start and end margins rather than
164
- * keeping them, which is what preserves the gap through a flip. So a flip across
165
- * the cross axis mirrors the shift along with the rest of the placement, rather
166
- * than preserving its physical direction. Only the diagonal fallback does that,
167
- * and only for `align: 'start' | 'end'`. See `placementToTryFallbacks`.
168
- *
169
- * A positive value always moves the popover toward the cross-axis END, so
170
- * `direction: 'forwards'` means the same thing for every `align` value. See
171
- * `notes/decisions/placement-offset.md`.
172
- */
173
- function crossAxisShiftMargins(_ref2) {
174
- var placement = _ref2.placement,
175
- crossAxisShiftCssValue = _ref2.crossAxisShiftCssValue,
176
- direction = _ref2.direction;
177
- var crossAxis = placement.axis === 'block' ? 'inline' : 'block';
178
- // Wrap any string in calc() with the sign factor. CSS handles the math,
179
- // so opaque values such as design tokens negate correctly.
180
- var negated = "calc(-1 * ".concat(crossAxisShiftCssValue, ")");
181
- var isForwards = direction === 'forwards';
182
- return [{
183
- property: "margin-".concat(crossAxis, "-start"),
184
- value: isForwards ? crossAxisShiftCssValue : negated
185
- }, {
186
- property: "margin-".concat(crossAxis, "-end"),
187
- value: isForwards ? negated : crossAxisShiftCssValue
188
- }];
189
- }
190
-
191
- /**
192
- * Returns a referentially-stable, fully-resolved `TPlacement`. The memo is
193
- * keyed on the resolved primitive fields so a fresh inline `placement` object
194
- * (or undefined fields vs explicit defaults) does not produce a fresh result.
195
- */
196
- function useStablePlacement(placement) {
197
- var resolved = (0, _resolvePlacement.resolvePlacement)({
198
- placement: placement
199
- });
200
- var axis = resolved.axis;
201
- var edge = resolved.edge;
202
- var align = resolved.align;
203
- var gap = resolved.offset.gap;
204
- var shiftValue = resolved.offset.crossAxisShift.value;
205
- var shiftDirection = resolved.offset.crossAxisShift.direction;
206
- // Rebuild inside the memo from primitive deps so the factory does not
207
- // close over the outer `resolved` reference and exhaustive-deps can verify.
208
- return (0, _react.useMemo)(function () {
209
- return {
210
- axis: axis,
211
- edge: edge,
212
- align: align,
213
- offset: {
214
- gap: gap,
215
- crossAxisShift: {
216
- value: shiftValue,
217
- direction: shiftDirection
218
- }
219
- }
220
- };
221
- }, [axis, edge, align, gap, shiftValue, shiftDirection]);
222
- }
223
-
224
- /**
225
- * Hook that positions an element relative to an anchor element using
226
- * CSS Anchor Positioning (with a JS fallback for older browsers).
227
- *
228
- * This hook is the positioning primitive. It has no knowledge of popovers,
229
- * visibility, or animation. Compose it with `Popover` for anchor-positioned
230
- * top-layer content.
231
- *
232
- * When CSS Anchor Positioning is supported, it sets CSS properties
233
- * (`anchor-name`, `position-anchor`, `position-area`, `position-try-fallbacks`)
234
- * directly on the elements via `el.style.setProperty()`.
235
- *
236
- * When not supported, it falls back to JavaScript-based positioning using
237
- * `position: fixed` with measured coordinates, re-running on scroll (capture)
238
- * and resize events.
239
- */
240
- // eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
241
- function useAnchorPosition(_ref3) {
242
- var anchorRef = _ref3.anchorRef,
243
- popoverRef = _ref3.popoverRef,
244
- _ref3$placement = _ref3.placement,
245
- placement = _ref3$placement === void 0 ? {} : _ref3$placement,
246
- _ref3$forceFallbackPo = _ref3.forceFallbackPositioning,
247
- forceFallbackPositioning = _ref3$forceFallbackPo === void 0 ? false : _ref3$forceFallbackPo,
248
- _ref3$isEnabled = _ref3.isEnabled,
249
- isEnabled = _ref3$isEnabled === void 0 ? true : _ref3$isEnabled,
250
- isOpen = _ref3.isOpen;
251
- var id = (0, _react.useId)();
252
- var stablePlacement = useStablePlacement(placement);
253
- (0, _react.useLayoutEffect)(function () {
254
- if (!isEnabled) {
255
- return;
256
- }
257
- var trigger = anchorRef.current;
258
- var popover = popoverRef.current;
259
- if (!trigger || !popover) {
260
- return;
261
- }
262
- var gapCssValue = stablePlacement.offset.gap;
263
- var crossAxisShiftCssValue = stablePlacement.offset.crossAxisShift.value;
264
- var shouldForceFallback = Boolean(forceFallbackPositioning);
265
- if (supportsAnchorPositioning() && !shouldForceFallback) {
266
- // Reuse an existing `anchor-name` if the element already has one.
267
- // Another popover might already be anchored to the old name.
268
- var anchorName = trigger.style.getPropertyValue('anchor-name') || "--anchor-".concat(id.replace(/:/g, ''));
269
- var gap = edgeMargin({
270
- placement: stablePlacement,
271
- offset: gapCssValue
272
- });
273
- // Computed once; also mirrored into the
274
- // `--ds-cross-axis-shift-margin-*` custom properties below.
275
- var crossAxisShift = crossAxisShiftMargins({
276
- placement: stablePlacement,
277
- crossAxisShiftCssValue: crossAxisShiftCssValue,
278
- direction: stablePlacement.offset.crossAxisShift.direction
279
- });
280
- var popoverStyles = [{
281
- property: 'position-anchor',
282
- value: anchorName
283
- }, {
284
- property: 'position-area',
285
- value: (0, _placementToPositionArea.placementToPositionArea)({
286
- placement: stablePlacement
287
- })
288
- }, {
289
- property: 'position-try-fallbacks',
290
- value: (0, _placementToTryFallbacks.placementToTryFallbacks)({
291
- placement: stablePlacement
292
- })
293
- },
294
- // Reset browser default popover positioning that conflicts
295
- // with anchor positioning (UA: `inset: 0; margin: auto;`)
296
- {
297
- property: 'margin',
298
- value: '0'
299
- }, {
300
- property: 'inset',
301
- value: 'auto'
302
- }, gap].concat((0, _toConsumableArray2.default)(crossAxisShift), (0, _toConsumableArray2.default)(ZEROED_CROSS_AXIS_SHIFT_CUSTOM_PROPERTIES), (0, _toConsumableArray2.default)(crossAxisShift.map(function (_ref4) {
303
- var property = _ref4.property,
304
- value = _ref4.value;
305
- return {
306
- property: CROSS_AXIS_SHIFT_CUSTOM_PROPERTY[property],
307
- value: value
308
- };
309
- })));
310
-
311
- /**
312
- * **We are never cleaning up anchor names**
313
- *
314
- * _Rationale_
315
- *
316
- * - Multiple popovers can share the same anchor element.
317
- * - Sometimes the `useAnchorPosition` hook and `Popover`
318
- * are not in the same component.
319
- * - There can be times when, even with reference counting, we
320
- * could remove the anchor-name while it is still being used
321
- * by something else - especially with async react updates
322
- * which can cause tearing
323
- *
324
- * _More_
325
- *
326
- * See `notes/decisions/anchor-name-lifetime.md`
327
- */
328
- trigger.style.setProperty('anchor-name', anchorName);
329
- return (0, _setStyle.setStyle)({
330
- element: popover,
331
- styles: popoverStyles
332
- });
333
- }
334
-
335
- // JS fallback. The popover is already in the top layer via
336
- // popover="auto", so we only reset UA defaults and set top/left
337
- // based on measurements.
338
- var cleanupBaseStyles = (0, _setStyle.setStyle)({
339
- element: popover,
340
- styles: [{
341
- property: 'margin',
342
- value: '0'
343
- }, {
344
- property: 'inset',
345
- value: 'auto'
346
- }]
347
- });
348
-
349
- // The popover can be consumer-owned (`@atlaskit/popper`'s `createPopper`),
350
- // so restore prior inline values rather than removing ours.
351
- var undoPosition;
352
- var undoHide;
353
-
354
- // `opacity: 0` not `visibility: hidden`: Firefox skips visibility-hidden
355
- // elements during `<dialog>` initial-focus traversal.
356
- function hideUntilPositioned() {
357
- // Keep the first snapshot, else we capture our own `opacity: 0`.
358
- // (`!popover` is for TS: narrowing does not reach nested functions.)
359
- if (!popover || undoHide) {
360
- return;
361
- }
362
- undoHide = (0, _setStyle.setStyle)({
363
- element: popover,
364
- styles: [{
365
- property: 'opacity',
366
- value: '0'
367
- }]
368
- });
369
- }
370
- function reveal() {
371
- var _undoHide;
372
- (_undoHide = undoHide) === null || _undoHide === void 0 || _undoHide();
373
- undoHide = undefined;
374
- }
375
- function restorePosition() {
376
- var _undoPosition;
377
- (_undoPosition = undoPosition) === null || _undoPosition === void 0 || _undoPosition();
378
- undoPosition = undefined;
379
- }
380
- function update() {
381
- if (!trigger || !popover) {
382
- return;
383
- }
384
- var triggerRect = trigger.getBoundingClientRect();
385
- var viewport = {
386
- width: window.innerWidth,
387
- height: window.innerHeight
388
- };
389
-
390
- // Resolve consumer-supplied CSS length strings (tokens, calc, var,
391
- // px, rem, etc) to pixels. The probe is mounted INSIDE the popover
392
- // itself so the resolved length matches the scope a token would
393
- // resolve against from inside the popover content. (The popover
394
- // lives in the top layer, not the trigger's DOM tree, so probing
395
- // at `popover.parentElement` would resolve in a different scope
396
- // than the consumer's token authoring expects.)
397
- var gapPx = (0, _resolveCssLengthToPixels.resolveCssLengthToPixels)({
398
- value: gapCssValue,
399
- container: popover
400
- });
401
- var crossAxisShiftPx = (0, _resolveCssLengthToPixels.resolveCssLengthToPixels)({
402
- value: crossAxisShiftCssValue,
403
- container: popover
404
- });
405
- var _computeFallbackPosit = (0, _anchorPositioningFallback.computeFallbackPosition)({
406
- triggerRect: triggerRect,
407
- popoverEl: popover,
408
- placement: stablePlacement,
409
- viewport: viewport,
410
- gap: gapPx,
411
- crossAxisShift: {
412
- value: crossAxisShiftPx,
413
- direction: stablePlacement.offset.crossAxisShift.direction
414
- }
415
- }),
416
- top = _computeFallbackPosit.top,
417
- left = _computeFallbackPosit.left;
418
-
419
- // Restore first so the snapshot stays the consumer's value.
420
- restorePosition();
421
- undoPosition = (0, _setStyle.setStyle)({
422
- element: popover,
423
- styles: [{
424
- property: 'top',
425
- value: "".concat(top, "px")
426
- }, {
427
- property: 'left',
428
- value: "".concat(left, "px")
429
- }]
430
- });
431
- reveal();
432
- }
433
-
434
- // Throttle scroll/resize updates to one per animation frame
435
- var scheduledUpdate = (0, _rafSchd.default)(update);
436
-
437
- // Wait for the FIRST valid layout before measuring: the popover
438
- // is `display: none` until `showPopover()`, and some browsers
439
- // fire `toggle` before layout, so RAF-after-toggle is unreliable.
440
- // ResizeObserver fires once the browser has real dimensions.
441
- // Self-disconnects after one valid measurement; ongoing
442
- // scroll/resize is handled by the window listeners below.
443
- // `ResizeObserver` is missing in some non-DOM jest environments
444
- // (e.g. post-office's `node` environment). Fall back to a no-op
445
- // observer there. The scroll/resize listeners below still keep
446
- // the popover positioned in the rare case the consumer also
447
- // polyfilled `showPopover` but not `ResizeObserver`. Real
448
- // browsers always have it. The `NoopResizeObserver` class is
449
- // hoisted to module scope (see top of file) so we do not allocate
450
- // a new constructor on every effect run.
451
- var ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
452
- var resizeObserver = new ResizeObserverImpl(function () {
453
- if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
454
- update();
455
- resizeObserver.disconnect();
456
- }
457
- });
458
-
459
- // If the popover is already open by the time this effect runs (for
460
- // example, the parent `useAnchorPosition` effect runs after the child
461
- // `Popover` effect that called `showPopover()`), the initial `toggle`
462
- // event has already fired and our listener below would miss it. Start
463
- // observing immediately so the first measurement still happens.
464
- if (isPopoverOpen(popover)) {
465
- hideUntilPositioned();
466
- resizeObserver.observe(popover);
467
- }
468
- var undoPositioning = (0, _combine.combine)(cleanupBaseStyles,
469
- // Each open needs a fresh measurement, so hide and re-observe.
470
- (0, _bindEventListener.bind)(popover, {
471
- type: 'toggle',
472
- listener: function listener(event) {
473
- var toggleEvent = event;
474
- if (toggleEvent.newState === 'open') {
475
- hideUntilPositioned();
476
- resizeObserver.observe(popover);
477
- }
478
- }
479
- }), function () {
480
- return resizeObserver.disconnect();
481
- }, (0, _bindEventListener.bind)(window, {
482
- type: 'scroll',
483
- listener: scheduledUpdate,
484
- options: {
485
- capture: true,
486
- passive: true
487
- }
488
- }), (0, _bindEventListener.bind)(window, {
489
- type: 'resize',
490
- listener: scheduledUpdate,
491
- options: {
492
- passive: true
493
- }
494
- }), function () {
495
- scheduledUpdate.cancel();
496
- restorePosition();
497
- reveal();
498
- });
499
- return undoPositioning;
500
- }, [anchorRef, popoverRef, stablePlacement, forceFallbackPositioning, isEnabled, id, isOpen]);
501
- }
@@ -1,124 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports.useWidthFromAnchor = useWidthFromAnchor;
8
- var _react = require("react");
9
- var _once = _interopRequireDefault(require("@atlaskit/ds-lib/once"));
10
- var _setStyle = require("./set-style");
11
- /**
12
- * Probes anchor SIZING, separately from `anchor-name` (see
13
- * `supportsAnchorPositioning`): some browsers have positioning but not sizing.
14
- * `once()` for SSR safety.
15
- */
16
- var supportsAnchorSize = (0, _once.default)(function () {
17
- if (typeof window === 'undefined' || typeof CSS === 'undefined' || typeof CSS.supports !== 'function') {
18
- return false;
19
- }
20
- return CSS.supports('min-inline-size', 'anchor-size(self-inline)');
21
- });
22
-
23
- /**
24
- * The JS fallback's stand-in for `anchor-size(self-inline)`. `offsetWidth` / `offsetHeight` are
25
- * physical, so the axis is picked from the popover's `writing-mode`. Anything not horizontal is
26
- * treated as vertical, and an unknown or empty value falls back to `offsetWidth`.
27
- */
28
- function getFallbackAnchorInlineSize(_ref) {
29
- var anchor = _ref.anchor,
30
- popover = _ref.popover;
31
- // `String()` because not every test environment implements `writing-mode`.
32
- var writingMode = String(getComputedStyle(popover).writingMode);
33
- var isVertical = writingMode.startsWith('vertical') || writingMode.startsWith('sideways');
34
- return isVertical ? anchor.offsetHeight : anchor.offsetWidth;
35
- }
36
-
37
- /**
38
- * Sets the width of a popover element relative to its anchor element.
39
- *
40
- * - `'match-anchor'` → `inline-size: anchor-size(self-inline)`, exact
41
- * - `'min-anchor'` → `min-inline-size: anchor-size(self-inline)`, floor only
42
- * - `'none'` → `min-inline-size: max-content`, content floor (default)
43
- *
44
- * `self-inline` is the inline axis of the element USING the function (the popover), never the
45
- * anchor, so it matches the axis `inline-size` constrains. See
46
- * `notes/decisions/width-from-anchor-floors.md`.
47
- */
48
- function useWidthFromAnchor(_ref2) {
49
- var mode = _ref2.mode,
50
- popoverRef = _ref2.popoverRef,
51
- anchorRef = _ref2.anchorRef,
52
- isOpen = _ref2.isOpen;
53
- (0, _react.useLayoutEffect)(function () {
54
- var node = popoverRef.current;
55
- if (!node) {
56
- return;
57
- }
58
- if (mode === 'match-anchor') {
59
- // No floor here: it would let the popover grow past the anchor.
60
- if (supportsAnchorSize()) {
61
- return (0, _setStyle.setStyle)({
62
- element: node,
63
- styles: [{
64
- property: 'inline-size',
65
- value: 'anchor-size(self-inline)'
66
- }]
67
- });
68
- }
69
- var anchor = anchorRef.current;
70
- if (anchor) {
71
- return (0, _setStyle.setStyle)({
72
- element: node,
73
- styles: [{
74
- property: 'inline-size',
75
- value: "".concat(getFallbackAnchorInlineSize({
76
- anchor: anchor,
77
- popover: node
78
- }), "px")
79
- }]
80
- });
81
- }
82
- return;
83
- }
84
- if (mode === 'min-anchor') {
85
- // One floor only. The content floor from mode 'none' deliberately does not also apply
86
- // here, and cannot: it would need this same property. See the decision note.
87
- if (supportsAnchorSize()) {
88
- return (0, _setStyle.setStyle)({
89
- element: node,
90
- styles: [{
91
- property: 'min-inline-size',
92
- value: 'anchor-size(self-inline)'
93
- }]
94
- });
95
- }
96
- var _anchor = anchorRef.current;
97
- if (_anchor) {
98
- return (0, _setStyle.setStyle)({
99
- element: node,
100
- styles: [{
101
- property: 'min-inline-size',
102
- value: "".concat(getFallbackAnchorInlineSize({
103
- anchor: _anchor,
104
- popover: node
105
- }), "px")
106
- }]
107
- });
108
- }
109
-
110
- // Nothing to measure, so no floor.
111
- return;
112
- }
113
-
114
- // Makes a too-narrow span overflow and drive `position-try-fallbacks` instead of wrapping.
115
- // `@atlaskit/popper` resets this exact property to `0` for its fit-to-viewport mode.
116
- return (0, _setStyle.setStyle)({
117
- element: node,
118
- styles: [{
119
- property: 'min-inline-size',
120
- value: 'max-content'
121
- }]
122
- });
123
- }, [mode, popoverRef, anchorRef, isOpen]);
124
- }