@atlaskit/top-layer 0.4.0 → 0.5.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.
- package/CHANGELOG.md +19 -0
- package/dist/cjs/animations/presets.js +2 -2
- package/dist/cjs/arrow/index.js +6 -6
- package/dist/cjs/entry-points/use-anchor-position.js +2 -2
- package/dist/cjs/internal/anchor-positioning-fallback.js +1 -1
- package/dist/cjs/internal/{use-anchor-positioning.js → use-anchor-position.js} +68 -24
- package/dist/cjs/popup/popup-content.js +2 -2
- package/dist/cjs/testing/polyfill.js +2 -2
- package/dist/es2019/animations/presets.js +1 -1
- package/dist/es2019/arrow/index.js +1 -1
- package/dist/es2019/entry-points/use-anchor-position.js +1 -1
- package/dist/es2019/internal/anchor-positioning-fallback.js +1 -1
- package/dist/es2019/internal/{use-anchor-positioning.js → use-anchor-position.js} +68 -25
- package/dist/es2019/popup/popup-content.js +1 -1
- package/dist/es2019/testing/polyfill.js +2 -2
- package/dist/esm/animations/presets.js +1 -1
- package/dist/esm/arrow/index.js +1 -1
- package/dist/esm/entry-points/use-anchor-position.js +1 -1
- package/dist/esm/internal/anchor-positioning-fallback.js +1 -1
- package/dist/esm/internal/{use-anchor-positioning.js → use-anchor-position.js} +69 -25
- package/dist/esm/popup/popup-content.js +1 -1
- package/dist/esm/testing/polyfill.js +2 -2
- package/dist/types/entry-points/use-anchor-position.d.ts +1 -1
- package/dist/{types-ts4.5/internal/use-anchor-positioning.d.ts → types/internal/use-anchor-position.d.ts} +20 -1
- package/dist/types/testing/polyfill.d.ts +1 -1
- package/dist/types-ts4.5/entry-points/use-anchor-position.d.ts +1 -1
- package/dist/{types/internal/use-anchor-positioning.d.ts → types-ts4.5/internal/use-anchor-position.d.ts} +20 -1
- package/dist/types-ts4.5/testing/polyfill.d.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @atlaskit/top-layer
|
|
2
2
|
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`693551fc3e8c4`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/693551fc3e8c4) -
|
|
8
|
+
useAnchorPosition no longer re-runs its positioning effect when a fresh placement object reference
|
|
9
|
+
with the same resolved shape is passed (eg an inline literal on every render). The hook
|
|
10
|
+
structurally compares the resolved placement and reuses the previous reference when the shape is
|
|
11
|
+
unchanged.
|
|
12
|
+
|
|
13
|
+
## 0.5.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- [`6e656fce5ceee`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6e656fce5ceee) -
|
|
18
|
+
Fix anchor positioning so multiple popovers can share the same trigger element. Previously the
|
|
19
|
+
second `useAnchorPosition` call on the same trigger would overwrite the first call's `anchor-name`
|
|
20
|
+
style, leaving the first popover unpositioned.
|
|
21
|
+
|
|
3
22
|
## 0.4.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
|
@@ -8,7 +8,7 @@ exports.dialogSlideUpAndFade = dialogSlideUpAndFade;
|
|
|
8
8
|
exports.fade = fade;
|
|
9
9
|
exports.scaleAndFade = scaleAndFade;
|
|
10
10
|
exports.slideAndFade = slideAndFade;
|
|
11
|
-
var
|
|
11
|
+
var _useAnchorPosition = require("../internal/use-anchor-position");
|
|
12
12
|
// ── slideAndFade ──
|
|
13
13
|
|
|
14
14
|
function getSlideAndFadeProperties(_ref) {
|
|
@@ -16,7 +16,7 @@ function getSlideAndFadeProperties(_ref) {
|
|
|
16
16
|
distance = _ref.distance;
|
|
17
17
|
var pos = "".concat(distance, "px");
|
|
18
18
|
var neg = "-".concat(distance, "px");
|
|
19
|
-
var _getPlacement = (0,
|
|
19
|
+
var _getPlacement = (0, _useAnchorPosition.getPlacement)({
|
|
20
20
|
placement: placement
|
|
21
21
|
}),
|
|
22
22
|
axis = _getPlacement.axis,
|
package/dist/cjs/arrow/index.js
CHANGED
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.arrow = void 0;
|
|
8
8
|
var _once = _interopRequireDefault(require("@atlaskit/ds-lib/once"));
|
|
9
|
-
var
|
|
9
|
+
var _useAnchorPosition = require("../internal/use-anchor-position");
|
|
10
10
|
/**
|
|
11
11
|
* CSS for popover arrows using the `clip-path: inset() margin-box` technique.
|
|
12
12
|
*
|
|
@@ -51,7 +51,7 @@ function positionAreaToRuleName(_ref) {
|
|
|
51
51
|
*/
|
|
52
52
|
function getTryFallbacks(_ref2) {
|
|
53
53
|
var placement = _ref2.placement;
|
|
54
|
-
var _getPlacement = (0,
|
|
54
|
+
var _getPlacement = (0, _useAnchorPosition.getPlacement)({
|
|
55
55
|
placement: placement
|
|
56
56
|
}),
|
|
57
57
|
axis = _getPlacement.axis,
|
|
@@ -61,7 +61,7 @@ function getTryFallbacks(_ref2) {
|
|
|
61
61
|
// Single-axis: only flip the edge
|
|
62
62
|
var _flippedEdge = edge === 'start' ? 'end' : 'start';
|
|
63
63
|
return positionAreaToRuleName({
|
|
64
|
-
positionArea: (0,
|
|
64
|
+
positionArea: (0, _useAnchorPosition.placementToPositionArea)({
|
|
65
65
|
placement: {
|
|
66
66
|
axis: axis,
|
|
67
67
|
edge: _flippedEdge
|
|
@@ -74,7 +74,7 @@ function getTryFallbacks(_ref2) {
|
|
|
74
74
|
var flippedEdge = edge === 'start' ? 'end' : 'start';
|
|
75
75
|
var flippedAlign = align === 'start' ? 'end' : 'start';
|
|
76
76
|
return [positionAreaToRuleName({
|
|
77
|
-
positionArea: (0,
|
|
77
|
+
positionArea: (0, _useAnchorPosition.placementToPositionArea)({
|
|
78
78
|
placement: {
|
|
79
79
|
axis: axis,
|
|
80
80
|
edge: flippedEdge,
|
|
@@ -82,7 +82,7 @@ function getTryFallbacks(_ref2) {
|
|
|
82
82
|
}
|
|
83
83
|
})
|
|
84
84
|
}), positionAreaToRuleName({
|
|
85
|
-
positionArea: (0,
|
|
85
|
+
positionArea: (0, _useAnchorPosition.placementToPositionArea)({
|
|
86
86
|
placement: {
|
|
87
87
|
axis: axis,
|
|
88
88
|
edge: edge,
|
|
@@ -90,7 +90,7 @@ function getTryFallbacks(_ref2) {
|
|
|
90
90
|
}
|
|
91
91
|
})
|
|
92
92
|
}), positionAreaToRuleName({
|
|
93
|
-
positionArea: (0,
|
|
93
|
+
positionArea: (0, _useAnchorPosition.placementToPositionArea)({
|
|
94
94
|
placement: {
|
|
95
95
|
axis: axis,
|
|
96
96
|
edge: flippedEdge,
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
Object.defineProperty(exports, "useAnchorPosition", {
|
|
7
7
|
enumerable: true,
|
|
8
8
|
get: function get() {
|
|
9
|
-
return
|
|
9
|
+
return _useAnchorPosition.useAnchorPosition;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
|
-
var
|
|
12
|
+
var _useAnchorPosition = require("../internal/use-anchor-position");
|
|
@@ -131,7 +131,7 @@ function applyAlignment(_ref2) {
|
|
|
131
131
|
* Applies the cross-axis shift offset.
|
|
132
132
|
*
|
|
133
133
|
* The sign mirrors the CSS path (see `crossAxisShiftMargin` in
|
|
134
|
-
* `use-anchor-
|
|
134
|
+
* `use-anchor-position.tsx`):
|
|
135
135
|
* - `align: 'start' | 'center'` + `forwards` → push toward end (positive)
|
|
136
136
|
* - `align: 'end'` + `forwards` → push toward start (negative)
|
|
137
137
|
* - `backwards` flips the sign in both cases.
|
|
@@ -210,6 +210,30 @@ function crossAxisShiftMargin(_ref4) {
|
|
|
210
210
|
};
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Returns a referentially-stable, fully-resolved `TPlacement`: the same
|
|
215
|
+
* reference is preserved across renders as long as the resolved shape
|
|
216
|
+
* does not change.
|
|
217
|
+
*/
|
|
218
|
+
function useStablePlacement(placement) {
|
|
219
|
+
var resolved = (0, _resolvePlacement.getPlacement)({
|
|
220
|
+
placement: placement
|
|
221
|
+
});
|
|
222
|
+
var stableRef = (0, _react.useRef)(resolved);
|
|
223
|
+
if (!isResolvedPlacementEqual(stableRef.current, resolved)) {
|
|
224
|
+
stableRef.current = resolved;
|
|
225
|
+
}
|
|
226
|
+
return stableRef.current;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Shallow-equals two fully-resolved placements. Avoids `JSON.stringify` so
|
|
231
|
+
* the comparison cost stays proportional to the number of fields.
|
|
232
|
+
*/
|
|
233
|
+
function isResolvedPlacementEqual(a, b) {
|
|
234
|
+
return a.axis === b.axis && a.edge === b.edge && a.align === b.align && a.offset.gap === b.offset.gap && a.offset.crossAxisShift.value === b.offset.crossAxisShift.value && a.offset.crossAxisShift.direction === b.offset.crossAxisShift.direction;
|
|
235
|
+
}
|
|
236
|
+
|
|
213
237
|
/**
|
|
214
238
|
* Hook that positions an element relative to an anchor element using
|
|
215
239
|
* CSS Anchor Positioning (with a JS fallback for older browsers).
|
|
@@ -225,37 +249,44 @@ function crossAxisShiftMargin(_ref4) {
|
|
|
225
249
|
* When not supported, it falls back to JavaScript-based positioning using
|
|
226
250
|
* `position: fixed` with measured coordinates, re-running on scroll (capture)
|
|
227
251
|
* and resize events.
|
|
252
|
+
*
|
|
253
|
+
* `placement` may be a fresh inline object on every render: a structural
|
|
254
|
+
* comparison is used internally so re-runs are skipped when the resolved
|
|
255
|
+
* placement shape is unchanged.
|
|
228
256
|
*/
|
|
229
257
|
function useAnchorPosition(_ref5) {
|
|
230
258
|
var anchorRef = _ref5.anchorRef,
|
|
231
259
|
popoverRef = _ref5.popoverRef,
|
|
232
|
-
placement = _ref5.placement,
|
|
260
|
+
_ref5$placement = _ref5.placement,
|
|
261
|
+
placement = _ref5$placement === void 0 ? {} : _ref5$placement,
|
|
233
262
|
_ref5$forceFallbackPo = _ref5.forceFallbackPositioning,
|
|
234
263
|
forceFallbackPositioning = _ref5$forceFallbackPo === void 0 ? false : _ref5$forceFallbackPo,
|
|
235
264
|
arrow = _ref5.arrow;
|
|
236
265
|
var id = (0, _react.useId)();
|
|
237
|
-
|
|
266
|
+
// Stabilize `placement` object so the same object literal
|
|
267
|
+
// value returns an object with the same reference
|
|
268
|
+
var stablePlacement = useStablePlacement(placement);
|
|
238
269
|
(0, _react.useLayoutEffect)(function () {
|
|
239
270
|
var trigger = anchorRef.current;
|
|
240
271
|
var popover = popoverRef.current;
|
|
241
272
|
if (!trigger || !popover) {
|
|
242
273
|
return;
|
|
243
274
|
}
|
|
244
|
-
var
|
|
245
|
-
|
|
246
|
-
});
|
|
247
|
-
var gapCssValue = resolvedPlacement.offset.gap;
|
|
248
|
-
var crossAxisShiftCssValue = resolvedPlacement.offset.crossAxisShift.value;
|
|
275
|
+
var gapCssValue = stablePlacement.offset.gap;
|
|
276
|
+
var crossAxisShiftCssValue = stablePlacement.offset.crossAxisShift.value;
|
|
249
277
|
var shouldForceFallback = Boolean(forceFallbackPositioning);
|
|
250
278
|
if (supportsAnchorPositioning() && !shouldForceFallback) {
|
|
279
|
+
// Reuse an existing `anchor-name` if the element already has one.
|
|
280
|
+
// Another popover might already be anchored to the old name.
|
|
281
|
+
var anchorName = trigger.style.getPropertyValue('anchor-name') || "--anchor-".concat(id.replace(/:/g, ''));
|
|
251
282
|
var gap = edgeMargin({
|
|
252
|
-
placement:
|
|
283
|
+
placement: stablePlacement,
|
|
253
284
|
offset: gapCssValue
|
|
254
285
|
});
|
|
255
286
|
var crossAxisShift = crossAxisShiftMargin({
|
|
256
|
-
placement:
|
|
287
|
+
placement: stablePlacement,
|
|
257
288
|
crossAxisShiftCssValue: crossAxisShiftCssValue,
|
|
258
|
-
direction:
|
|
289
|
+
direction: stablePlacement.offset.crossAxisShift.direction
|
|
259
290
|
});
|
|
260
291
|
var popoverStyles = [{
|
|
261
292
|
property: 'position-anchor',
|
|
@@ -263,14 +294,14 @@ function useAnchorPosition(_ref5) {
|
|
|
263
294
|
}, {
|
|
264
295
|
property: 'position-area',
|
|
265
296
|
value: placementToPositionArea({
|
|
266
|
-
placement:
|
|
297
|
+
placement: stablePlacement
|
|
267
298
|
})
|
|
268
299
|
}, {
|
|
269
300
|
property: 'position-try-fallbacks',
|
|
270
301
|
value: arrow ? arrow.getTryFallbacks({
|
|
271
|
-
placement:
|
|
302
|
+
placement: stablePlacement
|
|
272
303
|
}) : placementToTryFallbacks({
|
|
273
|
-
placement:
|
|
304
|
+
placement: stablePlacement
|
|
274
305
|
})
|
|
275
306
|
},
|
|
276
307
|
// Reset browser default popover positioning that conflicts
|
|
@@ -314,9 +345,9 @@ function useAnchorPosition(_ref5) {
|
|
|
314
345
|
value: '0px'
|
|
315
346
|
});
|
|
316
347
|
var crossAxisShiftActive = crossAxisShiftMargin({
|
|
317
|
-
placement:
|
|
348
|
+
placement: stablePlacement,
|
|
318
349
|
crossAxisShiftCssValue: crossAxisShiftCssValue,
|
|
319
|
-
direction:
|
|
350
|
+
direction: stablePlacement.offset.crossAxisShift.direction
|
|
320
351
|
});
|
|
321
352
|
// Map margin property to its corresponding custom property name.
|
|
322
353
|
var customPropertyByMarginProperty = {
|
|
@@ -345,13 +376,26 @@ function useAnchorPosition(_ref5) {
|
|
|
345
376
|
// because that's where useAnchorPosition sets the margin gap.
|
|
346
377
|
popover.setAttribute('data-ds-popover-arrow', '');
|
|
347
378
|
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* **We are never cleaning up anchor names**
|
|
382
|
+
*
|
|
383
|
+
* _Rationale_
|
|
384
|
+
*
|
|
385
|
+
* - Multiple popovers can share the same anchor element.
|
|
386
|
+
* - Sometimes the `useAnchorPosition` hook and `Popover`
|
|
387
|
+
* are not in the same component.
|
|
388
|
+
* - There can be times when, even with reference counting, we
|
|
389
|
+
* could remove the anchor-name while it's still being used
|
|
390
|
+
* by something else - especially with async react updates
|
|
391
|
+
* which can cause tearing
|
|
392
|
+
*
|
|
393
|
+
* _More_
|
|
394
|
+
*
|
|
395
|
+
* See `notes/decisions/anchor-name-lifetime.md`
|
|
396
|
+
*/
|
|
397
|
+
trigger.style.setProperty('anchor-name', anchorName);
|
|
348
398
|
var _undoPositioning = (0, _combine.combine)((0, _setStyle.setStyle)({
|
|
349
|
-
el: trigger,
|
|
350
|
-
styles: [{
|
|
351
|
-
property: 'anchor-name',
|
|
352
|
-
value: anchorName
|
|
353
|
-
}]
|
|
354
|
-
}), (0, _setStyle.setStyle)({
|
|
355
399
|
el: popover,
|
|
356
400
|
styles: popoverStyles
|
|
357
401
|
}), arrow ? function () {
|
|
@@ -403,12 +447,12 @@ function useAnchorPosition(_ref5) {
|
|
|
403
447
|
var _computeFallbackPosit = (0, _anchorPositioningFallback.computeFallbackPosition)({
|
|
404
448
|
triggerRect: triggerRect,
|
|
405
449
|
popoverEl: popover,
|
|
406
|
-
placement:
|
|
450
|
+
placement: stablePlacement,
|
|
407
451
|
viewport: viewport,
|
|
408
452
|
gap: gapPx,
|
|
409
453
|
crossAxisShift: {
|
|
410
454
|
value: crossAxisShiftPx,
|
|
411
|
-
direction:
|
|
455
|
+
direction: stablePlacement.offset.crossAxisShift.direction
|
|
412
456
|
}
|
|
413
457
|
}),
|
|
414
458
|
top = _computeFallbackPosit.top,
|
|
@@ -483,5 +527,5 @@ function useAnchorPosition(_ref5) {
|
|
|
483
527
|
popover.style.removeProperty('opacity');
|
|
484
528
|
});
|
|
485
529
|
return undoPositioning;
|
|
486
|
-
}, [anchorRef, popoverRef,
|
|
530
|
+
}, [anchorRef, popoverRef, stablePlacement, forceFallbackPositioning, arrow, id]);
|
|
487
531
|
}
|
|
@@ -12,7 +12,7 @@ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")
|
|
|
12
12
|
var _react = _interopRequireWildcard(require("react"));
|
|
13
13
|
var _mergeRefs = _interopRequireDefault(require("@atlaskit/ds-lib/merge-refs"));
|
|
14
14
|
var _roleTypes = require("../internal/role-types");
|
|
15
|
-
var
|
|
15
|
+
var _useAnchorPosition = require("../internal/use-anchor-position");
|
|
16
16
|
var _usePresetStyles = require("../internal/use-preset-styles");
|
|
17
17
|
var _popover = require("../popover/popover");
|
|
18
18
|
var _popupContext = require("./popup-context");
|
|
@@ -131,7 +131,7 @@ var PopupContent = exports.PopupContent = /*#__PURE__*/(0, _react.forwardRef)(fu
|
|
|
131
131
|
var arrowPreset = (0, _usePresetStyles.usePresetStyles)({
|
|
132
132
|
preset: arrow
|
|
133
133
|
});
|
|
134
|
-
(0,
|
|
134
|
+
(0, _useAnchorPosition.useAnchorPosition)({
|
|
135
135
|
anchorRef: triggerRef !== null && triggerRef !== void 0 ? triggerRef : {
|
|
136
136
|
current: null
|
|
137
137
|
},
|
|
@@ -17,7 +17,7 @@ var _bindEventListener = require("bind-event-listener");
|
|
|
17
17
|
* - Auto popovers: maintain an open stack, perform light-dismiss on document mousedown
|
|
18
18
|
* outside the open chain, and dismiss the topmost on Escape.
|
|
19
19
|
* - On open, removes any inline `opacity: 0` from the popover element so callers that
|
|
20
|
-
* rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-
|
|
20
|
+
* rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-position`) become
|
|
21
21
|
* visible in jsdom, where layout-driven RO callbacks never fire.
|
|
22
22
|
*
|
|
23
23
|
* Companion `toBeVisible` patch lives at `./to-be-visible`.
|
|
@@ -251,7 +251,7 @@ function stackForMode(_ref9) {
|
|
|
251
251
|
|
|
252
252
|
// Polyfill-only. Real browsers reveal the popover once `ResizeObserver`
|
|
253
253
|
// callbacks fire after the first layout pass. jsdom has no layout, so we clear
|
|
254
|
-
// any inline `opacity: 0` (set by callers like `use-anchor-
|
|
254
|
+
// any inline `opacity: 0` (set by callers like `use-anchor-position`) once
|
|
255
255
|
// the open toggle has fired.
|
|
256
256
|
function clearOpacityOnOpenToggle(_ref0) {
|
|
257
257
|
var element = _ref0.element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import once from '@atlaskit/ds-lib/once';
|
|
2
|
-
import { getPlacement, placementToPositionArea } from '../internal/use-anchor-
|
|
2
|
+
import { getPlacement, placementToPositionArea } from '../internal/use-anchor-position';
|
|
3
3
|
/**
|
|
4
4
|
* CSS for popover arrows using the `clip-path: inset() margin-box` technique.
|
|
5
5
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { useAnchorPosition } from '../internal/use-anchor-
|
|
1
|
+
export { useAnchorPosition } from '../internal/use-anchor-position';
|
|
@@ -127,7 +127,7 @@ function applyAlignment({
|
|
|
127
127
|
* Applies the cross-axis shift offset.
|
|
128
128
|
*
|
|
129
129
|
* The sign mirrors the CSS path (see `crossAxisShiftMargin` in
|
|
130
|
-
* `use-anchor-
|
|
130
|
+
* `use-anchor-position.tsx`):
|
|
131
131
|
* - `align: 'start' | 'center'` + `forwards` → push toward end (positive)
|
|
132
132
|
* - `align: 'end'` + `forwards` → push toward start (negative)
|
|
133
133
|
* - `backwards` flips the sign in both cases.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* popover with `opacity: 0` until the first measurement completes, so it
|
|
13
13
|
* is never painted at the wrong location.
|
|
14
14
|
*/
|
|
15
|
-
import { useId, useLayoutEffect } from 'react';
|
|
15
|
+
import { useId, useLayoutEffect, useRef } from 'react';
|
|
16
16
|
import { bind } from 'bind-event-listener';
|
|
17
17
|
import rafSchedule from 'raf-schd';
|
|
18
18
|
import once from '@atlaskit/ds-lib/once';
|
|
@@ -206,6 +206,30 @@ function crossAxisShiftMargin({
|
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Returns a referentially-stable, fully-resolved `TPlacement`: the same
|
|
211
|
+
* reference is preserved across renders as long as the resolved shape
|
|
212
|
+
* does not change.
|
|
213
|
+
*/
|
|
214
|
+
function useStablePlacement(placement) {
|
|
215
|
+
const resolved = getPlacement({
|
|
216
|
+
placement
|
|
217
|
+
});
|
|
218
|
+
const stableRef = useRef(resolved);
|
|
219
|
+
if (!isResolvedPlacementEqual(stableRef.current, resolved)) {
|
|
220
|
+
stableRef.current = resolved;
|
|
221
|
+
}
|
|
222
|
+
return stableRef.current;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Shallow-equals two fully-resolved placements. Avoids `JSON.stringify` so
|
|
227
|
+
* the comparison cost stays proportional to the number of fields.
|
|
228
|
+
*/
|
|
229
|
+
function isResolvedPlacementEqual(a, b) {
|
|
230
|
+
return a.axis === b.axis && a.edge === b.edge && a.align === b.align && a.offset.gap === b.offset.gap && a.offset.crossAxisShift.value === b.offset.crossAxisShift.value && a.offset.crossAxisShift.direction === b.offset.crossAxisShift.direction;
|
|
231
|
+
}
|
|
232
|
+
|
|
209
233
|
/**
|
|
210
234
|
* Hook that positions an element relative to an anchor element using
|
|
211
235
|
* CSS Anchor Positioning (with a JS fallback for older browsers).
|
|
@@ -221,37 +245,43 @@ function crossAxisShiftMargin({
|
|
|
221
245
|
* When not supported, it falls back to JavaScript-based positioning using
|
|
222
246
|
* `position: fixed` with measured coordinates, re-running on scroll (capture)
|
|
223
247
|
* and resize events.
|
|
248
|
+
*
|
|
249
|
+
* `placement` may be a fresh inline object on every render: a structural
|
|
250
|
+
* comparison is used internally so re-runs are skipped when the resolved
|
|
251
|
+
* placement shape is unchanged.
|
|
224
252
|
*/
|
|
225
253
|
export function useAnchorPosition({
|
|
226
254
|
anchorRef,
|
|
227
255
|
popoverRef,
|
|
228
|
-
placement,
|
|
256
|
+
placement = {},
|
|
229
257
|
forceFallbackPositioning = false,
|
|
230
258
|
arrow
|
|
231
259
|
}) {
|
|
232
260
|
const id = useId();
|
|
233
|
-
|
|
261
|
+
// Stabilize `placement` object so the same object literal
|
|
262
|
+
// value returns an object with the same reference
|
|
263
|
+
const stablePlacement = useStablePlacement(placement);
|
|
234
264
|
useLayoutEffect(() => {
|
|
235
265
|
const trigger = anchorRef.current;
|
|
236
266
|
const popover = popoverRef.current;
|
|
237
267
|
if (!trigger || !popover) {
|
|
238
268
|
return;
|
|
239
269
|
}
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
});
|
|
243
|
-
const gapCssValue = resolvedPlacement.offset.gap;
|
|
244
|
-
const crossAxisShiftCssValue = resolvedPlacement.offset.crossAxisShift.value;
|
|
270
|
+
const gapCssValue = stablePlacement.offset.gap;
|
|
271
|
+
const crossAxisShiftCssValue = stablePlacement.offset.crossAxisShift.value;
|
|
245
272
|
const shouldForceFallback = Boolean(forceFallbackPositioning);
|
|
246
273
|
if (supportsAnchorPositioning() && !shouldForceFallback) {
|
|
274
|
+
// Reuse an existing `anchor-name` if the element already has one.
|
|
275
|
+
// Another popover might already be anchored to the old name.
|
|
276
|
+
const anchorName = trigger.style.getPropertyValue('anchor-name') || `--anchor-${id.replace(/:/g, '')}`;
|
|
247
277
|
const gap = edgeMargin({
|
|
248
|
-
placement:
|
|
278
|
+
placement: stablePlacement,
|
|
249
279
|
offset: gapCssValue
|
|
250
280
|
});
|
|
251
281
|
const crossAxisShift = crossAxisShiftMargin({
|
|
252
|
-
placement:
|
|
282
|
+
placement: stablePlacement,
|
|
253
283
|
crossAxisShiftCssValue,
|
|
254
|
-
direction:
|
|
284
|
+
direction: stablePlacement.offset.crossAxisShift.direction
|
|
255
285
|
});
|
|
256
286
|
const popoverStyles = [{
|
|
257
287
|
property: 'position-anchor',
|
|
@@ -259,14 +289,14 @@ export function useAnchorPosition({
|
|
|
259
289
|
}, {
|
|
260
290
|
property: 'position-area',
|
|
261
291
|
value: placementToPositionArea({
|
|
262
|
-
placement:
|
|
292
|
+
placement: stablePlacement
|
|
263
293
|
})
|
|
264
294
|
}, {
|
|
265
295
|
property: 'position-try-fallbacks',
|
|
266
296
|
value: arrow ? arrow.getTryFallbacks({
|
|
267
|
-
placement:
|
|
297
|
+
placement: stablePlacement
|
|
268
298
|
}) : placementToTryFallbacks({
|
|
269
|
-
placement:
|
|
299
|
+
placement: stablePlacement
|
|
270
300
|
})
|
|
271
301
|
},
|
|
272
302
|
// Reset browser default popover positioning that conflicts
|
|
@@ -310,9 +340,9 @@ export function useAnchorPosition({
|
|
|
310
340
|
value: '0px'
|
|
311
341
|
});
|
|
312
342
|
const crossAxisShiftActive = crossAxisShiftMargin({
|
|
313
|
-
placement:
|
|
343
|
+
placement: stablePlacement,
|
|
314
344
|
crossAxisShiftCssValue,
|
|
315
|
-
direction:
|
|
345
|
+
direction: stablePlacement.offset.crossAxisShift.direction
|
|
316
346
|
});
|
|
317
347
|
// Map margin property to its corresponding custom property name.
|
|
318
348
|
const customPropertyByMarginProperty = {
|
|
@@ -341,13 +371,26 @@ export function useAnchorPosition({
|
|
|
341
371
|
// because that's where useAnchorPosition sets the margin gap.
|
|
342
372
|
popover.setAttribute('data-ds-popover-arrow', '');
|
|
343
373
|
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* **We are never cleaning up anchor names**
|
|
377
|
+
*
|
|
378
|
+
* _Rationale_
|
|
379
|
+
*
|
|
380
|
+
* - Multiple popovers can share the same anchor element.
|
|
381
|
+
* - Sometimes the `useAnchorPosition` hook and `Popover`
|
|
382
|
+
* are not in the same component.
|
|
383
|
+
* - There can be times when, even with reference counting, we
|
|
384
|
+
* could remove the anchor-name while it's still being used
|
|
385
|
+
* by something else - especially with async react updates
|
|
386
|
+
* which can cause tearing
|
|
387
|
+
*
|
|
388
|
+
* _More_
|
|
389
|
+
*
|
|
390
|
+
* See `notes/decisions/anchor-name-lifetime.md`
|
|
391
|
+
*/
|
|
392
|
+
trigger.style.setProperty('anchor-name', anchorName);
|
|
344
393
|
const undoPositioning = combine(setStyle({
|
|
345
|
-
el: trigger,
|
|
346
|
-
styles: [{
|
|
347
|
-
property: 'anchor-name',
|
|
348
|
-
value: anchorName
|
|
349
|
-
}]
|
|
350
|
-
}), setStyle({
|
|
351
394
|
el: popover,
|
|
352
395
|
styles: popoverStyles
|
|
353
396
|
}), arrow ? () => popover.removeAttribute('data-ds-popover-arrow') : () => {});
|
|
@@ -400,12 +443,12 @@ export function useAnchorPosition({
|
|
|
400
443
|
} = computeFallbackPosition({
|
|
401
444
|
triggerRect,
|
|
402
445
|
popoverEl: popover,
|
|
403
|
-
placement:
|
|
446
|
+
placement: stablePlacement,
|
|
404
447
|
viewport,
|
|
405
448
|
gap: gapPx,
|
|
406
449
|
crossAxisShift: {
|
|
407
450
|
value: crossAxisShiftPx,
|
|
408
|
-
direction:
|
|
451
|
+
direction: stablePlacement.offset.crossAxisShift.direction
|
|
409
452
|
}
|
|
410
453
|
});
|
|
411
454
|
popover.style.setProperty('top', `${top}px`);
|
|
@@ -476,5 +519,5 @@ export function useAnchorPosition({
|
|
|
476
519
|
popover.style.removeProperty('opacity');
|
|
477
520
|
});
|
|
478
521
|
return undoPositioning;
|
|
479
|
-
}, [anchorRef, popoverRef,
|
|
522
|
+
}, [anchorRef, popoverRef, stablePlacement, forceFallbackPositioning, arrow, id]);
|
|
480
523
|
}
|
|
@@ -4,7 +4,7 @@ import { ax, ix } from "@compiled/react/runtime";
|
|
|
4
4
|
import React, { forwardRef, useCallback, useLayoutEffect, useRef } from 'react';
|
|
5
5
|
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
6
6
|
import { roleToAriaHasPopup } from '../internal/role-types';
|
|
7
|
-
import { useAnchorPosition } from '../internal/use-anchor-
|
|
7
|
+
import { useAnchorPosition } from '../internal/use-anchor-position';
|
|
8
8
|
import { usePresetStyles } from '../internal/use-preset-styles';
|
|
9
9
|
import { Popover } from '../popover/popover';
|
|
10
10
|
import { useMaybePopupContext } from './popup-context';
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - Auto popovers: maintain an open stack, perform light-dismiss on document mousedown
|
|
15
15
|
* outside the open chain, and dismiss the topmost on Escape.
|
|
16
16
|
* - On open, removes any inline `opacity: 0` from the popover element so callers that
|
|
17
|
-
* rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-
|
|
17
|
+
* rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-position`) become
|
|
18
18
|
* visible in jsdom, where layout-driven RO callbacks never fire.
|
|
19
19
|
*
|
|
20
20
|
* Companion `toBeVisible` patch lives at `./to-be-visible`.
|
|
@@ -258,7 +258,7 @@ function stackForMode({
|
|
|
258
258
|
|
|
259
259
|
// Polyfill-only. Real browsers reveal the popover once `ResizeObserver`
|
|
260
260
|
// callbacks fire after the first layout pass. jsdom has no layout, so we clear
|
|
261
|
-
// any inline `opacity: 0` (set by callers like `use-anchor-
|
|
261
|
+
// any inline `opacity: 0` (set by callers like `use-anchor-position`) once
|
|
262
262
|
// the open toggle has fired.
|
|
263
263
|
function clearOpacityOnOpenToggle({
|
|
264
264
|
element
|
package/dist/esm/arrow/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import once from '@atlaskit/ds-lib/once';
|
|
2
|
-
import { getPlacement, placementToPositionArea } from '../internal/use-anchor-
|
|
2
|
+
import { getPlacement, placementToPositionArea } from '../internal/use-anchor-position';
|
|
3
3
|
/**
|
|
4
4
|
* CSS for popover arrows using the `clip-path: inset() margin-box` technique.
|
|
5
5
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { useAnchorPosition } from '../internal/use-anchor-
|
|
1
|
+
export { useAnchorPosition } from '../internal/use-anchor-position';
|
|
@@ -124,7 +124,7 @@ function applyAlignment(_ref2) {
|
|
|
124
124
|
* Applies the cross-axis shift offset.
|
|
125
125
|
*
|
|
126
126
|
* The sign mirrors the CSS path (see `crossAxisShiftMargin` in
|
|
127
|
-
* `use-anchor-
|
|
127
|
+
* `use-anchor-position.tsx`):
|
|
128
128
|
* - `align: 'start' | 'center'` + `forwards` → push toward end (positive)
|
|
129
129
|
* - `align: 'end'` + `forwards` → push toward start (negative)
|
|
130
130
|
* - `backwards` flips the sign in both cases.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* popover with `opacity: 0` until the first measurement completes, so it
|
|
13
13
|
* is never painted at the wrong location.
|
|
14
14
|
*/
|
|
15
|
-
import { useId, useLayoutEffect } from 'react';
|
|
15
|
+
import { useId, useLayoutEffect, useRef } from 'react';
|
|
16
16
|
import { bind } from 'bind-event-listener';
|
|
17
17
|
import rafSchedule from 'raf-schd';
|
|
18
18
|
import once from '@atlaskit/ds-lib/once';
|
|
@@ -196,6 +196,30 @@ function crossAxisShiftMargin(_ref4) {
|
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Returns a referentially-stable, fully-resolved `TPlacement`: the same
|
|
201
|
+
* reference is preserved across renders as long as the resolved shape
|
|
202
|
+
* does not change.
|
|
203
|
+
*/
|
|
204
|
+
function useStablePlacement(placement) {
|
|
205
|
+
var resolved = getPlacement({
|
|
206
|
+
placement: placement
|
|
207
|
+
});
|
|
208
|
+
var stableRef = useRef(resolved);
|
|
209
|
+
if (!isResolvedPlacementEqual(stableRef.current, resolved)) {
|
|
210
|
+
stableRef.current = resolved;
|
|
211
|
+
}
|
|
212
|
+
return stableRef.current;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Shallow-equals two fully-resolved placements. Avoids `JSON.stringify` so
|
|
217
|
+
* the comparison cost stays proportional to the number of fields.
|
|
218
|
+
*/
|
|
219
|
+
function isResolvedPlacementEqual(a, b) {
|
|
220
|
+
return a.axis === b.axis && a.edge === b.edge && a.align === b.align && a.offset.gap === b.offset.gap && a.offset.crossAxisShift.value === b.offset.crossAxisShift.value && a.offset.crossAxisShift.direction === b.offset.crossAxisShift.direction;
|
|
221
|
+
}
|
|
222
|
+
|
|
199
223
|
/**
|
|
200
224
|
* Hook that positions an element relative to an anchor element using
|
|
201
225
|
* CSS Anchor Positioning (with a JS fallback for older browsers).
|
|
@@ -211,37 +235,44 @@ function crossAxisShiftMargin(_ref4) {
|
|
|
211
235
|
* When not supported, it falls back to JavaScript-based positioning using
|
|
212
236
|
* `position: fixed` with measured coordinates, re-running on scroll (capture)
|
|
213
237
|
* and resize events.
|
|
238
|
+
*
|
|
239
|
+
* `placement` may be a fresh inline object on every render: a structural
|
|
240
|
+
* comparison is used internally so re-runs are skipped when the resolved
|
|
241
|
+
* placement shape is unchanged.
|
|
214
242
|
*/
|
|
215
243
|
export function useAnchorPosition(_ref5) {
|
|
216
244
|
var anchorRef = _ref5.anchorRef,
|
|
217
245
|
popoverRef = _ref5.popoverRef,
|
|
218
|
-
placement = _ref5.placement,
|
|
246
|
+
_ref5$placement = _ref5.placement,
|
|
247
|
+
placement = _ref5$placement === void 0 ? {} : _ref5$placement,
|
|
219
248
|
_ref5$forceFallbackPo = _ref5.forceFallbackPositioning,
|
|
220
249
|
forceFallbackPositioning = _ref5$forceFallbackPo === void 0 ? false : _ref5$forceFallbackPo,
|
|
221
250
|
arrow = _ref5.arrow;
|
|
222
251
|
var id = useId();
|
|
223
|
-
|
|
252
|
+
// Stabilize `placement` object so the same object literal
|
|
253
|
+
// value returns an object with the same reference
|
|
254
|
+
var stablePlacement = useStablePlacement(placement);
|
|
224
255
|
useLayoutEffect(function () {
|
|
225
256
|
var trigger = anchorRef.current;
|
|
226
257
|
var popover = popoverRef.current;
|
|
227
258
|
if (!trigger || !popover) {
|
|
228
259
|
return;
|
|
229
260
|
}
|
|
230
|
-
var
|
|
231
|
-
|
|
232
|
-
});
|
|
233
|
-
var gapCssValue = resolvedPlacement.offset.gap;
|
|
234
|
-
var crossAxisShiftCssValue = resolvedPlacement.offset.crossAxisShift.value;
|
|
261
|
+
var gapCssValue = stablePlacement.offset.gap;
|
|
262
|
+
var crossAxisShiftCssValue = stablePlacement.offset.crossAxisShift.value;
|
|
235
263
|
var shouldForceFallback = Boolean(forceFallbackPositioning);
|
|
236
264
|
if (supportsAnchorPositioning() && !shouldForceFallback) {
|
|
265
|
+
// Reuse an existing `anchor-name` if the element already has one.
|
|
266
|
+
// Another popover might already be anchored to the old name.
|
|
267
|
+
var anchorName = trigger.style.getPropertyValue('anchor-name') || "--anchor-".concat(id.replace(/:/g, ''));
|
|
237
268
|
var gap = edgeMargin({
|
|
238
|
-
placement:
|
|
269
|
+
placement: stablePlacement,
|
|
239
270
|
offset: gapCssValue
|
|
240
271
|
});
|
|
241
272
|
var crossAxisShift = crossAxisShiftMargin({
|
|
242
|
-
placement:
|
|
273
|
+
placement: stablePlacement,
|
|
243
274
|
crossAxisShiftCssValue: crossAxisShiftCssValue,
|
|
244
|
-
direction:
|
|
275
|
+
direction: stablePlacement.offset.crossAxisShift.direction
|
|
245
276
|
});
|
|
246
277
|
var popoverStyles = [{
|
|
247
278
|
property: 'position-anchor',
|
|
@@ -249,14 +280,14 @@ export function useAnchorPosition(_ref5) {
|
|
|
249
280
|
}, {
|
|
250
281
|
property: 'position-area',
|
|
251
282
|
value: placementToPositionArea({
|
|
252
|
-
placement:
|
|
283
|
+
placement: stablePlacement
|
|
253
284
|
})
|
|
254
285
|
}, {
|
|
255
286
|
property: 'position-try-fallbacks',
|
|
256
287
|
value: arrow ? arrow.getTryFallbacks({
|
|
257
|
-
placement:
|
|
288
|
+
placement: stablePlacement
|
|
258
289
|
}) : placementToTryFallbacks({
|
|
259
|
-
placement:
|
|
290
|
+
placement: stablePlacement
|
|
260
291
|
})
|
|
261
292
|
},
|
|
262
293
|
// Reset browser default popover positioning that conflicts
|
|
@@ -300,9 +331,9 @@ export function useAnchorPosition(_ref5) {
|
|
|
300
331
|
value: '0px'
|
|
301
332
|
});
|
|
302
333
|
var crossAxisShiftActive = crossAxisShiftMargin({
|
|
303
|
-
placement:
|
|
334
|
+
placement: stablePlacement,
|
|
304
335
|
crossAxisShiftCssValue: crossAxisShiftCssValue,
|
|
305
|
-
direction:
|
|
336
|
+
direction: stablePlacement.offset.crossAxisShift.direction
|
|
306
337
|
});
|
|
307
338
|
// Map margin property to its corresponding custom property name.
|
|
308
339
|
var customPropertyByMarginProperty = {
|
|
@@ -331,13 +362,26 @@ export function useAnchorPosition(_ref5) {
|
|
|
331
362
|
// because that's where useAnchorPosition sets the margin gap.
|
|
332
363
|
popover.setAttribute('data-ds-popover-arrow', '');
|
|
333
364
|
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* **We are never cleaning up anchor names**
|
|
368
|
+
*
|
|
369
|
+
* _Rationale_
|
|
370
|
+
*
|
|
371
|
+
* - Multiple popovers can share the same anchor element.
|
|
372
|
+
* - Sometimes the `useAnchorPosition` hook and `Popover`
|
|
373
|
+
* are not in the same component.
|
|
374
|
+
* - There can be times when, even with reference counting, we
|
|
375
|
+
* could remove the anchor-name while it's still being used
|
|
376
|
+
* by something else - especially with async react updates
|
|
377
|
+
* which can cause tearing
|
|
378
|
+
*
|
|
379
|
+
* _More_
|
|
380
|
+
*
|
|
381
|
+
* See `notes/decisions/anchor-name-lifetime.md`
|
|
382
|
+
*/
|
|
383
|
+
trigger.style.setProperty('anchor-name', anchorName);
|
|
334
384
|
var _undoPositioning = combine(setStyle({
|
|
335
|
-
el: trigger,
|
|
336
|
-
styles: [{
|
|
337
|
-
property: 'anchor-name',
|
|
338
|
-
value: anchorName
|
|
339
|
-
}]
|
|
340
|
-
}), setStyle({
|
|
341
385
|
el: popover,
|
|
342
386
|
styles: popoverStyles
|
|
343
387
|
}), arrow ? function () {
|
|
@@ -389,12 +433,12 @@ export function useAnchorPosition(_ref5) {
|
|
|
389
433
|
var _computeFallbackPosit = computeFallbackPosition({
|
|
390
434
|
triggerRect: triggerRect,
|
|
391
435
|
popoverEl: popover,
|
|
392
|
-
placement:
|
|
436
|
+
placement: stablePlacement,
|
|
393
437
|
viewport: viewport,
|
|
394
438
|
gap: gapPx,
|
|
395
439
|
crossAxisShift: {
|
|
396
440
|
value: crossAxisShiftPx,
|
|
397
|
-
direction:
|
|
441
|
+
direction: stablePlacement.offset.crossAxisShift.direction
|
|
398
442
|
}
|
|
399
443
|
}),
|
|
400
444
|
top = _computeFallbackPosit.top,
|
|
@@ -469,5 +513,5 @@ export function useAnchorPosition(_ref5) {
|
|
|
469
513
|
popover.style.removeProperty('opacity');
|
|
470
514
|
});
|
|
471
515
|
return undoPositioning;
|
|
472
|
-
}, [anchorRef, popoverRef,
|
|
516
|
+
}, [anchorRef, popoverRef, stablePlacement, forceFallbackPositioning, arrow, id]);
|
|
473
517
|
}
|
|
@@ -4,7 +4,7 @@ import { ax, ix } from "@compiled/react/runtime";
|
|
|
4
4
|
import React, { forwardRef, useCallback, useLayoutEffect, useRef } from 'react';
|
|
5
5
|
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
6
6
|
import { roleToAriaHasPopup } from '../internal/role-types';
|
|
7
|
-
import { useAnchorPosition } from '../internal/use-anchor-
|
|
7
|
+
import { useAnchorPosition } from '../internal/use-anchor-position';
|
|
8
8
|
import { usePresetStyles } from '../internal/use-preset-styles';
|
|
9
9
|
import { Popover } from '../popover/popover';
|
|
10
10
|
import { useMaybePopupContext } from './popup-context';
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - Auto popovers: maintain an open stack, perform light-dismiss on document mousedown
|
|
15
15
|
* outside the open chain, and dismiss the topmost on Escape.
|
|
16
16
|
* - On open, removes any inline `opacity: 0` from the popover element so callers that
|
|
17
|
-
* rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-
|
|
17
|
+
* rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-position`) become
|
|
18
18
|
* visible in jsdom, where layout-driven RO callbacks never fire.
|
|
19
19
|
*
|
|
20
20
|
* Companion `toBeVisible` patch lives at `./to-be-visible`.
|
|
@@ -249,7 +249,7 @@ function stackForMode(_ref9) {
|
|
|
249
249
|
|
|
250
250
|
// Polyfill-only. Real browsers reveal the popover once `ResizeObserver`
|
|
251
251
|
// callbacks fire after the first layout pass. jsdom has no layout, so we clear
|
|
252
|
-
// any inline `opacity: 0` (set by callers like `use-anchor-
|
|
252
|
+
// any inline `opacity: 0` (set by callers like `use-anchor-position`) once
|
|
253
253
|
// the open toggle has fired.
|
|
254
254
|
function clearOpacityOnOpenToggle(_ref0) {
|
|
255
255
|
var element = _ref0.element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { useAnchorPosition } from '../internal/use-anchor-
|
|
1
|
+
export { useAnchorPosition } from '../internal/use-anchor-position';
|
|
@@ -72,6 +72,10 @@ export declare function placementToTryFallbacks({ placement }: {
|
|
|
72
72
|
* When not supported, it falls back to JavaScript-based positioning using
|
|
73
73
|
* `position: fixed` with measured coordinates, re-running on scroll (capture)
|
|
74
74
|
* and resize events.
|
|
75
|
+
*
|
|
76
|
+
* `placement` may be a fresh inline object on every render: a structural
|
|
77
|
+
* comparison is used internally so re-runs are skipped when the resolved
|
|
78
|
+
* placement shape is unchanged.
|
|
75
79
|
*/
|
|
76
80
|
export declare function useAnchorPosition({ anchorRef, popoverRef, placement, forceFallbackPositioning, arrow, }: {
|
|
77
81
|
/**
|
|
@@ -86,8 +90,23 @@ export declare function useAnchorPosition({ anchorRef, popoverRef, placement, fo
|
|
|
86
90
|
* Where to place the element relative to the anchor.
|
|
87
91
|
* `offset.gap` and `offset.crossAxisShift` are part of the
|
|
88
92
|
* placement object.
|
|
93
|
+
*
|
|
94
|
+
* All fields are optional. Omitted fields fall back to:
|
|
95
|
+
* - `axis`: `'block'`
|
|
96
|
+
* - `edge`: `'end'`
|
|
97
|
+
* - `align`: `'center'`
|
|
98
|
+
* - `offset.gap`: `token('space.100', '8px')`
|
|
99
|
+
* - `offset.crossAxisShift.value`: `'0px'`
|
|
100
|
+
* - `offset.crossAxisShift.direction`: `'forwards'`
|
|
101
|
+
*
|
|
102
|
+
* The full default placement (`{}`) renders the popover centered
|
|
103
|
+
* below the trigger with one `space.100` of gap and no cross-axis
|
|
104
|
+
* shift.
|
|
105
|
+
*
|
|
106
|
+
* `offset.gap` and `offset.crossAxisShift.value` accept either a
|
|
107
|
+
* number (pixels) or a CSS length string (eg `token('space.200')`).
|
|
89
108
|
*/
|
|
90
|
-
placement
|
|
109
|
+
placement?: TPlacementOptions;
|
|
91
110
|
/**
|
|
92
111
|
* Forces the JavaScript positioning fallback even when the browser
|
|
93
112
|
* supports CSS Anchor Positioning. Useful for testing fallback
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - Auto popovers: maintain an open stack, perform light-dismiss on document mousedown
|
|
14
14
|
* outside the open chain, and dismiss the topmost on Escape.
|
|
15
15
|
* - On open, removes any inline `opacity: 0` from the popover element so callers that
|
|
16
|
-
* rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-
|
|
16
|
+
* rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-position`) become
|
|
17
17
|
* visible in jsdom, where layout-driven RO callbacks never fire.
|
|
18
18
|
*
|
|
19
19
|
* Companion `toBeVisible` patch lives at `./to-be-visible`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { useAnchorPosition } from '../internal/use-anchor-
|
|
1
|
+
export { useAnchorPosition } from '../internal/use-anchor-position';
|
|
@@ -72,6 +72,10 @@ export declare function placementToTryFallbacks({ placement }: {
|
|
|
72
72
|
* When not supported, it falls back to JavaScript-based positioning using
|
|
73
73
|
* `position: fixed` with measured coordinates, re-running on scroll (capture)
|
|
74
74
|
* and resize events.
|
|
75
|
+
*
|
|
76
|
+
* `placement` may be a fresh inline object on every render: a structural
|
|
77
|
+
* comparison is used internally so re-runs are skipped when the resolved
|
|
78
|
+
* placement shape is unchanged.
|
|
75
79
|
*/
|
|
76
80
|
export declare function useAnchorPosition({ anchorRef, popoverRef, placement, forceFallbackPositioning, arrow, }: {
|
|
77
81
|
/**
|
|
@@ -86,8 +90,23 @@ export declare function useAnchorPosition({ anchorRef, popoverRef, placement, fo
|
|
|
86
90
|
* Where to place the element relative to the anchor.
|
|
87
91
|
* `offset.gap` and `offset.crossAxisShift` are part of the
|
|
88
92
|
* placement object.
|
|
93
|
+
*
|
|
94
|
+
* All fields are optional. Omitted fields fall back to:
|
|
95
|
+
* - `axis`: `'block'`
|
|
96
|
+
* - `edge`: `'end'`
|
|
97
|
+
* - `align`: `'center'`
|
|
98
|
+
* - `offset.gap`: `token('space.100', '8px')`
|
|
99
|
+
* - `offset.crossAxisShift.value`: `'0px'`
|
|
100
|
+
* - `offset.crossAxisShift.direction`: `'forwards'`
|
|
101
|
+
*
|
|
102
|
+
* The full default placement (`{}`) renders the popover centered
|
|
103
|
+
* below the trigger with one `space.100` of gap and no cross-axis
|
|
104
|
+
* shift.
|
|
105
|
+
*
|
|
106
|
+
* `offset.gap` and `offset.crossAxisShift.value` accept either a
|
|
107
|
+
* number (pixels) or a CSS length string (eg `token('space.200')`).
|
|
89
108
|
*/
|
|
90
|
-
placement
|
|
109
|
+
placement?: TPlacementOptions;
|
|
91
110
|
/**
|
|
92
111
|
* Forces the JavaScript positioning fallback even when the browser
|
|
93
112
|
* supports CSS Anchor Positioning. Useful for testing fallback
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - Auto popovers: maintain an open stack, perform light-dismiss on document mousedown
|
|
14
14
|
* outside the open chain, and dismiss the topmost on Escape.
|
|
15
15
|
* - On open, removes any inline `opacity: 0` from the popover element so callers that
|
|
16
|
-
* rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-
|
|
16
|
+
* rely on a `ResizeObserver` reveal callback (e.g. `use-anchor-position`) become
|
|
17
17
|
* visible in jsdom, where layout-driven RO callbacks never fire.
|
|
18
18
|
*
|
|
19
19
|
* Companion `toBeVisible` patch lives at `./to-be-visible`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/top-layer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Low-level layering primitives based on popover and dialog",
|
|
5
5
|
"homepage": "https://atlassian.design/components/top-layer",
|
|
6
6
|
"repository": "https://bitbucket.org/atlassian/atlassian-frontend-mirror",
|