@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
@@ -0,0 +1,297 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.applyJavaScriptFallbackPositioning = applyJavaScriptFallbackPositioning;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _bindEventListener = require("bind-event-listener");
10
+ var _rafSchd = _interopRequireDefault(require("raf-schd"));
11
+ var _combine = require("../combine");
12
+ var _setStyle = require("../set-style");
13
+ var _anchorPositioningFallback = require("./anchor-positioning-fallback");
14
+ var _resolveCssLengthToPixels = require("./resolve-css-length-to-pixels");
15
+ var _warnFallbackFailure = require("./warn-fallback-failure");
16
+ /**
17
+ * The JavaScript positioning fallback: measured `position: fixed` coordinates for
18
+ * browsers without CSS Anchor Positioning.
19
+ *
20
+ * Best effort, degrading in that order: measured anchored position, then anchored
21
+ * with unresolvable offsets treated as `0`, then centred in the viewport, and
22
+ * always visible. The two hazards differ in kind: `new ResizeObserver` runs
23
+ * synchronously in the layout effect, where a throw unmounts the React tree,
24
+ * while `update` runs asynchronously, where the danger is an uncleared
25
+ * `opacity: 0`.
26
+ */
27
+
28
+ /**
29
+ * Wrapped because jsdom throws on the unknown `:popover-open` selector.
30
+ */
31
+ function isPopoverOpen(popover) {
32
+ try {
33
+ return popover.matches(':popover-open');
34
+ } catch (_unused) {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Observes the popover until its first non-zero layout, then self-disconnects;
41
+ * ongoing movement is handled by the scroll and resize listeners. The popover is
42
+ * `display: none` until `showPopover()`, and some browsers fire `toggle` before
43
+ * layout, so RAF-after-toggle is unreliable.
44
+ *
45
+ * `null` where `ResizeObserver` is missing (non-DOM jest environments). There is
46
+ * then no measurement to wait for, so the caller positions immediately and must
47
+ * not hide the popover, because no reveal would follow.
48
+ */
49
+ function createFirstLayoutObserver(_ref) {
50
+ var popover = _ref.popover,
51
+ onFirstLayout = _ref.onFirstLayout;
52
+ if (typeof ResizeObserver === 'undefined') {
53
+ return null;
54
+ }
55
+ try {
56
+ var observer = new ResizeObserver(function () {
57
+ if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
58
+ onFirstLayout();
59
+ observer.disconnect();
60
+ }
61
+ });
62
+ return observer;
63
+ } catch (error) {
64
+ (0, _warnFallbackFailure.warnFallbackFailure)({
65
+ error: error
66
+ });
67
+ return null;
68
+ }
69
+ }
70
+
71
+ /**
72
+ * The consumer's offsets in pixels. See `resolvedOffsets` below.
73
+ */
74
+
75
+ /**
76
+ * Positions `popover` against `anchor` from measurements, and keeps it there
77
+ * across opens, scroll and resize. Returns the cleanup.
78
+ *
79
+ * No fit margins on this path: the gap and the cross-axis shift are coordinate
80
+ * deltas here, so writing them as margins too would double-apply them.
81
+ */
82
+ function applyJavaScriptFallbackPositioning(_ref2) {
83
+ var anchor = _ref2.anchor,
84
+ popover = _ref2.popover,
85
+ placement = _ref2.placement,
86
+ sizeStyles = _ref2.sizeStyles;
87
+ // Already in the top layer via the `popover` attribute, so this only resets the
88
+ // UA defaults and writes measured `top` / `left`.
89
+ var cleanupBaseStyles = (0, _setStyle.setStyle)({
90
+ element: popover,
91
+ styles: [{
92
+ property: 'margin',
93
+ value: '0'
94
+ }, {
95
+ property: 'inset',
96
+ value: 'auto'
97
+ }].concat((0, _toConsumableArray2.default)(sizeStyles))
98
+ });
99
+
100
+ // The popover can be consumer-owned (`@atlaskit/popper`'s `createPopper`),
101
+ // so restore prior inline values rather than removing ours.
102
+ var undoPosition;
103
+ var undoHide;
104
+
105
+ // Resolved once per open and per resize, reused across scrolls: resolving is a
106
+ // full style and layout flush, and a scroll cannot change what a CSS length
107
+ // resolves to. A resize can (viewport units), and so can a re-open (a token
108
+ // retargeted while closed).
109
+ var resolvedOffsets = null;
110
+ function invalidateResolvedOffsets() {
111
+ resolvedOffsets = null;
112
+ }
113
+ function getResolvedOffsets() {
114
+ if (resolvedOffsets) {
115
+ return resolvedOffsets;
116
+ }
117
+ // Probed INSIDE the popover: it is in the top layer, not the anchor's DOM
118
+ // tree, so anywhere else resolves a token against a different scope.
119
+ resolvedOffsets = {
120
+ gap: (0, _resolveCssLengthToPixels.resolveCssLengthToPixels)({
121
+ value: placement.offset.gap,
122
+ container: popover
123
+ }),
124
+ crossAxisShift: (0, _resolveCssLengthToPixels.resolveCssLengthToPixels)({
125
+ value: placement.offset.crossAxisShift.value,
126
+ container: popover
127
+ })
128
+ };
129
+ return resolvedOffsets;
130
+ }
131
+ function reveal() {
132
+ var _undoHide;
133
+ (_undoHide = undoHide) === null || _undoHide === void 0 || _undoHide();
134
+ undoHide = undefined;
135
+ }
136
+ function restorePosition() {
137
+ var _undoPosition;
138
+ (_undoPosition = undoPosition) === null || _undoPosition === void 0 || _undoPosition();
139
+ undoPosition = undefined;
140
+ }
141
+
142
+ // `opacity: 0` not `visibility: hidden`: Firefox skips visibility-hidden
143
+ // elements during `<dialog>` initial-focus traversal.
144
+ function hideUntilPositioned() {
145
+ // Keep the first snapshot, else we capture our own `opacity: 0`.
146
+ if (undoHide) {
147
+ return;
148
+ }
149
+ undoHide = (0, _setStyle.setStyle)({
150
+ element: popover,
151
+ styles: [{
152
+ property: 'opacity',
153
+ value: '0'
154
+ }]
155
+ });
156
+ }
157
+
158
+ /**
159
+ * Last resort. The base styles above reset the UA
160
+ * `[popover] { inset: 0; margin: auto }`, so a popover with no `top` / `left`
161
+ * sits in the viewport corner rather than centred.
162
+ */
163
+ function centerInViewport() {
164
+ restorePosition();
165
+ undoPosition = (0, _setStyle.setStyle)({
166
+ element: popover,
167
+ styles: [{
168
+ property: 'inset',
169
+ value: '0'
170
+ }, {
171
+ property: 'margin',
172
+ value: 'auto'
173
+ }]
174
+ });
175
+ }
176
+ function update() {
177
+ try {
178
+ var triggerRect = anchor.getBoundingClientRect();
179
+ var viewport = {
180
+ width: window.innerWidth,
181
+ height: window.innerHeight
182
+ };
183
+ var _getResolvedOffsets = getResolvedOffsets(),
184
+ gap = _getResolvedOffsets.gap,
185
+ crossAxisShift = _getResolvedOffsets.crossAxisShift;
186
+ var _computeFallbackPosit = (0, _anchorPositioningFallback.computeFallbackPosition)({
187
+ triggerRect: triggerRect,
188
+ popoverEl: popover,
189
+ placement: placement,
190
+ viewport: viewport,
191
+ gap: gap,
192
+ crossAxisShift: {
193
+ value: crossAxisShift,
194
+ direction: placement.offset.crossAxisShift.direction
195
+ }
196
+ }),
197
+ top = _computeFallbackPosit.top,
198
+ left = _computeFallbackPosit.left;
199
+
200
+ // A non-finite coordinate serialises to a declaration the browser drops,
201
+ // landing the popover in the corner just as silently as a throw would.
202
+ if (!Number.isFinite(top) || !Number.isFinite(left)) {
203
+ centerInViewport();
204
+ return;
205
+ }
206
+
207
+ // Restore first so the snapshot stays the consumer's value.
208
+ restorePosition();
209
+ undoPosition = (0, _setStyle.setStyle)({
210
+ element: popover,
211
+ styles: [{
212
+ property: 'top',
213
+ value: "".concat(top, "px")
214
+ }, {
215
+ property: 'left',
216
+ value: "".concat(left, "px")
217
+ }]
218
+ });
219
+ } catch (error) {
220
+ (0, _warnFallbackFailure.warnFallbackFailure)({
221
+ error: error
222
+ });
223
+ // Anchoring needs the trigger geometry we just failed to get, so the
224
+ // centred position is the only one left to degrade to.
225
+ try {
226
+ centerInViewport();
227
+ } catch (_unused2) {}
228
+ } finally {
229
+ // Unconditional. A popover in the wrong place is recoverable on the
230
+ // next scroll or resize; one left at `opacity: 0` is invisible forever.
231
+ reveal();
232
+ }
233
+ }
234
+ function invalidateAndUpdate() {
235
+ invalidateResolvedOffsets();
236
+ update();
237
+ }
238
+
239
+ // One update per animation frame. Scroll reuses the resolved offsets; resize
240
+ // re-resolves them.
241
+ var scheduledScrollUpdate = (0, _rafSchd.default)(update);
242
+ var scheduledResizeUpdate = (0, _rafSchd.default)(invalidateAndUpdate);
243
+ var firstLayoutObserver = createFirstLayoutObserver({
244
+ popover: popover,
245
+ onFirstLayout: update
246
+ });
247
+ function positionOnNextLayout() {
248
+ // A token can have been retargeted while the popover was closed, so each
249
+ // open re-resolves the offsets.
250
+ invalidateResolvedOffsets();
251
+ // No observer means no measurement is coming: position now, and do not
252
+ // hide, because the reveal would never arrive.
253
+ if (!firstLayoutObserver) {
254
+ update();
255
+ return;
256
+ }
257
+ hideUntilPositioned();
258
+ firstLayoutObserver.observe(popover);
259
+ }
260
+
261
+ // The popover can already be open when this runs, in which case the initial
262
+ // `toggle` has fired and the listener below would miss it.
263
+ if (isPopoverOpen(popover)) {
264
+ positionOnNextLayout();
265
+ }
266
+ return (0, _combine.combine)(cleanupBaseStyles,
267
+ // Each open needs a fresh measurement, so hide and re-observe.
268
+ (0, _bindEventListener.bind)(popover, {
269
+ type: 'toggle',
270
+ listener: function listener(event) {
271
+ var toggleEvent = event;
272
+ if (toggleEvent.newState === 'open') {
273
+ positionOnNextLayout();
274
+ }
275
+ }
276
+ }), function () {
277
+ return firstLayoutObserver === null || firstLayoutObserver === void 0 ? void 0 : firstLayoutObserver.disconnect();
278
+ }, (0, _bindEventListener.bind)(window, {
279
+ type: 'scroll',
280
+ listener: scheduledScrollUpdate,
281
+ options: {
282
+ capture: true,
283
+ passive: true
284
+ }
285
+ }), (0, _bindEventListener.bind)(window, {
286
+ type: 'resize',
287
+ listener: scheduledResizeUpdate,
288
+ options: {
289
+ passive: true
290
+ }
291
+ }), function () {
292
+ scheduledScrollUpdate.cancel();
293
+ scheduledResizeUpdate.cancel();
294
+ restorePosition();
295
+ reveal();
296
+ });
297
+ }
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.resolveCssLengthToPixels = resolveCssLengthToPixels;
7
+ var _warnFallbackFailure = require("./warn-fallback-failure");
8
+ /**
9
+ * `null` when the environment cannot measure at all.
10
+ */
11
+ function measureWithProbe(_ref) {
12
+ var value = _ref.value,
13
+ container = _ref.container;
14
+ // Reached through the container rather than the global, so a popover in
15
+ // another document still measures and one with no view degrades gracefully.
16
+ var view = container.ownerDocument.defaultView;
17
+ if (!view) {
18
+ return null;
19
+ }
20
+ var probe = container.ownerDocument.createElement('div');
21
+ probe.style.position = 'absolute';
22
+ probe.style.visibility = 'hidden';
23
+ probe.style.pointerEvents = 'none';
24
+ probe.style.height = '0';
25
+ probe.style.padding = '0';
26
+ probe.style.border = '0';
27
+ // `width` clamps negatives to 0; use `margin-left` instead so signs are
28
+ // preserved. `getComputedStyle` returns the resolved pixel value for
29
+ // margin-* properties even when the source was a token / calc / var.
30
+ probe.style.marginLeft = value;
31
+ // Hidden from assistive tech and event targeting; defensive against
32
+ // `getElementsByTagName('div')` walks in consumer code.
33
+ probe.setAttribute('aria-hidden', 'true');
34
+ probe.setAttribute('inert', '');
35
+ try {
36
+ container.appendChild(probe);
37
+ var resolved = parseFloat(view.getComputedStyle(probe).marginLeft);
38
+ return Number.isFinite(resolved) ? resolved : 0;
39
+ } catch (error) {
40
+ (0, _warnFallbackFailure.warnFallbackFailure)({
41
+ error: error
42
+ });
43
+ return null;
44
+ } finally {
45
+ // `remove()` rather than `removeChild()`: consumer code may already have
46
+ // detached the probe, which must not throw out of a layout effect.
47
+ probe.remove();
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Resolves a CSS length value to a pixel number using a hidden DOM probe.
53
+ *
54
+ * Used by the JS positioning fallback, where a consumer offset can be a number, a
55
+ * `${n}px` string, a token, a `calc()` expression, a viewport unit, and so on.
56
+ * Parsing arbitrary CSS in JS is fragile, and impossible for `calc(var(...))`
57
+ * without a layout context, so the browser does the math instead. The probe is
58
+ * appended to `container` so it inherits the popover's containing block, font
59
+ * size and custom-property scope. Anything unmeasurable resolves to `0`.
60
+ *
61
+ * Costs one synchronous style and layout flush per call that reaches the probe.
62
+ * Deliberately NOT memoised: a token can be retargeted by an override on the
63
+ * consumer's wrapper, a viewport unit changes on resize and an `em` on a font
64
+ * change, so no (container, value) cache can be proven fresh. The caller decides
65
+ * when to re-resolve; see `applyJavaScriptFallbackPositioning`.
66
+ */
67
+ function resolveCssLengthToPixels(_ref2) {
68
+ var _measureWithProbe;
69
+ var value = _ref2.value,
70
+ container = _ref2.container;
71
+ if (typeof value === 'number') {
72
+ return value;
73
+ }
74
+
75
+ // Fast path: consumers occasionally pass `'0'` instead of the number `0`.
76
+ if (value === '0' || value === '-0') {
77
+ return 0;
78
+ }
79
+
80
+ // Fast path: bare `${n}px` strings come from `resolvePlacement`, so this avoids
81
+ // a reflow for the common case.
82
+ var pxMatch = value.match(/^(-?\d+(?:\.\d+)?)px$/);
83
+ if (pxMatch) {
84
+ return Number(pxMatch[1]);
85
+ }
86
+ return (_measureWithProbe = measureWithProbe({
87
+ value: value,
88
+ container: container
89
+ })) !== null && _measureWithProbe !== void 0 ? _measureWithProbe : 0;
90
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.warnFallbackFailure = warnFallbackFailure;
8
+ var _warnOnce = _interopRequireDefault(require("@atlaskit/ds-lib/warn-once"));
9
+ /**
10
+ * Callers on the JavaScript fallback path degrade rather than throw, so this is
11
+ * the only signal that a popover is not where it should be.
12
+ */
13
+ function warnFallbackFailure(_ref) {
14
+ var error = _ref.error;
15
+ if (process.env.NODE_ENV === 'production') {
16
+ return;
17
+ }
18
+ (0, _warnOnce.default)("@atlaskit/top-layer: the JavaScript positioning fallback hit an error, so this popover may be positioned incorrectly. ".concat(String(error)));
19
+ }
@@ -25,8 +25,9 @@ var DEFAULT_GAP = "var(--ds-space-100, 8px)";
25
25
 
26
26
  /**
27
27
  * Fully-resolved placement (internal). Use `resolvePlacement` for partial input.
28
- * `offset.gap` and `offset.crossAxisShift.value` are always CSS
29
- * length strings.
28
+ * `offset.gap`, `offset.crossAxisShift.value` and `minSize` are always CSS length
29
+ * strings. `minSize` stays `undefined` when unset, so "not specified" and an
30
+ * explicit `0` remain distinguishable.
30
31
  */
31
32
 
32
33
  /**
@@ -46,18 +47,25 @@ var DEFAULT_GAP = "var(--ds-space-100, 8px)";
46
47
  * Defaults: `axis: 'block'`, `edge: 'end'`, `align: 'center'`,
47
48
  * `offset.gap: token('space.100', '8px')`,
48
49
  * `offset.crossAxisShift: { value: '0px', direction: 'forwards' }`.
50
+ *
51
+ * `minSize` has no default here: whether it needs one depends on how the popover
52
+ * is sized, which only `useAnchoredPopover` knows.
49
53
  */
50
54
  function resolvePlacement(_ref) {
51
- var _placement$offset, _placement$axis, _placement$edge, _placement$align, _placement$offset$cro, _placement$offset2, _placement$offset$cro2, _placement$offset3;
55
+ var _placement$axis, _placement$edge, _placement$align, _placement$offset$gap, _placement$offset, _placement$offset$cro, _placement$offset2, _placement$offset$cro2, _placement$offset3;
52
56
  var placement = _ref.placement;
53
- var consumerGap = (_placement$offset = placement.offset) === null || _placement$offset === void 0 ? void 0 : _placement$offset.gap;
54
57
  return {
55
58
  axis: (_placement$axis = placement.axis) !== null && _placement$axis !== void 0 ? _placement$axis : 'block',
56
59
  edge: (_placement$edge = placement.edge) !== null && _placement$edge !== void 0 ? _placement$edge : 'end',
57
60
  align: (_placement$align = placement.align) !== null && _placement$align !== void 0 ? _placement$align : 'center',
61
+ // Not `??`: `undefined` must survive, so "not specified" stays
62
+ // distinguishable from an explicit `0`.
63
+ minSize: placement.minSize === undefined ? undefined : (0, _resolveCssLength.toCssLengthString)({
64
+ value: placement.minSize
65
+ }),
58
66
  offset: {
59
- gap: consumerGap === undefined ? DEFAULT_GAP : (0, _resolveCssLength.toCssLengthString)({
60
- value: consumerGap
67
+ gap: (0, _resolveCssLength.toCssLengthString)({
68
+ value: (_placement$offset$gap = (_placement$offset = placement.offset) === null || _placement$offset === void 0 ? void 0 : _placement$offset.gap) !== null && _placement$offset$gap !== void 0 ? _placement$offset$gap : DEFAULT_GAP
61
69
  }),
62
70
  crossAxisShift: {
63
71
  value: (0, _resolveCssLength.toCssLengthString)({
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.supportsAnchorPositioning = void 0;
7
+ var _supportsCssDeclaration = require("./supports-css-declaration");
8
+ /**
9
+ * Probes `anchor-name` and NOT `anchor-size()`: some browsers have positioning
10
+ * without sizing, which is what `supportsAnchorSize` is for.
11
+ */
12
+ // Annotated rather than inferred: `--isolatedDeclarations` cannot emit a type
13
+ // for a `const` initialised from a call.
14
+ var supportsAnchorPositioning = exports.supportsAnchorPositioning = (0, _supportsCssDeclaration.createCssDeclarationProbe)({
15
+ property: 'anchor-name',
16
+ value: '--a'
17
+ });
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.supportsAnchorSize = void 0;
7
+ var _supportsCssDeclaration = require("./supports-css-declaration");
8
+ /**
9
+ * Separate from `supportsAnchorPositioning`: some browsers have anchor
10
+ * positioning without anchor sizing.
11
+ */
12
+ // Annotated rather than inferred: `--isolatedDeclarations` cannot emit a type
13
+ // for a `const` initialised from a call.
14
+ var supportsAnchorSize = exports.supportsAnchorSize = (0, _supportsCssDeclaration.createCssDeclarationProbe)({
15
+ property: 'min-inline-size',
16
+ value: 'anchor-size(self-inline)'
17
+ });
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.createCssDeclarationProbe = createCssDeclarationProbe;
8
+ var _once = _interopRequireDefault(require("@atlaskit/ds-lib/once"));
9
+ /**
10
+ * A lazy, cached `CSS.supports(property, value)` probe. Lazy so it is SSR safe
11
+ * and cannot cause a hydration mismatch: nothing is read until the first call,
12
+ * which happens in an effect. Cached because the answer cannot change within a
13
+ * page. `false` wherever `CSS.supports` is missing (SSR, jsdom), so a caller
14
+ * falls back rather than throws.
15
+ */
16
+ function createCssDeclarationProbe(_ref) {
17
+ var property = _ref.property,
18
+ value = _ref.value;
19
+ return (0, _once.default)(function supportsCssDeclaration() {
20
+ if (typeof window === 'undefined' || typeof CSS === 'undefined' || typeof CSS.supports !== 'function') {
21
+ return false;
22
+ }
23
+ return CSS.supports(property, value);
24
+ });
25
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.useAnchoredPopoverAtPoint = useAnchoredPopoverAtPoint;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
10
+ var _react = require("react");
11
+ var _useAnchoredPopover = require("./use-anchored-popover");
12
+ var _excluded = ["getPoint", "isEnabled"];
13
+ /**
14
+ * Positioning and sizing for a popover anchored to a viewport COORDINATE. No
15
+ * positioning logic here: CSS Anchor Positioning needs a real element to carry
16
+ * `anchor-name`, so this hook creates a hidden, zero-size one at the requested
17
+ * point and delegates everything else to `useAnchoredPopover`.
18
+ *
19
+ * See `notes/decisions/anchored-popover-at-point.md` for why this is a sibling
20
+ * hook instead of an anchor union inside `useAnchoredPopover`.
21
+ */
22
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
23
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
24
+ /**
25
+ * A point in viewport coordinates (CSS pixels). Axis-named rather than
26
+ * edge-named, because viewport coordinates are always physical.
27
+ */
28
+
29
+ /**
30
+ * Appended to `document.body` to escape any transformed ancestor, which would
31
+ * break viewport-relative resolution of `position: fixed`. `Object.assign`
32
+ * rather than `setStyle`: we own the element, so there is nothing to restore.
33
+ */
34
+ function mountAnchorElementAtPoint(_ref) {
35
+ var point = _ref.point;
36
+ var element = document.createElement('div');
37
+ element.setAttribute('aria-hidden', 'true');
38
+ Object.assign(element.style, {
39
+ position: 'fixed',
40
+ // Physical insets: `inset-inline-start` would need `viewportWidth - point.x`
41
+ // in RTL.
42
+ top: "".concat(point.y, "px"),
43
+ left: "".concat(point.x, "px"),
44
+ // Zero size, so placement alone decides which side the popover sits on.
45
+ width: '0',
46
+ height: '0',
47
+ pointerEvents: 'none'
48
+ });
49
+ document.body.appendChild(element);
50
+ return {
51
+ element: element,
52
+ cleanup: function cleanup() {
53
+ element.remove();
54
+ }
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Positions and sizes a popover at a viewport coordinate. Takes every option
60
+ * `useAnchoredPopover` does except `anchorRef`, with the same meaning. One caveat
61
+ * is specific to a point: it has no size, so `'match-anchor'` and `'min-anchor'`
62
+ * resolve to zero against it.
63
+ *
64
+ * A consumer that anchors to an element sometimes and to a point at other times
65
+ * calls BOTH hooks with complementary `isEnabled` values, since a hook cannot be
66
+ * called conditionally. Nothing enforces that; see `isEnabled` on
67
+ * `useAnchoredPopover` for why two enabled hooks on one popover is a bug.
68
+ *
69
+ * @example Anchor at the cursor, falling back to the trigger element
70
+ * ```tsx
71
+ * const shared = { popoverRef, placement, isOpen };
72
+ *
73
+ * useAnchoredPopover({ ...shared, anchorRef: triggerRef, isEnabled: !mousePos });
74
+ * useAnchoredPopoverAtPoint({
75
+ * ...shared,
76
+ * isEnabled: Boolean(mousePos),
77
+ * // Read through a ref: `getPoint` is latched, see below.
78
+ * getPoint: () => mousePosRef.current,
79
+ * });
80
+ * ```
81
+ */
82
+ function useAnchoredPopoverAtPoint(_ref2) {
83
+ var getPoint = _ref2.getPoint,
84
+ _ref2$isEnabled = _ref2.isEnabled,
85
+ isEnabled = _ref2$isEnabled === void 0 ? true : _ref2$isEnabled,
86
+ rest = (0, _objectWithoutProperties2.default)(_ref2, _excluded);
87
+ var anchorRef = (0, _react.useRef)(null);
88
+
89
+ // Latched, keyed on `isEnabled`: consumers read mutable refs inside `getPoint`,
90
+ // so re-reading it would move an already-open popover, and keying on
91
+ // `getPoint`'s identity would re-latch on every parent render.
92
+ var getPointRef = (0, _react.useRef)(getPoint);
93
+ getPointRef.current = getPoint;
94
+
95
+ // Declared BEFORE `useAnchoredPopover` below, so the element exists when that
96
+ // hook's effect reads the ref (React runs layout effects in source order). This
97
+ // effect must not depend on anything the delegated effect does not: a dependency
98
+ // here alone re-creates the element without that hook writing an `anchor-name`
99
+ // onto it, and positioning silently dies.
100
+ (0, _react.useLayoutEffect)(function () {
101
+ if (!isEnabled) {
102
+ return;
103
+ }
104
+ var point = getPointRef.current();
105
+ if (!point) {
106
+ return;
107
+ }
108
+ var _mountAnchorElementAt = mountAnchorElementAtPoint({
109
+ point: point
110
+ }),
111
+ element = _mountAnchorElementAt.element,
112
+ unmountAnchorElement = _mountAnchorElementAt.cleanup;
113
+ anchorRef.current = element;
114
+ return function cleanup() {
115
+ unmountAnchorElement();
116
+ anchorRef.current = null;
117
+ };
118
+ // The latch. See `getPointRef` above: `getPoint` is deliberately absent.
119
+ }, [isEnabled]);
120
+ (0, _useAnchoredPopover.useAnchoredPopover)(_objectSpread(_objectSpread({}, rest), {}, {
121
+ anchorRef: anchorRef,
122
+ isEnabled: isEnabled
123
+ }));
124
+ }