@atlaskit/top-layer 4.4.5 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +13 -4
  3. package/dist/cjs/dialog/dialog-content.js +2 -0
  4. package/dist/cjs/entry-points/use-popover-id.js +5 -10
  5. package/dist/cjs/internal/anchor-positioning/apply-anchor-positioning.js +86 -0
  6. package/dist/cjs/internal/anchor-positioning/cross-axis-shift-margins.js +34 -0
  7. package/dist/cjs/internal/anchor-positioning/edge-margin.js +21 -0
  8. package/dist/cjs/internal/anchor-positioning/fit-margins.js +77 -0
  9. package/dist/cjs/internal/anchor-positioning/get-existing-anchor-name.js +18 -0
  10. package/dist/cjs/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +11 -11
  11. package/dist/cjs/internal/anchor-positioning/placement-to-try-fallbacks.js +95 -0
  12. package/dist/cjs/internal/anchored-popover-size.js +345 -0
  13. package/dist/cjs/internal/get-aria-for-trigger.js +7 -13
  14. package/dist/cjs/internal/is-native-element-open.js +19 -0
  15. package/dist/cjs/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
  16. package/dist/cjs/internal/javascript-fallback/apply-javascript-fallback-positioning.js +297 -0
  17. package/dist/cjs/internal/javascript-fallback/resolve-css-length-to-pixels.js +90 -0
  18. package/dist/cjs/internal/javascript-fallback/warn-fallback-failure.js +19 -0
  19. package/dist/cjs/internal/resolve-placement.js +14 -6
  20. package/dist/cjs/internal/supports-anchor-positioning.js +17 -0
  21. package/dist/cjs/internal/supports-anchor-size.js +17 -0
  22. package/dist/cjs/internal/supports-css-declaration.js +25 -0
  23. package/dist/cjs/internal/surface-reset.js +5 -0
  24. package/dist/cjs/internal/use-anchored-popover-at-point.js +124 -0
  25. package/dist/cjs/internal/use-anchored-popover.js +277 -0
  26. package/dist/cjs/internal/use-animated-visibility.js +11 -23
  27. package/dist/cjs/popover/popover.compiled.css +4 -0
  28. package/dist/cjs/popover/popover.js +63 -61
  29. package/dist/cjs/testing/polyfill.js +6 -7
  30. package/dist/es2019/dialog/dialog-content.js +2 -0
  31. package/dist/es2019/entry-points/use-popover-id.js +6 -10
  32. package/dist/es2019/internal/anchor-positioning/apply-anchor-positioning.js +83 -0
  33. package/dist/es2019/internal/anchor-positioning/cross-axis-shift-margins.js +29 -0
  34. package/dist/es2019/internal/anchor-positioning/edge-margin.js +18 -0
  35. package/dist/es2019/internal/anchor-positioning/fit-margins.js +69 -0
  36. package/dist/es2019/internal/anchor-positioning/get-existing-anchor-name.js +12 -0
  37. package/dist/es2019/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +9 -9
  38. package/dist/es2019/internal/anchor-positioning/placement-to-try-fallbacks.js +94 -0
  39. package/dist/es2019/internal/anchored-popover-size.js +343 -0
  40. package/dist/es2019/internal/get-aria-for-trigger.js +7 -13
  41. package/dist/es2019/internal/is-native-element-open.js +14 -0
  42. package/dist/es2019/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
  43. package/dist/es2019/internal/javascript-fallback/apply-javascript-fallback-positioning.js +291 -0
  44. package/dist/es2019/internal/javascript-fallback/resolve-css-length-to-pixels.js +87 -0
  45. package/dist/es2019/internal/javascript-fallback/warn-fallback-failure.js +14 -0
  46. package/dist/es2019/internal/resolve-placement.js +14 -6
  47. package/dist/es2019/internal/supports-anchor-positioning.js +12 -0
  48. package/dist/es2019/internal/supports-anchor-size.js +12 -0
  49. package/dist/es2019/internal/supports-css-declaration.js +20 -0
  50. package/dist/es2019/internal/surface-reset.js +1 -0
  51. package/dist/es2019/internal/use-anchored-popover-at-point.js +116 -0
  52. package/dist/es2019/internal/use-anchored-popover.js +265 -0
  53. package/dist/es2019/internal/use-animated-visibility.js +1 -14
  54. package/dist/es2019/popover/popover.compiled.css +4 -0
  55. package/dist/es2019/popover/popover.js +69 -61
  56. package/dist/es2019/testing/polyfill.js +6 -7
  57. package/dist/esm/dialog/dialog-content.js +2 -0
  58. package/dist/esm/entry-points/use-popover-id.js +6 -10
  59. package/dist/esm/internal/anchor-positioning/apply-anchor-positioning.js +80 -0
  60. package/dist/esm/internal/anchor-positioning/cross-axis-shift-margins.js +28 -0
  61. package/dist/esm/internal/anchor-positioning/edge-margin.js +15 -0
  62. package/dist/esm/internal/anchor-positioning/fit-margins.js +71 -0
  63. package/dist/esm/internal/anchor-positioning/get-existing-anchor-name.js +12 -0
  64. package/dist/esm/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +11 -12
  65. package/dist/esm/internal/anchor-positioning/placement-to-try-fallbacks.js +89 -0
  66. package/dist/esm/internal/anchored-popover-size.js +338 -0
  67. package/dist/esm/internal/get-aria-for-trigger.js +7 -13
  68. package/dist/esm/internal/is-native-element-open.js +13 -0
  69. package/dist/esm/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
  70. package/dist/esm/internal/javascript-fallback/apply-javascript-fallback-positioning.js +290 -0
  71. package/dist/esm/internal/javascript-fallback/resolve-css-length-to-pixels.js +85 -0
  72. package/dist/esm/internal/javascript-fallback/warn-fallback-failure.js +13 -0
  73. package/dist/esm/internal/resolve-placement.js +14 -6
  74. package/dist/esm/internal/supports-anchor-positioning.js +12 -0
  75. package/dist/esm/internal/supports-anchor-size.js +12 -0
  76. package/dist/esm/internal/supports-css-declaration.js +19 -0
  77. package/dist/esm/internal/surface-reset.js +1 -0
  78. package/dist/esm/internal/use-anchored-popover-at-point.js +118 -0
  79. package/dist/esm/internal/use-anchored-popover.js +271 -0
  80. package/dist/esm/internal/use-animated-visibility.js +10 -22
  81. package/dist/esm/popover/popover.compiled.css +4 -0
  82. package/dist/esm/popover/popover.js +63 -61
  83. package/dist/esm/testing/polyfill.js +6 -7
  84. package/dist/types/entry-points/placement-map.d.ts +2 -2
  85. package/dist/types/entry-points/use-popover-id.d.ts +3 -7
  86. package/dist/types/internal/anchor-positioning/apply-anchor-positioning.d.ts +26 -0
  87. package/dist/types/internal/anchor-positioning/cross-axis-shift-margins.d.ts +19 -0
  88. package/dist/types/internal/anchor-positioning/edge-margin.d.ts +10 -0
  89. package/dist/types/internal/anchor-positioning/fit-margins.d.ts +30 -0
  90. package/dist/types/internal/anchor-positioning/get-existing-anchor-name.d.ts +8 -0
  91. package/dist/types/internal/{placement-to-position-area.d.ts → anchor-positioning/placement-to-position-area.d.ts} +10 -6
  92. package/dist/types/internal/anchor-positioning/placement-to-try-fallbacks.d.ts +30 -0
  93. package/dist/types/internal/anchored-popover-size.d.ts +126 -0
  94. package/dist/types/internal/get-aria-for-trigger.d.ts +13 -25
  95. package/dist/types/internal/is-native-element-open.d.ts +3 -0
  96. package/dist/types/internal/javascript-fallback/anchor-positioning-fallback.d.ts +36 -0
  97. package/dist/types/internal/javascript-fallback/apply-javascript-fallback-positioning.d.ts +15 -0
  98. package/dist/types/internal/javascript-fallback/resolve-css-length-to-pixels.d.ts +20 -0
  99. package/dist/types/internal/javascript-fallback/warn-fallback-failure.d.ts +7 -0
  100. package/dist/types/internal/resolve-placement.d.ts +18 -2
  101. package/dist/types/internal/supports-anchor-positioning.d.ts +5 -0
  102. package/dist/types/internal/supports-anchor-size.d.ts +5 -0
  103. package/dist/types/internal/supports-css-declaration.d.ts +11 -0
  104. package/dist/types/internal/surface-reset.d.ts +25 -0
  105. package/dist/types/internal/use-anchored-popover-at-point.d.ts +48 -0
  106. package/dist/types/internal/use-anchored-popover.d.ts +143 -0
  107. package/dist/types/popover/index.d.ts +2 -1
  108. package/dist/types/popover/popover.d.ts +1 -1
  109. package/dist/types/popover/types.d.ts +15 -17
  110. package/dist/types/testing/polyfill.d.ts +3 -3
  111. package/package.json +2 -2
  112. package/use-anchored-popover/package.json +10 -0
  113. package/use-anchored-popover-at-point/package.json +10 -0
  114. package/dist/cjs/internal/placement-to-try-fallbacks.js +0 -108
  115. package/dist/cjs/internal/resolve-css-length-to-pixels.js +0 -104
  116. package/dist/cjs/internal/use-anchor-position-at-point.js +0 -129
  117. package/dist/cjs/internal/use-anchor-position.js +0 -501
  118. package/dist/cjs/internal/use-width-from-anchor.js +0 -124
  119. package/dist/es2019/internal/placement-to-try-fallbacks.js +0 -108
  120. package/dist/es2019/internal/resolve-css-length-to-pixels.js +0 -101
  121. package/dist/es2019/internal/use-anchor-position-at-point.js +0 -124
  122. package/dist/es2019/internal/use-anchor-position.js +0 -480
  123. package/dist/es2019/internal/use-width-from-anchor.js +0 -120
  124. package/dist/esm/internal/placement-to-try-fallbacks.js +0 -103
  125. package/dist/esm/internal/resolve-css-length-to-pixels.js +0 -98
  126. package/dist/esm/internal/use-anchor-position-at-point.js +0 -124
  127. package/dist/esm/internal/use-anchor-position.js +0 -494
  128. package/dist/esm/internal/use-width-from-anchor.js +0 -118
  129. package/dist/types/internal/anchor-positioning-fallback.d.ts +0 -51
  130. package/dist/types/internal/placement-to-try-fallbacks.d.ts +0 -13
  131. package/dist/types/internal/resolve-css-length-to-pixels.d.ts +0 -20
  132. package/dist/types/internal/use-anchor-position-at-point.d.ts +0 -67
  133. package/dist/types/internal/use-anchor-position.d.ts +0 -87
  134. package/dist/types/internal/use-width-from-anchor.d.ts +0 -19
  135. package/use-anchor-position/package.json +0 -10
  136. package/use-anchor-position-at-point/package.json +0 -10
  137. package/use-width-from-anchor/package.json +0 -10
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Positioning AND anchor-relative sizing for top-layer popovers. Anchors an
3
+ * ELEMENT; to anchor a viewport coordinate use `useAnchoredPopoverAtPoint`.
4
+ *
5
+ * Two runtime paths, each a function that applies its styles and returns the
6
+ * cleanup: CSS Anchor Positioning in `./anchor-positioning`, and the JavaScript
7
+ * fallback in `./javascript-fallback`. The path is resolved ONCE, at the top of
8
+ * the hook, and threaded through positioning, sizing and margins.
9
+ *
10
+ * See `notes/architecture/positioning.md` and
11
+ * `notes/decisions/fit-available-space.md`.
12
+ */
13
+ import { type RefObject } from 'react';
14
+ import { type TPopoverAxisSize } from './anchored-popover-size';
15
+ import { type TPlacementOptions } from './resolve-placement';
16
+ /**
17
+ * Exported so `useAnchoredPopoverAtPoint` can forward the options it does not own.
18
+ */
19
+ export type TAnchoredPopoverOptions = {
20
+ /**
21
+ * The element to position against. The ref OBJECT must be referentially stable,
22
+ * as the effect depends on it. `.current` may be `null` on the first render.
23
+ */
24
+ anchorRef: RefObject<HTMLElement | null>;
25
+ /**
26
+ * `false` means "do not position": the hook applies nothing and touches no DOM,
27
+ * so another strategy can own the popover. Defaults to `true`.
28
+ *
29
+ * A disabled hook holds no `setStyle` snapshot, which is what lets a consumer
30
+ * call this AND `useAnchoredPopoverAtPoint` on one popover with COMPLEMENTARY
31
+ * values. Two enabled hooks nest their snapshots, and React unwinds them in
32
+ * commit order rather than write order, so a stale inline value can survive.
33
+ */
34
+ isEnabled?: boolean;
35
+ /**
36
+ * Element being positioned. May be unmounted between opens; see `isOpen`.
37
+ */
38
+ popoverRef: RefObject<HTMLElement | null>;
39
+ /**
40
+ * Where the popover sits relative to the anchor, plus `offset.gap`,
41
+ * `offset.crossAxisShift` and `minSize`. Required, because the sizing rules read
42
+ * the placement axis; individual fields are optional. See `TPlacementOptions`.
43
+ */
44
+ placement: TPlacementOptions;
45
+ /**
46
+ * Re-runs the effect across open cycles, so styles and listeners follow the live
47
+ * host element through a remount.
48
+ */
49
+ isOpen: boolean;
50
+ /**
51
+ * How wide the popover is, defaulting to `'content'`: the natural width, so a
52
+ * popover too wide for the space beside its anchor slides to a roomier side
53
+ * rather than wrapping into it. Both axes take the same four values under the
54
+ * same rules - see `TPopoverAxisSize` in `anchored-popover-size.tsx`.
55
+ */
56
+ inlineSize?: TPopoverAxisSize;
57
+ /**
58
+ * The block-axis twin of `inlineSize`, so `'max-available'` caps the HEIGHT.
59
+ */
60
+ blockSize?: TPopoverAxisSize;
61
+ /**
62
+ * Leaves `inline-size` to the popover element's own styles, skipping
63
+ * `TPopoverAxisSize` rule 4. For an element the consumer owns and may have given
64
+ * a `width` of its own - `@atlaskit/popper`'s imperative `createPopper` adapter
65
+ * is the case. Everything positioning an unstyled `Popover` host leaves this
66
+ * `false`.
67
+ */
68
+ shouldPreserveInlineSize?: boolean;
69
+ /**
70
+ * Forces the JavaScript positioning fallback, so it can be exercised in any
71
+ * environment.
72
+ *
73
+ * @internal Testing only. Also switches sizing to measured pixels, because
74
+ * `anchor-size()` has no anchor to resolve against without `position-anchor`.
75
+ */
76
+ forceFallbackPositioning?: boolean;
77
+ };
78
+ /**
79
+ * Positions and sizes a popover relative to an anchor. Owns every inline style on
80
+ * the popover host: where it goes, how big it is relative to its anchor, and the
81
+ * margins that keep it clear of the anchor and the viewport edge. It knows nothing
82
+ * about visibility or animation - compose it with `Popover`.
83
+ *
84
+ * On modern browsers the browser handles flipping via CSS Anchor Positioning;
85
+ * otherwise it falls back to measured `position: fixed` coordinates, re-run on
86
+ * scroll and resize.
87
+ *
88
+ * `inlineSize` and `blockSize` both default to `'content'`. Two rules are
89
+ * surprising: fitting one axis also fits an axis left on `'content'`, and fitting
90
+ * either axis floors the placement axis. See `TPopoverAxisSize`.
91
+ *
92
+ * **Several React roots on one page.** The `anchor-name` this hook writes to an
93
+ * anchor that has none is minted from `useId()`, like every other id in the design
94
+ * system. `useId()` is unique within a root; across roots it is unique for
95
+ * client-rendered roots but NOT for roots that hydrate the same markup, where it
96
+ * is derived from tree position. Two anchors carrying one name resolve to the last
97
+ * in tree order, so a popover can attach to another root's trigger. A host that
98
+ * hydrates more than one root must give each a distinct `identifierPrefix` (on
99
+ * `hydrateRoot` and the matching server render). That is already required for the
100
+ * popover's own `id`, which `aria-controls` and `popovertarget` point at, and for
101
+ * every `aria-*` id the design system mints. A bundle with two copies of
102
+ * `react-dom` has the same exposure for client-rendered roots.
103
+ *
104
+ * @example Position a popover below its trigger
105
+ * ```tsx
106
+ * const triggerRef = useRef<HTMLButtonElement>(null);
107
+ * const popoverRef = useRef<HTMLDivElement>(null);
108
+ *
109
+ * useAnchoredPopover({
110
+ * anchorRef: triggerRef,
111
+ * popoverRef,
112
+ * placement: { axis: 'block', edge: 'end' },
113
+ * isOpen,
114
+ * });
115
+ * ```
116
+ *
117
+ * @example Match the trigger's width and keep the popover on screen
118
+ * ```tsx
119
+ * // What `<Popup shouldFitContainer shouldFitViewport>` maps to.
120
+ * useAnchoredPopover({
121
+ * anchorRef: triggerRef,
122
+ * popoverRef,
123
+ * placement: { axis: 'block', edge: 'end' },
124
+ * isOpen,
125
+ * inlineSize: 'match-anchor',
126
+ * blockSize: 'max-available',
127
+ * });
128
+ * ```
129
+ *
130
+ * @example Switch to a cursor position mid-mount
131
+ * ```tsx
132
+ * // Complementary `isEnabled`, so exactly one hook owns the popover.
133
+ * const shared = { popoverRef, placement, isOpen };
134
+ *
135
+ * useAnchoredPopover({ ...shared, anchorRef: triggerRef, isEnabled: !mousePos });
136
+ * useAnchoredPopoverAtPoint({
137
+ * ...shared,
138
+ * isEnabled: Boolean(mousePos),
139
+ * getPoint: () => mousePosRef.current,
140
+ * });
141
+ * ```
142
+ */
143
+ export declare function useAnchoredPopover({ anchorRef, popoverRef, placement, isOpen, isEnabled, inlineSize, blockSize, shouldPreserveInlineSize, forceFallbackPositioning, }: TAnchoredPopoverOptions): void;
@@ -9,4 +9,5 @@ export { createPopoverCloseEvent } from './create-close-event';
9
9
  /**
10
10
  * @deprecated Import from the generated per-export subpath instead.
11
11
  */
12
- export type { TPopoverCloseReason, TPopoverProps, TPlacementOptions } from './types';
12
+ export type { TPopoverCloseReason, TPopoverProps } from './types';
13
+ export type { TPlacementOptions } from '../internal/resolve-placement';
@@ -6,7 +6,7 @@ import React from 'react';
6
6
  import { type TPopoverForwardedProps } from './types';
7
7
  /**
8
8
  * Unopinionated top-layer primitive. Owns visibility and animation only;
9
- * compose with `useAnchorPosition` / `useWidthFromAnchor` for positioning.
9
+ * compose with `useAnchoredPopover` for positioning and sizing.
10
10
  *
11
11
  * ### 🔌 Visibility
12
12
  *
@@ -30,6 +30,18 @@ export type TPopoverForwardedProps = TPopoverBaseProps & {
30
30
  };
31
31
  export type { TPlacementOptions };
32
32
  type TPopoverBaseProps = {
33
+ /**
34
+ * Pass ONE element. The host is a flex row while open, so that a size cap can
35
+ * reach it (see `useAnchoredPopover`); two element children become two flex
36
+ * items SIDE BY SIDE at half width each. A fragment does not help - its children
37
+ * are the flex items - which is why this is not expressible as a type. It
38
+ * matters most where a consumer's render prop is handed through unwrapped, as
39
+ * `@atlaskit/popper` and `@atlaskit/spotlight` do.
40
+ *
41
+ * The host zeroes that element's `min-inline-size` and `min-block-size` so the
42
+ * cap can shrink a non-scrolling child, at zero specificity, so a minimum the
43
+ * element sets itself wins. See the host styles in `popover.tsx`.
44
+ */
33
45
  children: ReactNode;
34
46
  /**
35
47
  * Animation styles applied while the popover is entering.
@@ -100,7 +112,7 @@ type TPopoverBaseProps = {
100
112
  * properties (like `--ds-popover-tx`, `--ds-popover-ty`) that control the
101
113
  * slide direction. Has no effect without `shouldAnimate`.
102
114
  *
103
- * This does NOT control positioning. Use `useAnchorPosition` for that.
115
+ * This does NOT control positioning. Use `useAnchoredPopover` for that.
104
116
  */
105
117
  placement?: TPlacementOptions;
106
118
  /**
@@ -125,8 +137,8 @@ type TPopoverBaseProps = {
125
137
  * Unopinionated top-layer primitive.
126
138
  *
127
139
  * `Popover` manages only top-layer visibility and animation. It has no
128
- * knowledge of positioning. For anchor positioning, compose with the
129
- * `useAnchorPosition` hook separately.
140
+ * knowledge of positioning. For anchor positioning and sizing, compose with the
141
+ * `useAnchoredPopover` hook separately.
130
142
  *
131
143
  * Use `Popover` directly for custom trigger lifecycles (hover, timers,
132
144
  * external state) or trigger-less UI (flags, toasts). For the common
@@ -164,17 +176,3 @@ export type TPopoverProps = TPopoverBaseProps & TAriaRoleRequired & ({
164
176
  mode: 'manual';
165
177
  onClose?: never;
166
178
  });
167
- /**
168
- * The width mode of the popover relative to its anchor element.
169
- *
170
- * - `'none'` (default): popover sizes to its content, ignoring the anchor width.
171
- * - `'match-anchor'`: popover matches the anchor element's width exactly
172
- * via CSS `inline-size: anchor-size(self-inline)`. Falls back to a
173
- * one-off measurement of `anchorRef.current.offsetWidth` when CSS
174
- * Anchor Positioning is not supported.
175
- * - `'min-anchor'`: popover is at least as wide as the anchor, but
176
- * can grow wider if content requires it. Uses
177
- * `min-inline-size: anchor-size(self-inline)`. Falls back to a one-off
178
- * measurement of the anchor's width.
179
- */
180
- export type TWidthFromAnchorMode = 'none' | 'match-anchor' | 'min-anchor';
@@ -12,9 +12,9 @@
12
12
  * - Popover open state tracked via `data-popover-open` (no `:popover-open` in jsdom).
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
- * - 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-position`) become
17
- * visible in jsdom, where layout-driven RO callbacks never fire.
15
+ * - On open, removes any inline `opacity: 0` from the popover element, so the
16
+ * JavaScript positioning fallback's `ResizeObserver` reveal is not needed in
17
+ * jsdom, where its non-zero-layout guard can never pass.
18
18
  *
19
19
  * Companion `toBeVisible` patch lives at `./to-be-visible`.
20
20
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/top-layer",
3
- "version": "4.4.5",
3
+ "version": "5.0.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",
@@ -40,7 +40,7 @@
40
40
  "@atlaskit/ds-lib": "^8.0.0",
41
41
  "@atlaskit/layering": "^5.2.0",
42
42
  "@atlaskit/react-compiler-gating": "^0.2.0",
43
- "@atlaskit/tokens": "^16.11.0",
43
+ "@atlaskit/tokens": "^17.0.0",
44
44
  "@babel/runtime": "^7.0.0",
45
45
  "@compiled/react": "^1.0.2",
46
46
  "bind-event-listener": "^3.0.0",
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@atlaskit/top-layer/use-anchored-popover",
3
+ "main": "../dist/cjs/internal/use-anchored-popover.js",
4
+ "module": "../dist/esm/internal/use-anchored-popover.js",
5
+ "module:es2019": "../dist/es2019/internal/use-anchored-popover.js",
6
+ "sideEffects": [
7
+ "*.compiled.css"
8
+ ],
9
+ "types": "../dist/types/internal/use-anchored-popover.d.ts"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@atlaskit/top-layer/use-anchored-popover-at-point",
3
+ "main": "../dist/cjs/internal/use-anchored-popover-at-point.js",
4
+ "module": "../dist/esm/internal/use-anchored-popover-at-point.js",
5
+ "module:es2019": "../dist/es2019/internal/use-anchored-popover-at-point.js",
6
+ "sideEffects": [
7
+ "*.compiled.css"
8
+ ],
9
+ "types": "../dist/types/internal/use-anchored-popover-at-point.d.ts"
10
+ }
@@ -1,108 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.placementToTryFallbacks = placementToTryFallbacks;
7
- var _resolvePlacement = require("./resolve-placement");
8
- /**
9
- * A `position-area` primary edge — the placement axis joined to its edge, e.g.
10
- * `block-end` or `inline-start`. These are the four edges a popover can sit on.
11
- */
12
-
13
- function slideOnEdge(_ref) {
14
- var align = _ref.align,
15
- edgeKey = _ref.edgeKey,
16
- crossAxis = _ref.crossAxis;
17
- if (align === 'center') {
18
- return ["".concat(edgeKey, " span-").concat(crossAxis, "-end"), "".concat(edgeKey, " span-").concat(crossAxis, "-start")];
19
- }
20
- // For `align: 'start'` the popover expands toward `end`, so the "near"
21
- // span is `end` and the "far" span is `start`; `align: 'end'` mirrors
22
- // this. The bare `edgeKey` (re-centered) sits between them.
23
- var near = align === 'start' ? 'end' : 'start';
24
- var far = align === 'start' ? 'start' : 'end';
25
- return ["".concat(edgeKey, " span-").concat(crossAxis, "-").concat(near), edgeKey, "".concat(edgeKey, " span-").concat(crossAxis, "-").concat(far)];
26
- }
27
- function flipDiagonally(_ref2) {
28
- var axis = _ref2.axis;
29
- var flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
30
- var flipToCrossAxis = axis === 'block' ? 'flip-inline' : 'flip-block';
31
- return "".concat(flipOnMainAxis, " ").concat(flipToCrossAxis);
32
- }
33
-
34
- /**
35
- * Returns the `position-try-fallbacks` value for a placement.
36
- *
37
- * @example
38
- * // Centered on the block-end edge (the default placement):
39
- * placementToTryFallbacks({ placement: { axis: 'block', edge: 'end', align: 'center' } });
40
- * // => 'block-end span-inline-end, block-end span-inline-start, flip-block,
41
- * // block-start span-inline-end, block-start span-inline-start'
42
- */
43
- function placementToTryFallbacks(_ref3) {
44
- var placement = _ref3.placement;
45
- /**
46
- * **Build the fallback list**
47
- *
48
- * Each entry is a complete alternative position.
49
- * The browser tries them _in order_ and uses the _first_ one that fits.
50
- */
51
-
52
- var resolved = (0, _resolvePlacement.resolvePlacement)({
53
- placement: placement
54
- });
55
- var axis = resolved.axis,
56
- edge = resolved.edge,
57
- align = resolved.align;
58
- var crossAxis = axis === 'block' ? 'inline' : 'block';
59
- var flippedEdge = edge === 'start' ? 'end' : 'start';
60
- var sameEdgeArea = "".concat(axis, "-").concat(edge);
61
- var oppositeEdgeArea = "".concat(axis, "-").concat(flippedEdge);
62
- var 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: align,
99
- edgeKey: sameEdgeArea,
100
- crossAxis: crossAxis
101
- }), flipOnMainAxis, align !== 'center' ? flipDiagonally({
102
- axis: axis
103
- }) : null, slideOnEdge({
104
- align: align,
105
- edgeKey: oppositeEdgeArea,
106
- crossAxis: crossAxis
107
- })].filter(Boolean).flat().join(', ');
108
- }
@@ -1,104 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.resolveCssLengthToPixels = resolveCssLengthToPixels;
7
- var elementCaches = new WeakMap();
8
- function canCacheResolvedLength(value) {
9
- // Custom-property values can be retargeted by inline overrides on the
10
- // consumer's wrapper, so we cannot prove a cached pixel value is still valid.
11
- return !value.includes('var(');
12
- }
13
- function getCachedResolvedLength(_ref) {
14
- var _cacheForElement$get;
15
- var element = _ref.element,
16
- value = _ref.value;
17
- if (!canCacheResolvedLength(value)) {
18
- return null;
19
- }
20
- var cacheForElement = elementCaches.get(element);
21
- return (_cacheForElement$get = cacheForElement === null || cacheForElement === void 0 ? void 0 : cacheForElement.get(value)) !== null && _cacheForElement$get !== void 0 ? _cacheForElement$get : null;
22
- }
23
- function cacheResolvedLength(_ref2) {
24
- var _elementCaches$get;
25
- var element = _ref2.element,
26
- value = _ref2.value,
27
- result = _ref2.result;
28
- if (!canCacheResolvedLength(value)) {
29
- return;
30
- }
31
- var cacheForElement = (_elementCaches$get = elementCaches.get(element)) !== null && _elementCaches$get !== void 0 ? _elementCaches$get : new Map();
32
- cacheForElement.set(value, result);
33
- elementCaches.set(element, cacheForElement);
34
- }
35
-
36
- /**
37
- * Resolves a CSS length value to a pixel number using a hidden DOM probe.
38
- *
39
- * Used by the JS positioning fallback: consumer offsets can be numbers,
40
- * `${n}px` strings, tokenised `var(--ds-space-100, 8px)` strings, `calc()`
41
- * expressions, viewport units, etc. Parsing arbitrary CSS in JS is fragile
42
- * (and impossible for `calc(var(...))` without a layout context), so we let
43
- * the browser do the math.
44
- *
45
- * The probe is appended to `container` so it inherits the same containing
46
- * block, font size, and custom-property scope as the popover.
47
- *
48
- * Cost: one synchronous reflow on first cacheable resolution per
49
- * (container, value) pair, then a `WeakMap` lookup. Resolutions involving
50
- * `var(` are intentionally not cached.
51
- */
52
- function resolveCssLengthToPixels(_ref3) {
53
- var value = _ref3.value,
54
- container = _ref3.container;
55
- if (typeof value === 'number') {
56
- return value;
57
- }
58
-
59
- // Fast path: unitless zero is universally zero pixels - accept `'0'` and
60
- // `'-0'` without a probe. (Consumers occasionally pass `'0'` instead of
61
- // the number `0`.)
62
- if (value === '0' || value === '-0') {
63
- return 0;
64
- }
65
-
66
- // Fast path: bare `${n}px` strings come from the consumer normalisation
67
- // in `resolvePlacement`. Avoid a reflow when we can.
68
- var pxMatch = value.match(/^(-?\d+(?:\.\d+)?)px$/);
69
- if (pxMatch) {
70
- return Number(pxMatch[1]);
71
- }
72
- var cached = getCachedResolvedLength({
73
- element: container,
74
- value: value
75
- });
76
- if (cached !== null) {
77
- return cached;
78
- }
79
- var probe = container.ownerDocument.createElement('div');
80
- probe.style.position = 'absolute';
81
- probe.style.visibility = 'hidden';
82
- probe.style.pointerEvents = 'none';
83
- probe.style.height = '0';
84
- probe.style.padding = '0';
85
- probe.style.border = '0';
86
- // `width` clamps negatives to 0; use `margin-left` instead so signs are
87
- // preserved. `getComputedStyle` returns the resolved pixel value for
88
- // margin-* properties even when the source was a token / calc / var.
89
- probe.style.marginLeft = value;
90
- // Hide the probe from assistive tech and event targeting; defensive
91
- // against `getElementsByTagName('div')` walks in consumer code.
92
- probe.setAttribute('aria-hidden', 'true');
93
- probe.setAttribute('inert', '');
94
- container.appendChild(probe);
95
- var resolved = parseFloat(getComputedStyle(probe).marginLeft);
96
- container.removeChild(probe);
97
- var result = Number.isFinite(resolved) ? resolved : 0;
98
- cacheResolvedLength({
99
- element: container,
100
- value: value,
101
- result: result
102
- });
103
- return result;
104
- }
@@ -1,129 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.useAnchorPositionAtPoint = useAnchorPositionAtPoint;
7
- var _react = require("react");
8
- var _useAnchorPosition = require("./use-anchor-position");
9
- /**
10
- * A point in viewport coordinates (CSS pixels) at which the synthetic
11
- * anchor should be placed.
12
- *
13
- * Axis-named (`x`/`y`) rather than edge-named (`left`/`top`) so the
14
- * shape is unambiguous in RTL writing modes - there is no ambiguity
15
- * about whether a coordinate is logical (`inline-start`/`block-start`)
16
- * or physical (`left`/`top`). Viewport coordinates are always
17
- * physical, so we name them with the physical axis labels.
18
- */
19
-
20
- /**
21
- * Styles the synthetic anchor as an invisible, zero-size point.
22
- * Dynamic `inset-*` overrides are written by the positioning effect.
23
- *
24
- * Uses `Object.assign` rather than Compiled CSS (element is outside the React tree)
25
- * or the internal `setStyle` helper (we own this element entirely - it is created
26
- * and removed by this hook - so the snapshot/restore semantics `setStyle`
27
- * provides for caller-owned elements would be dead work here).
28
- */
29
- function applyStaticAnchorStyles(element) {
30
- Object.assign(element.style, {
31
- position: 'fixed',
32
- // `top`/`left` rather than `inset-block-start`/`inset-inline-start`
33
- // for consistency with the dynamic positioning effect below, which
34
- // uses physical properties (see comment there for the rationale).
35
- top: '0',
36
- left: '0',
37
- // Zero size - placement decides which side the popover sits on.
38
- width: '0',
39
- height: '0',
40
- // Prevent the overlay from intercepting pointer events.
41
- pointerEvents: 'none'
42
- });
43
- }
44
-
45
- // `useAnchorPosition` requires a real DOM element. When the caller only
46
- // has a viewport coordinate (e.g. cursor at hover time), this hook
47
- // manages a hidden `<div>` at that point and delegates the rest.
48
- //
49
- // The `<div>` is appended directly to `document.body` to escape any
50
- // transformed ancestor, which would otherwise break `position: fixed`
51
- // viewport-relative resolution.
52
-
53
- /**
54
- * Positions a popover at a consumer-supplied viewport coordinate using a
55
- * hidden synthetic anchor.
56
- *
57
- * @example
58
- * ```tsx
59
- * function PointPositionedPopover({ popoverRef, placement, mousePos }) {
60
- * useAnchorPositionAtPoint({
61
- * popoverRef,
62
- * placement,
63
- * isEnabled: Boolean(mousePos),
64
- * getPoint: () => {
65
- * if (!mousePos) return null;
66
- * return { x: mousePos.clientX, y: mousePos.clientY };
67
- * },
68
- * });
69
- * return <Popover ref={popoverRef}>...</Popover>;
70
- * }
71
- * ```
72
- */
73
- function useAnchorPositionAtPoint(_ref) {
74
- var popoverRef = _ref.popoverRef,
75
- placement = _ref.placement,
76
- getPoint = _ref.getPoint,
77
- _ref$isEnabled = _ref.isEnabled,
78
- isEnabled = _ref$isEnabled === void 0 ? true : _ref$isEnabled,
79
- isOpen = _ref.isOpen;
80
- var syntheticAnchorRef = (0, _react.useRef)(null);
81
-
82
- // `getPoint` is kept in a ref so the layout effect can call the
83
- // latest version without listing it as a dep - that would re-fire
84
- // on every render and re-latch the point.
85
- var getPointRef = (0, _react.useRef)(getPoint);
86
- getPointRef.current = getPoint;
87
-
88
- // Lazy element creation: the `<div>` is only created when both
89
- // `isEnabled` is true AND `getPoint()` returns a non-null point.
90
- // `useLayoutEffect` ensures the element exists before the inner
91
- // `useAnchorPosition` (also a layout effect) reads the ref.
92
- (0, _react.useLayoutEffect)(function () {
93
- if (!isEnabled) {
94
- return;
95
- }
96
- var point = getPointRef.current();
97
- if (!point) {
98
- return;
99
- }
100
- var anchor = document.createElement('div');
101
- anchor.setAttribute('aria-hidden', 'true');
102
- applyStaticAnchorStyles(anchor);
103
- // `point.x`/`y` are physical viewport coordinates (from
104
- // `MouseEvent.clientX/Y`), so map directly onto physical
105
- // `left`/`top`. This is RTL-safe: `position: fixed` + physical
106
- // insets is direction-independent. Using logical
107
- // `inset-inline-start` would need `viewportWidth - point.x` in
108
- // RTL to land at the same physical pixel.
109
- anchor.style.top = "".concat(point.y, "px");
110
- anchor.style.left = "".concat(point.x, "px");
111
- document.body.appendChild(anchor);
112
- syntheticAnchorRef.current = anchor;
113
- return function cleanup() {
114
- anchor.remove();
115
- syntheticAnchorRef.current = null;
116
- };
117
- }, [isEnabled]);
118
-
119
- // Mirror `isEnabled` so both hooks stay in sync - when disabled,
120
- // neither this hook nor the inner one touches the popover, leaving
121
- // any other positioning the consumer has set up free to take effect.
122
- (0, _useAnchorPosition.useAnchorPosition)({
123
- anchorRef: syntheticAnchorRef,
124
- popoverRef: popoverRef,
125
- placement: placement,
126
- isEnabled: isEnabled,
127
- isOpen: isOpen
128
- });
129
- }