@atlaskit/top-layer 4.4.5 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/CHANGELOG.md +41 -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/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
  15. package/dist/cjs/internal/javascript-fallback/apply-javascript-fallback-positioning.js +297 -0
  16. package/dist/cjs/internal/javascript-fallback/resolve-css-length-to-pixels.js +90 -0
  17. package/dist/cjs/internal/javascript-fallback/warn-fallback-failure.js +19 -0
  18. package/dist/cjs/internal/resolve-placement.js +14 -6
  19. package/dist/cjs/internal/supports-anchor-positioning.js +17 -0
  20. package/dist/cjs/internal/supports-anchor-size.js +17 -0
  21. package/dist/cjs/internal/supports-css-declaration.js +25 -0
  22. package/dist/cjs/internal/surface-reset.js +5 -0
  23. package/dist/cjs/internal/use-anchored-popover-at-point.js +124 -0
  24. package/dist/cjs/internal/use-anchored-popover.js +277 -0
  25. package/dist/cjs/popover/popover.compiled.css +4 -0
  26. package/dist/cjs/popover/popover.js +11 -4
  27. package/dist/cjs/testing/polyfill.js +6 -7
  28. package/dist/es2019/dialog/dialog-content.js +2 -0
  29. package/dist/es2019/entry-points/use-popover-id.js +6 -10
  30. package/dist/es2019/internal/anchor-positioning/apply-anchor-positioning.js +83 -0
  31. package/dist/es2019/internal/anchor-positioning/cross-axis-shift-margins.js +29 -0
  32. package/dist/es2019/internal/anchor-positioning/edge-margin.js +18 -0
  33. package/dist/es2019/internal/anchor-positioning/fit-margins.js +69 -0
  34. package/dist/es2019/internal/anchor-positioning/get-existing-anchor-name.js +12 -0
  35. package/dist/es2019/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +9 -9
  36. package/dist/es2019/internal/anchor-positioning/placement-to-try-fallbacks.js +94 -0
  37. package/dist/es2019/internal/anchored-popover-size.js +343 -0
  38. package/dist/es2019/internal/get-aria-for-trigger.js +7 -13
  39. package/dist/es2019/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
  40. package/dist/es2019/internal/javascript-fallback/apply-javascript-fallback-positioning.js +291 -0
  41. package/dist/es2019/internal/javascript-fallback/resolve-css-length-to-pixels.js +87 -0
  42. package/dist/es2019/internal/javascript-fallback/warn-fallback-failure.js +14 -0
  43. package/dist/es2019/internal/resolve-placement.js +14 -6
  44. package/dist/es2019/internal/supports-anchor-positioning.js +12 -0
  45. package/dist/es2019/internal/supports-anchor-size.js +12 -0
  46. package/dist/es2019/internal/supports-css-declaration.js +20 -0
  47. package/dist/es2019/internal/surface-reset.js +1 -0
  48. package/dist/es2019/internal/use-anchored-popover-at-point.js +116 -0
  49. package/dist/es2019/internal/use-anchored-popover.js +265 -0
  50. package/dist/es2019/popover/popover.compiled.css +4 -0
  51. package/dist/es2019/popover/popover.js +11 -4
  52. package/dist/es2019/testing/polyfill.js +6 -7
  53. package/dist/esm/dialog/dialog-content.js +2 -0
  54. package/dist/esm/entry-points/use-popover-id.js +6 -10
  55. package/dist/esm/internal/anchor-positioning/apply-anchor-positioning.js +80 -0
  56. package/dist/esm/internal/anchor-positioning/cross-axis-shift-margins.js +28 -0
  57. package/dist/esm/internal/anchor-positioning/edge-margin.js +15 -0
  58. package/dist/esm/internal/anchor-positioning/fit-margins.js +71 -0
  59. package/dist/esm/internal/anchor-positioning/get-existing-anchor-name.js +12 -0
  60. package/dist/esm/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +11 -12
  61. package/dist/esm/internal/anchor-positioning/placement-to-try-fallbacks.js +89 -0
  62. package/dist/esm/internal/anchored-popover-size.js +338 -0
  63. package/dist/esm/internal/get-aria-for-trigger.js +7 -13
  64. package/dist/esm/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
  65. package/dist/esm/internal/javascript-fallback/apply-javascript-fallback-positioning.js +290 -0
  66. package/dist/esm/internal/javascript-fallback/resolve-css-length-to-pixels.js +85 -0
  67. package/dist/esm/internal/javascript-fallback/warn-fallback-failure.js +13 -0
  68. package/dist/esm/internal/resolve-placement.js +14 -6
  69. package/dist/esm/internal/supports-anchor-positioning.js +12 -0
  70. package/dist/esm/internal/supports-anchor-size.js +12 -0
  71. package/dist/esm/internal/supports-css-declaration.js +19 -0
  72. package/dist/esm/internal/surface-reset.js +1 -0
  73. package/dist/esm/internal/use-anchored-popover-at-point.js +118 -0
  74. package/dist/esm/internal/use-anchored-popover.js +271 -0
  75. package/dist/esm/popover/popover.compiled.css +4 -0
  76. package/dist/esm/popover/popover.js +11 -4
  77. package/dist/esm/testing/polyfill.js +6 -7
  78. package/dist/types/entry-points/placement-map.d.ts +2 -2
  79. package/dist/types/entry-points/use-popover-id.d.ts +3 -7
  80. package/dist/types/internal/anchor-positioning/apply-anchor-positioning.d.ts +26 -0
  81. package/dist/types/internal/anchor-positioning/cross-axis-shift-margins.d.ts +19 -0
  82. package/dist/types/internal/anchor-positioning/edge-margin.d.ts +10 -0
  83. package/dist/types/internal/anchor-positioning/fit-margins.d.ts +30 -0
  84. package/dist/types/internal/anchor-positioning/get-existing-anchor-name.d.ts +8 -0
  85. package/dist/types/internal/{placement-to-position-area.d.ts → anchor-positioning/placement-to-position-area.d.ts} +10 -6
  86. package/dist/types/internal/anchor-positioning/placement-to-try-fallbacks.d.ts +30 -0
  87. package/dist/types/internal/anchored-popover-size.d.ts +126 -0
  88. package/dist/types/internal/get-aria-for-trigger.d.ts +13 -25
  89. package/dist/types/internal/javascript-fallback/anchor-positioning-fallback.d.ts +36 -0
  90. package/dist/types/internal/javascript-fallback/apply-javascript-fallback-positioning.d.ts +15 -0
  91. package/dist/types/internal/javascript-fallback/resolve-css-length-to-pixels.d.ts +20 -0
  92. package/dist/types/internal/javascript-fallback/warn-fallback-failure.d.ts +7 -0
  93. package/dist/types/internal/resolve-placement.d.ts +18 -2
  94. package/dist/types/internal/supports-anchor-positioning.d.ts +5 -0
  95. package/dist/types/internal/supports-anchor-size.d.ts +5 -0
  96. package/dist/types/internal/supports-css-declaration.d.ts +11 -0
  97. package/dist/types/internal/surface-reset.d.ts +25 -0
  98. package/dist/types/internal/use-anchored-popover-at-point.d.ts +48 -0
  99. package/dist/types/internal/use-anchored-popover.d.ts +143 -0
  100. package/dist/types/popover/index.d.ts +2 -1
  101. package/dist/types/popover/popover.d.ts +1 -1
  102. package/dist/types/popover/types.d.ts +15 -17
  103. package/dist/types/testing/polyfill.d.ts +3 -3
  104. package/package.json +2 -2
  105. package/use-anchored-popover/package.json +10 -0
  106. package/use-anchored-popover-at-point/package.json +10 -0
  107. package/dist/cjs/internal/placement-to-try-fallbacks.js +0 -108
  108. package/dist/cjs/internal/resolve-css-length-to-pixels.js +0 -104
  109. package/dist/cjs/internal/use-anchor-position-at-point.js +0 -129
  110. package/dist/cjs/internal/use-anchor-position.js +0 -501
  111. package/dist/cjs/internal/use-width-from-anchor.js +0 -124
  112. package/dist/es2019/internal/placement-to-try-fallbacks.js +0 -108
  113. package/dist/es2019/internal/resolve-css-length-to-pixels.js +0 -101
  114. package/dist/es2019/internal/use-anchor-position-at-point.js +0 -124
  115. package/dist/es2019/internal/use-anchor-position.js +0 -480
  116. package/dist/es2019/internal/use-width-from-anchor.js +0 -120
  117. package/dist/esm/internal/placement-to-try-fallbacks.js +0 -103
  118. package/dist/esm/internal/resolve-css-length-to-pixels.js +0 -98
  119. package/dist/esm/internal/use-anchor-position-at-point.js +0 -124
  120. package/dist/esm/internal/use-anchor-position.js +0 -494
  121. package/dist/esm/internal/use-width-from-anchor.js +0 -118
  122. package/dist/types/internal/anchor-positioning-fallback.d.ts +0 -51
  123. package/dist/types/internal/placement-to-try-fallbacks.d.ts +0 -13
  124. package/dist/types/internal/resolve-css-length-to-pixels.d.ts +0 -20
  125. package/dist/types/internal/use-anchor-position-at-point.d.ts +0 -67
  126. package/dist/types/internal/use-anchor-position.d.ts +0 -87
  127. package/dist/types/internal/use-width-from-anchor.d.ts +0 -19
  128. package/use-anchor-position/package.json +0 -10
  129. package/use-anchor-position-at-point/package.json +0 -10
  130. package/use-width-from-anchor/package.json +0 -10
@@ -1,108 +0,0 @@
1
- import { resolvePlacement } from './resolve-placement';
2
-
3
- /**
4
- * A `position-area` primary edge — the placement axis joined to its edge, e.g.
5
- * `block-end` or `inline-start`. These are the four edges a popover can sit on.
6
- */
7
-
8
- function slideOnEdge({
9
- align,
10
- edgeKey,
11
- crossAxis
12
- }) {
13
- if (align === 'center') {
14
- return [`${edgeKey} span-${crossAxis}-end`, `${edgeKey} span-${crossAxis}-start`];
15
- }
16
- // For `align: 'start'` the popover expands toward `end`, so the "near"
17
- // span is `end` and the "far" span is `start`; `align: 'end'` mirrors
18
- // this. The bare `edgeKey` (re-centered) sits between them.
19
- const near = align === 'start' ? 'end' : 'start';
20
- const far = align === 'start' ? 'start' : 'end';
21
- return [`${edgeKey} span-${crossAxis}-${near}`, edgeKey, `${edgeKey} span-${crossAxis}-${far}`];
22
- }
23
- function flipDiagonally({
24
- axis
25
- }) {
26
- const flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
27
- const flipToCrossAxis = axis === 'block' ? 'flip-inline' : 'flip-block';
28
- return `${flipOnMainAxis} ${flipToCrossAxis}`;
29
- }
30
-
31
- /**
32
- * Returns the `position-try-fallbacks` value for a placement.
33
- *
34
- * @example
35
- * // Centered on the block-end edge (the default placement):
36
- * placementToTryFallbacks({ placement: { axis: 'block', edge: 'end', align: 'center' } });
37
- * // => 'block-end span-inline-end, block-end span-inline-start, flip-block,
38
- * // block-start span-inline-end, block-start span-inline-start'
39
- */
40
- export function placementToTryFallbacks({
41
- placement
42
- }) {
43
- /**
44
- * **Build the fallback list**
45
- *
46
- * Each entry is a complete alternative position.
47
- * The browser tries them _in order_ and uses the _first_ one that fits.
48
- */
49
-
50
- const resolved = resolvePlacement({
51
- placement
52
- });
53
- const {
54
- axis,
55
- edge,
56
- align
57
- } = resolved;
58
- const crossAxis = axis === 'block' ? 'inline' : 'block';
59
- const flippedEdge = edge === 'start' ? 'end' : 'start';
60
- const sameEdgeArea = `${axis}-${edge}`;
61
- const oppositeEdgeArea = `${axis}-${flippedEdge}`;
62
- const flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
63
-
64
- /**
65
- * **Fallback algorithm**
66
- *
67
- * We have two things we can do to keep something visible:
68
- *
69
- * 1. _Slide_ along edges
70
- * 2. _Flip_ to another edge
71
- *
72
- * _Centered popover_
73
- *
74
- * Desired: Sits in middle of main edge
75
- *
76
- * Fallbacks:
77
- * 1: _Slide_ along main edge on the cross axis
78
- * 2: _Flip_ on main axis to opposite edge (centered)
79
- * 3: _Slide_ along opposite edge on the cross axis
80
- *
81
- * _Start or end aligned popover_
82
- *
83
- * Desired: Sits at start / end of main edge
84
- *
85
- * Fallbacks:
86
- * 1: _Slide_ along main edge on the cross axis
87
- * 2: _Flip_ on main axis to opposite edge
88
- * 3: _Flip_ on the diagonal (flip main axis + flip cross axis) into the
89
- * opposite corner. For start / end alignment, this is the clean escape
90
- * when the popover would otherwise land offscreen on both axes (ie in a
91
- * corner). Rule 4 gets the job done, but a slide drops the gap
92
- * as named position-area values don't carry margins).
93
- * The diagonal flip keeps the gap and the alignment.
94
- * 4: _Slide_ along opposite edge on the cross axis
95
- */
96
-
97
- return [slideOnEdge({
98
- align,
99
- edgeKey: sameEdgeArea,
100
- crossAxis
101
- }), flipOnMainAxis, align !== 'center' ? flipDiagonally({
102
- axis
103
- }) : null, slideOnEdge({
104
- align,
105
- edgeKey: oppositeEdgeArea,
106
- crossAxis
107
- })].filter(Boolean).flat().join(', ');
108
- }
@@ -1,101 +0,0 @@
1
- const elementCaches = new WeakMap();
2
- function canCacheResolvedLength(value) {
3
- // Custom-property values can be retargeted by inline overrides on the
4
- // consumer's wrapper, so we cannot prove a cached pixel value is still valid.
5
- return !value.includes('var(');
6
- }
7
- function getCachedResolvedLength({
8
- element,
9
- value
10
- }) {
11
- var _cacheForElement$get;
12
- if (!canCacheResolvedLength(value)) {
13
- return null;
14
- }
15
- const cacheForElement = elementCaches.get(element);
16
- return (_cacheForElement$get = cacheForElement === null || cacheForElement === void 0 ? void 0 : cacheForElement.get(value)) !== null && _cacheForElement$get !== void 0 ? _cacheForElement$get : null;
17
- }
18
- function cacheResolvedLength({
19
- element,
20
- value,
21
- result
22
- }) {
23
- var _elementCaches$get;
24
- if (!canCacheResolvedLength(value)) {
25
- return;
26
- }
27
- const cacheForElement = (_elementCaches$get = elementCaches.get(element)) !== null && _elementCaches$get !== void 0 ? _elementCaches$get : new Map();
28
- cacheForElement.set(value, result);
29
- elementCaches.set(element, cacheForElement);
30
- }
31
-
32
- /**
33
- * Resolves a CSS length value to a pixel number using a hidden DOM probe.
34
- *
35
- * Used by the JS positioning fallback: consumer offsets can be numbers,
36
- * `${n}px` strings, tokenised `var(--ds-space-100, 8px)` strings, `calc()`
37
- * expressions, viewport units, etc. Parsing arbitrary CSS in JS is fragile
38
- * (and impossible for `calc(var(...))` without a layout context), so we let
39
- * the browser do the math.
40
- *
41
- * The probe is appended to `container` so it inherits the same containing
42
- * block, font size, and custom-property scope as the popover.
43
- *
44
- * Cost: one synchronous reflow on first cacheable resolution per
45
- * (container, value) pair, then a `WeakMap` lookup. Resolutions involving
46
- * `var(` are intentionally not cached.
47
- */
48
- export function resolveCssLengthToPixels({
49
- value,
50
- container
51
- }) {
52
- if (typeof value === 'number') {
53
- return value;
54
- }
55
-
56
- // Fast path: unitless zero is universally zero pixels - accept `'0'` and
57
- // `'-0'` without a probe. (Consumers occasionally pass `'0'` instead of
58
- // the number `0`.)
59
- if (value === '0' || value === '-0') {
60
- return 0;
61
- }
62
-
63
- // Fast path: bare `${n}px` strings come from the consumer normalisation
64
- // in `resolvePlacement`. Avoid a reflow when we can.
65
- const pxMatch = value.match(/^(-?\d+(?:\.\d+)?)px$/);
66
- if (pxMatch) {
67
- return Number(pxMatch[1]);
68
- }
69
- const cached = getCachedResolvedLength({
70
- element: container,
71
- value
72
- });
73
- if (cached !== null) {
74
- return cached;
75
- }
76
- const probe = container.ownerDocument.createElement('div');
77
- probe.style.position = 'absolute';
78
- probe.style.visibility = 'hidden';
79
- probe.style.pointerEvents = 'none';
80
- probe.style.height = '0';
81
- probe.style.padding = '0';
82
- probe.style.border = '0';
83
- // `width` clamps negatives to 0; use `margin-left` instead so signs are
84
- // preserved. `getComputedStyle` returns the resolved pixel value for
85
- // margin-* properties even when the source was a token / calc / var.
86
- probe.style.marginLeft = value;
87
- // Hide the probe from assistive tech and event targeting; defensive
88
- // against `getElementsByTagName('div')` walks in consumer code.
89
- probe.setAttribute('aria-hidden', 'true');
90
- probe.setAttribute('inert', '');
91
- container.appendChild(probe);
92
- const resolved = parseFloat(getComputedStyle(probe).marginLeft);
93
- container.removeChild(probe);
94
- const result = Number.isFinite(resolved) ? resolved : 0;
95
- cacheResolvedLength({
96
- element: container,
97
- value,
98
- result
99
- });
100
- return result;
101
- }
@@ -1,124 +0,0 @@
1
- import { useLayoutEffect, useRef } from 'react';
2
- import { useAnchorPosition } from './use-anchor-position';
3
-
4
- /**
5
- * A point in viewport coordinates (CSS pixels) at which the synthetic
6
- * anchor should be placed.
7
- *
8
- * Axis-named (`x`/`y`) rather than edge-named (`left`/`top`) so the
9
- * shape is unambiguous in RTL writing modes - there is no ambiguity
10
- * about whether a coordinate is logical (`inline-start`/`block-start`)
11
- * or physical (`left`/`top`). Viewport coordinates are always
12
- * physical, so we name them with the physical axis labels.
13
- */
14
-
15
- /**
16
- * Styles the synthetic anchor as an invisible, zero-size point.
17
- * Dynamic `inset-*` overrides are written by the positioning effect.
18
- *
19
- * Uses `Object.assign` rather than Compiled CSS (element is outside the React tree)
20
- * or the internal `setStyle` helper (we own this element entirely - it is created
21
- * and removed by this hook - so the snapshot/restore semantics `setStyle`
22
- * provides for caller-owned elements would be dead work here).
23
- */
24
- function applyStaticAnchorStyles(element) {
25
- Object.assign(element.style, {
26
- position: 'fixed',
27
- // `top`/`left` rather than `inset-block-start`/`inset-inline-start`
28
- // for consistency with the dynamic positioning effect below, which
29
- // uses physical properties (see comment there for the rationale).
30
- top: '0',
31
- left: '0',
32
- // Zero size - placement decides which side the popover sits on.
33
- width: '0',
34
- height: '0',
35
- // Prevent the overlay from intercepting pointer events.
36
- pointerEvents: 'none'
37
- });
38
- }
39
-
40
- // `useAnchorPosition` requires a real DOM element. When the caller only
41
- // has a viewport coordinate (e.g. cursor at hover time), this hook
42
- // manages a hidden `<div>` at that point and delegates the rest.
43
- //
44
- // The `<div>` is appended directly to `document.body` to escape any
45
- // transformed ancestor, which would otherwise break `position: fixed`
46
- // viewport-relative resolution.
47
-
48
- /**
49
- * Positions a popover at a consumer-supplied viewport coordinate using a
50
- * hidden synthetic anchor.
51
- *
52
- * @example
53
- * ```tsx
54
- * function PointPositionedPopover({ popoverRef, placement, mousePos }) {
55
- * useAnchorPositionAtPoint({
56
- * popoverRef,
57
- * placement,
58
- * isEnabled: Boolean(mousePos),
59
- * getPoint: () => {
60
- * if (!mousePos) return null;
61
- * return { x: mousePos.clientX, y: mousePos.clientY };
62
- * },
63
- * });
64
- * return <Popover ref={popoverRef}>...</Popover>;
65
- * }
66
- * ```
67
- */
68
- export function useAnchorPositionAtPoint({
69
- popoverRef,
70
- placement,
71
- getPoint,
72
- isEnabled = true,
73
- isOpen
74
- }) {
75
- const syntheticAnchorRef = useRef(null);
76
-
77
- // `getPoint` is kept in a ref so the layout effect can call the
78
- // latest version without listing it as a dep - that would re-fire
79
- // on every render and re-latch the point.
80
- const getPointRef = useRef(getPoint);
81
- getPointRef.current = getPoint;
82
-
83
- // Lazy element creation: the `<div>` is only created when both
84
- // `isEnabled` is true AND `getPoint()` returns a non-null point.
85
- // `useLayoutEffect` ensures the element exists before the inner
86
- // `useAnchorPosition` (also a layout effect) reads the ref.
87
- useLayoutEffect(() => {
88
- if (!isEnabled) {
89
- return;
90
- }
91
- const point = getPointRef.current();
92
- if (!point) {
93
- return;
94
- }
95
- const anchor = document.createElement('div');
96
- anchor.setAttribute('aria-hidden', 'true');
97
- applyStaticAnchorStyles(anchor);
98
- // `point.x`/`y` are physical viewport coordinates (from
99
- // `MouseEvent.clientX/Y`), so map directly onto physical
100
- // `left`/`top`. This is RTL-safe: `position: fixed` + physical
101
- // insets is direction-independent. Using logical
102
- // `inset-inline-start` would need `viewportWidth - point.x` in
103
- // RTL to land at the same physical pixel.
104
- anchor.style.top = `${point.y}px`;
105
- anchor.style.left = `${point.x}px`;
106
- document.body.appendChild(anchor);
107
- syntheticAnchorRef.current = anchor;
108
- return function cleanup() {
109
- anchor.remove();
110
- syntheticAnchorRef.current = null;
111
- };
112
- }, [isEnabled]);
113
-
114
- // Mirror `isEnabled` so both hooks stay in sync - when disabled,
115
- // neither this hook nor the inner one touches the popover, leaving
116
- // any other positioning the consumer has set up free to take effect.
117
- useAnchorPosition({
118
- anchorRef: syntheticAnchorRef,
119
- popoverRef,
120
- placement,
121
- isEnabled,
122
- isOpen
123
- });
124
- }