@atlaskit/top-layer 4.2.2 → 4.2.4
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 +18 -0
- package/dist/cjs/internal/anchor-positioning-fallback.js +24 -9
- package/dist/cjs/internal/get-aria-for-trigger.js +3 -2
- package/dist/cjs/internal/resolve-placement.js +7 -2
- package/dist/cjs/internal/set-style.js +9 -0
- package/dist/cjs/internal/use-anchor-position.js +95 -93
- package/dist/cjs/internal/use-width-from-anchor.js +68 -52
- package/dist/es2019/internal/anchor-positioning-fallback.js +24 -9
- package/dist/es2019/internal/get-aria-for-trigger.js +3 -2
- package/dist/es2019/internal/resolve-placement.js +7 -2
- package/dist/es2019/internal/set-style.js +9 -0
- package/dist/es2019/internal/use-anchor-position.js +94 -95
- package/dist/es2019/internal/use-width-from-anchor.js +63 -47
- package/dist/esm/internal/anchor-positioning-fallback.js +24 -9
- package/dist/esm/internal/get-aria-for-trigger.js +3 -2
- package/dist/esm/internal/resolve-placement.js +7 -2
- package/dist/esm/internal/set-style.js +9 -0
- package/dist/esm/internal/use-anchor-position.js +95 -93
- package/dist/esm/internal/use-width-from-anchor.js +67 -52
- package/dist/types/internal/anchor-positioning-fallback.d.ts +34 -9
- package/dist/types/internal/get-aria-for-trigger.d.ts +3 -2
- package/dist/types/internal/resolve-placement.d.ts +15 -12
- package/dist/types/internal/set-style.d.ts +13 -4
- package/dist/types/internal/use-width-from-anchor.d.ts +6 -8
- package/dist/types/popover/types.d.ts +6 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @atlaskit/top-layer
|
|
2
2
|
|
|
3
|
+
## 4.2.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`41f64e5df21c7`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/41f64e5df21c7) -
|
|
8
|
+
`useWidthFromAnchor` now sizes against `anchor-size(self-inline)` rather than
|
|
9
|
+
`anchor-size(width)`, so an anchor-relative popover width is measured on the same axis as the
|
|
10
|
+
property it is set on. No change in a horizontal writing mode.
|
|
11
|
+
|
|
12
|
+
## 4.2.3
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- [`3f3fc95b7af6b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/3f3fc95b7af6b) -
|
|
17
|
+
Fixed `offset.crossAxisShift` moving the popover the wrong distance or direction in some
|
|
18
|
+
placements, and restored the documented `useWidthFromAnchor({ mode: 'min-anchor' })` width
|
|
19
|
+
behaviour.
|
|
20
|
+
|
|
3
21
|
## 4.2.2
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
|
@@ -20,6 +20,19 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
20
20
|
* position.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* A viewport-relative position, in pixels. Physical rather than logical
|
|
25
|
+
* because it is written straight to `top` / `left`.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The cross-axis shift with its length already resolved to pixels.
|
|
30
|
+
*
|
|
31
|
+
* Mirrors `TCrossAxisShiftOffset`, whose `value` is an unresolved CSS length
|
|
32
|
+
* string. Only this module needs the pixel form, because only this module does
|
|
33
|
+
* the arithmetic itself.
|
|
34
|
+
*/
|
|
35
|
+
|
|
23
36
|
/**
|
|
24
37
|
* Computes the base {top, left} position based on the primary edge,
|
|
25
38
|
* flipping to the opposite side when there is not enough space.
|
|
@@ -130,23 +143,26 @@ function applyAlignment(_ref2) {
|
|
|
130
143
|
/**
|
|
131
144
|
* Applies the cross-axis shift offset.
|
|
132
145
|
*
|
|
133
|
-
*
|
|
134
|
-
* `
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
146
|
+
* `forwards` always moves the popover toward the cross-axis END and
|
|
147
|
+
* `backwards` toward the START, for every `align` value. See
|
|
148
|
+
* `notes/decisions/placement-offset.md`.
|
|
149
|
+
*
|
|
150
|
+
* This is a coordinate, so the direction is the sign and nothing else. There
|
|
151
|
+
* is deliberately no per-`align` sign inversion here: the CSS path inverts the
|
|
152
|
+
* sign only because a margin on the END side pushes a box the opposite way to
|
|
153
|
+
* a margin on the START side, which is a property of margins rather than of
|
|
154
|
+
* the shift. Applying that inversion to a coordinate moved `align: 'end'`
|
|
155
|
+
* popovers the wrong way.
|
|
138
156
|
*/
|
|
139
157
|
function applyCrossAxisShift(_ref3) {
|
|
140
158
|
var position = _ref3.position,
|
|
141
159
|
axis = _ref3.axis,
|
|
142
|
-
align = _ref3.align,
|
|
143
160
|
crossAxisShift = _ref3.crossAxisShift;
|
|
144
161
|
if (crossAxisShift.value === 0) {
|
|
145
162
|
return position;
|
|
146
163
|
}
|
|
147
164
|
var directionSign = crossAxisShift.direction === 'forwards' ? 1 : -1;
|
|
148
|
-
var
|
|
149
|
-
var delta = crossAxisShift.value * directionSign * sideSign;
|
|
165
|
+
var delta = crossAxisShift.value * directionSign;
|
|
150
166
|
|
|
151
167
|
// Cross-axis is the OPPOSITE of the placement axis.
|
|
152
168
|
if (axis === 'block') {
|
|
@@ -202,7 +218,6 @@ function computeFallbackPosition(_ref4) {
|
|
|
202
218
|
var shiftedPosition = applyCrossAxisShift({
|
|
203
219
|
position: alignedPosition,
|
|
204
220
|
axis: axis,
|
|
205
|
-
align: align,
|
|
206
221
|
crossAxisShift: crossAxisShift
|
|
207
222
|
});
|
|
208
223
|
|
|
@@ -50,8 +50,9 @@ var roleToAriaHasPopup = {
|
|
|
50
50
|
* `menu → "menu"`, `tooltip → undefined`). React omits the attribute when
|
|
51
51
|
* the value is `undefined`.
|
|
52
52
|
* - `aria-expanded` - reflects the current open state.
|
|
53
|
-
* - `aria-controls` - references the popover element by its id
|
|
54
|
-
*
|
|
53
|
+
* - `aria-controls` - references the popover element by its id, even
|
|
54
|
+
* while the popover is closed. The relationship is stable; `aria-expanded`
|
|
55
|
+
* carries the current visibility state.
|
|
55
56
|
*
|
|
56
57
|
* **This function is for click/keyboard-activated popovers only.** For
|
|
57
58
|
* hover-driven tooltips, the trigger should use `aria-describedby` instead.
|
|
@@ -12,10 +12,15 @@ var _resolveCssLength = require("./resolve-css-length");
|
|
|
12
12
|
*/
|
|
13
13
|
var DEFAULT_GAP = "var(--ds-space-100, 8px)";
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Which way along the cross axis a shift moves the popover. `'forwards'` is
|
|
17
|
+
* always toward the cross-axis END and `'backwards'` toward the START, for
|
|
18
|
+
* every `align` value. See `notes/decisions/placement-offset.md`.
|
|
19
|
+
*/
|
|
20
|
+
|
|
15
21
|
/**
|
|
16
22
|
* Cross-axis shift. `value` is a CSS length string (consumer numbers are
|
|
17
|
-
* normalized to `${n}px`).
|
|
18
|
-
* `'backwards'` (toward start).
|
|
23
|
+
* normalized to `${n}px`).
|
|
19
24
|
*/
|
|
20
25
|
|
|
21
26
|
/**
|
|
@@ -4,6 +4,15 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.setStyle = setStyle;
|
|
7
|
+
/**
|
|
8
|
+
* A single inline style declaration.
|
|
9
|
+
*
|
|
10
|
+
* `TProperty` narrows the property name for callers that write a known, closed
|
|
11
|
+
* set of properties. Narrowing it lets a record keyed on those same names be
|
|
12
|
+
* checked for exhaustiveness at compile time, rather than silently resolving to
|
|
13
|
+
* `undefined` for a name that was never mapped.
|
|
14
|
+
*/
|
|
15
|
+
|
|
7
16
|
/**
|
|
8
17
|
* Sets inline styles on an element and returns a cleanup function that
|
|
9
18
|
* restores the prior inline values (so we do not stomp consumer styles).
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.useAnchorPosition = useAnchorPosition;
|
|
8
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
8
9
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
9
10
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
11
|
var _react = require("react");
|
|
@@ -81,6 +82,40 @@ var supportsAnchorPositioning = (0, _once.default)(function () {
|
|
|
81
82
|
return CSS.supports('anchor-name', '--a');
|
|
82
83
|
});
|
|
83
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Every logical margin property this module can write: one per axis, per side.
|
|
87
|
+
*
|
|
88
|
+
* Deriving the union from `TPlacementAxis` and `TPlacementEdge` rather than
|
|
89
|
+
* writing the four names out keeps it in step with the placement model, and
|
|
90
|
+
* makes `CROSS_AXIS_SHIFT_CUSTOM_PROPERTY` below exhaustive by construction.
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The custom property mirroring each cross-axis shift margin.
|
|
95
|
+
*
|
|
96
|
+
* These are written for the planned named arrow `@position-try` rules. Nothing
|
|
97
|
+
* reads them yet, and the shift no longer depends on them: the antisymmetric
|
|
98
|
+
* margins written by `crossAxisShiftMargins` survive a cross-axis slide on
|
|
99
|
+
* their own.
|
|
100
|
+
*
|
|
101
|
+
* Keyed on `TLogicalMarginProperty` and not on `string`, so a margin property
|
|
102
|
+
* that has no custom property (or a custom property whose margin no longer
|
|
103
|
+
* exists) is a compile error rather than an `undefined` lookup that reaches
|
|
104
|
+
* `setStyle` as `{ property: undefined, value }`.
|
|
105
|
+
*/
|
|
106
|
+
var CROSS_AXIS_SHIFT_CUSTOM_PROPERTY = {
|
|
107
|
+
'margin-inline-start': '--ds-cross-axis-shift-margin-start',
|
|
108
|
+
'margin-inline-end': '--ds-cross-axis-shift-margin-end',
|
|
109
|
+
'margin-block-start': '--ds-cross-axis-shift-margin-block-start',
|
|
110
|
+
'margin-block-end': '--ds-cross-axis-shift-margin-block-end'
|
|
111
|
+
};
|
|
112
|
+
var ZEROED_CROSS_AXIS_SHIFT_CUSTOM_PROPERTIES = Object.values(CROSS_AXIS_SHIFT_CUSTOM_PROPERTY).map(function (property) {
|
|
113
|
+
return {
|
|
114
|
+
property: property,
|
|
115
|
+
value: '0px'
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
|
|
84
119
|
/**
|
|
85
120
|
* Returns the CSS margin declaration that creates a gap between the
|
|
86
121
|
* popover and its trigger on the side facing the anchor.
|
|
@@ -93,62 +128,64 @@ function edgeMargin(_ref) {
|
|
|
93
128
|
offset = _ref.offset;
|
|
94
129
|
var axis = placement.axis,
|
|
95
130
|
edge = placement.edge;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
property: 'margin-block-start',
|
|
100
|
-
value: value
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
if (axis === 'block' && edge === 'start') {
|
|
104
|
-
return {
|
|
105
|
-
property: 'margin-block-end',
|
|
106
|
-
value: value
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
if (axis === 'inline' && edge === 'end') {
|
|
110
|
-
return {
|
|
111
|
-
property: 'margin-inline-start',
|
|
112
|
-
value: value
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
if (axis === 'inline' && edge === 'start') {
|
|
116
|
-
return {
|
|
117
|
-
property: 'margin-inline-end',
|
|
118
|
-
value: value
|
|
119
|
-
};
|
|
120
|
-
}
|
|
131
|
+
// The gap sits on the side FACING the anchor, which is always the side
|
|
132
|
+
// opposite the placement edge.
|
|
133
|
+
var anchorFacingEdge = edge === 'end' ? 'start' : 'end';
|
|
121
134
|
return {
|
|
122
|
-
property:
|
|
123
|
-
value:
|
|
135
|
+
property: "margin-".concat(axis, "-").concat(anchorFacingEdge),
|
|
136
|
+
value: offset
|
|
124
137
|
};
|
|
125
138
|
}
|
|
126
139
|
|
|
127
140
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
141
|
+
* **The cross-axis shift margins.**
|
|
142
|
+
*
|
|
143
|
+
* The shift is written antisymmetrically on BOTH cross-axis sides
|
|
144
|
+
* (`start: +value`, `end: -value`) rather than as a single margin on the side
|
|
145
|
+
* picked from `align`. Two separate behaviours require it:
|
|
146
|
+
*
|
|
147
|
+
* 1. **`align: 'center'` is centered with `anchor-center`, which centers the
|
|
148
|
+
* popover's MARGIN box on the anchor.** A single-sided margin widens the
|
|
149
|
+
* margin box, so it displaces the border box by only half its value. An
|
|
150
|
+
* antisymmetric pair leaves the margin box width unchanged (`+value` and
|
|
151
|
+
* `-value` sum to zero) while moving its center by the full value.
|
|
152
|
+
* 2. **`position-try-fallbacks` can slide the popover onto the opposite
|
|
153
|
+
* cross-axis side.** A `<position-area>` fallback keeps the base style's
|
|
154
|
+
* margins, and margin on the un-anchored side has no effect, so a
|
|
155
|
+
* single-sided margin is silently dropped once the browser slides across the
|
|
156
|
+
* cross axis. With both sides written, whichever side ends up anchored moves
|
|
157
|
+
* the popover the same physical direction.
|
|
158
|
+
*
|
|
159
|
+
* Leaving the margin box width unchanged also means the shift does not move
|
|
160
|
+
* the point at which `position-try-fallbacks` decides the popover overflows.
|
|
161
|
+
*
|
|
162
|
+
* A `<try-tactic>` fallback (`flip-block`, `flip-inline`) behaves differently to
|
|
163
|
+
* a `<position-area>` one: it SWAPS the start and end margins rather than
|
|
164
|
+
* keeping them, which is what preserves the gap through a flip. So a flip across
|
|
165
|
+
* the cross axis mirrors the shift along with the rest of the placement, rather
|
|
166
|
+
* than preserving its physical direction. Only the diagonal fallback does that,
|
|
167
|
+
* and only for `align: 'start' | 'end'`. See `placementToTryFallbacks`.
|
|
168
|
+
*
|
|
169
|
+
* A positive value always moves the popover toward the cross-axis END, so
|
|
170
|
+
* `direction: 'forwards'` means the same thing for every `align` value. See
|
|
171
|
+
* `notes/decisions/placement-offset.md`.
|
|
133
172
|
*/
|
|
134
|
-
function
|
|
173
|
+
function crossAxisShiftMargins(_ref2) {
|
|
135
174
|
var placement = _ref2.placement,
|
|
136
175
|
crossAxisShiftCssValue = _ref2.crossAxisShiftCssValue,
|
|
137
176
|
direction = _ref2.direction;
|
|
138
|
-
var
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
var
|
|
142
|
-
var
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
value: value
|
|
151
|
-
};
|
|
177
|
+
var crossAxis = placement.axis === 'block' ? 'inline' : 'block';
|
|
178
|
+
// Wrap any string in calc() with the sign factor. CSS handles the math,
|
|
179
|
+
// so opaque values such as design tokens negate correctly.
|
|
180
|
+
var negated = "calc(-1 * ".concat(crossAxisShiftCssValue, ")");
|
|
181
|
+
var isForwards = direction === 'forwards';
|
|
182
|
+
return [{
|
|
183
|
+
property: "margin-".concat(crossAxis, "-start"),
|
|
184
|
+
value: isForwards ? crossAxisShiftCssValue : negated
|
|
185
|
+
}, {
|
|
186
|
+
property: "margin-".concat(crossAxis, "-end"),
|
|
187
|
+
value: isForwards ? negated : crossAxisShiftCssValue
|
|
188
|
+
}];
|
|
152
189
|
}
|
|
153
190
|
|
|
154
191
|
/**
|
|
@@ -233,10 +270,9 @@ function useAnchorPosition(_ref3) {
|
|
|
233
270
|
placement: stablePlacement,
|
|
234
271
|
offset: gapCssValue
|
|
235
272
|
});
|
|
236
|
-
// Computed once;
|
|
237
|
-
// `--ds-cross-axis-shift-margin-*` custom
|
|
238
|
-
|
|
239
|
-
var crossAxisShift = crossAxisShiftMargin({
|
|
273
|
+
// Computed once; also mirrored into the
|
|
274
|
+
// `--ds-cross-axis-shift-margin-*` custom properties below.
|
|
275
|
+
var crossAxisShift = crossAxisShiftMargins({
|
|
240
276
|
placement: stablePlacement,
|
|
241
277
|
crossAxisShiftCssValue: crossAxisShiftCssValue,
|
|
242
278
|
direction: stablePlacement.offset.crossAxisShift.direction
|
|
@@ -263,48 +299,14 @@ function useAnchorPosition(_ref3) {
|
|
|
263
299
|
}, {
|
|
264
300
|
property: 'inset',
|
|
265
301
|
value: 'auto'
|
|
266
|
-
}, {
|
|
267
|
-
property
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
// Expose the active cross-axis shift via custom properties so each
|
|
275
|
-
// named arrow @position-try rule can re-apply it after a flip.
|
|
276
|
-
// One of the four (cross-axis, side) properties is non-zero at a time.
|
|
277
|
-
popoverStyles.push({
|
|
278
|
-
property: '--ds-cross-axis-shift-margin-start',
|
|
279
|
-
value: '0px'
|
|
280
|
-
});
|
|
281
|
-
popoverStyles.push({
|
|
282
|
-
property: '--ds-cross-axis-shift-margin-end',
|
|
283
|
-
value: '0px'
|
|
284
|
-
});
|
|
285
|
-
popoverStyles.push({
|
|
286
|
-
property: '--ds-cross-axis-shift-margin-block-start',
|
|
287
|
-
value: '0px'
|
|
288
|
-
});
|
|
289
|
-
popoverStyles.push({
|
|
290
|
-
property: '--ds-cross-axis-shift-margin-block-end',
|
|
291
|
-
value: '0px'
|
|
292
|
-
});
|
|
293
|
-
// `crossAxisShift` IS the active margin; reuse instead of recomputing.
|
|
294
|
-
var crossAxisShiftActive = crossAxisShift;
|
|
295
|
-
var customPropertyByMarginProperty = {
|
|
296
|
-
'margin-inline-start': '--ds-cross-axis-shift-margin-start',
|
|
297
|
-
'margin-inline-end': '--ds-cross-axis-shift-margin-end',
|
|
298
|
-
'margin-block-start': '--ds-cross-axis-shift-margin-block-start',
|
|
299
|
-
'margin-block-end': '--ds-cross-axis-shift-margin-block-end'
|
|
300
|
-
};
|
|
301
|
-
var crossAxisShiftCustomProperty = customPropertyByMarginProperty[crossAxisShiftActive.property];
|
|
302
|
-
if (crossAxisShiftCustomProperty) {
|
|
303
|
-
popoverStyles.push({
|
|
304
|
-
property: crossAxisShiftCustomProperty,
|
|
305
|
-
value: crossAxisShiftActive.value
|
|
306
|
-
});
|
|
307
|
-
}
|
|
302
|
+
}, gap].concat((0, _toConsumableArray2.default)(crossAxisShift), (0, _toConsumableArray2.default)(ZEROED_CROSS_AXIS_SHIFT_CUSTOM_PROPERTIES), (0, _toConsumableArray2.default)(crossAxisShift.map(function (_ref4) {
|
|
303
|
+
var property = _ref4.property,
|
|
304
|
+
value = _ref4.value;
|
|
305
|
+
return {
|
|
306
|
+
property: CROSS_AXIS_SHIFT_CUSTOM_PROPERTY[property],
|
|
307
|
+
value: value
|
|
308
|
+
};
|
|
309
|
+
})));
|
|
308
310
|
|
|
309
311
|
/**
|
|
310
312
|
* **We are never cleaning up anchor names**
|
|
@@ -1,83 +1,95 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
5
6
|
});
|
|
6
7
|
exports.useWidthFromAnchor = useWidthFromAnchor;
|
|
7
8
|
var _react = require("react");
|
|
9
|
+
var _once = _interopRequireDefault(require("@atlaskit/ds-lib/once"));
|
|
8
10
|
var _setStyle = require("./set-style");
|
|
11
|
+
/**
|
|
12
|
+
* Probes anchor SIZING, separately from `anchor-name` (see
|
|
13
|
+
* `supportsAnchorPositioning`): some browsers have positioning but not sizing.
|
|
14
|
+
* `once()` for SSR safety.
|
|
15
|
+
*/
|
|
16
|
+
var supportsAnchorSize = (0, _once.default)(function () {
|
|
17
|
+
if (typeof window === 'undefined' || typeof CSS === 'undefined' || typeof CSS.supports !== 'function') {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return CSS.supports('min-inline-size', 'anchor-size(self-inline)');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The JS fallback's stand-in for `anchor-size(self-inline)`. `offsetWidth` / `offsetHeight` are
|
|
25
|
+
* physical, so the axis is picked from the popover's `writing-mode`. Anything not horizontal is
|
|
26
|
+
* treated as vertical, and an unknown or empty value falls back to `offsetWidth`.
|
|
27
|
+
*/
|
|
28
|
+
function getFallbackAnchorInlineSize(_ref) {
|
|
29
|
+
var anchor = _ref.anchor,
|
|
30
|
+
popover = _ref.popover;
|
|
31
|
+
// `String()` because not every test environment implements `writing-mode`.
|
|
32
|
+
var writingMode = String(getComputedStyle(popover).writingMode);
|
|
33
|
+
var isVertical = writingMode.startsWith('vertical') || writingMode.startsWith('sideways');
|
|
34
|
+
return isVertical ? anchor.offsetHeight : anchor.offsetWidth;
|
|
35
|
+
}
|
|
36
|
+
|
|
9
37
|
/**
|
|
10
38
|
* Sets the width of a popover element relative to its anchor element.
|
|
11
39
|
*
|
|
12
|
-
* - `'match-anchor'` → `
|
|
13
|
-
* - `'min-anchor'` → `min-
|
|
14
|
-
*
|
|
15
|
-
* - `'none'` → no explicit width is set (default behaviour)
|
|
40
|
+
* - `'match-anchor'` → `inline-size: anchor-size(self-inline)`, exact
|
|
41
|
+
* - `'min-anchor'` → `min-inline-size: anchor-size(self-inline)`, floor only
|
|
42
|
+
* - `'none'` → `min-inline-size: max-content`, content floor (default)
|
|
16
43
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* Designed to be composed alongside `useAnchorPosition` for top-layer popovers.
|
|
44
|
+
* `self-inline` is the inline axis of the element USING the function (the popover), never the
|
|
45
|
+
* anchor, so it matches the axis `inline-size` constrains. See
|
|
46
|
+
* `notes/decisions/width-from-anchor-floors.md`.
|
|
21
47
|
*/
|
|
22
|
-
function useWidthFromAnchor(
|
|
23
|
-
var mode =
|
|
24
|
-
popoverRef =
|
|
25
|
-
anchorRef =
|
|
26
|
-
isOpen =
|
|
48
|
+
function useWidthFromAnchor(_ref2) {
|
|
49
|
+
var mode = _ref2.mode,
|
|
50
|
+
popoverRef = _ref2.popoverRef,
|
|
51
|
+
anchorRef = _ref2.anchorRef,
|
|
52
|
+
isOpen = _ref2.isOpen;
|
|
27
53
|
(0, _react.useLayoutEffect)(function () {
|
|
28
54
|
var node = popoverRef.current;
|
|
29
55
|
if (!node) {
|
|
30
56
|
return;
|
|
31
57
|
}
|
|
32
|
-
|
|
33
|
-
// Feature-detect `anchor-size()` specifically (not just `anchor-name`)
|
|
34
|
-
// so the JS fallback fires correctly in browsers that support anchor
|
|
35
|
-
// positioning but not anchor sizing.
|
|
36
|
-
var supportsAnchorSize = typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('width', 'anchor-size(width)');
|
|
37
58
|
if (mode === 'match-anchor') {
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
// explicit width constraint, allowing the popover to grow past the anchor's width.
|
|
41
|
-
if (supportsAnchorSize) {
|
|
59
|
+
// No floor here: it would let the popover grow past the anchor.
|
|
60
|
+
if (supportsAnchorSize()) {
|
|
42
61
|
return (0, _setStyle.setStyle)({
|
|
43
62
|
element: node,
|
|
44
63
|
styles: [{
|
|
45
|
-
property: '
|
|
46
|
-
value: 'anchor-size(
|
|
64
|
+
property: 'inline-size',
|
|
65
|
+
value: 'anchor-size(self-inline)'
|
|
47
66
|
}]
|
|
48
67
|
});
|
|
49
68
|
}
|
|
50
|
-
|
|
51
|
-
// JS fallback: one-off read of the anchor's width.
|
|
52
69
|
var anchor = anchorRef.current;
|
|
53
70
|
if (anchor) {
|
|
54
71
|
return (0, _setStyle.setStyle)({
|
|
55
72
|
element: node,
|
|
56
73
|
styles: [{
|
|
57
|
-
property: '
|
|
58
|
-
value: "".concat(
|
|
74
|
+
property: 'inline-size',
|
|
75
|
+
value: "".concat(getFallbackAnchorInlineSize({
|
|
76
|
+
anchor: anchor,
|
|
77
|
+
popover: node
|
|
78
|
+
}), "px")
|
|
59
79
|
}]
|
|
60
80
|
});
|
|
61
81
|
}
|
|
62
82
|
return;
|
|
63
83
|
}
|
|
64
|
-
|
|
65
|
-
// For 'min-anchor' and 'none', apply `min-inline-size: max-content` to ensure
|
|
66
|
-
// correct position-try-fallbacks behaviour (popover margin box overflows the
|
|
67
|
-
// viewport when its span region is too narrow, rather than wrapping content).
|
|
68
|
-
var minInlineSizeStyle = {
|
|
69
|
-
property: 'min-inline-size',
|
|
70
|
-
value: 'max-content'
|
|
71
|
-
};
|
|
72
84
|
if (mode === 'min-anchor') {
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
if (supportsAnchorSize) {
|
|
85
|
+
// One floor only. The content floor from mode 'none' deliberately does not also apply
|
|
86
|
+
// here, and cannot: it would need this same property. See the decision note.
|
|
87
|
+
if (supportsAnchorSize()) {
|
|
76
88
|
return (0, _setStyle.setStyle)({
|
|
77
89
|
element: node,
|
|
78
|
-
styles: [
|
|
79
|
-
property: 'min-
|
|
80
|
-
value: 'anchor-size(
|
|
90
|
+
styles: [{
|
|
91
|
+
property: 'min-inline-size',
|
|
92
|
+
value: 'anchor-size(self-inline)'
|
|
81
93
|
}]
|
|
82
94
|
});
|
|
83
95
|
}
|
|
@@ -85,24 +97,28 @@ function useWidthFromAnchor(_ref) {
|
|
|
85
97
|
if (_anchor) {
|
|
86
98
|
return (0, _setStyle.setStyle)({
|
|
87
99
|
element: node,
|
|
88
|
-
styles: [
|
|
89
|
-
property: 'min-
|
|
90
|
-
value: "".concat(
|
|
100
|
+
styles: [{
|
|
101
|
+
property: 'min-inline-size',
|
|
102
|
+
value: "".concat(getFallbackAnchorInlineSize({
|
|
103
|
+
anchor: _anchor,
|
|
104
|
+
popover: node
|
|
105
|
+
}), "px")
|
|
91
106
|
}]
|
|
92
107
|
});
|
|
93
108
|
}
|
|
94
109
|
|
|
95
|
-
//
|
|
96
|
-
return
|
|
97
|
-
element: node,
|
|
98
|
-
styles: [minInlineSizeStyle]
|
|
99
|
-
});
|
|
110
|
+
// Nothing to measure, so no floor.
|
|
111
|
+
return;
|
|
100
112
|
}
|
|
101
113
|
|
|
102
|
-
//
|
|
114
|
+
// Makes a too-narrow span overflow and drive `position-try-fallbacks` instead of wrapping.
|
|
115
|
+
// `@atlaskit/popper` resets this exact property to `0` for its fit-to-viewport mode.
|
|
103
116
|
return (0, _setStyle.setStyle)({
|
|
104
117
|
element: node,
|
|
105
|
-
styles: [
|
|
118
|
+
styles: [{
|
|
119
|
+
property: 'min-inline-size',
|
|
120
|
+
value: 'max-content'
|
|
121
|
+
}]
|
|
106
122
|
});
|
|
107
123
|
}, [mode, popoverRef, anchorRef, isOpen]);
|
|
108
124
|
}
|
|
@@ -10,6 +10,19 @@
|
|
|
10
10
|
* position.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* A viewport-relative position, in pixels. Physical rather than logical
|
|
15
|
+
* because it is written straight to `top` / `left`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The cross-axis shift with its length already resolved to pixels.
|
|
20
|
+
*
|
|
21
|
+
* Mirrors `TCrossAxisShiftOffset`, whose `value` is an unresolved CSS length
|
|
22
|
+
* string. Only this module needs the pixel form, because only this module does
|
|
23
|
+
* the arithmetic itself.
|
|
24
|
+
*/
|
|
25
|
+
|
|
13
26
|
/**
|
|
14
27
|
* Computes the base {top, left} position based on the primary edge,
|
|
15
28
|
* flipping to the opposite side when there is not enough space.
|
|
@@ -126,24 +139,27 @@ function applyAlignment({
|
|
|
126
139
|
/**
|
|
127
140
|
* Applies the cross-axis shift offset.
|
|
128
141
|
*
|
|
129
|
-
*
|
|
130
|
-
* `
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
142
|
+
* `forwards` always moves the popover toward the cross-axis END and
|
|
143
|
+
* `backwards` toward the START, for every `align` value. See
|
|
144
|
+
* `notes/decisions/placement-offset.md`.
|
|
145
|
+
*
|
|
146
|
+
* This is a coordinate, so the direction is the sign and nothing else. There
|
|
147
|
+
* is deliberately no per-`align` sign inversion here: the CSS path inverts the
|
|
148
|
+
* sign only because a margin on the END side pushes a box the opposite way to
|
|
149
|
+
* a margin on the START side, which is a property of margins rather than of
|
|
150
|
+
* the shift. Applying that inversion to a coordinate moved `align: 'end'`
|
|
151
|
+
* popovers the wrong way.
|
|
134
152
|
*/
|
|
135
153
|
function applyCrossAxisShift({
|
|
136
154
|
position,
|
|
137
155
|
axis,
|
|
138
|
-
align,
|
|
139
156
|
crossAxisShift
|
|
140
157
|
}) {
|
|
141
158
|
if (crossAxisShift.value === 0) {
|
|
142
159
|
return position;
|
|
143
160
|
}
|
|
144
161
|
const directionSign = crossAxisShift.direction === 'forwards' ? 1 : -1;
|
|
145
|
-
const
|
|
146
|
-
const delta = crossAxisShift.value * directionSign * sideSign;
|
|
162
|
+
const delta = crossAxisShift.value * directionSign;
|
|
147
163
|
|
|
148
164
|
// Cross-axis is the OPPOSITE of the placement axis.
|
|
149
165
|
if (axis === 'block') {
|
|
@@ -204,7 +220,6 @@ export function computeFallbackPosition({
|
|
|
204
220
|
const shiftedPosition = applyCrossAxisShift({
|
|
205
221
|
position: alignedPosition,
|
|
206
222
|
axis,
|
|
207
|
-
align,
|
|
208
223
|
crossAxisShift
|
|
209
224
|
});
|
|
210
225
|
|
|
@@ -44,8 +44,9 @@ const roleToAriaHasPopup = {
|
|
|
44
44
|
* `menu → "menu"`, `tooltip → undefined`). React omits the attribute when
|
|
45
45
|
* the value is `undefined`.
|
|
46
46
|
* - `aria-expanded` - reflects the current open state.
|
|
47
|
-
* - `aria-controls` - references the popover element by its id
|
|
48
|
-
*
|
|
47
|
+
* - `aria-controls` - references the popover element by its id, even
|
|
48
|
+
* while the popover is closed. The relationship is stable; `aria-expanded`
|
|
49
|
+
* carries the current visibility state.
|
|
49
50
|
*
|
|
50
51
|
* **This function is for click/keyboard-activated popovers only.** For
|
|
51
52
|
* hover-driven tooltips, the trigger should use `aria-describedby` instead.
|
|
@@ -7,10 +7,15 @@ import { toCssLengthString } from './resolve-css-length';
|
|
|
7
7
|
*/
|
|
8
8
|
const DEFAULT_GAP = "var(--ds-space-100, 8px)";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Which way along the cross axis a shift moves the popover. `'forwards'` is
|
|
12
|
+
* always toward the cross-axis END and `'backwards'` toward the START, for
|
|
13
|
+
* every `align` value. See `notes/decisions/placement-offset.md`.
|
|
14
|
+
*/
|
|
15
|
+
|
|
10
16
|
/**
|
|
11
17
|
* Cross-axis shift. `value` is a CSS length string (consumer numbers are
|
|
12
|
-
* normalized to `${n}px`).
|
|
13
|
-
* `'backwards'` (toward start).
|
|
18
|
+
* normalized to `${n}px`).
|
|
14
19
|
*/
|
|
15
20
|
|
|
16
21
|
/**
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single inline style declaration.
|
|
3
|
+
*
|
|
4
|
+
* `TProperty` narrows the property name for callers that write a known, closed
|
|
5
|
+
* set of properties. Narrowing it lets a record keyed on those same names be
|
|
6
|
+
* checked for exhaustiveness at compile time, rather than silently resolving to
|
|
7
|
+
* `undefined` for a name that was never mapped.
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
/**
|
|
2
11
|
* Sets inline styles on an element and returns a cleanup function that
|
|
3
12
|
* restores the prior inline values (so we do not stomp consumer styles).
|