@atlaskit/top-layer 0.1.5 → 0.2.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 +24 -0
- package/dist/cjs/arrow/index.js +1 -1
- package/dist/cjs/internal/anchor-positioning-fallback.js +82 -22
- package/dist/cjs/internal/resolve-css-length-to-pixels.js +53 -0
- package/dist/cjs/internal/resolve-css-length.js +18 -0
- package/dist/cjs/internal/resolve-placement.js +47 -6
- package/dist/cjs/internal/use-anchor-positioning.js +180 -36
- package/dist/cjs/placement-map/index.js +31 -3
- package/dist/cjs/popup/popup-content.js +0 -2
- package/dist/es2019/arrow/index.js +22 -3
- package/dist/es2019/internal/anchor-positioning-fallback.js +80 -17
- package/dist/es2019/internal/resolve-css-length-to-pixels.js +48 -0
- package/dist/es2019/internal/resolve-css-length.js +13 -0
- package/dist/es2019/internal/resolve-placement.js +48 -6
- package/dist/es2019/internal/use-anchor-positioning.js +173 -28
- package/dist/es2019/placement-map/index.js +25 -3
- package/dist/es2019/popup/popup-content.js +0 -2
- package/dist/esm/arrow/index.js +1 -1
- package/dist/esm/internal/anchor-positioning-fallback.js +82 -22
- package/dist/esm/internal/resolve-css-length-to-pixels.js +47 -0
- package/dist/esm/internal/resolve-css-length.js +12 -0
- package/dist/esm/internal/resolve-placement.js +48 -6
- package/dist/esm/internal/use-anchor-positioning.js +179 -36
- package/dist/esm/placement-map/index.js +30 -3
- package/dist/esm/popup/popup-content.js +0 -2
- package/dist/types/internal/anchor-positioning-fallback.d.ts +11 -9
- package/dist/types/internal/resolve-css-length-to-pixels.d.ts +22 -0
- package/dist/types/internal/resolve-css-length.d.ts +8 -0
- package/dist/types/internal/resolve-placement.d.ts +47 -5
- package/dist/types/internal/use-anchor-positioning.d.ts +18 -7
- package/dist/types/placement-map/index.d.ts +11 -5
- package/dist/types/popup/types.d.ts +15 -30
- package/dist/types-ts4.5/internal/anchor-positioning-fallback.d.ts +11 -9
- package/dist/types-ts4.5/internal/resolve-css-length-to-pixels.d.ts +22 -0
- package/dist/types-ts4.5/internal/resolve-css-length.d.ts +8 -0
- package/dist/types-ts4.5/internal/resolve-placement.d.ts +47 -5
- package/dist/types-ts4.5/internal/use-anchor-positioning.d.ts +18 -7
- package/dist/types-ts4.5/placement-map/index.d.ts +14 -5
- package/dist/types-ts4.5/popup/types.d.ts +15 -30
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @atlaskit/top-layer
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`997849983979b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/997849983979b) -
|
|
8
|
+
Add `placement.offset = { gap, crossAxisShift }`.
|
|
9
|
+
- `gap` is the distance from the trigger along the placement axis (default
|
|
10
|
+
`token('space.100', '8px')`).
|
|
11
|
+
- `crossAxisShift` is a perpendicular nudge with `{ value, direction: 'forwards' | 'backwards' }`.
|
|
12
|
+
- Both accept numbers or CSS length strings (tokens, `calc()`, `var()`, etc).
|
|
13
|
+
|
|
14
|
+
The JS fallback path now also honours `gap` and `crossAxisShift`. CSS length strings are resolved
|
|
15
|
+
to pixels per measurement via a hidden DOM probe (the popover stays at `opacity: 0` until the
|
|
16
|
+
first measurement completes, so there is no flash). Previously, the JS fallback applied a fixed
|
|
17
|
+
8px gap and ignored `crossAxisShift`.
|
|
18
|
+
|
|
19
|
+
The standalone `Popup.Content` `offset` prop is removed in favour of `placement.offset`.
|
|
20
|
+
`fromLegacyPlacement` continues to accept a popper-style `[along, away]` tuple for migrations and
|
|
21
|
+
now produces the new field names internally.
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Updated dependencies
|
|
26
|
+
|
|
3
27
|
## 0.1.5
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/dist/cjs/arrow/index.js
CHANGED
|
@@ -26,7 +26,7 @@ var _useAnchorPositioning = require("../internal/use-anchor-positioning");
|
|
|
26
26
|
*
|
|
27
27
|
* @see https://goulet.dev/posts/tooltip-with-popover-and-anchor-positioning/
|
|
28
28
|
*/
|
|
29
|
-
var ARROW_CSS = "\n[data-ds-popover-arrow] {\n clip-path: inset(var(--ds-arrow-offset, 0px)) margin-box;\n box-shadow: none;\n}\n\n/* Top and Bottom arrows (vertical hexagon) */\n[data-ds-popover-arrow]::before {\n content: \"\";\n position: absolute;\n z-index: -1;\n background: inherit;\n left: 50%;\n transform: translateX(-50%);\n width: calc(var(--ds-arrow-size, 8px) * 2);\n height: calc(100% + var(--ds-arrow-size, 8px) * 2);\n top: calc(var(--ds-arrow-size, 8px) * -1);\n clip-path: polygon(\n 0 var(--ds-arrow-size, 8px),\n 50% 0,\n 100% var(--ds-arrow-size, 8px),\n 100% calc(100% - var(--ds-arrow-size, 8px)),\n 50% 100%,\n 0 calc(100% - var(--ds-arrow-size, 8px))\n );\n}\n\n/* Left and Right arrows (horizontal hexagon) */\n[data-ds-popover-arrow]::after {\n content: \"\";\n position: absolute;\n z-index: -1;\n background: inherit;\n top: 50%;\n transform: translateY(-50%);\n height: calc(var(--ds-arrow-size, 8px) * 2);\n width: calc(100% + var(--ds-arrow-size, 8px) * 2);\n left: calc(var(--ds-arrow-size, 8px) * -1);\n clip-path: polygon(\n var(--ds-arrow-size, 8px) 0,\n calc(100% - var(--ds-arrow-size, 8px)) 0,\n 100% 50%,\n calc(100% - var(--ds-arrow-size, 8px)) 100%,\n var(--ds-arrow-size, 8px) 100%,\n 0 50%\n );\n}\n\n/* \u2500\u2500 @position-try rules \u2500\u2500\n * One rule per possible position-area value.\n * Each sets the position-area and the correct margin direction\n * so the arrow on the anchor-facing side is revealed.\n *\n * Margin direction per edge:\n * block-start (above anchor) \u2192 margin-block-end (bottom, facing anchor)\n * block-end (below anchor) \u2192 margin-block-start (top, facing anchor)\n * inline-start (left of anchor) \u2192 margin-inline-end (right, facing anchor)\n * inline-end (right of anchor) \u2192 margin-inline-start (left, facing anchor)\n */\n\n/* Single-axis centered */\n@position-try --ds-arrow-block-start {\n position-area: block-start;\n margin: 0;\n margin-block-end: var(--ds-arrow-size, 8px);\n}\n@position-try --ds-arrow-block-end {\n position-area: block-end;\n margin: 0;\n margin-block-start: var(--ds-arrow-size, 8px);\n}\n@position-try --ds-arrow-inline-start {\n position-area: inline-start;\n margin: 0;\n margin-inline-end: var(--ds-arrow-size, 8px);\n}\n@position-try --ds-arrow-inline-end {\n position-area: inline-end;\n margin: 0;\n margin-inline-start: var(--ds-arrow-size, 8px);\n}\n\n/* Block edge + inline span */\n@position-try --ds-arrow-block-start-span-inline-start {\n position-area: block-start span-inline-start;\n margin: 0;\n margin-block-end: var(--ds-arrow-size, 8px);\n}\n@position-try --ds-arrow-block-start-span-inline-end {\n position-area: block-start span-inline-end;\n margin: 0;\n margin-block-end: var(--ds-arrow-size, 8px);\n}\n@position-try --ds-arrow-block-end-span-inline-start {\n position-area: block-end span-inline-start;\n margin: 0;\n margin-block-start: var(--ds-arrow-size, 8px);\n}\n@position-try --ds-arrow-block-end-span-inline-end {\n position-area: block-end span-inline-end;\n margin: 0;\n margin-block-start: var(--ds-arrow-size, 8px);\n}\n\n/* Inline edge + block span */\n@position-try --ds-arrow-inline-start-span-block-start {\n position-area: inline-start span-block-start;\n margin: 0;\n margin-inline-end: var(--ds-arrow-size, 8px);\n}\n@position-try --ds-arrow-inline-start-span-block-end {\n position-area: inline-start span-block-end;\n margin: 0;\n margin-inline-end: var(--ds-arrow-size, 8px);\n}\n@position-try --ds-arrow-inline-end-span-block-start {\n position-area: inline-end span-block-start;\n margin: 0;\n margin-inline-start: var(--ds-arrow-size, 8px);\n}\n@position-try --ds-arrow-inline-end-span-block-end {\n position-area: inline-end span-block-end;\n margin: 0;\n margin-inline-start: var(--ds-arrow-size, 8px);\n}\n";
|
|
29
|
+
var ARROW_CSS = "\n[data-ds-popover-arrow] {\n clip-path: inset(var(--ds-arrow-offset, 0px)) margin-box;\n box-shadow: none;\n}\n\n/* Top and Bottom arrows (vertical hexagon) */\n[data-ds-popover-arrow]::before {\n content: \"\";\n position: absolute;\n z-index: -1;\n background: inherit;\n left: 50%;\n transform: translateX(-50%);\n width: calc(var(--ds-arrow-size, 8px) * 2);\n height: calc(100% + var(--ds-arrow-size, 8px) * 2);\n top: calc(var(--ds-arrow-size, 8px) * -1);\n clip-path: polygon(\n 0 var(--ds-arrow-size, 8px),\n 50% 0,\n 100% var(--ds-arrow-size, 8px),\n 100% calc(100% - var(--ds-arrow-size, 8px)),\n 50% 100%,\n 0 calc(100% - var(--ds-arrow-size, 8px))\n );\n}\n\n/* Left and Right arrows (horizontal hexagon) */\n[data-ds-popover-arrow]::after {\n content: \"\";\n position: absolute;\n z-index: -1;\n background: inherit;\n top: 50%;\n transform: translateY(-50%);\n height: calc(var(--ds-arrow-size, 8px) * 2);\n width: calc(100% + var(--ds-arrow-size, 8px) * 2);\n left: calc(var(--ds-arrow-size, 8px) * -1);\n clip-path: polygon(\n var(--ds-arrow-size, 8px) 0,\n calc(100% - var(--ds-arrow-size, 8px)) 0,\n 100% 50%,\n calc(100% - var(--ds-arrow-size, 8px)) 100%,\n var(--ds-arrow-size, 8px) 100%,\n 0 50%\n );\n}\n\n/* \u2500\u2500 @position-try rules \u2500\u2500\n * One rule per possible position-area value.\n * Each sets the position-area and the correct margin direction\n * so the arrow on the anchor-facing side is revealed.\n *\n * Margin direction per edge:\n * block-start (above anchor) \u2192 margin-block-end (bottom, facing anchor)\n * block-end (below anchor) \u2192 margin-block-start (top, facing anchor)\n * inline-start (left of anchor) \u2192 margin-inline-end (right, facing anchor)\n * inline-end (right of anchor) \u2192 margin-inline-start (left, facing anchor)\n */\n\n/* Each rule sets two margins: the anchor-facing margin for the gap\n (via --ds-arrow-size) and one cross-axis margin for the shift\n (via one of --ds-cross-axis-shift-margin-start, --ds-cross-axis-shift-margin-end,\n --ds-cross-axis-shift-margin-block-start, or --ds-cross-axis-shift-margin-block-end). The\n side matches the popover's anchored cross-axis edge per align. Only\n one of the four properties is non-zero at a time; useAnchorPosition\n picks it. See notes/architecture/positioning.md for details. */\n/* Single-axis centered (align: center) */\n@position-try --ds-arrow-block-start {\n position-area: block-start;\n margin: 0;\n margin-block-end: var(--ds-arrow-size, 8px);\n margin-inline-start: var(--ds-cross-axis-shift-margin-start, 0px);\n}\n@position-try --ds-arrow-block-end {\n position-area: block-end;\n margin: 0;\n margin-block-start: var(--ds-arrow-size, 8px);\n margin-inline-start: var(--ds-cross-axis-shift-margin-start, 0px);\n}\n@position-try --ds-arrow-inline-start {\n position-area: inline-start;\n margin: 0;\n margin-inline-end: var(--ds-arrow-size, 8px);\n margin-block-start: var(--ds-cross-axis-shift-margin-block-start, 0px);\n}\n@position-try --ds-arrow-inline-end {\n position-area: inline-end;\n margin: 0;\n margin-inline-start: var(--ds-arrow-size, 8px);\n margin-block-start: var(--ds-cross-axis-shift-margin-block-start, 0px);\n}\n\n/* Block edge + inline span (align: start uses span-inline-end; align: end uses span-inline-start) */\n@position-try --ds-arrow-block-start-span-inline-start {\n position-area: block-start span-inline-start;\n margin: 0;\n margin-block-end: var(--ds-arrow-size, 8px);\n margin-inline-end: var(--ds-cross-axis-shift-margin-end, 0px);\n}\n@position-try --ds-arrow-block-start-span-inline-end {\n position-area: block-start span-inline-end;\n margin: 0;\n margin-block-end: var(--ds-arrow-size, 8px);\n margin-inline-start: var(--ds-cross-axis-shift-margin-start, 0px);\n}\n@position-try --ds-arrow-block-end-span-inline-start {\n position-area: block-end span-inline-start;\n margin: 0;\n margin-block-start: var(--ds-arrow-size, 8px);\n margin-inline-end: var(--ds-cross-axis-shift-margin-end, 0px);\n}\n@position-try --ds-arrow-block-end-span-inline-end {\n position-area: block-end span-inline-end;\n margin: 0;\n margin-block-start: var(--ds-arrow-size, 8px);\n margin-inline-start: var(--ds-cross-axis-shift-margin-start, 0px);\n}\n\n/* Inline edge + block span (align: start uses span-block-end; align: end uses span-block-start) */\n@position-try --ds-arrow-inline-start-span-block-start {\n position-area: inline-start span-block-start;\n margin: 0;\n margin-inline-end: var(--ds-arrow-size, 8px);\n margin-block-end: var(--ds-cross-axis-shift-margin-block-end, 0px);\n}\n@position-try --ds-arrow-inline-start-span-block-end {\n position-area: inline-start span-block-end;\n margin: 0;\n margin-inline-end: var(--ds-arrow-size, 8px);\n margin-block-start: var(--ds-cross-axis-shift-margin-block-start, 0px);\n}\n@position-try --ds-arrow-inline-end-span-block-start {\n position-area: inline-end span-block-start;\n margin: 0;\n margin-inline-start: var(--ds-arrow-size, 8px);\n margin-block-end: var(--ds-cross-axis-shift-margin-block-end, 0px);\n}\n@position-try --ds-arrow-inline-end-span-block-end {\n position-area: inline-end span-block-end;\n margin: 0;\n margin-inline-start: var(--ds-arrow-size, 8px);\n margin-block-start: var(--ds-cross-axis-shift-margin-block-start, 0px);\n}\n";
|
|
30
30
|
|
|
31
31
|
// ── Placement utilities ──
|
|
32
32
|
|
|
@@ -8,9 +8,23 @@ exports.computeFallbackPosition = computeFallbackPosition;
|
|
|
8
8
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
9
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
10
10
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
11
|
+
/**
|
|
12
|
+
* JS fallback positioning math. Used only when the browser does not
|
|
13
|
+
* support CSS Anchor Positioning (less than 6% of users).
|
|
14
|
+
*
|
|
15
|
+
* Consumer-supplied `offset.gap` and `offset.crossAxisShift` are
|
|
16
|
+
* honored: the caller (`useAnchorPosition`) resolves CSS length strings
|
|
17
|
+
* (tokens, calc, var, etc) to pixels via a DOM probe before passing them
|
|
18
|
+
* in. The caller also keeps the popover hidden (`opacity: 0`) until the
|
|
19
|
+
* first measurement completes, so the popover never paints at the wrong
|
|
20
|
+
* position.
|
|
21
|
+
*/
|
|
22
|
+
|
|
11
23
|
/**
|
|
12
24
|
* Computes the base {top, left} position based on the primary edge,
|
|
13
25
|
* flipping to the opposite side when there is not enough space.
|
|
26
|
+
*
|
|
27
|
+
* `gap` is applied along the main axis between trigger and popover.
|
|
14
28
|
*/
|
|
15
29
|
function computeEdgePosition(_ref) {
|
|
16
30
|
var axis = _ref.axis,
|
|
@@ -19,13 +33,15 @@ function computeEdgePosition(_ref) {
|
|
|
19
33
|
popoverWidth = _ref.popoverWidth,
|
|
20
34
|
popoverHeight = _ref.popoverHeight,
|
|
21
35
|
viewport = _ref.viewport,
|
|
22
|
-
|
|
36
|
+
gap = _ref.gap;
|
|
23
37
|
if (axis === 'block' && edge === 'end') {
|
|
24
38
|
// Below trigger
|
|
25
39
|
var spaceBelow = viewport.height - triggerRect.bottom;
|
|
26
40
|
var spaceAbove = triggerRect.top;
|
|
41
|
+
var fitsBelow = spaceBelow >= popoverHeight + gap;
|
|
42
|
+
var useBelow = fitsBelow || spaceBelow >= spaceAbove;
|
|
27
43
|
return {
|
|
28
|
-
top:
|
|
44
|
+
top: useBelow ? triggerRect.bottom + gap : triggerRect.top - popoverHeight - gap,
|
|
29
45
|
left: triggerRect.left + triggerRect.width / 2 - popoverWidth / 2
|
|
30
46
|
};
|
|
31
47
|
}
|
|
@@ -33,8 +49,10 @@ function computeEdgePosition(_ref) {
|
|
|
33
49
|
// Above trigger
|
|
34
50
|
var _spaceAbove = triggerRect.top;
|
|
35
51
|
var _spaceBelow = viewport.height - triggerRect.bottom;
|
|
52
|
+
var fitsAbove = _spaceAbove >= popoverHeight + gap;
|
|
53
|
+
var useAbove = fitsAbove || _spaceAbove >= _spaceBelow;
|
|
36
54
|
return {
|
|
37
|
-
top:
|
|
55
|
+
top: useAbove ? triggerRect.top - popoverHeight - gap : triggerRect.bottom + gap,
|
|
38
56
|
left: triggerRect.left + triggerRect.width / 2 - popoverWidth / 2
|
|
39
57
|
};
|
|
40
58
|
}
|
|
@@ -42,24 +60,28 @@ function computeEdgePosition(_ref) {
|
|
|
42
60
|
// Right of trigger
|
|
43
61
|
var spaceRight = viewport.width - triggerRect.right;
|
|
44
62
|
var spaceLeft = triggerRect.left;
|
|
63
|
+
var fitsRight = spaceRight >= popoverWidth + gap;
|
|
64
|
+
var useRight = fitsRight || spaceRight >= spaceLeft;
|
|
45
65
|
return {
|
|
46
66
|
top: triggerRect.top + triggerRect.height / 2 - popoverHeight / 2,
|
|
47
|
-
left:
|
|
67
|
+
left: useRight ? triggerRect.right + gap : triggerRect.left - popoverWidth - gap
|
|
48
68
|
};
|
|
49
69
|
}
|
|
50
70
|
if (axis === 'inline' && edge === 'start') {
|
|
51
71
|
// Left of trigger
|
|
52
72
|
var _spaceLeft = triggerRect.left;
|
|
53
73
|
var _spaceRight = viewport.width - triggerRect.right;
|
|
74
|
+
var fitsLeft = _spaceLeft >= popoverWidth + gap;
|
|
75
|
+
var useLeft = fitsLeft || _spaceLeft >= _spaceRight;
|
|
54
76
|
return {
|
|
55
77
|
top: triggerRect.top + triggerRect.height / 2 - popoverHeight / 2,
|
|
56
|
-
left:
|
|
78
|
+
left: useLeft ? triggerRect.left - popoverWidth - gap : triggerRect.right + gap
|
|
57
79
|
};
|
|
58
80
|
}
|
|
59
81
|
|
|
60
82
|
// Unreachable for valid placements; defaults to below trigger
|
|
61
83
|
return {
|
|
62
|
-
top: triggerRect.bottom +
|
|
84
|
+
top: triggerRect.bottom + gap,
|
|
63
85
|
left: triggerRect.left + triggerRect.width / 2 - popoverWidth / 2
|
|
64
86
|
};
|
|
65
87
|
}
|
|
@@ -106,26 +128,58 @@ function applyAlignment(_ref2) {
|
|
|
106
128
|
}
|
|
107
129
|
|
|
108
130
|
/**
|
|
109
|
-
*
|
|
131
|
+
* Applies the cross-axis shift offset.
|
|
110
132
|
*
|
|
111
|
-
*
|
|
112
|
-
* -
|
|
113
|
-
*
|
|
114
|
-
*
|
|
133
|
+
* The sign mirrors the CSS path (see `crossAxisShiftMargin` in
|
|
134
|
+
* `use-anchor-positioning.tsx`):
|
|
135
|
+
* - `align: 'start' | 'center'` + `forwards` → push toward end (positive)
|
|
136
|
+
* - `align: 'end'` + `forwards` → push toward start (negative)
|
|
137
|
+
* - `backwards` flips the sign in both cases.
|
|
138
|
+
*/
|
|
139
|
+
function applyCrossAxisShift(_ref3) {
|
|
140
|
+
var position = _ref3.position,
|
|
141
|
+
axis = _ref3.axis,
|
|
142
|
+
align = _ref3.align,
|
|
143
|
+
crossAxisShift = _ref3.crossAxisShift;
|
|
144
|
+
if (crossAxisShift.value === 0) {
|
|
145
|
+
return position;
|
|
146
|
+
}
|
|
147
|
+
var directionSign = crossAxisShift.direction === 'forwards' ? 1 : -1;
|
|
148
|
+
var sideSign = align === 'end' ? -1 : 1;
|
|
149
|
+
var delta = crossAxisShift.value * directionSign * sideSign;
|
|
150
|
+
|
|
151
|
+
// Cross-axis is the OPPOSITE of the placement axis.
|
|
152
|
+
if (axis === 'block') {
|
|
153
|
+
return _objectSpread(_objectSpread({}, position), {}, {
|
|
154
|
+
left: position.left + delta
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return _objectSpread(_objectSpread({}, position), {}, {
|
|
158
|
+
top: position.top + delta
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Computes popover position from trigger rect and viewport, flipping to
|
|
164
|
+
* the side with more space when needed. Re-runs on scroll/resize.
|
|
115
165
|
*
|
|
116
|
-
*
|
|
166
|
+
* `gap` and `crossAxisShift` are pre-resolved to pixels by the
|
|
167
|
+
* caller (see `resolveCssLengthToPixels`), so this function stays purely
|
|
168
|
+
* numeric.
|
|
117
169
|
*/
|
|
118
|
-
function computeFallbackPosition(
|
|
119
|
-
var triggerRect =
|
|
120
|
-
popoverEl =
|
|
121
|
-
placement =
|
|
122
|
-
viewport =
|
|
123
|
-
|
|
170
|
+
function computeFallbackPosition(_ref4) {
|
|
171
|
+
var triggerRect = _ref4.triggerRect,
|
|
172
|
+
popoverEl = _ref4.popoverEl,
|
|
173
|
+
placement = _ref4.placement,
|
|
174
|
+
viewport = _ref4.viewport,
|
|
175
|
+
gap = _ref4.gap,
|
|
176
|
+
crossAxisShift = _ref4.crossAxisShift;
|
|
124
177
|
var axis = placement.axis,
|
|
125
178
|
edge = placement.edge,
|
|
126
179
|
align = placement.align;
|
|
127
180
|
|
|
128
|
-
// Measure popover dimensions
|
|
181
|
+
// Measure popover dimensions. Callers must ensure the popover has
|
|
182
|
+
// laid out before calling this (it should not be `display: none`).
|
|
129
183
|
var popoverWidth = popoverEl.offsetWidth;
|
|
130
184
|
var popoverHeight = popoverEl.offsetHeight;
|
|
131
185
|
var basePosition = computeEdgePosition({
|
|
@@ -135,7 +189,7 @@ function computeFallbackPosition(_ref3) {
|
|
|
135
189
|
popoverWidth: popoverWidth,
|
|
136
190
|
popoverHeight: popoverHeight,
|
|
137
191
|
viewport: viewport,
|
|
138
|
-
|
|
192
|
+
gap: gap
|
|
139
193
|
});
|
|
140
194
|
var alignedPosition = applyAlignment({
|
|
141
195
|
position: basePosition,
|
|
@@ -145,10 +199,16 @@ function computeFallbackPosition(_ref3) {
|
|
|
145
199
|
popoverWidth: popoverWidth,
|
|
146
200
|
popoverHeight: popoverHeight
|
|
147
201
|
});
|
|
202
|
+
var shiftedPosition = applyCrossAxisShift({
|
|
203
|
+
position: alignedPosition,
|
|
204
|
+
axis: axis,
|
|
205
|
+
align: align,
|
|
206
|
+
crossAxisShift: crossAxisShift
|
|
207
|
+
});
|
|
148
208
|
|
|
149
209
|
// Clamp to viewport so the popover is never offscreen
|
|
150
210
|
return {
|
|
151
|
-
top: Math.max(0, Math.min(
|
|
152
|
-
left: Math.max(0, Math.min(
|
|
211
|
+
top: Math.max(0, Math.min(shiftedPosition.top, viewport.height - popoverHeight)),
|
|
212
|
+
left: Math.max(0, Math.min(shiftedPosition.left, viewport.width - popoverWidth))
|
|
153
213
|
};
|
|
154
214
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.resolveCssLengthToPixels = resolveCssLengthToPixels;
|
|
7
|
+
/**
|
|
8
|
+
* Resolves a CSS length value to a pixel number using a hidden DOM probe.
|
|
9
|
+
*
|
|
10
|
+
* Used by the JS positioning fallback: consumer offsets can be numbers,
|
|
11
|
+
* `${n}px` strings, tokenised `var(--ds-space-100, 8px)` strings, `calc()`
|
|
12
|
+
* expressions, viewport units, etc. Parsing arbitrary CSS in JS is fragile
|
|
13
|
+
* (and impossible for `calc(var(...))` without a layout context), so we let
|
|
14
|
+
* the browser do the math.
|
|
15
|
+
*
|
|
16
|
+
* The probe is appended to `container` so it inherits the same containing
|
|
17
|
+
* block, font size, and custom-property scope as the popover. We use `width`
|
|
18
|
+
* because it accepts any CSS length, including negative `calc()` results
|
|
19
|
+
* (negative widths are clamped to 0 — see note below).
|
|
20
|
+
*
|
|
21
|
+
* Cost: one synchronous reflow per call. The fallback only resolves on
|
|
22
|
+
* placement/offset changes, not on every scroll/resize update, so this is
|
|
23
|
+
* not a hot path.
|
|
24
|
+
*/
|
|
25
|
+
function resolveCssLengthToPixels(_ref) {
|
|
26
|
+
var value = _ref.value,
|
|
27
|
+
container = _ref.container;
|
|
28
|
+
if (typeof value === 'number') {
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Fast path: bare `${n}px` strings come from the consumer normalisation
|
|
33
|
+
// in `getPlacement`. Avoid a reflow when we can.
|
|
34
|
+
var pxMatch = value.match(/^(-?\d+(?:\.\d+)?)px$/);
|
|
35
|
+
if (pxMatch) {
|
|
36
|
+
return Number(pxMatch[1]);
|
|
37
|
+
}
|
|
38
|
+
var probe = container.ownerDocument.createElement('div');
|
|
39
|
+
probe.style.position = 'absolute';
|
|
40
|
+
probe.style.visibility = 'hidden';
|
|
41
|
+
probe.style.pointerEvents = 'none';
|
|
42
|
+
probe.style.height = '0';
|
|
43
|
+
probe.style.padding = '0';
|
|
44
|
+
probe.style.border = '0';
|
|
45
|
+
// `width` clamps negatives to 0; use `margin-left` instead so signs are
|
|
46
|
+
// preserved. `getComputedStyle` returns the resolved pixel value for
|
|
47
|
+
// margin-* properties even when the source was a token / calc / var.
|
|
48
|
+
probe.style.marginLeft = value;
|
|
49
|
+
container.appendChild(probe);
|
|
50
|
+
var resolved = parseFloat(getComputedStyle(probe).marginLeft);
|
|
51
|
+
container.removeChild(probe);
|
|
52
|
+
return Number.isFinite(resolved) ? resolved : 0;
|
|
53
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.toCssLengthString = toCssLengthString;
|
|
7
|
+
/**
|
|
8
|
+
* Normalizes an offset to a CSS length string. Numbers become `${n}px`;
|
|
9
|
+
* strings pass through. Apply at the API boundary so internal code only
|
|
10
|
+
* deals with strings.
|
|
11
|
+
*/
|
|
12
|
+
function toCssLengthString(_ref) {
|
|
13
|
+
var value = _ref.value;
|
|
14
|
+
if (typeof value === 'number') {
|
|
15
|
+
return "".concat(value, "px");
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
@@ -4,21 +4,62 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.getPlacement = getPlacement;
|
|
7
|
+
var _resolveCssLength = require("./resolve-css-length");
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* Default gap between trigger and popover. Resolves to a design
|
|
10
|
+
* token (`space.100`) so the value follows the design system's spacing
|
|
11
|
+
* scale. Used when `placement.offset.gap` is not provided.
|
|
10
12
|
*/
|
|
13
|
+
var DEFAULT_GAP = "var(--ds-space-100, 8px)";
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
16
|
+
* Cross-axis shift. `value` is a CSS length string (consumer numbers are
|
|
17
|
+
* normalized to `${n}px`). `direction` is `'forwards'` (toward end) or
|
|
18
|
+
* `'backwards'` (toward start).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Fully-resolved placement (internal). Use `getPlacement` for partial input.
|
|
23
|
+
* `offset.gap` and `offset.crossAxisShift.value` are always CSS
|
|
24
|
+
* length strings.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Partial placement options. `offset.gap` and
|
|
29
|
+
* `offset.crossAxisShift.value` accept either a number (pixels) or a
|
|
30
|
+
* CSS length string (e.g. `token('space.100')`).
|
|
31
|
+
*
|
|
32
|
+
* The two offset axes are named for clarity at the call site:
|
|
33
|
+
* - `gap` — distance away from the trigger along the placement axis
|
|
34
|
+
* - `crossAxisShift` — nudge along the trigger edge (perpendicular to the placement axis)
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Resolves a partial placement to its fully-specified form. Number offsets
|
|
39
|
+
* are normalized to `${n}px` strings.
|
|
40
|
+
*
|
|
41
|
+
* Defaults: `axis: 'block'`, `edge: 'end'`, `align: 'center'`,
|
|
42
|
+
* `offset.gap: token('space.100', '8px')`,
|
|
43
|
+
* `offset.crossAxisShift: { value: '0px', direction: 'forwards' }`.
|
|
15
44
|
*/
|
|
16
45
|
function getPlacement(_ref) {
|
|
17
|
-
var _placement$axis, _placement$edge, _placement$align;
|
|
46
|
+
var _placement$offset, _placement$axis, _placement$edge, _placement$align, _placement$offset$cro, _placement$offset2, _placement$offset$cro2, _placement$offset3;
|
|
18
47
|
var placement = _ref.placement;
|
|
48
|
+
var consumerGap = (_placement$offset = placement.offset) === null || _placement$offset === void 0 ? void 0 : _placement$offset.gap;
|
|
19
49
|
return {
|
|
20
50
|
axis: (_placement$axis = placement.axis) !== null && _placement$axis !== void 0 ? _placement$axis : 'block',
|
|
21
51
|
edge: (_placement$edge = placement.edge) !== null && _placement$edge !== void 0 ? _placement$edge : 'end',
|
|
22
|
-
align: (_placement$align = placement.align) !== null && _placement$align !== void 0 ? _placement$align : 'center'
|
|
52
|
+
align: (_placement$align = placement.align) !== null && _placement$align !== void 0 ? _placement$align : 'center',
|
|
53
|
+
offset: {
|
|
54
|
+
gap: consumerGap === undefined ? DEFAULT_GAP : (0, _resolveCssLength.toCssLengthString)({
|
|
55
|
+
value: consumerGap
|
|
56
|
+
}),
|
|
57
|
+
crossAxisShift: {
|
|
58
|
+
value: (0, _resolveCssLength.toCssLengthString)({
|
|
59
|
+
value: (_placement$offset$cro = (_placement$offset2 = placement.offset) === null || _placement$offset2 === void 0 || (_placement$offset2 = _placement$offset2.crossAxisShift) === null || _placement$offset2 === void 0 ? void 0 : _placement$offset2.value) !== null && _placement$offset$cro !== void 0 ? _placement$offset$cro : 0
|
|
60
|
+
}),
|
|
61
|
+
direction: (_placement$offset$cro2 = (_placement$offset3 = placement.offset) === null || _placement$offset3 === void 0 || (_placement$offset3 = _placement$offset3.crossAxisShift) === null || _placement$offset3 === void 0 ? void 0 : _placement$offset3.direction) !== null && _placement$offset$cro2 !== void 0 ? _placement$offset$cro2 : 'forwards'
|
|
62
|
+
}
|
|
63
|
+
}
|
|
23
64
|
};
|
|
24
65
|
}
|