@atlaskit/top-layer 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/README.md +5 -1
- package/dialog/create-close-event/package.json +17 -0
- package/dist/cjs/animations/presets.js +11 -4
- package/dist/cjs/arrow/index.js +131 -0
- package/dist/cjs/arrow/types.js +5 -0
- package/dist/cjs/dialog/dialog-content.js +23 -6
- package/dist/cjs/entry-points/dialog/create-close-event.js +12 -0
- package/dist/cjs/entry-points/placement-map.js +6 -5
- package/dist/cjs/entry-points/popover/create-close-event.js +12 -0
- package/dist/cjs/focus/focus.js +73 -19
- package/dist/cjs/index.js +3 -4
- package/dist/cjs/internal/resolve-css-length-to-pixels.js +61 -10
- package/dist/cjs/internal/role-types.js +40 -9
- package/dist/cjs/internal/set-style.js +23 -25
- package/dist/cjs/internal/use-anchor-position.js +109 -68
- package/dist/cjs/internal/use-focus-wrap.js +13 -2
- package/dist/cjs/internal/use-initial-focus.js +31 -10
- package/dist/cjs/placement-map/index.js +9 -110
- package/dist/cjs/placement-map/legacy-placements.js +113 -0
- package/dist/cjs/popover/popover.js +44 -11
- package/dist/cjs/popup/popup-content.js +19 -13
- package/dist/cjs/popup/popup-context.js +2 -0
- package/dist/cjs/popup/popup-surface.js +6 -0
- package/dist/cjs/popup/popup-trigger-function.js +1 -1
- package/dist/cjs/popup/popup-trigger.js +17 -37
- package/dist/cjs/popup/popup.js +21 -10
- package/dist/cjs/use-arrow-navigation/use-arrow-navigation.js +27 -10
- package/dist/es2019/animations/presets.js +10 -3
- package/dist/es2019/arrow/index.js +269 -0
- package/dist/es2019/arrow/types.js +1 -0
- package/dist/es2019/dialog/dialog-content.js +23 -6
- package/dist/es2019/entry-points/create-close-event.js +7 -0
- package/dist/es2019/entry-points/dialog/create-close-event.js +1 -0
- package/dist/es2019/entry-points/placement-map.js +2 -1
- package/dist/es2019/entry-points/popover/create-close-event.js +1 -0
- package/dist/es2019/focus/focus.js +58 -7
- package/dist/es2019/index.js +3 -4
- package/dist/es2019/internal/resolve-css-length-to-pixels.js +60 -7
- package/dist/es2019/internal/role-types.js +40 -9
- package/dist/es2019/internal/set-style.js +19 -22
- package/dist/es2019/internal/use-anchor-position.js +97 -54
- package/dist/es2019/internal/use-focus-wrap.js +14 -3
- package/dist/es2019/internal/use-initial-focus.js +32 -11
- package/dist/es2019/placement-map/index.js +8 -108
- package/dist/es2019/placement-map/legacy-placements.js +107 -0
- package/dist/es2019/popover/popover.js +44 -10
- package/dist/es2019/popup/popup-content.js +20 -14
- package/dist/es2019/popup/popup-context.js +2 -0
- package/dist/es2019/popup/popup-surface.js +6 -0
- package/dist/es2019/popup/popup-trigger-function.js +1 -1
- package/dist/es2019/popup/popup-trigger.js +17 -37
- package/dist/es2019/popup/popup.js +20 -9
- package/dist/es2019/use-arrow-navigation/use-arrow-navigation.js +27 -10
- package/dist/esm/animations/presets.js +10 -3
- package/dist/esm/arrow/index.js +124 -0
- package/dist/esm/arrow/types.js +1 -0
- package/dist/esm/dialog/dialog-content.js +23 -6
- package/dist/esm/entry-points/create-close-event.js +7 -0
- package/dist/esm/entry-points/dialog/create-close-event.js +1 -0
- package/dist/esm/entry-points/placement-map.js +2 -1
- package/dist/esm/entry-points/popover/create-close-event.js +1 -0
- package/dist/esm/focus/focus.js +72 -19
- package/dist/esm/index.js +3 -4
- package/dist/esm/internal/resolve-css-length-to-pixels.js +61 -10
- package/dist/esm/internal/role-types.js +39 -9
- package/dist/esm/internal/set-style.js +23 -25
- package/dist/esm/internal/use-anchor-position.js +110 -64
- package/dist/esm/internal/use-focus-wrap.js +14 -3
- package/dist/esm/internal/use-initial-focus.js +32 -11
- package/dist/esm/placement-map/index.js +8 -108
- package/dist/esm/placement-map/legacy-placements.js +107 -0
- package/dist/esm/popover/popover.js +44 -11
- package/dist/esm/popup/popup-content.js +20 -14
- package/dist/esm/popup/popup-context.js +2 -0
- package/dist/esm/popup/popup-surface.js +6 -0
- package/dist/esm/popup/popup-trigger-function.js +1 -1
- package/dist/esm/popup/popup-trigger.js +17 -37
- package/dist/esm/popup/popup.js +21 -10
- package/dist/esm/use-arrow-navigation/use-arrow-navigation.js +27 -10
- package/dist/types/arrow/index.d.ts +24 -0
- package/dist/types/arrow/types.d.ts +29 -0
- package/dist/types/dialog/dialog-content.d.ts +5 -1
- package/dist/types/dialog/types.d.ts +50 -24
- package/dist/types/entry-points/create-close-event.d.ts +7 -0
- package/dist/types/entry-points/dialog/create-close-event.d.ts +2 -0
- package/dist/types/entry-points/placement-map.d.ts +2 -1
- package/dist/types/entry-points/popover/create-close-event.d.ts +2 -0
- package/dist/types/focus/focus.d.ts +8 -0
- package/dist/types/internal/resolve-css-length-to-pixels.d.ts +4 -6
- package/dist/types/internal/role-types.d.ts +25 -4
- package/dist/types/internal/set-style.d.ts +2 -19
- package/dist/types/internal/use-anchor-position.d.ts +2 -3
- package/dist/types/internal/use-initial-focus.d.ts +5 -4
- package/dist/types/placement-map/index.d.ts +8 -21
- package/dist/types/placement-map/legacy-placements.d.ts +21 -0
- package/dist/types/popover/popover.d.ts +1 -1
- package/dist/types/popover/types.d.ts +20 -19
- package/dist/types/popup/popup-surface.d.ts +6 -0
- package/dist/types/popup/popup-trigger-function.d.ts +10 -6
- package/dist/types/popup/popup-trigger.d.ts +8 -17
- package/dist/types/popup/popup.d.ts +2 -2
- package/dist/types/popup/types.d.ts +68 -22
- package/dist/types/use-arrow-navigation/use-arrow-navigation.d.ts +19 -5
- package/dist/types-ts4.5/arrow/index.d.ts +24 -0
- package/dist/types-ts4.5/arrow/types.d.ts +29 -0
- package/dist/types-ts4.5/dialog/dialog-content.d.ts +5 -1
- package/dist/types-ts4.5/dialog/types.d.ts +50 -24
- package/dist/types-ts4.5/entry-points/create-close-event.d.ts +7 -0
- package/dist/types-ts4.5/entry-points/dialog/create-close-event.d.ts +2 -0
- package/dist/types-ts4.5/entry-points/placement-map.d.ts +2 -1
- package/dist/types-ts4.5/entry-points/popover/create-close-event.d.ts +2 -0
- package/dist/types-ts4.5/focus/focus.d.ts +8 -0
- package/dist/types-ts4.5/internal/resolve-css-length-to-pixels.d.ts +4 -6
- package/dist/types-ts4.5/internal/role-types.d.ts +25 -4
- package/dist/types-ts4.5/internal/set-style.d.ts +2 -19
- package/dist/types-ts4.5/internal/use-anchor-position.d.ts +2 -3
- package/dist/types-ts4.5/internal/use-initial-focus.d.ts +5 -4
- package/dist/types-ts4.5/placement-map/index.d.ts +8 -21
- package/dist/types-ts4.5/placement-map/legacy-placements.d.ts +39 -0
- package/dist/types-ts4.5/popover/popover.d.ts +1 -1
- package/dist/types-ts4.5/popover/types.d.ts +20 -19
- package/dist/types-ts4.5/popup/popup-surface.d.ts +6 -0
- package/dist/types-ts4.5/popup/popup-trigger-function.d.ts +10 -6
- package/dist/types-ts4.5/popup/popup-trigger.d.ts +8 -17
- package/dist/types-ts4.5/popup/popup.d.ts +2 -2
- package/dist/types-ts4.5/popup/types.d.ts +68 -22
- package/dist/types-ts4.5/use-arrow-navigation/use-arrow-navigation.d.ts +19 -5
- package/package.json +3 -1
- package/popover/create-close-event/package.json +17 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
1
2
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
3
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
4
|
/**
|
|
@@ -14,7 +15,7 @@ import _createClass from "@babel/runtime/helpers/createClass";
|
|
|
14
15
|
* popover with `opacity: 0` until the first measurement completes, so it
|
|
15
16
|
* is never painted at the wrong location.
|
|
16
17
|
*/
|
|
17
|
-
import { useId, useLayoutEffect,
|
|
18
|
+
import { useId, useLayoutEffect, useMemo } from 'react';
|
|
18
19
|
import { bind } from 'bind-event-listener';
|
|
19
20
|
import rafSchedule from 'raf-schd';
|
|
20
21
|
import once from '@atlaskit/ds-lib/once';
|
|
@@ -23,7 +24,30 @@ import { combine } from './combine';
|
|
|
23
24
|
import { resolveCssLengthToPixels } from './resolve-css-length-to-pixels';
|
|
24
25
|
import { getPlacement } from './resolve-placement';
|
|
25
26
|
import { setStyle } from './set-style';
|
|
26
|
-
|
|
27
|
+
|
|
28
|
+
// `getPlacement` is intentionally NOT re-exported here - import it directly
|
|
29
|
+
// from `./resolve-placement` so search-and-jump lands at the source of truth.
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Module-scope no-op `ResizeObserver` used in non-DOM jest environments where
|
|
33
|
+
* `ResizeObserver` is `undefined`. Hoisted out of the effect to avoid
|
|
34
|
+
* allocating a new class declaration on every run.
|
|
35
|
+
*/
|
|
36
|
+
var NoopResizeObserver = /*#__PURE__*/function () {
|
|
37
|
+
function NoopResizeObserver() {
|
|
38
|
+
_classCallCheck(this, NoopResizeObserver);
|
|
39
|
+
}
|
|
40
|
+
return _createClass(NoopResizeObserver, [{
|
|
41
|
+
key: "observe",
|
|
42
|
+
value: function observe() {}
|
|
43
|
+
}, {
|
|
44
|
+
key: "unobserve",
|
|
45
|
+
value: function unobserve() {}
|
|
46
|
+
}, {
|
|
47
|
+
key: "disconnect",
|
|
48
|
+
value: function disconnect() {}
|
|
49
|
+
}]);
|
|
50
|
+
}();
|
|
27
51
|
|
|
28
52
|
/**
|
|
29
53
|
* Resolves placement options to CSS `position-area` syntax.
|
|
@@ -86,7 +110,7 @@ export function placementToPositionArea(_ref) {
|
|
|
86
110
|
* top-right), flipping only the primary axis (`flip-inline`) moves the popup
|
|
87
111
|
* to the left but keeps the same cross-axis span direction (e.g. upward),
|
|
88
112
|
* which is still off-screen. The combined keyword `flip-inline flip-block`
|
|
89
|
-
* mirrors the popup diagonally
|
|
113
|
+
* mirrors the popup diagonally. It flips BOTH the position-area AND both
|
|
90
114
|
* inline and block margins simultaneously, placing the popup at the
|
|
91
115
|
* diagonally opposite corner where there is always space.
|
|
92
116
|
*
|
|
@@ -94,6 +118,7 @@ export function placementToPositionArea(_ref) {
|
|
|
94
118
|
* `position-try-fallbacks` do NOT update margins, so only the `flip-*`
|
|
95
119
|
* tactic keywords correctly flip the gap margin along with the position.
|
|
96
120
|
*/
|
|
121
|
+
// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
|
|
97
122
|
export function placementToTryFallbacks(_ref2) {
|
|
98
123
|
var placement = _ref2.placement;
|
|
99
124
|
var _getPlacement2 = getPlacement({
|
|
@@ -104,19 +129,36 @@ export function placementToTryFallbacks(_ref2) {
|
|
|
104
129
|
align = _getPlacement2.align;
|
|
105
130
|
var crossAxis = axis === 'block' ? 'inline' : 'block';
|
|
106
131
|
var flippedEdge = edge === 'start' ? 'end' : 'start';
|
|
107
|
-
if (align !== 'center') {
|
|
108
|
-
var _sameEdge = "".concat(axis, "-").concat(edge);
|
|
109
|
-
var _oppositeEdge = "".concat(axis, "-").concat(flippedEdge);
|
|
110
|
-
var _flipKeyword = axis === 'block' ? 'flip-block' : 'flip-inline';
|
|
111
|
-
var flipCrossKeyword = axis === 'block' ? 'flip-inline' : 'flip-block';
|
|
112
|
-
// Try same-edge shifts first; two flip entries cover single-edge then corner overflow.
|
|
113
|
-
// Legacy Popper fallbacks for e.g. bottom-start: [bottom, bottom-end, top-start, top, top-end, auto].
|
|
114
|
-
return ["".concat(_sameEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'end' : 'start'), _sameEdge, "".concat(_sameEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'start' : 'end'), _flipKeyword, "".concat(_flipKeyword, " ").concat(flipCrossKeyword), "".concat(_oppositeEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'end' : 'start'), _oppositeEdge, "".concat(_oppositeEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'start' : 'end')].join(', ');
|
|
115
|
-
}
|
|
116
132
|
var sameEdge = "".concat(axis, "-").concat(edge);
|
|
117
133
|
var oppositeEdge = "".concat(axis, "-").concat(flippedEdge);
|
|
118
134
|
var flipKeyword = axis === 'block' ? 'flip-block' : 'flip-inline';
|
|
119
|
-
|
|
135
|
+
var flipCrossKeyword = axis === 'block' ? 'flip-inline' : 'flip-block';
|
|
136
|
+
|
|
137
|
+
// Single algorithm: produce the shift list against any base alignment.
|
|
138
|
+
// For `align: 'start'` the "near" shift expands toward `end`; for
|
|
139
|
+
// `align: 'end'` it expands toward `start`; for `align: 'center'`
|
|
140
|
+
// either order is symmetric (we use end-then-start to match the
|
|
141
|
+
// historical fallback list).
|
|
142
|
+
function shifts(baseAlign, edgeKey) {
|
|
143
|
+
if (baseAlign === 'center') {
|
|
144
|
+
return ["".concat(edgeKey, " span-").concat(crossAxis, "-end"), "".concat(edgeKey, " span-").concat(crossAxis, "-start")];
|
|
145
|
+
}
|
|
146
|
+
var near = baseAlign === 'start' ? 'end' : 'start';
|
|
147
|
+
var far = baseAlign === 'start' ? 'start' : 'end';
|
|
148
|
+
return ["".concat(edgeKey, " span-").concat(crossAxis, "-").concat(near), edgeKey, "".concat(edgeKey, " span-").concat(crossAxis, "-").concat(far)];
|
|
149
|
+
}
|
|
150
|
+
if (align !== 'center') {
|
|
151
|
+
// Aligned (start/end): try same-edge shifts, then single-axis flip,
|
|
152
|
+
// then diagonal flip for corner overflow, then opposite-edge shifts.
|
|
153
|
+
// Legacy Popper fallback ordering for e.g. bottom-start:
|
|
154
|
+
// [bottom, bottom-end, top-start, top, top-end, auto].
|
|
155
|
+
return [].concat(_toConsumableArray(shifts(align, sameEdge)), [flipKeyword, "".concat(flipKeyword, " ").concat(flipCrossKeyword)], _toConsumableArray(shifts(align, oppositeEdge))).join(', ');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Centered: same-edge shifts, single-axis flip, opposite-edge shifts.
|
|
159
|
+
// Diagonal flip is unnecessary because centered placements expand
|
|
160
|
+
// equally in both cross-axis directions.
|
|
161
|
+
return [].concat(_toConsumableArray(shifts('center', sameEdge)), [flipKeyword], _toConsumableArray(shifts('center', oppositeEdge))).join(', ');
|
|
120
162
|
}
|
|
121
163
|
|
|
122
164
|
/**
|
|
@@ -134,7 +176,7 @@ function isPopoverOpen(popover) {
|
|
|
134
176
|
|
|
135
177
|
/**
|
|
136
178
|
* Detects whether the browser supports CSS Anchor Positioning.
|
|
137
|
-
* Uses `once()` for lazy evaluation
|
|
179
|
+
* Uses `once()` for lazy evaluation: safe for SSR and avoids hydration mismatches.
|
|
138
180
|
*/
|
|
139
181
|
var supportsAnchorPositioning = once(function () {
|
|
140
182
|
if (typeof window === 'undefined' || typeof CSS === 'undefined' || typeof CSS.supports !== 'function') {
|
|
@@ -214,34 +256,51 @@ function crossAxisShiftMargin(_ref4) {
|
|
|
214
256
|
}
|
|
215
257
|
|
|
216
258
|
/**
|
|
217
|
-
* Returns a referentially-stable, fully-resolved `TPlacement
|
|
218
|
-
*
|
|
219
|
-
* does not
|
|
259
|
+
* Returns a referentially-stable, fully-resolved `TPlacement`. `useMemo` is
|
|
260
|
+
* keyed on the primitive fields of the input so a fresh inline `placement`
|
|
261
|
+
* object on every render does not produce a fresh resolved object. Both
|
|
262
|
+
* `getPlacement` and the equality check are skipped when the inputs are
|
|
263
|
+
* unchanged.
|
|
220
264
|
*/
|
|
221
265
|
function useStablePlacement(placement) {
|
|
266
|
+
// Resolve to the fully-defaulted primitives BEFORE the memo so the deps
|
|
267
|
+
// array sees the same key for `{}`, `undefined` fields, and explicit
|
|
268
|
+
// defaults. Otherwise `axis: undefined` and `axis: 'block'` would be
|
|
269
|
+
// treated as different inputs and re-run the downstream effect.
|
|
222
270
|
var resolved = getPlacement({
|
|
223
271
|
placement: placement
|
|
224
272
|
});
|
|
225
|
-
var
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
273
|
+
var axis = resolved.axis;
|
|
274
|
+
var edge = resolved.edge;
|
|
275
|
+
var align = resolved.align;
|
|
276
|
+
var gap = resolved.offset.gap;
|
|
277
|
+
var shiftValue = resolved.offset.crossAxisShift.value;
|
|
278
|
+
var shiftDirection = resolved.offset.crossAxisShift.direction;
|
|
279
|
+
// Rebuild the placement object inside the memo from the resolved primitive
|
|
280
|
+
// deps so the factory does not close over the (potentially fresh) outer
|
|
281
|
+
// `resolved` reference, and `react-hooks/exhaustive-deps` can verify the
|
|
282
|
+
// deps array.
|
|
283
|
+
return useMemo(function () {
|
|
284
|
+
return {
|
|
285
|
+
axis: axis,
|
|
286
|
+
edge: edge,
|
|
287
|
+
align: align,
|
|
288
|
+
offset: {
|
|
289
|
+
gap: gap,
|
|
290
|
+
crossAxisShift: {
|
|
291
|
+
value: shiftValue,
|
|
292
|
+
direction: shiftDirection
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
}, [axis, edge, align, gap, shiftValue, shiftDirection]);
|
|
238
297
|
}
|
|
239
298
|
|
|
240
299
|
/**
|
|
241
300
|
* Hook that positions an element relative to an anchor element using
|
|
242
301
|
* CSS Anchor Positioning (with a JS fallback for older browsers).
|
|
243
302
|
*
|
|
244
|
-
* This hook is the positioning primitive
|
|
303
|
+
* This hook is the positioning primitive. It has no knowledge of popovers,
|
|
245
304
|
* visibility, or animation. Compose it with `Popover` for anchor-positioned
|
|
246
305
|
* top-layer content.
|
|
247
306
|
*
|
|
@@ -257,6 +316,7 @@ function isResolvedPlacementEqual(a, b) {
|
|
|
257
316
|
* comparison is used internally so re-runs are skipped when the resolved
|
|
258
317
|
* placement shape is unchanged.
|
|
259
318
|
*/
|
|
319
|
+
// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
|
|
260
320
|
export function useAnchorPosition(_ref5) {
|
|
261
321
|
var anchorRef = _ref5.anchorRef,
|
|
262
322
|
popoverRef = _ref5.popoverRef,
|
|
@@ -285,6 +345,9 @@ export function useAnchorPosition(_ref5) {
|
|
|
285
345
|
placement: stablePlacement,
|
|
286
346
|
offset: gapCssValue
|
|
287
347
|
});
|
|
348
|
+
// Hoist crossAxisShift to a single computation; reused below to
|
|
349
|
+
// populate the active `--ds-cross-axis-shift-margin-*` custom
|
|
350
|
+
// property for the named arrow @position-try rules.
|
|
288
351
|
var crossAxisShift = crossAxisShiftMargin({
|
|
289
352
|
placement: stablePlacement,
|
|
290
353
|
crossAxisShiftCssValue: crossAxisShiftCssValue,
|
|
@@ -344,11 +407,8 @@ export function useAnchorPosition(_ref5) {
|
|
|
344
407
|
property: '--ds-cross-axis-shift-margin-block-end',
|
|
345
408
|
value: '0px'
|
|
346
409
|
});
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
crossAxisShiftCssValue: crossAxisShiftCssValue,
|
|
350
|
-
direction: stablePlacement.offset.crossAxisShift.direction
|
|
351
|
-
});
|
|
410
|
+
// `crossAxisShift` IS the active margin - reuse instead of recomputing.
|
|
411
|
+
var crossAxisShiftActive = crossAxisShift;
|
|
352
412
|
// Map margin property to its corresponding custom property name.
|
|
353
413
|
var customPropertyByMarginProperty = {
|
|
354
414
|
'margin-inline-start': '--ds-cross-axis-shift-margin-start',
|
|
@@ -373,7 +433,7 @@ export function useAnchorPosition(_ref5) {
|
|
|
373
433
|
* - Sometimes the `useAnchorPosition` hook and `Popover`
|
|
374
434
|
* are not in the same component.
|
|
375
435
|
* - There can be times when, even with reference counting, we
|
|
376
|
-
* could remove the anchor-name while it
|
|
436
|
+
* could remove the anchor-name while it is still being used
|
|
377
437
|
* by something else - especially with async react updates
|
|
378
438
|
* which can cause tearing
|
|
379
439
|
*
|
|
@@ -404,7 +464,6 @@ export function useAnchorPosition(_ref5) {
|
|
|
404
464
|
}]
|
|
405
465
|
});
|
|
406
466
|
function update() {
|
|
407
|
-
var _popover$parentElemen;
|
|
408
467
|
if (!trigger || !popover) {
|
|
409
468
|
return;
|
|
410
469
|
}
|
|
@@ -415,19 +474,19 @@ export function useAnchorPosition(_ref5) {
|
|
|
415
474
|
};
|
|
416
475
|
|
|
417
476
|
// Resolve consumer-supplied CSS length strings (tokens, calc, var,
|
|
418
|
-
// px, rem, etc) to pixels. The probe is mounted
|
|
419
|
-
// so
|
|
420
|
-
//
|
|
421
|
-
//
|
|
422
|
-
//
|
|
423
|
-
|
|
477
|
+
// px, rem, etc) to pixels. The probe is mounted INSIDE the popover
|
|
478
|
+
// itself so the resolved length matches the scope a token would
|
|
479
|
+
// resolve against from inside the popover content. (The popover
|
|
480
|
+
// lives in the top layer, not the trigger's DOM tree, so probing
|
|
481
|
+
// at `popover.parentElement` would resolve in a different scope
|
|
482
|
+
// than the consumer's token authoring expects.)
|
|
424
483
|
var gapPx = resolveCssLengthToPixels({
|
|
425
484
|
value: gapCssValue,
|
|
426
|
-
container:
|
|
485
|
+
container: popover
|
|
427
486
|
});
|
|
428
487
|
var crossAxisShiftPx = resolveCssLengthToPixels({
|
|
429
488
|
value: crossAxisShiftCssValue,
|
|
430
|
-
container:
|
|
489
|
+
container: popover
|
|
431
490
|
});
|
|
432
491
|
var _computeFallbackPosit = computeFallbackPosition({
|
|
433
492
|
triggerRect: triggerRect,
|
|
@@ -460,25 +519,12 @@ export function useAnchorPosition(_ref5) {
|
|
|
460
519
|
// scroll/resize is handled by the window listeners below.
|
|
461
520
|
// `ResizeObserver` is missing in some non-DOM jest environments
|
|
462
521
|
// (e.g. post-office's `node` environment). Fall back to a no-op
|
|
463
|
-
// observer there
|
|
522
|
+
// observer there. The scroll/resize listeners below still keep
|
|
464
523
|
// the popover positioned in the rare case the consumer also
|
|
465
524
|
// polyfilled `showPopover` but not `ResizeObserver`. Real
|
|
466
|
-
// browsers always have it.
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
_classCallCheck(this, NoopResizeObserver);
|
|
470
|
-
}
|
|
471
|
-
return _createClass(NoopResizeObserver, [{
|
|
472
|
-
key: "observe",
|
|
473
|
-
value: function observe() {}
|
|
474
|
-
}, {
|
|
475
|
-
key: "unobserve",
|
|
476
|
-
value: function unobserve() {}
|
|
477
|
-
}, {
|
|
478
|
-
key: "disconnect",
|
|
479
|
-
value: function disconnect() {}
|
|
480
|
-
}]);
|
|
481
|
-
}();
|
|
525
|
+
// browsers always have it. The `NoopResizeObserver` class is
|
|
526
|
+
// hoisted to module scope (see top of file) so we do not allocate
|
|
527
|
+
// a new constructor on every effect run.
|
|
482
528
|
var ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
|
|
483
529
|
var resizeObserver = new ResizeObserverImpl(function () {
|
|
484
530
|
if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
|
|
@@ -501,7 +547,7 @@ export function useAnchorPosition(_ref5) {
|
|
|
501
547
|
// the UA-default position, then re-observe for a fresh
|
|
502
548
|
// measurement. We use `opacity: 0` rather than
|
|
503
549
|
// `visibility: hidden` because Firefox skips visibility-hidden
|
|
504
|
-
// elements during `<dialog>` initial-focus traversal
|
|
550
|
+
// elements during `<dialog>` initial-focus traversal. See
|
|
505
551
|
// `form-in-popup.spec.tsx` on `desktop-firefox`.
|
|
506
552
|
bind(popover, {
|
|
507
553
|
type: 'toggle',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
import { bind } from 'bind-event-listener';
|
|
3
|
-
import { getFirstFocusable, getLastFocusable, getNextFocusable } from '../focus/focus';
|
|
3
|
+
import { getFirstFocusable, getLastFocusable, getNextFocusable, isNestedLayerFocused } from '../focus/focus';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Roles that require focus wrapping per WAI-ARIA APG.
|
|
@@ -14,7 +14,7 @@ import { getFirstFocusable, getLastFocusable, getNextFocusable } from '../focus/
|
|
|
14
14
|
* not Tab. Tab/Shift+Tab should move focus OUT of a menu entirely.
|
|
15
15
|
*
|
|
16
16
|
* Menu keyboard behavior (arrow keys, Home/End, type-ahead, Enter/Space)
|
|
17
|
-
* is context-dependent
|
|
17
|
+
* is context-dependent. It varies by orientation, nesting depth, item
|
|
18
18
|
* type, and control pattern (menu button vs menubar). This makes it
|
|
19
19
|
* impossible to implement generically here. The consumer component
|
|
20
20
|
* (e.g. `dropdown-menu`) owns all menu keyboard navigation.
|
|
@@ -54,6 +54,17 @@ export function useFocusWrap(_ref) {
|
|
|
54
54
|
if (event.key !== 'Tab') {
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
// If focus is already in a nested layer, then
|
|
59
|
+
// we continue to let that nested layer own focus
|
|
60
|
+
if (isNestedLayerFocused({
|
|
61
|
+
container: element
|
|
62
|
+
})) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Prevent the browser giving focus to where it wants to
|
|
67
|
+
// (we will be handling it, including with wrapping)
|
|
57
68
|
event.preventDefault();
|
|
58
69
|
var direction = event.shiftKey ? 'backwards' : 'forwards';
|
|
59
70
|
|
|
@@ -69,7 +80,7 @@ export function useFocusWrap(_ref) {
|
|
|
69
80
|
}
|
|
70
81
|
|
|
71
82
|
// Nothing is currently focused inside the container (or the
|
|
72
|
-
// focused element
|
|
83
|
+
// focused element is not in the focusable list). Fall back to
|
|
73
84
|
// the first or last focusable element depending on direction.
|
|
74
85
|
var fallback = direction === 'forwards' ? getFirstFocusable({
|
|
75
86
|
container: element
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
2
|
import { getFirstFocusable } from '../focus/focus';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -19,8 +19,8 @@ import { getFirstFocusable } from '../focus/focus';
|
|
|
19
19
|
* React 19+ reflects the JSX prop as the HTML attribute automatically.
|
|
20
20
|
*/
|
|
21
21
|
function getInitialFocusTarget(_ref) {
|
|
22
|
-
var container = _ref.container
|
|
23
|
-
|
|
22
|
+
var container = _ref.container,
|
|
23
|
+
role = _ref.role;
|
|
24
24
|
if (role === 'dialog' || role === 'alertdialog') {
|
|
25
25
|
// Prefer element with the native HTML autofocus attribute.
|
|
26
26
|
var autofocusEl = container.querySelector('[autofocus]');
|
|
@@ -61,14 +61,15 @@ function getInitialFocusTarget(_ref) {
|
|
|
61
61
|
/**
|
|
62
62
|
* Moves focus into a popover element when it opens, based on its ARIA role.
|
|
63
63
|
*
|
|
64
|
-
*
|
|
64
|
+
* Follows the WAI-ARIA APG initial-focus patterns for each role:
|
|
65
65
|
* - `dialog` / `alertdialog` → focus first focusable (or `[autofocus]`)
|
|
66
66
|
* - `menu` → focus first menu item
|
|
67
67
|
* - `listbox` → focus selected or first option
|
|
68
|
-
* - `tooltip` / no role → no focus movement
|
|
68
|
+
* - `tooltip` / no role → no focus movement (focus must remain on trigger;
|
|
69
|
+
* moving focus into the tooltip would dismiss it)
|
|
69
70
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
71
|
+
* Role is taken from the typed `role` prop - this is the consumer's contract
|
|
72
|
+
* and is not subject to drift from a directly-mutated DOM attribute.
|
|
72
73
|
*
|
|
73
74
|
* Always call this hook unconditionally. Focus is only moved when `isOpen`
|
|
74
75
|
* transitions to `true` and the role requires it.
|
|
@@ -77,6 +78,12 @@ export function useInitialFocus(_ref2) {
|
|
|
77
78
|
var elementRef = _ref2.elementRef,
|
|
78
79
|
isOpen = _ref2.isOpen,
|
|
79
80
|
role = _ref2.role;
|
|
81
|
+
// Track the most recently scheduled RAF so a rapid `isOpen → false → true`
|
|
82
|
+
// transition can cancel the previous frame before its closure runs against
|
|
83
|
+
// a stale popover element. Without this, the RAF queued during the first
|
|
84
|
+
// open could fire after the second open had begun and focus the wrong
|
|
85
|
+
// instance.
|
|
86
|
+
var pendingRafRef = useRef(null);
|
|
80
87
|
useEffect(function () {
|
|
81
88
|
if (!isOpen) {
|
|
82
89
|
return;
|
|
@@ -86,6 +93,11 @@ export function useInitialFocus(_ref2) {
|
|
|
86
93
|
return;
|
|
87
94
|
}
|
|
88
95
|
|
|
96
|
+
// Cancel any RAF queued by the previous open cycle.
|
|
97
|
+
if (pendingRafRef.current !== null) {
|
|
98
|
+
cancelAnimationFrame(pendingRafRef.current);
|
|
99
|
+
}
|
|
100
|
+
|
|
89
101
|
// Use requestAnimationFrame to ensure the popover is fully rendered
|
|
90
102
|
// and visible in the top layer before attempting to move focus.
|
|
91
103
|
// showPopover() is called in useLayoutEffect (which runs before this
|
|
@@ -93,15 +105,24 @@ export function useInitialFocus(_ref2) {
|
|
|
93
105
|
// element is guaranteed to be in the top layer.
|
|
94
106
|
var rafId = requestAnimationFrame(function () {
|
|
95
107
|
var _getInitialFocusTarge;
|
|
108
|
+
pendingRafRef.current = null;
|
|
109
|
+
// Verify the element we captured is still the live popover. In
|
|
110
|
+
// rapid-toggle scenarios the ref may already point to a different
|
|
111
|
+
// instance - skip rather than focus the wrong popover.
|
|
112
|
+
if (elementRef.current !== el) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
96
115
|
(_getInitialFocusTarge = getInitialFocusTarget({
|
|
97
|
-
container: el
|
|
116
|
+
container: el,
|
|
117
|
+
role: role
|
|
98
118
|
})) === null || _getInitialFocusTarge === void 0 || _getInitialFocusTarge.focus();
|
|
99
119
|
});
|
|
120
|
+
pendingRafRef.current = rafId;
|
|
100
121
|
return function () {
|
|
101
122
|
cancelAnimationFrame(rafId);
|
|
123
|
+
if (pendingRafRef.current === rafId) {
|
|
124
|
+
pendingRafRef.current = null;
|
|
125
|
+
}
|
|
102
126
|
};
|
|
103
|
-
// We intentionally depend on `role` even though `getInitialFocusTarget`
|
|
104
|
-
// reads from the DOM attribute. This ensures the effect re-runs if
|
|
105
|
-
// the role prop changes while the popover is open.
|
|
106
127
|
}, [elementRef, isOpen, role]);
|
|
107
128
|
}
|
|
@@ -2,10 +2,7 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
|
2
2
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
3
|
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; }
|
|
4
4
|
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) { _defineProperty(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; }
|
|
5
|
-
|
|
6
|
-
* Legacy Popper.js placement values (used by `@atlaskit/popper`, `@atlaskit/popup`,
|
|
7
|
-
* `@atlaskit/tooltip`, etc.).
|
|
8
|
-
*/
|
|
5
|
+
import { placementMapping } from './legacy-placements';
|
|
9
6
|
|
|
10
7
|
/**
|
|
11
8
|
* Maps legacy Popper.js placement values to the new object-based
|
|
@@ -17,9 +14,11 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
17
14
|
* | ------------------- | --------------------------------------------------- |
|
|
18
15
|
* | `top` | `{ axis: 'block', edge: 'start', align: 'center' }` |
|
|
19
16
|
* | `top-start` | `{ axis: 'block', edge: 'start', align: 'start' }` |
|
|
17
|
+
* | `top-center` | `{ axis: 'block', edge: 'start', align: 'center' }` |
|
|
20
18
|
* | `top-end` | `{ axis: 'block', edge: 'start', align: 'end' }` |
|
|
21
19
|
* | `bottom` | `{ axis: 'block', edge: 'end', align: 'center' }` |
|
|
22
20
|
* | `bottom-start` | `{ axis: 'block', edge: 'end', align: 'start' }` |
|
|
21
|
+
* | `bottom-center` | `{ axis: 'block', edge: 'end', align: 'center' }` |
|
|
23
22
|
* | `bottom-end` | `{ axis: 'block', edge: 'end', align: 'end' }` |
|
|
24
23
|
* | `right` | `{ axis: 'inline', edge: 'end', align: 'center' }` |
|
|
25
24
|
* | `right-start` | `{ axis: 'inline', edge: 'end', align: 'start' }` |
|
|
@@ -31,7 +30,10 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
31
30
|
* | `auto-start` | `{ axis: 'block', edge: 'end', align: 'start' }` |
|
|
32
31
|
* | `auto-end` | `{ axis: 'block', edge: 'end', align: 'end' }` |
|
|
33
32
|
*
|
|
34
|
-
*
|
|
33
|
+
* `auto*` is mapped to `block-end` (a reduction in expressiveness vs Popper's
|
|
34
|
+
* runtime auto-flip). CSS `position-try-fallbacks` provides flipping at the
|
|
35
|
+
* edge - but the initial placement is fixed. If migrating away from Popper's
|
|
36
|
+
* dynamic auto, prefer an explicit placement.
|
|
35
37
|
*
|
|
36
38
|
* @example
|
|
37
39
|
* ```ts
|
|
@@ -43,103 +45,6 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
43
45
|
* // newPlacement === { axis: 'block', edge: 'end', align: 'start' }
|
|
44
46
|
* ```
|
|
45
47
|
*/
|
|
46
|
-
var placementMapping = {
|
|
47
|
-
top: {
|
|
48
|
-
axis: 'block',
|
|
49
|
-
edge: 'start',
|
|
50
|
-
align: 'center'
|
|
51
|
-
},
|
|
52
|
-
'top-start': {
|
|
53
|
-
axis: 'block',
|
|
54
|
-
edge: 'start',
|
|
55
|
-
align: 'start'
|
|
56
|
-
},
|
|
57
|
-
'top-center': {
|
|
58
|
-
axis: 'block',
|
|
59
|
-
edge: 'start',
|
|
60
|
-
align: 'center'
|
|
61
|
-
},
|
|
62
|
-
'top-end': {
|
|
63
|
-
axis: 'block',
|
|
64
|
-
edge: 'start',
|
|
65
|
-
align: 'end'
|
|
66
|
-
},
|
|
67
|
-
bottom: {
|
|
68
|
-
axis: 'block',
|
|
69
|
-
edge: 'end',
|
|
70
|
-
align: 'center'
|
|
71
|
-
},
|
|
72
|
-
'bottom-start': {
|
|
73
|
-
axis: 'block',
|
|
74
|
-
edge: 'end',
|
|
75
|
-
align: 'start'
|
|
76
|
-
},
|
|
77
|
-
'bottom-center': {
|
|
78
|
-
axis: 'block',
|
|
79
|
-
edge: 'end',
|
|
80
|
-
align: 'center'
|
|
81
|
-
},
|
|
82
|
-
'bottom-end': {
|
|
83
|
-
axis: 'block',
|
|
84
|
-
edge: 'end',
|
|
85
|
-
align: 'end'
|
|
86
|
-
},
|
|
87
|
-
right: {
|
|
88
|
-
axis: 'inline',
|
|
89
|
-
edge: 'end',
|
|
90
|
-
align: 'center'
|
|
91
|
-
},
|
|
92
|
-
'right-start': {
|
|
93
|
-
axis: 'inline',
|
|
94
|
-
edge: 'end',
|
|
95
|
-
align: 'start'
|
|
96
|
-
},
|
|
97
|
-
'right-end': {
|
|
98
|
-
axis: 'inline',
|
|
99
|
-
edge: 'end',
|
|
100
|
-
align: 'end'
|
|
101
|
-
},
|
|
102
|
-
left: {
|
|
103
|
-
axis: 'inline',
|
|
104
|
-
edge: 'start',
|
|
105
|
-
align: 'center'
|
|
106
|
-
},
|
|
107
|
-
'left-start': {
|
|
108
|
-
axis: 'inline',
|
|
109
|
-
edge: 'start',
|
|
110
|
-
align: 'start'
|
|
111
|
-
},
|
|
112
|
-
'left-end': {
|
|
113
|
-
axis: 'inline',
|
|
114
|
-
edge: 'start',
|
|
115
|
-
align: 'end'
|
|
116
|
-
},
|
|
117
|
-
auto: {
|
|
118
|
-
axis: 'block',
|
|
119
|
-
edge: 'end',
|
|
120
|
-
align: 'center'
|
|
121
|
-
},
|
|
122
|
-
'auto-start': {
|
|
123
|
-
axis: 'block',
|
|
124
|
-
edge: 'end',
|
|
125
|
-
align: 'start'
|
|
126
|
-
},
|
|
127
|
-
'auto-end': {
|
|
128
|
-
axis: 'block',
|
|
129
|
-
edge: 'end',
|
|
130
|
-
align: 'end'
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Convert a legacy Popper.js placement to the new `position-area`-based Placement.
|
|
136
|
-
* Optional `offset` is the legacy Popper `[along, away]` tuple (also known as
|
|
137
|
-
* `[skidding, distance]`); negative `along` becomes `direction: 'backwards'`.
|
|
138
|
-
*
|
|
139
|
-
* The tuple keeps the historical popper names so call sites that already pass
|
|
140
|
-
* `[along, away]` migrate without thinking; the new internal field names
|
|
141
|
-
* (`gap` / `crossAxisShift`) are produced inside this adapter.
|
|
142
|
-
*/
|
|
143
48
|
export function fromLegacyPlacement(_ref) {
|
|
144
49
|
var legacy = _ref.legacy,
|
|
145
50
|
offset = _ref.offset;
|
|
@@ -160,9 +65,4 @@ export function fromLegacyPlacement(_ref) {
|
|
|
160
65
|
}
|
|
161
66
|
}
|
|
162
67
|
});
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* The full mapping record, exposed for consumers that need to iterate or introspect.
|
|
167
|
-
*/
|
|
168
|
-
export { placementMapping };
|
|
68
|
+
}
|