@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # @atlaskit/top-layer
2
2
 
3
+ ## 5.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [`a7ec100f7d560`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a7ec100f7d560) -
8
+ **Breaking:** `useAnchorPosition`, `useAnchorPositionAtPoint` and `useWidthFromAnchor` are
9
+ replaced by `useAnchoredPopover` and `useAnchoredPopoverAtPoint`, which own positioning and
10
+ anchor-relative sizing together. The `./use-anchor-position`, `./use-anchor-position-at-point` and
11
+ `./use-width-from-anchor` entry points are removed with no aliases; `./use-anchored-popover` and
12
+ `./use-anchored-popover-at-point` are added. Every consumer in the monorepo is migrated: the
13
+ `platform/packages/design-system` components, and kitsune's idea-select menu portal.
14
+
15
+ ```tsx
16
+ import { useAnchoredPopover } from '@atlaskit/top-layer/use-anchored-popover';
17
+
18
+ useAnchoredPopover({
19
+ anchorRef: triggerRef,
20
+ popoverRef,
21
+ placement,
22
+ isOpen,
23
+ // `useWidthFromAnchor`'s `mode`, now per axis:
24
+ // 'content' | 'match-anchor' | 'min-anchor' | 'max-available'
25
+ inlineSize: 'match-anchor',
26
+ blockSize: 'max-available',
27
+ });
28
+ ```
29
+
30
+ `useAnchoredPopoverAtPoint` takes `getPoint: () => { x, y } | null` in place of `anchorRef`. Both
31
+ axes are now always capped to the viewport, and asking either axis to fit also applies a minimum
32
+ size of up to 150px along the placement axis, so the popover flips to a roomier side rather than
33
+ shrinking in place. Rationale and rejected alternatives: `notes/decisions/fit-available-space.md`.
34
+
35
+ The `anchor-name` the hook mints is still `--anchor-{useId()}`. A host that hydrates several React
36
+ roots from the same markup must give each a distinct `identifierPrefix`, as it already must for
37
+ every other id the design system mints; the hook's JSDoc now says so.
38
+
39
+ ### Patch Changes
40
+
41
+ - [`50733a142e6d4`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/50733a142e6d4) -
42
+ Narrow the `aria-haspopup` type returned by `getAriaForTrigger` to the supplied popover role.
43
+
3
44
  ## 4.4.5
4
45
 
5
46
  ### Patch Changes
package/README.md CHANGED
@@ -8,7 +8,8 @@ Low-level top-layer primitives using the native
8
8
 
9
9
  The primary primitive: a `<div>` with the `popover` attribute, plus a small lifecycle (animations,
10
10
  role-based focus management, light-dismiss, nested-focus restoration). It does **not** know about
11
- placement — compose it with the `useAnchorPosition` hook when you need anchor-positioned content.
11
+ placement or size — compose it with the `useAnchoredPopover` hook when you need anchor-positioned
12
+ content.
12
13
 
13
14
  ```tsx
14
15
  import { useRef } from 'react';
@@ -16,17 +17,18 @@ import { getAriaForTrigger } from '@atlaskit/top-layer/get-aria-for-trigger';
16
17
  import { Popover } from '@atlaskit/top-layer/popover';
17
18
  import { PopoverSurface } from '@atlaskit/top-layer/popover-surface';
18
19
  import { usePopoverId } from '@atlaskit/top-layer/use-popover-id';
19
- import { useAnchorPosition } from '@atlaskit/top-layer/use-anchor-position';
20
+ import { useAnchoredPopover } from '@atlaskit/top-layer/use-anchored-popover';
20
21
 
21
22
  function MyPopup({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) {
22
23
  const triggerRef = useRef<HTMLButtonElement>(null);
23
24
  const popoverRef = useRef<HTMLDivElement>(null);
24
25
  const popoverId = usePopoverId();
25
26
 
26
- useAnchorPosition({
27
+ useAnchoredPopover({
27
28
  anchorRef: triggerRef,
28
29
  popoverRef,
29
30
  placement: { axis: 'block', edge: 'end', align: 'start' },
31
+ isOpen,
30
32
  });
31
33
 
32
34
  return (
@@ -59,7 +61,14 @@ function MyPopup({ isOpen, onClose }: { isOpen: boolean; onClose: () => void })
59
61
  - For default overlay styling (background, shadow, border-radius), wrap content in `PopoverSurface`
60
62
  from `@atlaskit/top-layer/popover-surface`.
61
63
  - For trigger-less or custom-positioned UI (flag, tooltip, react-select menu portal), use `Popover`
62
- on its own without `useAnchorPosition`.
64
+ on its own without `useAnchoredPopover`, or pass `isEnabled: false` to turn positioning off.
65
+ - `useAnchoredPopover` also owns anchor-relative sizing via `inlineSize` / `blockSize`
66
+ (`'content' | 'match-anchor' | 'min-anchor' | 'max-available'`, both defaulting to `'content'`). A
67
+ viewport cap is written on both axes whatever you pass, and only a placement-axis minimum can beat
68
+ it. A `'content'` inline axis is the content's natural width, so a popover too wide for the space
69
+ beside its anchor slides to a roomier side rather than wrapping; `shouldPreserveInlineSize` opts
70
+ an element you own and have styled out of that write. See the hook's JSDoc and
71
+ [`notes/decisions/fit-available-space.md`](notes/decisions/fit-available-space.md).
63
72
 
64
73
  ## Dialog
65
74
 
@@ -28,9 +28,11 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
28
28
  //
29
29
  // KEEP IN SYNC with the identical `surfaceResetStyles` in `popover/popover.tsx`
30
30
  // (ADS forbids sharing styles across files, so it is co-located and duplicated).
31
+ // The `satisfies` check below fails the build if either copy drifts.
31
32
  var surfaceResetStyles = {
32
33
  root: "_lcxv1wug _o5724jg8 _1nmz4jg8 _1i4q4jg8 _y3gnv2br _azhwidpf _1p1dglyw"
33
34
  };
35
+ true;
34
36
  var dialogStyles = {
35
37
  root: "_19itglyw _19pk1wug _2hwx1wug _otyr1wug _18u01wug _1q51ze3t _y4tize3t _85i5ze3t _bozgze3t _p12fglyw _c71lglyw _bfhk1j28",
36
38
  motion: "_k8m011k7 _1oeci9qs _1s9z1a5r _1o511hrf _bl8aglyw _156y147i",
@@ -6,18 +6,13 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.usePopoverId = usePopoverId;
7
7
  var _useId = require("@atlaskit/ds-lib/use-id");
8
8
  /**
9
- * Returns a stable HTML `id` used to wire a trigger element to its popover
10
- * via ARIA (`aria-controls`) and the Popover API (`popovertarget`).
9
+ * A stable `id` for wiring a trigger to its popover: the popover's `id`, and the
10
+ * trigger's matching `aria-controls` / `popovertarget`.
11
11
  *
12
- * The returned value is intended for the `id` attribute on the popover and
13
- * for the matching `aria-controls` / `popovertarget` references on the
14
- * trigger. It is NOT a CSS `anchor-name` value: CSS anchor positioning is
15
- * handled internally by `useAnchorPosition`, which mints and applies its
16
- * own `anchor-name` on the trigger element.
12
+ * NOT a CSS `anchor-name` - `useAnchoredPopover` mints and writes its own.
17
13
  */
18
14
  function usePopoverId() {
19
- // `@atlaskit/ds-lib/use-id` already strips characters that React's
20
- // `useId` produces (`:`, `«`, `»`) which are invalid in HTML ID
21
- // tokens. The `popover-` prefix is purely for DOM debug clarity.
15
+ // `@atlaskit/ds-lib/use-id`, not React's `useId`: React's output contains
16
+ // `:`, `«` and `»`, which are invalid in an HTML id token.
22
17
  return "popover-".concat((0, _useId.useId)());
23
18
  }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.applyAnchorPositioning = applyAnchorPositioning;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _setStyle = require("../set-style");
10
+ var _crossAxisShiftMargins = require("./cross-axis-shift-margins");
11
+ var _edgeMargin = require("./edge-margin");
12
+ var _fitMargins = require("./fit-margins");
13
+ var _getExistingAnchorName = require("./get-existing-anchor-name");
14
+ var _placementToPositionArea = require("./placement-to-position-area");
15
+ var _placementToTryFallbacks = require("./placement-to-try-fallbacks");
16
+ /**
17
+ * The CSS Anchor Positioning path: `position-anchor`, `position-area`,
18
+ * `position-try-fallbacks` and the gap / shift margins, all declared on the
19
+ * popover so the browser owns placement and flipping. The twin of
20
+ * `../javascript-fallback/apply-javascript-fallback-positioning`.
21
+ */
22
+
23
+ /**
24
+ * Returns the cleanup.
25
+ */
26
+ function applyAnchorPositioning(_ref) {
27
+ var anchor = _ref.anchor,
28
+ popover = _ref.popover,
29
+ placement = _ref.placement,
30
+ sizeStyles = _ref.sizeStyles,
31
+ isFitting = _ref.isFitting,
32
+ fallbackAnchorName = _ref.fallbackAnchorName;
33
+ // Reuse rather than mint: another popover may already be anchored to it, or a
34
+ // CONSUMER may have set it on their own element, as `post-office` does.
35
+ var existingAnchorName = (0, _getExistingAnchorName.getExistingAnchorName)(anchor);
36
+ var anchorName = existingAnchorName !== null && existingAnchorName !== void 0 ? existingAnchorName : fallbackAnchorName;
37
+ var gap = (0, _edgeMargin.edgeMargin)({
38
+ placement: placement,
39
+ offset: placement.offset.gap
40
+ });
41
+ var crossAxisShift = (0, _crossAxisShiftMargins.crossAxisShiftMargins)({
42
+ placement: placement,
43
+ crossAxisShiftCssValue: placement.offset.crossAxisShift.value,
44
+ direction: placement.offset.crossAxisShift.direction
45
+ });
46
+ var popoverStyles = [{
47
+ property: 'position-anchor',
48
+ value: anchorName
49
+ }, {
50
+ property: 'position-area',
51
+ value: (0, _placementToPositionArea.placementToPositionArea)({
52
+ placement: placement
53
+ })
54
+ }, {
55
+ property: 'position-try-fallbacks',
56
+ value: (0, _placementToTryFallbacks.placementToTryFallbacks)({
57
+ placement: placement
58
+ })
59
+ },
60
+ // Reset browser default popover positioning that conflicts
61
+ // with anchor positioning (UA: `inset: 0; margin: auto;`)
62
+ {
63
+ property: 'margin',
64
+ value: '0'
65
+ }, {
66
+ property: 'inset',
67
+ value: 'auto'
68
+ }, gap].concat((0, _toConsumableArray2.default)(isFitting ? (0, _fitMargins.getFitMarginDeclarations)({
69
+ placement: placement,
70
+ crossAxisShiftMargins: crossAxisShift
71
+ }) : crossAxisShift), (0, _toConsumableArray2.default)(sizeStyles));
72
+
73
+ // Anchor names are never cleaned up: multiple popovers can share an anchor,
74
+ // and even with reference counting an async React update could remove the name
75
+ // while something else still uses it. See
76
+ // `notes/decisions/anchor-name-lifetime.md`. Only written when minted: a name
77
+ // from a stylesheet may be a list, which an inline copy of its first entry
78
+ // would collapse.
79
+ if (existingAnchorName === null) {
80
+ anchor.style.setProperty('anchor-name', anchorName);
81
+ }
82
+ return (0, _setStyle.setStyle)({
83
+ element: popover,
84
+ styles: popoverStyles
85
+ });
86
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.crossAxisShiftMargins = crossAxisShiftMargins;
7
+ /**
8
+ * The cross-axis shift, written antisymmetrically on BOTH cross-axis sides rather
9
+ * than as one margin. Do not collapse it to one side: a single margin widens the
10
+ * margin box, so `anchor-center` displaces the border box by only half the value,
11
+ * a `<position-area>` fallback sliding across the cross axis drops it entirely,
12
+ * and the widened box changes where the popover is judged to overflow.
13
+ *
14
+ * A positive value always moves the popover toward the cross-axis END, so
15
+ * `direction: 'forwards'` means the same thing for every `align` value. See
16
+ * `notes/decisions/placement-offset.md`.
17
+ */
18
+ function crossAxisShiftMargins(_ref) {
19
+ var placement = _ref.placement,
20
+ crossAxisShiftCssValue = _ref.crossAxisShiftCssValue,
21
+ direction = _ref.direction;
22
+ var crossAxis = placement.axis === 'block' ? 'inline' : 'block';
23
+ // `calc()` rather than JavaScript math, so opaque values such as design tokens
24
+ // negate correctly.
25
+ var negated = "calc(-1 * ".concat(crossAxisShiftCssValue, ")");
26
+ var isForwards = direction === 'forwards';
27
+ return [{
28
+ property: "margin-".concat(crossAxis, "-start"),
29
+ value: isForwards ? crossAxisShiftCssValue : negated
30
+ }, {
31
+ property: "margin-".concat(crossAxis, "-end"),
32
+ value: isForwards ? negated : crossAxisShiftCssValue
33
+ }];
34
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.edgeMargin = edgeMargin;
7
+ /**
8
+ * The margin that creates the gap between the popover and its anchor.
9
+ */
10
+ function edgeMargin(_ref) {
11
+ var placement = _ref.placement,
12
+ offset = _ref.offset;
13
+ var axis = placement.axis,
14
+ edge = placement.edge;
15
+ // The side FACING the anchor is always opposite the placement edge.
16
+ var anchorFacingEdge = edge === 'end' ? 'start' : 'end';
17
+ return {
18
+ property: "margin-".concat(axis, "-").concat(anchorFacingEdge),
19
+ value: offset
20
+ };
21
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getFitMarginDeclarations = getFitMarginDeclarations;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _anchoredPopoverSize = require("../anchored-popover-size");
10
+ /**
11
+ * Every logical margin property the fit recipe can write. Declared here and
12
+ * imported by `edge-margin.tsx` and `cross-axis-shift-margins.tsx`: two
13
+ * structurally identical declarations are interchangeable to the compiler, so a
14
+ * divergence would surface only as a silently-ignored property name at
15
+ * `setStyle`.
16
+ */
17
+
18
+ /**
19
+ * The cross-axis sides that face the viewport rather than the anchor, and so take
20
+ * the reserved padding.
21
+ *
22
+ * A `span-*` cell aligns the popover's MARGIN box to the anchor's edge, so padding
23
+ * on the anchor-facing side does not reserve space at the viewport: it insets the
24
+ * border box from the edge the consumer asked it to line up with. A centred
25
+ * popover has no anchor-facing side, and padding both keeps the shift pair
26
+ * antisymmetric so `anchor-center` still centres.
27
+ *
28
+ * Known cost: the slide fallbacks do not swap the inline margins the way
29
+ * `flip-inline` does, so a slid popover keeps its padding on the anchor side (or,
30
+ * re-centred, sits 2.5px off centre). Alignment in the requested position wins.
31
+ */
32
+ function viewportFacingCrossAxisSides(_ref) {
33
+ var align = _ref.align;
34
+ if (align === 'center') {
35
+ return ['start', 'end'];
36
+ }
37
+ // `align: 'start'` sits on the anchor's start edge and expands toward end.
38
+ return [align === 'start' ? 'end' : 'start'];
39
+ }
40
+
41
+ /**
42
+ * The margin half of the fit recipe. The caps reserve the viewport padding by
43
+ * subtracting it, but nothing makes the reservation land on the viewport side, so
44
+ * a capped popover packs flush against the edge it slid or flipped to.
45
+ *
46
+ * The padding buys visual clearance and nothing else: at the cap the margin box
47
+ * is exactly `100%` of the cell, so these margins never make
48
+ * `position-try-fallbacks` fire. Only the unclamped placement-axis floor does
49
+ * that; see `getPlacementAxisFloor`.
50
+ *
51
+ * The cross-axis sides are composed, not overwritten: they already carry the
52
+ * antisymmetric `crossAxisShift` pair.
53
+ */
54
+ function getFitMarginDeclarations(_ref2) {
55
+ var placement = _ref2.placement,
56
+ crossAxisShiftMargins = _ref2.crossAxisShiftMargins;
57
+ var crossAxis = placement.axis === 'block' ? 'inline' : 'block';
58
+ var paddedProperties = new Set(viewportFacingCrossAxisSides({
59
+ align: placement.align
60
+ }).map(function (side) {
61
+ return "margin-".concat(crossAxis, "-").concat(side);
62
+ }));
63
+ return [{
64
+ property: "margin-".concat(placement.axis, "-").concat(placement.edge),
65
+ value: _anchoredPopoverSize.VIEWPORT_PADDING
66
+ }].concat((0, _toConsumableArray2.default)(crossAxisShiftMargins.map(function (_ref3) {
67
+ var property = _ref3.property,
68
+ value = _ref3.value;
69
+ return paddedProperties.has(property) ? {
70
+ property: property,
71
+ value: "calc(".concat(value, " + ").concat(_anchoredPopoverSize.VIEWPORT_PADDING, ")")
72
+ } : {
73
+ property: property,
74
+ value: value
75
+ };
76
+ })));
77
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getExistingAnchorName = getExistingAnchorName;
7
+ /**
8
+ * The `anchor-name` an element already carries, or `null`. Computed as well as
9
+ * inline, so a name set from a STYLESHEET is found: a minted inline name would
10
+ * otherwise override it for every other rule anchored to that element.
11
+ * `anchor-name` is a list and `position-anchor` takes one ident, so the first
12
+ * name is the one to anchor to.
13
+ */
14
+ function getExistingAnchorName(element) {
15
+ var declared = element.style.getPropertyValue('anchor-name') || getComputedStyle(element).getPropertyValue('anchor-name');
16
+ var first = declared.split(',')[0].trim();
17
+ return first !== '' && first !== 'none' ? first : null;
18
+ }
@@ -4,9 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.placementToPositionArea = placementToPositionArea;
7
- var _resolvePlacement2 = require("./resolve-placement");
8
7
  /**
9
- * Resolves placement options to CSS `position-area` syntax.
8
+ * Resolves a placement to CSS `position-area` syntax.
10
9
  *
11
10
  * The `align` field represents the *visual* alignment:
12
11
  * - `align: 'start'` means "aligned to the trigger's start edge" (left in LTR for block axis)
@@ -17,19 +16,20 @@ var _resolvePlacement2 = require("./resolve-placement");
17
16
  * Visual start-alignment requires `span-{cross-axis}-end` (expand toward end = start-aligned).
18
17
  * This function handles the inversion internally.
19
18
  *
19
+ * Takes the RESOLVED placement, which the hook threads through positioning,
20
+ * sizing and margins alike, so nothing here can disagree with them.
21
+ *
20
22
  * @example
21
- * placementToPositionArea({ placement: { axis: 'block', edge: 'end', align: 'center' } }) // → 'block-end'
22
- * placementToPositionArea({ placement: { axis: 'block', edge: 'end', align: 'start' } }) // → 'block-end span-inline-end'
23
- * placementToPositionArea({ placement: { axis: 'block', edge: 'end', align: 'end' } }) // → 'block-end span-inline-start'
23
+ * // For a `block-end` placement, by `align`:
24
+ * // 'center' → 'block-end'
25
+ * // 'start' → 'block-end span-inline-end'
26
+ * // 'end' → 'block-end span-inline-start'
24
27
  */
25
28
  function placementToPositionArea(_ref) {
26
29
  var placement = _ref.placement;
27
- var _resolvePlacement = (0, _resolvePlacement2.resolvePlacement)({
28
- placement: placement
29
- }),
30
- axis = _resolvePlacement.axis,
31
- edge = _resolvePlacement.edge,
32
- align = _resolvePlacement.align;
30
+ var axis = placement.axis,
31
+ edge = placement.edge,
32
+ align = placement.align;
33
33
  var edgeValue = "".concat(axis, "-").concat(edge);
34
34
  if (align === 'center') {
35
35
  return edgeValue;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.placementToTryFallbacks = placementToTryFallbacks;
7
+ /**
8
+ * The placement axis joined to its edge, e.g. `block-end`.
9
+ */
10
+
11
+ /**
12
+ * The cells to slide to along one edge, on the cross axis.
13
+ *
14
+ * A try option is only worth listing if its margin box can fit where an earlier
15
+ * one did not, and two options over the SAME cell have the same margin box and
16
+ * the same fit result. That rules out three cells for an aligned placement: the
17
+ * near span on the requested edge IS the base position-area, and on the opposite
18
+ * edge the near and far spans are where `flip-{A}` and the diagonal flip land.
19
+ *
20
+ * A centred placement has no near or far, so it slides to both spans on both
21
+ * edges.
22
+ */
23
+ function slideOnEdge(_ref) {
24
+ var align = _ref.align,
25
+ edgeKey = _ref.edgeKey,
26
+ crossAxis = _ref.crossAxis,
27
+ isOppositeEdge = _ref.isOppositeEdge;
28
+ if (align === 'center') {
29
+ return ["".concat(edgeKey, " span-").concat(crossAxis, "-end"), "".concat(edgeKey, " span-").concat(crossAxis, "-start")];
30
+ }
31
+ if (isOppositeEdge) {
32
+ return [edgeKey];
33
+ }
34
+ // For `align: 'start'` the popover expands toward `end`, so the far span is
35
+ // `start`; `align: 'end'` mirrors this.
36
+ var far = align === 'start' ? 'start' : 'end';
37
+ return [edgeKey, "".concat(edgeKey, " span-").concat(crossAxis, "-").concat(far)];
38
+ }
39
+ function flipDiagonally(_ref2) {
40
+ var axis = _ref2.axis;
41
+ var flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
42
+ var flipToCrossAxis = axis === 'block' ? 'flip-inline' : 'flip-block';
43
+ return "".concat(flipOnMainAxis, " ").concat(flipToCrossAxis);
44
+ }
45
+
46
+ /**
47
+ * Returns the `position-try-fallbacks` value for a RESOLVED placement. The
48
+ * browser tries the entries in order and uses the first one whose margin box
49
+ * fits, so an entry over a cell already tried can never be chosen; `slideOnEdge`
50
+ * explains which ones those are.
51
+ *
52
+ * Centred: slide along the requested edge to either span, flip to the opposite
53
+ * edge, then slide along that edge to either span.
54
+ *
55
+ * Start / end aligned: slide along the requested edge (re-centred, then the far
56
+ * span), flip to the opposite edge keeping the alignment, flip on the diagonal
57
+ * into the opposite corner, then re-centre on the opposite edge. The diagonal is
58
+ * the clean escape when the popover would land off screen on both axes: a flip
59
+ * keyword carries the gap and shift margins across, where a position-area slide
60
+ * leaves them on the original sides.
61
+ *
62
+ * @example
63
+ * // Centred on the block-end edge (the default placement):
64
+ * placementToTryFallbacks({ placement: resolvePlacement({ placement: {} }) });
65
+ * // => 'block-end span-inline-end, block-end span-inline-start, flip-block,
66
+ * // block-start span-inline-end, block-start span-inline-start'
67
+ *
68
+ * // Start-aligned on the block-end edge:
69
+ * placementToTryFallbacks({ placement: resolvePlacement({ placement: { align: 'start' } }) });
70
+ * // => 'block-end, block-end span-inline-start, flip-block, flip-block flip-inline, block-start'
71
+ */
72
+ function placementToTryFallbacks(_ref3) {
73
+ var placement = _ref3.placement;
74
+ var axis = placement.axis,
75
+ edge = placement.edge,
76
+ align = placement.align;
77
+ var crossAxis = axis === 'block' ? 'inline' : 'block';
78
+ var flippedEdge = edge === 'start' ? 'end' : 'start';
79
+ var sameEdgeArea = "".concat(axis, "-").concat(edge);
80
+ var oppositeEdgeArea = "".concat(axis, "-").concat(flippedEdge);
81
+ var flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
82
+ return [slideOnEdge({
83
+ align: align,
84
+ edgeKey: sameEdgeArea,
85
+ crossAxis: crossAxis,
86
+ isOppositeEdge: false
87
+ }), flipOnMainAxis, align !== 'center' ? flipDiagonally({
88
+ axis: axis
89
+ }) : null, slideOnEdge({
90
+ align: align,
91
+ edgeKey: oppositeEdgeArea,
92
+ crossAxis: crossAxis,
93
+ isOppositeEdge: true
94
+ })].filter(Boolean).flat().join(', ');
95
+ }