@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.
- package/CHANGELOG.md +41 -0
- package/README.md +13 -4
- package/dist/cjs/dialog/dialog-content.js +2 -0
- package/dist/cjs/entry-points/use-popover-id.js +5 -10
- package/dist/cjs/internal/anchor-positioning/apply-anchor-positioning.js +86 -0
- package/dist/cjs/internal/anchor-positioning/cross-axis-shift-margins.js +34 -0
- package/dist/cjs/internal/anchor-positioning/edge-margin.js +21 -0
- package/dist/cjs/internal/anchor-positioning/fit-margins.js +77 -0
- package/dist/cjs/internal/anchor-positioning/get-existing-anchor-name.js +18 -0
- package/dist/cjs/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +11 -11
- package/dist/cjs/internal/anchor-positioning/placement-to-try-fallbacks.js +95 -0
- package/dist/cjs/internal/anchored-popover-size.js +345 -0
- package/dist/cjs/internal/get-aria-for-trigger.js +7 -13
- package/dist/cjs/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
- package/dist/cjs/internal/javascript-fallback/apply-javascript-fallback-positioning.js +297 -0
- package/dist/cjs/internal/javascript-fallback/resolve-css-length-to-pixels.js +90 -0
- package/dist/cjs/internal/javascript-fallback/warn-fallback-failure.js +19 -0
- package/dist/cjs/internal/resolve-placement.js +14 -6
- package/dist/cjs/internal/supports-anchor-positioning.js +17 -0
- package/dist/cjs/internal/supports-anchor-size.js +17 -0
- package/dist/cjs/internal/supports-css-declaration.js +25 -0
- package/dist/cjs/internal/surface-reset.js +5 -0
- package/dist/cjs/internal/use-anchored-popover-at-point.js +124 -0
- package/dist/cjs/internal/use-anchored-popover.js +277 -0
- package/dist/cjs/popover/popover.compiled.css +4 -0
- package/dist/cjs/popover/popover.js +11 -4
- package/dist/cjs/testing/polyfill.js +6 -7
- package/dist/es2019/dialog/dialog-content.js +2 -0
- package/dist/es2019/entry-points/use-popover-id.js +6 -10
- package/dist/es2019/internal/anchor-positioning/apply-anchor-positioning.js +83 -0
- package/dist/es2019/internal/anchor-positioning/cross-axis-shift-margins.js +29 -0
- package/dist/es2019/internal/anchor-positioning/edge-margin.js +18 -0
- package/dist/es2019/internal/anchor-positioning/fit-margins.js +69 -0
- package/dist/es2019/internal/anchor-positioning/get-existing-anchor-name.js +12 -0
- package/dist/es2019/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +9 -9
- package/dist/es2019/internal/anchor-positioning/placement-to-try-fallbacks.js +94 -0
- package/dist/es2019/internal/anchored-popover-size.js +343 -0
- package/dist/es2019/internal/get-aria-for-trigger.js +7 -13
- package/dist/es2019/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
- package/dist/es2019/internal/javascript-fallback/apply-javascript-fallback-positioning.js +291 -0
- package/dist/es2019/internal/javascript-fallback/resolve-css-length-to-pixels.js +87 -0
- package/dist/es2019/internal/javascript-fallback/warn-fallback-failure.js +14 -0
- package/dist/es2019/internal/resolve-placement.js +14 -6
- package/dist/es2019/internal/supports-anchor-positioning.js +12 -0
- package/dist/es2019/internal/supports-anchor-size.js +12 -0
- package/dist/es2019/internal/supports-css-declaration.js +20 -0
- package/dist/es2019/internal/surface-reset.js +1 -0
- package/dist/es2019/internal/use-anchored-popover-at-point.js +116 -0
- package/dist/es2019/internal/use-anchored-popover.js +265 -0
- package/dist/es2019/popover/popover.compiled.css +4 -0
- package/dist/es2019/popover/popover.js +11 -4
- package/dist/es2019/testing/polyfill.js +6 -7
- package/dist/esm/dialog/dialog-content.js +2 -0
- package/dist/esm/entry-points/use-popover-id.js +6 -10
- package/dist/esm/internal/anchor-positioning/apply-anchor-positioning.js +80 -0
- package/dist/esm/internal/anchor-positioning/cross-axis-shift-margins.js +28 -0
- package/dist/esm/internal/anchor-positioning/edge-margin.js +15 -0
- package/dist/esm/internal/anchor-positioning/fit-margins.js +71 -0
- package/dist/esm/internal/anchor-positioning/get-existing-anchor-name.js +12 -0
- package/dist/esm/internal/{placement-to-position-area.js → anchor-positioning/placement-to-position-area.js} +11 -12
- package/dist/esm/internal/anchor-positioning/placement-to-try-fallbacks.js +89 -0
- package/dist/esm/internal/anchored-popover-size.js +338 -0
- package/dist/esm/internal/get-aria-for-trigger.js +7 -13
- package/dist/esm/internal/{anchor-positioning-fallback.js → javascript-fallback/anchor-positioning-fallback.js} +12 -33
- package/dist/esm/internal/javascript-fallback/apply-javascript-fallback-positioning.js +290 -0
- package/dist/esm/internal/javascript-fallback/resolve-css-length-to-pixels.js +85 -0
- package/dist/esm/internal/javascript-fallback/warn-fallback-failure.js +13 -0
- package/dist/esm/internal/resolve-placement.js +14 -6
- package/dist/esm/internal/supports-anchor-positioning.js +12 -0
- package/dist/esm/internal/supports-anchor-size.js +12 -0
- package/dist/esm/internal/supports-css-declaration.js +19 -0
- package/dist/esm/internal/surface-reset.js +1 -0
- package/dist/esm/internal/use-anchored-popover-at-point.js +118 -0
- package/dist/esm/internal/use-anchored-popover.js +271 -0
- package/dist/esm/popover/popover.compiled.css +4 -0
- package/dist/esm/popover/popover.js +11 -4
- package/dist/esm/testing/polyfill.js +6 -7
- package/dist/types/entry-points/placement-map.d.ts +2 -2
- package/dist/types/entry-points/use-popover-id.d.ts +3 -7
- package/dist/types/internal/anchor-positioning/apply-anchor-positioning.d.ts +26 -0
- package/dist/types/internal/anchor-positioning/cross-axis-shift-margins.d.ts +19 -0
- package/dist/types/internal/anchor-positioning/edge-margin.d.ts +10 -0
- package/dist/types/internal/anchor-positioning/fit-margins.d.ts +30 -0
- package/dist/types/internal/anchor-positioning/get-existing-anchor-name.d.ts +8 -0
- package/dist/types/internal/{placement-to-position-area.d.ts → anchor-positioning/placement-to-position-area.d.ts} +10 -6
- package/dist/types/internal/anchor-positioning/placement-to-try-fallbacks.d.ts +30 -0
- package/dist/types/internal/anchored-popover-size.d.ts +126 -0
- package/dist/types/internal/get-aria-for-trigger.d.ts +13 -25
- package/dist/types/internal/javascript-fallback/anchor-positioning-fallback.d.ts +36 -0
- package/dist/types/internal/javascript-fallback/apply-javascript-fallback-positioning.d.ts +15 -0
- package/dist/types/internal/javascript-fallback/resolve-css-length-to-pixels.d.ts +20 -0
- package/dist/types/internal/javascript-fallback/warn-fallback-failure.d.ts +7 -0
- package/dist/types/internal/resolve-placement.d.ts +18 -2
- package/dist/types/internal/supports-anchor-positioning.d.ts +5 -0
- package/dist/types/internal/supports-anchor-size.d.ts +5 -0
- package/dist/types/internal/supports-css-declaration.d.ts +11 -0
- package/dist/types/internal/surface-reset.d.ts +25 -0
- package/dist/types/internal/use-anchored-popover-at-point.d.ts +48 -0
- package/dist/types/internal/use-anchored-popover.d.ts +143 -0
- package/dist/types/popover/index.d.ts +2 -1
- package/dist/types/popover/popover.d.ts +1 -1
- package/dist/types/popover/types.d.ts +15 -17
- package/dist/types/testing/polyfill.d.ts +3 -3
- package/package.json +2 -2
- package/use-anchored-popover/package.json +10 -0
- package/use-anchored-popover-at-point/package.json +10 -0
- package/dist/cjs/internal/placement-to-try-fallbacks.js +0 -108
- package/dist/cjs/internal/resolve-css-length-to-pixels.js +0 -104
- package/dist/cjs/internal/use-anchor-position-at-point.js +0 -129
- package/dist/cjs/internal/use-anchor-position.js +0 -501
- package/dist/cjs/internal/use-width-from-anchor.js +0 -124
- package/dist/es2019/internal/placement-to-try-fallbacks.js +0 -108
- package/dist/es2019/internal/resolve-css-length-to-pixels.js +0 -101
- package/dist/es2019/internal/use-anchor-position-at-point.js +0 -124
- package/dist/es2019/internal/use-anchor-position.js +0 -480
- package/dist/es2019/internal/use-width-from-anchor.js +0 -120
- package/dist/esm/internal/placement-to-try-fallbacks.js +0 -103
- package/dist/esm/internal/resolve-css-length-to-pixels.js +0 -98
- package/dist/esm/internal/use-anchor-position-at-point.js +0 -124
- package/dist/esm/internal/use-anchor-position.js +0 -494
- package/dist/esm/internal/use-width-from-anchor.js +0 -118
- package/dist/types/internal/anchor-positioning-fallback.d.ts +0 -51
- package/dist/types/internal/placement-to-try-fallbacks.d.ts +0 -13
- package/dist/types/internal/resolve-css-length-to-pixels.d.ts +0 -20
- package/dist/types/internal/use-anchor-position-at-point.d.ts +0 -67
- package/dist/types/internal/use-anchor-position.d.ts +0 -87
- package/dist/types/internal/use-width-from-anchor.d.ts +0 -19
- package/use-anchor-position/package.json +0 -10
- package/use-anchor-position-at-point/package.json +0 -10
- package/use-width-from-anchor/package.json +0 -10
|
@@ -0,0 +1,265 @@
|
|
|
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 { useLayoutEffect, useMemo } from 'react';
|
|
14
|
+
import { useId } from '@atlaskit/ds-lib/use-id';
|
|
15
|
+
import { applyAnchorPositioning } from './anchor-positioning/apply-anchor-positioning';
|
|
16
|
+
import { getAnchoredPopoverSizeDeclarations } from './anchored-popover-size';
|
|
17
|
+
import { applyJavaScriptFallbackPositioning } from './javascript-fallback/apply-javascript-fallback-positioning';
|
|
18
|
+
import { resolvePlacement } from './resolve-placement';
|
|
19
|
+
import { supportsAnchorPositioning } from './supports-anchor-positioning';
|
|
20
|
+
import { supportsAnchorSize } from './supports-anchor-size';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Which way the popover's inline axis runs. Maps every physical measurement below
|
|
24
|
+
* onto a logical axis: the viewport unit of each cap and the anchor's measured
|
|
25
|
+
* size. A style read, not a layout read, so it is cheap enough to take for every
|
|
26
|
+
* popover.
|
|
27
|
+
*/
|
|
28
|
+
function getPopoverWritingMode({
|
|
29
|
+
popover
|
|
30
|
+
}) {
|
|
31
|
+
// `String()` because not every test environment implements `writing-mode`.
|
|
32
|
+
const writingMode = String(getComputedStyle(popover).writingMode);
|
|
33
|
+
const isVertical = writingMode.startsWith('vertical') || writingMode.startsWith('sideways');
|
|
34
|
+
return isVertical ? 'vertical' : 'horizontal';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Measured stand-in for `anchor-size(self-*)`, used wherever `anchor-size()` is
|
|
39
|
+
* not: the JavaScript fallback, and browsers with anchor positioning but no
|
|
40
|
+
* `anchor-size()`.
|
|
41
|
+
*
|
|
42
|
+
* `offsetWidth` / `offsetHeight` are physical, so the axis is picked from the
|
|
43
|
+
* POPOVER's `writing-mode`. Deliberately not memoized: a cached anchor size is a
|
|
44
|
+
* stale one. Runs once per effect, not per frame.
|
|
45
|
+
*/
|
|
46
|
+
function measureAnchorSize({
|
|
47
|
+
anchor,
|
|
48
|
+
writingMode
|
|
49
|
+
}) {
|
|
50
|
+
if (writingMode === 'vertical') {
|
|
51
|
+
return {
|
|
52
|
+
inline: `${anchor.offsetHeight}px`,
|
|
53
|
+
block: `${anchor.offsetWidth}px`
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
inline: `${anchor.offsetWidth}px`,
|
|
58
|
+
block: `${anchor.offsetHeight}px`
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const NO_ANCHOR_SIZE = {
|
|
62
|
+
inline: null,
|
|
63
|
+
block: null
|
|
64
|
+
};
|
|
65
|
+
const CSS_ANCHOR_SIZE = {
|
|
66
|
+
inline: 'anchor-size(self-inline)',
|
|
67
|
+
block: 'anchor-size(self-block)'
|
|
68
|
+
};
|
|
69
|
+
function isAnchorRelative(size) {
|
|
70
|
+
return size === 'match-anchor' || size === 'min-anchor';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The `anchor-name` written to an anchor that does not already carry one, as a CSS
|
|
75
|
+
* `<dashed-ident>`. `useId()` is the same source as every other id in the design
|
|
76
|
+
* system, including the popover's own `id` that `aria-controls` and `popovertarget`
|
|
77
|
+
* point at, so it is unique exactly where those are and collides exactly where
|
|
78
|
+
* they do. See `useAnchoredPopover` for the one case that needs the host's help.
|
|
79
|
+
*
|
|
80
|
+
* `@atlaskit/ds-lib`'s `useId` already swaps React's `:` and `«»` for `_`. The
|
|
81
|
+
* replace covers a host `identifierPrefix`, which may carry characters a
|
|
82
|
+
* `<dashed-ident>` cannot.
|
|
83
|
+
*/
|
|
84
|
+
function useNewAnchorName() {
|
|
85
|
+
const id = useId();
|
|
86
|
+
return useMemo(() => `--anchor-${id.replace(/[^A-Za-z0-9_-]/g, '_')}`, [id]);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A referentially-stable, fully-resolved `TPlacement`, so a fresh inline
|
|
91
|
+
* `placement` object does not re-run the effect.
|
|
92
|
+
*/
|
|
93
|
+
function useStablePlacement(placement) {
|
|
94
|
+
const resolved = resolvePlacement({
|
|
95
|
+
placement
|
|
96
|
+
});
|
|
97
|
+
const axis = resolved.axis;
|
|
98
|
+
const edge = resolved.edge;
|
|
99
|
+
const align = resolved.align;
|
|
100
|
+
const minSize = resolved.minSize;
|
|
101
|
+
const gap = resolved.offset.gap;
|
|
102
|
+
const shiftValue = resolved.offset.crossAxisShift.value;
|
|
103
|
+
const shiftDirection = resolved.offset.crossAxisShift.direction;
|
|
104
|
+
// Rebuilt from primitive deps, so the factory does not close over `resolved`
|
|
105
|
+
// and exhaustive-deps can verify it.
|
|
106
|
+
return useMemo(() => ({
|
|
107
|
+
axis,
|
|
108
|
+
edge,
|
|
109
|
+
align,
|
|
110
|
+
minSize,
|
|
111
|
+
offset: {
|
|
112
|
+
gap,
|
|
113
|
+
crossAxisShift: {
|
|
114
|
+
value: shiftValue,
|
|
115
|
+
direction: shiftDirection
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}), [axis, edge, align, minSize, gap, shiftValue, shiftDirection]);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Exported so `useAnchoredPopoverAtPoint` can forward the options it does not own.
|
|
123
|
+
*/
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Positions and sizes a popover relative to an anchor. Owns every inline style on
|
|
127
|
+
* the popover host: where it goes, how big it is relative to its anchor, and the
|
|
128
|
+
* margins that keep it clear of the anchor and the viewport edge. It knows nothing
|
|
129
|
+
* about visibility or animation - compose it with `Popover`.
|
|
130
|
+
*
|
|
131
|
+
* On modern browsers the browser handles flipping via CSS Anchor Positioning;
|
|
132
|
+
* otherwise it falls back to measured `position: fixed` coordinates, re-run on
|
|
133
|
+
* scroll and resize.
|
|
134
|
+
*
|
|
135
|
+
* `inlineSize` and `blockSize` both default to `'content'`. Two rules are
|
|
136
|
+
* surprising: fitting one axis also fits an axis left on `'content'`, and fitting
|
|
137
|
+
* either axis floors the placement axis. See `TPopoverAxisSize`.
|
|
138
|
+
*
|
|
139
|
+
* **Several React roots on one page.** The `anchor-name` this hook writes to an
|
|
140
|
+
* anchor that has none is minted from `useId()`, like every other id in the design
|
|
141
|
+
* system. `useId()` is unique within a root; across roots it is unique for
|
|
142
|
+
* client-rendered roots but NOT for roots that hydrate the same markup, where it
|
|
143
|
+
* is derived from tree position. Two anchors carrying one name resolve to the last
|
|
144
|
+
* in tree order, so a popover can attach to another root's trigger. A host that
|
|
145
|
+
* hydrates more than one root must give each a distinct `identifierPrefix` (on
|
|
146
|
+
* `hydrateRoot` and the matching server render). That is already required for the
|
|
147
|
+
* popover's own `id`, which `aria-controls` and `popovertarget` point at, and for
|
|
148
|
+
* every `aria-*` id the design system mints. A bundle with two copies of
|
|
149
|
+
* `react-dom` has the same exposure for client-rendered roots.
|
|
150
|
+
*
|
|
151
|
+
* @example Position a popover below its trigger
|
|
152
|
+
* ```tsx
|
|
153
|
+
* const triggerRef = useRef<HTMLButtonElement>(null);
|
|
154
|
+
* const popoverRef = useRef<HTMLDivElement>(null);
|
|
155
|
+
*
|
|
156
|
+
* useAnchoredPopover({
|
|
157
|
+
* anchorRef: triggerRef,
|
|
158
|
+
* popoverRef,
|
|
159
|
+
* placement: { axis: 'block', edge: 'end' },
|
|
160
|
+
* isOpen,
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* @example Match the trigger's width and keep the popover on screen
|
|
165
|
+
* ```tsx
|
|
166
|
+
* // What `<Popup shouldFitContainer shouldFitViewport>` maps to.
|
|
167
|
+
* useAnchoredPopover({
|
|
168
|
+
* anchorRef: triggerRef,
|
|
169
|
+
* popoverRef,
|
|
170
|
+
* placement: { axis: 'block', edge: 'end' },
|
|
171
|
+
* isOpen,
|
|
172
|
+
* inlineSize: 'match-anchor',
|
|
173
|
+
* blockSize: 'max-available',
|
|
174
|
+
* });
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* @example Switch to a cursor position mid-mount
|
|
178
|
+
* ```tsx
|
|
179
|
+
* // Complementary `isEnabled`, so exactly one hook owns the popover.
|
|
180
|
+
* const shared = { popoverRef, placement, isOpen };
|
|
181
|
+
*
|
|
182
|
+
* useAnchoredPopover({ ...shared, anchorRef: triggerRef, isEnabled: !mousePos });
|
|
183
|
+
* useAnchoredPopoverAtPoint({
|
|
184
|
+
* ...shared,
|
|
185
|
+
* isEnabled: Boolean(mousePos),
|
|
186
|
+
* getPoint: () => mousePosRef.current,
|
|
187
|
+
* });
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
export function useAnchoredPopover({
|
|
191
|
+
anchorRef,
|
|
192
|
+
popoverRef,
|
|
193
|
+
placement,
|
|
194
|
+
isOpen,
|
|
195
|
+
isEnabled = true,
|
|
196
|
+
inlineSize = 'content',
|
|
197
|
+
blockSize = 'content',
|
|
198
|
+
shouldPreserveInlineSize = false,
|
|
199
|
+
forceFallbackPositioning = false
|
|
200
|
+
}) {
|
|
201
|
+
// Stable for the life of the hook instance, so it follows a replacement anchor
|
|
202
|
+
// element (the point hook remounts its `<div>`).
|
|
203
|
+
const fallbackAnchorName = useNewAnchorName();
|
|
204
|
+
const stablePlacement = useStablePlacement(placement);
|
|
205
|
+
useLayoutEffect(() => {
|
|
206
|
+
if (!isEnabled) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Resolved once, so positioning, sizing and margins cannot disagree about it.
|
|
211
|
+
const isUsingCssAnchorPositioning = supportsAnchorPositioning() && !forceFallbackPositioning;
|
|
212
|
+
|
|
213
|
+
// BOTH probes: a browser can have positioning without sizing, and
|
|
214
|
+
// `anchor-size()` needs the `position-anchor` only the CSS path writes.
|
|
215
|
+
const canUseAnchorSize = isUsingCssAnchorPositioning && supportsAnchorSize();
|
|
216
|
+
const trigger = anchorRef.current;
|
|
217
|
+
const popover = popoverRef.current;
|
|
218
|
+
if (!trigger || !popover) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Fitting also reserves padding from the viewport edge as a margin.
|
|
223
|
+
const isFitting = inlineSize === 'max-available' || blockSize === 'max-available';
|
|
224
|
+
|
|
225
|
+
// Always read: the viewport caps are always written, and their unit follows
|
|
226
|
+
// the popover's writing mode.
|
|
227
|
+
const writingMode = getPopoverWritingMode({
|
|
228
|
+
popover
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Skipped where possible, so a position-only consumer pays no layout read.
|
|
232
|
+
// Fitting on the CSS path needs it to clamp the default flip floor; see
|
|
233
|
+
// `getDefaultPlacementAxisFloor`.
|
|
234
|
+
const needsAnchorSize = isAnchorRelative(inlineSize) || isAnchorRelative(blockSize) || isFitting && isUsingCssAnchorPositioning;
|
|
235
|
+
const anchorSize = needsAnchorSize ? canUseAnchorSize ? CSS_ANCHOR_SIZE : measureAnchorSize({
|
|
236
|
+
anchor: trigger,
|
|
237
|
+
writingMode
|
|
238
|
+
}) : NO_ANCHOR_SIZE;
|
|
239
|
+
const sizeStyles = getAnchoredPopoverSizeDeclarations({
|
|
240
|
+
placement: stablePlacement,
|
|
241
|
+
inlineSize,
|
|
242
|
+
blockSize,
|
|
243
|
+
isUsingCssAnchorPositioning,
|
|
244
|
+
anchorSize,
|
|
245
|
+
writingMode,
|
|
246
|
+
shouldPreserveInlineSize
|
|
247
|
+
});
|
|
248
|
+
if (isUsingCssAnchorPositioning) {
|
|
249
|
+
return applyAnchorPositioning({
|
|
250
|
+
anchor: trigger,
|
|
251
|
+
popover,
|
|
252
|
+
placement: stablePlacement,
|
|
253
|
+
sizeStyles,
|
|
254
|
+
isFitting,
|
|
255
|
+
fallbackAnchorName
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return applyJavaScriptFallbackPositioning({
|
|
259
|
+
anchor: trigger,
|
|
260
|
+
popover,
|
|
261
|
+
placement: stablePlacement,
|
|
262
|
+
sizeStyles
|
|
263
|
+
});
|
|
264
|
+
}, [isEnabled, anchorRef, popoverRef, stablePlacement, inlineSize, blockSize, shouldPreserveInlineSize, fallbackAnchorName, forceFallbackPositioning, isOpen]);
|
|
265
|
+
}
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
._n3tdidpf{padding-bottom:0}
|
|
23
23
|
._o5724jg8{white-space:normal}
|
|
24
24
|
._otyridpf{margin-bottom:0}
|
|
25
|
+
._p6861txw:popover-open{display:flex}
|
|
25
26
|
._u5f3idpf{padding-right:0}
|
|
26
27
|
._y3gnv2br{text-align:start}
|
|
28
|
+
:where(._1yp3idpf)>*{min-inline-size:0}
|
|
29
|
+
:where(._51hckb7n)>*{flex-grow:1}
|
|
30
|
+
:where(._f5r5idpf)>*{min-block-size:0}
|
|
27
31
|
@media (prefers-reduced-motion:reduce){._bl8aglyw{animation-name:none}._156y147i{transition-duration:var(--ds-duration-instant,0ms)}}
|
|
@@ -33,15 +33,22 @@ const supportsPopoverHint = once(() => {
|
|
|
33
33
|
// avoided this by rendering at `<body>`). Excludes `color`/`font` (theming) and
|
|
34
34
|
// `direction`/`unicode-bidi` (RTL must inherit).
|
|
35
35
|
//
|
|
36
|
+
// Not `all: initial`: the target is what `<body>` gave the portal path, not the
|
|
37
|
+
// spec initial values (UA serif, black, `color-scheme: normal`), and as an author
|
|
38
|
+
// declaration it would also override the UA `[popover]` rules (`position: fixed`,
|
|
39
|
+
// `display: none` when closed).
|
|
40
|
+
//
|
|
36
41
|
// KEEP IN SYNC with the identical `surfaceResetStyles` in `dialog/dialog-content.tsx`.
|
|
37
42
|
// ADS forbids sharing styles across files (`no-exported-styles` /
|
|
38
43
|
// `no-imported-style-values` — Compiled styles are null at runtime), so the reset is
|
|
39
|
-
// co-located and duplicated deliberately.
|
|
44
|
+
// co-located and duplicated deliberately. The `satisfies` check below fails the
|
|
45
|
+
// build if either copy drifts.
|
|
40
46
|
const surfaceResetStyles = {
|
|
41
47
|
root: "_lcxv1wug _o5724jg8 _1nmz4jg8 _1i4q4jg8 _y3gnv2br _azhwidpf _1p1dglyw"
|
|
42
48
|
};
|
|
49
|
+
true;
|
|
43
50
|
const styles = {
|
|
44
|
-
root: "_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _19pkidpf _2hwxidpf _otyridpf _18u0idpf _1r041wug _1reoewfl _18m9ewfl _bfhk1j28 _4t3i1wug",
|
|
51
|
+
root: "_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _19pkidpf _2hwxidpf _otyridpf _18u0idpf _1r041wug _1reoewfl _18m9ewfl _bfhk1j28 _4t3i1wug _p6861txw _51hckb7n _1yp3idpf _f5r5idpf",
|
|
45
52
|
motion: "_k8m011k7 _1oecdn4k _1s9z1a5r _1o511hrf _bl8aglyw _156y147i",
|
|
46
53
|
enter: "_y44v179n",
|
|
47
54
|
exit: "_y44vof1f"
|
|
@@ -79,7 +86,7 @@ const POPUP_ROLES = new Set(['menu', 'listbox', 'dialog', 'alertdialog', 'tree',
|
|
|
79
86
|
|
|
80
87
|
/**
|
|
81
88
|
* Unopinionated top-layer primitive. Owns visibility and animation only;
|
|
82
|
-
* compose with `
|
|
89
|
+
* compose with `useAnchoredPopover` for positioning and sizing.
|
|
83
90
|
*
|
|
84
91
|
* ### 🔌 Visibility
|
|
85
92
|
*
|
|
@@ -249,7 +256,7 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
249
256
|
// for dialog roles. Restoration is native for outermost popovers; nested
|
|
250
257
|
// focus-capturing roles are handled above via the `beforetoggle` snapshot.
|
|
251
258
|
// Passing `phase` keeps `useFocusWrap` attached through the animated-exit
|
|
252
|
-
// window (WCAG 2.4.3 guard). See notes/architecture/focus
|
|
259
|
+
// window (WCAG 2.4.3 guard). See notes/architecture/focus.md.
|
|
253
260
|
useFocusWrap({
|
|
254
261
|
elementRef: ownRef,
|
|
255
262
|
role,
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* - Popover open state tracked via `data-popover-open` (no `:popover-open` in jsdom).
|
|
14
14
|
* - Auto popovers: maintain an open stack, perform light-dismiss on document mousedown
|
|
15
15
|
* outside the open chain, and dismiss the topmost on Escape.
|
|
16
|
-
* - On open, removes any inline `opacity: 0` from the popover element so
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* - On open, removes any inline `opacity: 0` from the popover element, so the
|
|
17
|
+
* JavaScript positioning fallback's `ResizeObserver` reveal is not needed in
|
|
18
|
+
* jsdom, where its non-zero-layout guard can never pass.
|
|
19
19
|
*
|
|
20
20
|
* Companion `toBeVisible` patch lives at `./to-be-visible`.
|
|
21
21
|
*
|
|
@@ -256,10 +256,9 @@ function stackForMode({
|
|
|
256
256
|
return null;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
// Polyfill-only. Real browsers reveal the popover
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
// the open toggle has fired.
|
|
259
|
+
// Polyfill-only. Real browsers reveal the popover on the first non-zero layout
|
|
260
|
+
// their `ResizeObserver` reports; jsdom always reports 0, so that guard never
|
|
261
|
+
// passes and the inline `opacity: 0` is cleared on the open toggle instead.
|
|
263
262
|
function clearOpacityOnOpenToggle({
|
|
264
263
|
element
|
|
265
264
|
}) {
|
|
@@ -19,9 +19,11 @@ import { useSafariEscapeFix } from '../internal/use-safari-escape-fix';
|
|
|
19
19
|
//
|
|
20
20
|
// KEEP IN SYNC with the identical `surfaceResetStyles` in `popover/popover.tsx`
|
|
21
21
|
// (ADS forbids sharing styles across files, so it is co-located and duplicated).
|
|
22
|
+
// The `satisfies` check below fails the build if either copy drifts.
|
|
22
23
|
var surfaceResetStyles = {
|
|
23
24
|
root: "_lcxv1wug _o5724jg8 _1nmz4jg8 _1i4q4jg8 _y3gnv2br _azhwidpf _1p1dglyw"
|
|
24
25
|
};
|
|
26
|
+
true;
|
|
25
27
|
var dialogStyles = {
|
|
26
28
|
root: "_19itglyw _19pk1wug _2hwx1wug _otyr1wug _18u01wug _1q51ze3t _y4tize3t _85i5ze3t _bozgze3t _p12fglyw _c71lglyw _bfhk1j28",
|
|
27
29
|
motion: "_k8m011k7 _1oeci9qs _1s9z1a5r _1o511hrf _bl8aglyw _156y147i",
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import { useId } from '@atlaskit/ds-lib/use-id';
|
|
2
|
+
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
4
|
+
* A stable `id` for wiring a trigger to its popover: the popover's `id`, and the
|
|
5
|
+
* trigger's matching `aria-controls` / `popovertarget`.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
* for the matching `aria-controls` / `popovertarget` references on the
|
|
8
|
-
* trigger. It is NOT a CSS `anchor-name` value: CSS anchor positioning is
|
|
9
|
-
* handled internally by `useAnchorPosition`, which mints and applies its
|
|
10
|
-
* own `anchor-name` on the trigger element.
|
|
7
|
+
* NOT a CSS `anchor-name` - `useAnchoredPopover` mints and writes its own.
|
|
11
8
|
*/
|
|
12
9
|
export function usePopoverId() {
|
|
13
|
-
// `@atlaskit/ds-lib/use-id
|
|
14
|
-
//
|
|
15
|
-
// tokens. The `popover-` prefix is purely for DOM debug clarity.
|
|
10
|
+
// `@atlaskit/ds-lib/use-id`, not React's `useId`: React's output contains
|
|
11
|
+
// `:`, `«` and `»`, which are invalid in an HTML id token.
|
|
16
12
|
return "popover-".concat(useId());
|
|
17
13
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
+
/**
|
|
3
|
+
* The CSS Anchor Positioning path: `position-anchor`, `position-area`,
|
|
4
|
+
* `position-try-fallbacks` and the gap / shift margins, all declared on the
|
|
5
|
+
* popover so the browser owns placement and flipping. The twin of
|
|
6
|
+
* `../javascript-fallback/apply-javascript-fallback-positioning`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { setStyle } from '../set-style';
|
|
10
|
+
import { crossAxisShiftMargins } from './cross-axis-shift-margins';
|
|
11
|
+
import { edgeMargin } from './edge-margin';
|
|
12
|
+
import { getFitMarginDeclarations } from './fit-margins';
|
|
13
|
+
import { getExistingAnchorName } from './get-existing-anchor-name';
|
|
14
|
+
import { placementToPositionArea } from './placement-to-position-area';
|
|
15
|
+
import { placementToTryFallbacks } from './placement-to-try-fallbacks';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Returns the cleanup.
|
|
19
|
+
*/
|
|
20
|
+
export function applyAnchorPositioning(_ref) {
|
|
21
|
+
var anchor = _ref.anchor,
|
|
22
|
+
popover = _ref.popover,
|
|
23
|
+
placement = _ref.placement,
|
|
24
|
+
sizeStyles = _ref.sizeStyles,
|
|
25
|
+
isFitting = _ref.isFitting,
|
|
26
|
+
fallbackAnchorName = _ref.fallbackAnchorName;
|
|
27
|
+
// Reuse rather than mint: another popover may already be anchored to it, or a
|
|
28
|
+
// CONSUMER may have set it on their own element, as `post-office` does.
|
|
29
|
+
var existingAnchorName = getExistingAnchorName(anchor);
|
|
30
|
+
var anchorName = existingAnchorName !== null && existingAnchorName !== void 0 ? existingAnchorName : fallbackAnchorName;
|
|
31
|
+
var gap = edgeMargin({
|
|
32
|
+
placement: placement,
|
|
33
|
+
offset: placement.offset.gap
|
|
34
|
+
});
|
|
35
|
+
var crossAxisShift = crossAxisShiftMargins({
|
|
36
|
+
placement: placement,
|
|
37
|
+
crossAxisShiftCssValue: placement.offset.crossAxisShift.value,
|
|
38
|
+
direction: placement.offset.crossAxisShift.direction
|
|
39
|
+
});
|
|
40
|
+
var popoverStyles = [{
|
|
41
|
+
property: 'position-anchor',
|
|
42
|
+
value: anchorName
|
|
43
|
+
}, {
|
|
44
|
+
property: 'position-area',
|
|
45
|
+
value: placementToPositionArea({
|
|
46
|
+
placement: placement
|
|
47
|
+
})
|
|
48
|
+
}, {
|
|
49
|
+
property: 'position-try-fallbacks',
|
|
50
|
+
value: placementToTryFallbacks({
|
|
51
|
+
placement: placement
|
|
52
|
+
})
|
|
53
|
+
},
|
|
54
|
+
// Reset browser default popover positioning that conflicts
|
|
55
|
+
// with anchor positioning (UA: `inset: 0; margin: auto;`)
|
|
56
|
+
{
|
|
57
|
+
property: 'margin',
|
|
58
|
+
value: '0'
|
|
59
|
+
}, {
|
|
60
|
+
property: 'inset',
|
|
61
|
+
value: 'auto'
|
|
62
|
+
}, gap].concat(_toConsumableArray(isFitting ? getFitMarginDeclarations({
|
|
63
|
+
placement: placement,
|
|
64
|
+
crossAxisShiftMargins: crossAxisShift
|
|
65
|
+
}) : crossAxisShift), _toConsumableArray(sizeStyles));
|
|
66
|
+
|
|
67
|
+
// Anchor names are never cleaned up: multiple popovers can share an anchor,
|
|
68
|
+
// and even with reference counting an async React update could remove the name
|
|
69
|
+
// while something else still uses it. See
|
|
70
|
+
// `notes/decisions/anchor-name-lifetime.md`. Only written when minted: a name
|
|
71
|
+
// from a stylesheet may be a list, which an inline copy of its first entry
|
|
72
|
+
// would collapse.
|
|
73
|
+
if (existingAnchorName === null) {
|
|
74
|
+
anchor.style.setProperty('anchor-name', anchorName);
|
|
75
|
+
}
|
|
76
|
+
return setStyle({
|
|
77
|
+
element: popover,
|
|
78
|
+
styles: popoverStyles
|
|
79
|
+
});
|
|
80
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cross-axis shift, written antisymmetrically on BOTH cross-axis sides rather
|
|
3
|
+
* than as one margin. Do not collapse it to one side: a single margin widens the
|
|
4
|
+
* margin box, so `anchor-center` displaces the border box by only half the value,
|
|
5
|
+
* a `<position-area>` fallback sliding across the cross axis drops it entirely,
|
|
6
|
+
* and the widened box changes where the popover is judged to overflow.
|
|
7
|
+
*
|
|
8
|
+
* A positive value always moves the popover toward the cross-axis END, so
|
|
9
|
+
* `direction: 'forwards'` means the same thing for every `align` value. See
|
|
10
|
+
* `notes/decisions/placement-offset.md`.
|
|
11
|
+
*/
|
|
12
|
+
export function crossAxisShiftMargins(_ref) {
|
|
13
|
+
var placement = _ref.placement,
|
|
14
|
+
crossAxisShiftCssValue = _ref.crossAxisShiftCssValue,
|
|
15
|
+
direction = _ref.direction;
|
|
16
|
+
var crossAxis = placement.axis === 'block' ? 'inline' : 'block';
|
|
17
|
+
// `calc()` rather than JavaScript math, so opaque values such as design tokens
|
|
18
|
+
// negate correctly.
|
|
19
|
+
var negated = "calc(-1 * ".concat(crossAxisShiftCssValue, ")");
|
|
20
|
+
var isForwards = direction === 'forwards';
|
|
21
|
+
return [{
|
|
22
|
+
property: "margin-".concat(crossAxis, "-start"),
|
|
23
|
+
value: isForwards ? crossAxisShiftCssValue : negated
|
|
24
|
+
}, {
|
|
25
|
+
property: "margin-".concat(crossAxis, "-end"),
|
|
26
|
+
value: isForwards ? negated : crossAxisShiftCssValue
|
|
27
|
+
}];
|
|
28
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The margin that creates the gap between the popover and its anchor.
|
|
3
|
+
*/
|
|
4
|
+
export function edgeMargin(_ref) {
|
|
5
|
+
var placement = _ref.placement,
|
|
6
|
+
offset = _ref.offset;
|
|
7
|
+
var axis = placement.axis,
|
|
8
|
+
edge = placement.edge;
|
|
9
|
+
// The side FACING the anchor is always opposite the placement edge.
|
|
10
|
+
var anchorFacingEdge = edge === 'end' ? 'start' : 'end';
|
|
11
|
+
return {
|
|
12
|
+
property: "margin-".concat(axis, "-").concat(anchorFacingEdge),
|
|
13
|
+
value: offset
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
+
import { VIEWPORT_PADDING } from '../anchored-popover-size';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Every logical margin property the fit recipe can write. Declared here and
|
|
6
|
+
* imported by `edge-margin.tsx` and `cross-axis-shift-margins.tsx`: two
|
|
7
|
+
* structurally identical declarations are interchangeable to the compiler, so a
|
|
8
|
+
* divergence would surface only as a silently-ignored property name at
|
|
9
|
+
* `setStyle`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The cross-axis sides that face the viewport rather than the anchor, and so take
|
|
14
|
+
* the reserved padding.
|
|
15
|
+
*
|
|
16
|
+
* A `span-*` cell aligns the popover's MARGIN box to the anchor's edge, so padding
|
|
17
|
+
* on the anchor-facing side does not reserve space at the viewport: it insets the
|
|
18
|
+
* border box from the edge the consumer asked it to line up with. A centred
|
|
19
|
+
* popover has no anchor-facing side, and padding both keeps the shift pair
|
|
20
|
+
* antisymmetric so `anchor-center` still centres.
|
|
21
|
+
*
|
|
22
|
+
* Known cost: the slide fallbacks do not swap the inline margins the way
|
|
23
|
+
* `flip-inline` does, so a slid popover keeps its padding on the anchor side (or,
|
|
24
|
+
* re-centred, sits 2.5px off centre). Alignment in the requested position wins.
|
|
25
|
+
*/
|
|
26
|
+
function viewportFacingCrossAxisSides(_ref) {
|
|
27
|
+
var align = _ref.align;
|
|
28
|
+
if (align === 'center') {
|
|
29
|
+
return ['start', 'end'];
|
|
30
|
+
}
|
|
31
|
+
// `align: 'start'` sits on the anchor's start edge and expands toward end.
|
|
32
|
+
return [align === 'start' ? 'end' : 'start'];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The margin half of the fit recipe. The caps reserve the viewport padding by
|
|
37
|
+
* subtracting it, but nothing makes the reservation land on the viewport side, so
|
|
38
|
+
* a capped popover packs flush against the edge it slid or flipped to.
|
|
39
|
+
*
|
|
40
|
+
* The padding buys visual clearance and nothing else: at the cap the margin box
|
|
41
|
+
* is exactly `100%` of the cell, so these margins never make
|
|
42
|
+
* `position-try-fallbacks` fire. Only the unclamped placement-axis floor does
|
|
43
|
+
* that; see `getPlacementAxisFloor`.
|
|
44
|
+
*
|
|
45
|
+
* The cross-axis sides are composed, not overwritten: they already carry the
|
|
46
|
+
* antisymmetric `crossAxisShift` pair.
|
|
47
|
+
*/
|
|
48
|
+
export function getFitMarginDeclarations(_ref2) {
|
|
49
|
+
var placement = _ref2.placement,
|
|
50
|
+
crossAxisShiftMargins = _ref2.crossAxisShiftMargins;
|
|
51
|
+
var crossAxis = placement.axis === 'block' ? 'inline' : 'block';
|
|
52
|
+
var paddedProperties = new Set(viewportFacingCrossAxisSides({
|
|
53
|
+
align: placement.align
|
|
54
|
+
}).map(function (side) {
|
|
55
|
+
return "margin-".concat(crossAxis, "-").concat(side);
|
|
56
|
+
}));
|
|
57
|
+
return [{
|
|
58
|
+
property: "margin-".concat(placement.axis, "-").concat(placement.edge),
|
|
59
|
+
value: VIEWPORT_PADDING
|
|
60
|
+
}].concat(_toConsumableArray(crossAxisShiftMargins.map(function (_ref3) {
|
|
61
|
+
var property = _ref3.property,
|
|
62
|
+
value = _ref3.value;
|
|
63
|
+
return paddedProperties.has(property) ? {
|
|
64
|
+
property: property,
|
|
65
|
+
value: "calc(".concat(value, " + ").concat(VIEWPORT_PADDING, ")")
|
|
66
|
+
} : {
|
|
67
|
+
property: property,
|
|
68
|
+
value: value
|
|
69
|
+
};
|
|
70
|
+
})));
|
|
71
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `anchor-name` an element already carries, or `null`. Computed as well as
|
|
3
|
+
* inline, so a name set from a STYLESHEET is found: a minted inline name would
|
|
4
|
+
* otherwise override it for every other rule anchored to that element.
|
|
5
|
+
* `anchor-name` is a list and `position-anchor` takes one ident, so the first
|
|
6
|
+
* name is the one to anchor to.
|
|
7
|
+
*/
|
|
8
|
+
export function getExistingAnchorName(element) {
|
|
9
|
+
var declared = element.style.getPropertyValue('anchor-name') || getComputedStyle(element).getPropertyValue('anchor-name');
|
|
10
|
+
var first = declared.split(',')[0].trim();
|
|
11
|
+
return first !== '' && first !== 'none' ? first : null;
|
|
12
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { resolvePlacement } from './resolve-placement';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Resolves placement
|
|
2
|
+
* Resolves a placement to CSS `position-area` syntax.
|
|
5
3
|
*
|
|
6
4
|
* The `align` field represents the *visual* alignment:
|
|
7
5
|
* - `align: 'start'` means "aligned to the trigger's start edge" (left in LTR for block axis)
|
|
@@ -12,19 +10,20 @@ import { resolvePlacement } from './resolve-placement';
|
|
|
12
10
|
* Visual start-alignment requires `span-{cross-axis}-end` (expand toward end = start-aligned).
|
|
13
11
|
* This function handles the inversion internally.
|
|
14
12
|
*
|
|
13
|
+
* Takes the RESOLVED placement, which the hook threads through positioning,
|
|
14
|
+
* sizing and margins alike, so nothing here can disagree with them.
|
|
15
|
+
*
|
|
15
16
|
* @example
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* // For a `block-end` placement, by `align`:
|
|
18
|
+
* // 'center' → 'block-end'
|
|
19
|
+
* // 'start' → 'block-end span-inline-end'
|
|
20
|
+
* // 'end' → 'block-end span-inline-start'
|
|
19
21
|
*/
|
|
20
22
|
export function placementToPositionArea(_ref) {
|
|
21
23
|
var placement = _ref.placement;
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
axis = _resolvePlacement.axis,
|
|
26
|
-
edge = _resolvePlacement.edge,
|
|
27
|
-
align = _resolvePlacement.align;
|
|
24
|
+
var axis = placement.axis,
|
|
25
|
+
edge = placement.edge,
|
|
26
|
+
align = placement.align;
|
|
28
27
|
var edgeValue = "".concat(axis, "-").concat(edge);
|
|
29
28
|
if (align === 'center') {
|
|
30
29
|
return edgeValue;
|