@atlaskit/top-layer 1.0.1 → 1.1.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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/top-layer
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`ff76ce8167751`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ff76ce8167751) -
8
+ Internal refactoring. No behaviour change.
9
+
10
+ ## 1.0.2
11
+
12
+ ### Patch Changes
13
+
14
+ - [`ee28cf33718b0`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ee28cf33718b0) -
15
+ Add @atlassian/react-compiler-gating as a runtime dependency to enable React Compiler platform
16
+ gating.
17
+ - Updated dependencies
18
+
3
19
  ## 1.0.1
4
20
 
5
21
  ### Patch Changes
@@ -1,82 +1,108 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
3
  Object.defineProperty(exports, "__esModule", {
5
4
  value: true
6
5
  });
7
6
  exports.placementToTryFallbacks = placementToTryFallbacks;
8
- var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
7
  var _resolvePlacement = require("./resolve-placement");
10
8
  /**
11
- * Returns `position-try-fallbacks` value based on placement.
12
- *
13
- * For centered placements, includes cross-axis aligned position-area
14
- * values so the browser can shift the popover along the cross-axis
15
- * when the centered position would overflow the viewport edge.
16
- *
17
- * Fallback order for centered placements (e.g. `block-end`):
18
- * 1. Same edge, start-aligned (shift for near-edge overflow)
19
- * 2. Same edge, end-aligned (shift for far-edge overflow)
20
- * 3. Flipped edge, centered
21
- * 4. Flipped edge, start-aligned
22
- * 5. Flipped edge, end-aligned
23
- *
24
- * For aligned placements (start/end), includes the same-edge centered
25
- * position as fallbacks so the browser can try centering when the aligned
26
- * position would overflow, before flipping to the opposite edge.
27
- *
28
- * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
29
- *
30
- * When a popup is in a viewport corner (e.g. inline-end align-end at the
31
- * top-right), flipping only the primary axis (`flip-inline`) moves the popup
32
- * to the left but keeps the same cross-axis span direction (e.g. upward),
33
- * which is still off-screen. The combined keyword `flip-inline flip-block`
34
- * mirrors the popup diagonally. It flips BOTH the position-area AND both
35
- * inline and block margins simultaneously, placing the popup at the
36
- * diagonally opposite corner where there is always space.
9
+ * A `position-area` primary edge — the placement axis joined to its edge, e.g.
10
+ * `block-end` or `inline-start`. These are the four edges a popover can sit on.
11
+ */
12
+
13
+ function slideOnEdge(_ref) {
14
+ var align = _ref.align,
15
+ edgeKey = _ref.edgeKey,
16
+ crossAxis = _ref.crossAxis;
17
+ if (align === 'center') {
18
+ return ["".concat(edgeKey, " span-").concat(crossAxis, "-end"), "".concat(edgeKey, " span-").concat(crossAxis, "-start")];
19
+ }
20
+ // For `align: 'start'` the popover expands toward `end`, so the "near"
21
+ // span is `end` and the "far" span is `start`; `align: 'end'` mirrors
22
+ // this. The bare `edgeKey` (re-centered) sits between them.
23
+ var near = align === 'start' ? 'end' : 'start';
24
+ var far = align === 'start' ? 'start' : 'end';
25
+ return ["".concat(edgeKey, " span-").concat(crossAxis, "-").concat(near), edgeKey, "".concat(edgeKey, " span-").concat(crossAxis, "-").concat(far)];
26
+ }
27
+ function flipDiagonally(_ref2) {
28
+ var axis = _ref2.axis;
29
+ var flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
30
+ var flipToCrossAxis = axis === 'block' ? 'flip-inline' : 'flip-block';
31
+ return "".concat(flipOnMainAxis, " ").concat(flipToCrossAxis);
32
+ }
33
+
34
+ /**
35
+ * Returns the `position-try-fallbacks` value for a placement.
37
36
  *
38
- * Named `position-area` entries (e.g. `inline-start span-block-end`) in
39
- * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
40
- * tactic keywords correctly flip the gap margin along with the position.
37
+ * @example
38
+ * // Centered on the block-end edge (the default placement):
39
+ * placementToTryFallbacks({ placement: { axis: 'block', edge: 'end', align: 'center' } });
40
+ * // => 'block-end span-inline-end, block-end span-inline-start, flip-block,
41
+ * // block-start span-inline-end, block-start span-inline-start'
41
42
  */
42
- function placementToTryFallbacks(_ref) {
43
- var placement = _ref.placement;
44
- var _getPlacement = (0, _resolvePlacement.getPlacement)({
45
- placement: placement
46
- }),
47
- axis = _getPlacement.axis,
48
- edge = _getPlacement.edge,
49
- align = _getPlacement.align;
43
+ function placementToTryFallbacks(_ref3) {
44
+ var placement = _ref3.placement;
45
+ /**
46
+ * **Build the fallback list**
47
+ *
48
+ * Each entry is a complete alternative position.
49
+ * The browser tries them _in order_ and uses the _first_ one that fits.
50
+ */
51
+
52
+ var resolved = (0, _resolvePlacement.getPlacement)({
53
+ placement: placement
54
+ });
55
+ var axis = resolved.axis,
56
+ edge = resolved.edge,
57
+ align = resolved.align;
50
58
  var crossAxis = axis === 'block' ? 'inline' : 'block';
51
59
  var flippedEdge = edge === 'start' ? 'end' : 'start';
52
- var sameEdge = "".concat(axis, "-").concat(edge);
53
- var oppositeEdge = "".concat(axis, "-").concat(flippedEdge);
54
- var flipKeyword = axis === 'block' ? 'flip-block' : 'flip-inline';
55
- var flipCrossKeyword = axis === 'block' ? 'flip-inline' : 'flip-block';
60
+ var sameEdgeArea = "".concat(axis, "-").concat(edge);
61
+ var oppositeEdgeArea = "".concat(axis, "-").concat(flippedEdge);
62
+ var flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
56
63
 
57
- // Single algorithm: produce the shift list against any base alignment.
58
- // For `align: 'start'` the "near" shift expands toward `end`; for
59
- // `align: 'end'` it expands toward `start`; for `align: 'center'`
60
- // either order is symmetric (we use end-then-start to match the
61
- // historical fallback list).
62
- function shifts(baseAlign, edgeKey) {
63
- if (baseAlign === 'center') {
64
- return ["".concat(edgeKey, " span-").concat(crossAxis, "-end"), "".concat(edgeKey, " span-").concat(crossAxis, "-start")];
65
- }
66
- var near = baseAlign === 'start' ? 'end' : 'start';
67
- var far = baseAlign === 'start' ? 'start' : 'end';
68
- return ["".concat(edgeKey, " span-").concat(crossAxis, "-").concat(near), edgeKey, "".concat(edgeKey, " span-").concat(crossAxis, "-").concat(far)];
69
- }
70
- if (align !== 'center') {
71
- // Aligned (start/end): try same-edge shifts, then single-axis flip,
72
- // then diagonal flip for corner overflow, then opposite-edge shifts.
73
- // Legacy Popper fallback ordering for e.g. bottom-start:
74
- // [bottom, bottom-end, top-start, top, top-end, auto].
75
- return [].concat((0, _toConsumableArray2.default)(shifts(align, sameEdge)), [flipKeyword, "".concat(flipKeyword, " ").concat(flipCrossKeyword)], (0, _toConsumableArray2.default)(shifts(align, oppositeEdge))).join(', ');
76
- }
64
+ /**
65
+ * **Fallback algorithm**
66
+ *
67
+ * We have two things we can do to keep something visible:
68
+ *
69
+ * 1. _Slide_ along edges
70
+ * 2. _Flip_ to another edge
71
+ *
72
+ * _Centered popover_
73
+ *
74
+ * Desired: Sits in middle of main edge
75
+ *
76
+ * Fallbacks:
77
+ * 1: _Slide_ along main edge on the cross axis
78
+ * 2: _Flip_ on main axis to opposite edge (centered)
79
+ * 3: _Slide_ along opposite edge on the cross axis
80
+ *
81
+ * _Start or end aligned popover_
82
+ *
83
+ * Desired: Sits at start / end of main edge
84
+ *
85
+ * Fallbacks:
86
+ * 1: _Slide_ along main edge on the cross axis
87
+ * 2: _Flip_ on main axis to opposite edge
88
+ * 3: _Flip_ on the diagonal (flip main axis + flip cross axis) into the
89
+ * opposite corner. For start / end alignment, this is the clean escape
90
+ * when the popover would otherwise land offscreen on both axes (ie in a
91
+ * corner). Rule 4 gets the job done, but a slide drops the gap
92
+ * as named position-area values don't carry margins).
93
+ * The diagonal flip keeps the gap and the alignment.
94
+ * 4: _Slide_ along opposite edge on the cross axis
95
+ */
77
96
 
78
- // Centered: same-edge shifts, single-axis flip, opposite-edge shifts.
79
- // Diagonal flip is unnecessary because centered placements expand
80
- // equally in both cross-axis directions.
81
- return [].concat((0, _toConsumableArray2.default)(shifts('center', sameEdge)), [flipKeyword], (0, _toConsumableArray2.default)(shifts('center', oppositeEdge))).join(', ');
97
+ return [slideOnEdge({
98
+ align: align,
99
+ edgeKey: sameEdgeArea,
100
+ crossAxis: crossAxis
101
+ }), flipOnMainAxis, align !== 'center' ? flipDiagonally({
102
+ axis: axis
103
+ }) : null, slideOnEdge({
104
+ align: align,
105
+ edgeKey: oppositeEdgeArea,
106
+ crossAxis: crossAxis
107
+ })].filter(Boolean).flat().join(', ');
82
108
  }
@@ -1,77 +1,108 @@
1
1
  import { getPlacement } from './resolve-placement';
2
2
 
3
3
  /**
4
- * Returns `position-try-fallbacks` value based on placement.
5
- *
6
- * For centered placements, includes cross-axis aligned position-area
7
- * values so the browser can shift the popover along the cross-axis
8
- * when the centered position would overflow the viewport edge.
9
- *
10
- * Fallback order for centered placements (e.g. `block-end`):
11
- * 1. Same edge, start-aligned (shift for near-edge overflow)
12
- * 2. Same edge, end-aligned (shift for far-edge overflow)
13
- * 3. Flipped edge, centered
14
- * 4. Flipped edge, start-aligned
15
- * 5. Flipped edge, end-aligned
16
- *
17
- * For aligned placements (start/end), includes the same-edge centered
18
- * position as fallbacks so the browser can try centering when the aligned
19
- * position would overflow, before flipping to the opposite edge.
20
- *
21
- * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
22
- *
23
- * When a popup is in a viewport corner (e.g. inline-end align-end at the
24
- * top-right), flipping only the primary axis (`flip-inline`) moves the popup
25
- * to the left but keeps the same cross-axis span direction (e.g. upward),
26
- * which is still off-screen. The combined keyword `flip-inline flip-block`
27
- * mirrors the popup diagonally. It flips BOTH the position-area AND both
28
- * inline and block margins simultaneously, placing the popup at the
29
- * diagonally opposite corner where there is always space.
4
+ * A `position-area` primary edge — the placement axis joined to its edge, e.g.
5
+ * `block-end` or `inline-start`. These are the four edges a popover can sit on.
6
+ */
7
+
8
+ function slideOnEdge({
9
+ align,
10
+ edgeKey,
11
+ crossAxis
12
+ }) {
13
+ if (align === 'center') {
14
+ return [`${edgeKey} span-${crossAxis}-end`, `${edgeKey} span-${crossAxis}-start`];
15
+ }
16
+ // For `align: 'start'` the popover expands toward `end`, so the "near"
17
+ // span is `end` and the "far" span is `start`; `align: 'end'` mirrors
18
+ // this. The bare `edgeKey` (re-centered) sits between them.
19
+ const near = align === 'start' ? 'end' : 'start';
20
+ const far = align === 'start' ? 'start' : 'end';
21
+ return [`${edgeKey} span-${crossAxis}-${near}`, edgeKey, `${edgeKey} span-${crossAxis}-${far}`];
22
+ }
23
+ function flipDiagonally({
24
+ axis
25
+ }) {
26
+ const flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
27
+ const flipToCrossAxis = axis === 'block' ? 'flip-inline' : 'flip-block';
28
+ return `${flipOnMainAxis} ${flipToCrossAxis}`;
29
+ }
30
+
31
+ /**
32
+ * Returns the `position-try-fallbacks` value for a placement.
30
33
  *
31
- * Named `position-area` entries (e.g. `inline-start span-block-end`) in
32
- * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
33
- * tactic keywords correctly flip the gap margin along with the position.
34
+ * @example
35
+ * // Centered on the block-end edge (the default placement):
36
+ * placementToTryFallbacks({ placement: { axis: 'block', edge: 'end', align: 'center' } });
37
+ * // => 'block-end span-inline-end, block-end span-inline-start, flip-block,
38
+ * // block-start span-inline-end, block-start span-inline-start'
34
39
  */
35
40
  export function placementToTryFallbacks({
36
41
  placement
37
42
  }) {
43
+ /**
44
+ * **Build the fallback list**
45
+ *
46
+ * Each entry is a complete alternative position.
47
+ * The browser tries them _in order_ and uses the _first_ one that fits.
48
+ */
49
+
50
+ const resolved = getPlacement({
51
+ placement
52
+ });
38
53
  const {
39
54
  axis,
40
55
  edge,
41
56
  align
42
- } = getPlacement({
43
- placement
44
- });
57
+ } = resolved;
45
58
  const crossAxis = axis === 'block' ? 'inline' : 'block';
46
59
  const flippedEdge = edge === 'start' ? 'end' : 'start';
47
- const sameEdge = `${axis}-${edge}`;
48
- const oppositeEdge = `${axis}-${flippedEdge}`;
49
- const flipKeyword = axis === 'block' ? 'flip-block' : 'flip-inline';
50
- const flipCrossKeyword = axis === 'block' ? 'flip-inline' : 'flip-block';
60
+ const sameEdgeArea = `${axis}-${edge}`;
61
+ const oppositeEdgeArea = `${axis}-${flippedEdge}`;
62
+ const flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
51
63
 
52
- // Single algorithm: produce the shift list against any base alignment.
53
- // For `align: 'start'` the "near" shift expands toward `end`; for
54
- // `align: 'end'` it expands toward `start`; for `align: 'center'`
55
- // either order is symmetric (we use end-then-start to match the
56
- // historical fallback list).
57
- function shifts(baseAlign, edgeKey) {
58
- if (baseAlign === 'center') {
59
- return [`${edgeKey} span-${crossAxis}-end`, `${edgeKey} span-${crossAxis}-start`];
60
- }
61
- const near = baseAlign === 'start' ? 'end' : 'start';
62
- const far = baseAlign === 'start' ? 'start' : 'end';
63
- return [`${edgeKey} span-${crossAxis}-${near}`, edgeKey, `${edgeKey} span-${crossAxis}-${far}`];
64
- }
65
- if (align !== 'center') {
66
- // Aligned (start/end): try same-edge shifts, then single-axis flip,
67
- // then diagonal flip for corner overflow, then opposite-edge shifts.
68
- // Legacy Popper fallback ordering for e.g. bottom-start:
69
- // [bottom, bottom-end, top-start, top, top-end, auto].
70
- return [...shifts(align, sameEdge), flipKeyword, `${flipKeyword} ${flipCrossKeyword}`, ...shifts(align, oppositeEdge)].join(', ');
71
- }
64
+ /**
65
+ * **Fallback algorithm**
66
+ *
67
+ * We have two things we can do to keep something visible:
68
+ *
69
+ * 1. _Slide_ along edges
70
+ * 2. _Flip_ to another edge
71
+ *
72
+ * _Centered popover_
73
+ *
74
+ * Desired: Sits in middle of main edge
75
+ *
76
+ * Fallbacks:
77
+ * 1: _Slide_ along main edge on the cross axis
78
+ * 2: _Flip_ on main axis to opposite edge (centered)
79
+ * 3: _Slide_ along opposite edge on the cross axis
80
+ *
81
+ * _Start or end aligned popover_
82
+ *
83
+ * Desired: Sits at start / end of main edge
84
+ *
85
+ * Fallbacks:
86
+ * 1: _Slide_ along main edge on the cross axis
87
+ * 2: _Flip_ on main axis to opposite edge
88
+ * 3: _Flip_ on the diagonal (flip main axis + flip cross axis) into the
89
+ * opposite corner. For start / end alignment, this is the clean escape
90
+ * when the popover would otherwise land offscreen on both axes (ie in a
91
+ * corner). Rule 4 gets the job done, but a slide drops the gap
92
+ * as named position-area values don't carry margins).
93
+ * The diagonal flip keeps the gap and the alignment.
94
+ * 4: _Slide_ along opposite edge on the cross axis
95
+ */
72
96
 
73
- // Centered: same-edge shifts, single-axis flip, opposite-edge shifts.
74
- // Diagonal flip is unnecessary because centered placements expand
75
- // equally in both cross-axis directions.
76
- return [...shifts('center', sameEdge), flipKeyword, ...shifts('center', oppositeEdge)].join(', ');
97
+ return [slideOnEdge({
98
+ align,
99
+ edgeKey: sameEdgeArea,
100
+ crossAxis
101
+ }), flipOnMainAxis, align !== 'center' ? flipDiagonally({
102
+ axis
103
+ }) : null, slideOnEdge({
104
+ align,
105
+ edgeKey: oppositeEdgeArea,
106
+ crossAxis
107
+ })].filter(Boolean).flat().join(', ');
77
108
  }
@@ -1,76 +1,103 @@
1
- import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
1
  import { getPlacement } from './resolve-placement';
3
2
 
4
3
  /**
5
- * Returns `position-try-fallbacks` value based on placement.
6
- *
7
- * For centered placements, includes cross-axis aligned position-area
8
- * values so the browser can shift the popover along the cross-axis
9
- * when the centered position would overflow the viewport edge.
10
- *
11
- * Fallback order for centered placements (e.g. `block-end`):
12
- * 1. Same edge, start-aligned (shift for near-edge overflow)
13
- * 2. Same edge, end-aligned (shift for far-edge overflow)
14
- * 3. Flipped edge, centered
15
- * 4. Flipped edge, start-aligned
16
- * 5. Flipped edge, end-aligned
17
- *
18
- * For aligned placements (start/end), includes the same-edge centered
19
- * position as fallbacks so the browser can try centering when the aligned
20
- * position would overflow, before flipping to the opposite edge.
21
- *
22
- * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
23
- *
24
- * When a popup is in a viewport corner (e.g. inline-end align-end at the
25
- * top-right), flipping only the primary axis (`flip-inline`) moves the popup
26
- * to the left but keeps the same cross-axis span direction (e.g. upward),
27
- * which is still off-screen. The combined keyword `flip-inline flip-block`
28
- * mirrors the popup diagonally. It flips BOTH the position-area AND both
29
- * inline and block margins simultaneously, placing the popup at the
30
- * diagonally opposite corner where there is always space.
4
+ * A `position-area` primary edge — the placement axis joined to its edge, e.g.
5
+ * `block-end` or `inline-start`. These are the four edges a popover can sit on.
6
+ */
7
+
8
+ function slideOnEdge(_ref) {
9
+ var align = _ref.align,
10
+ edgeKey = _ref.edgeKey,
11
+ crossAxis = _ref.crossAxis;
12
+ if (align === 'center') {
13
+ return ["".concat(edgeKey, " span-").concat(crossAxis, "-end"), "".concat(edgeKey, " span-").concat(crossAxis, "-start")];
14
+ }
15
+ // For `align: 'start'` the popover expands toward `end`, so the "near"
16
+ // span is `end` and the "far" span is `start`; `align: 'end'` mirrors
17
+ // this. The bare `edgeKey` (re-centered) sits between them.
18
+ var near = align === 'start' ? 'end' : 'start';
19
+ var far = align === 'start' ? 'start' : 'end';
20
+ return ["".concat(edgeKey, " span-").concat(crossAxis, "-").concat(near), edgeKey, "".concat(edgeKey, " span-").concat(crossAxis, "-").concat(far)];
21
+ }
22
+ function flipDiagonally(_ref2) {
23
+ var axis = _ref2.axis;
24
+ var flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
25
+ var flipToCrossAxis = axis === 'block' ? 'flip-inline' : 'flip-block';
26
+ return "".concat(flipOnMainAxis, " ").concat(flipToCrossAxis);
27
+ }
28
+
29
+ /**
30
+ * Returns the `position-try-fallbacks` value for a placement.
31
31
  *
32
- * Named `position-area` entries (e.g. `inline-start span-block-end`) in
33
- * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
34
- * tactic keywords correctly flip the gap margin along with the position.
32
+ * @example
33
+ * // Centered on the block-end edge (the default placement):
34
+ * placementToTryFallbacks({ placement: { axis: 'block', edge: 'end', align: 'center' } });
35
+ * // => 'block-end span-inline-end, block-end span-inline-start, flip-block,
36
+ * // block-start span-inline-end, block-start span-inline-start'
35
37
  */
36
- export function placementToTryFallbacks(_ref) {
37
- var placement = _ref.placement;
38
- var _getPlacement = getPlacement({
39
- placement: placement
40
- }),
41
- axis = _getPlacement.axis,
42
- edge = _getPlacement.edge,
43
- align = _getPlacement.align;
38
+ export function placementToTryFallbacks(_ref3) {
39
+ var placement = _ref3.placement;
40
+ /**
41
+ * **Build the fallback list**
42
+ *
43
+ * Each entry is a complete alternative position.
44
+ * The browser tries them _in order_ and uses the _first_ one that fits.
45
+ */
46
+
47
+ var resolved = getPlacement({
48
+ placement: placement
49
+ });
50
+ var axis = resolved.axis,
51
+ edge = resolved.edge,
52
+ align = resolved.align;
44
53
  var crossAxis = axis === 'block' ? 'inline' : 'block';
45
54
  var flippedEdge = edge === 'start' ? 'end' : 'start';
46
- var sameEdge = "".concat(axis, "-").concat(edge);
47
- var oppositeEdge = "".concat(axis, "-").concat(flippedEdge);
48
- var flipKeyword = axis === 'block' ? 'flip-block' : 'flip-inline';
49
- var flipCrossKeyword = axis === 'block' ? 'flip-inline' : 'flip-block';
55
+ var sameEdgeArea = "".concat(axis, "-").concat(edge);
56
+ var oppositeEdgeArea = "".concat(axis, "-").concat(flippedEdge);
57
+ var flipOnMainAxis = axis === 'block' ? 'flip-block' : 'flip-inline';
50
58
 
51
- // Single algorithm: produce the shift list against any base alignment.
52
- // For `align: 'start'` the "near" shift expands toward `end`; for
53
- // `align: 'end'` it expands toward `start`; for `align: 'center'`
54
- // either order is symmetric (we use end-then-start to match the
55
- // historical fallback list).
56
- function shifts(baseAlign, edgeKey) {
57
- if (baseAlign === 'center') {
58
- return ["".concat(edgeKey, " span-").concat(crossAxis, "-end"), "".concat(edgeKey, " span-").concat(crossAxis, "-start")];
59
- }
60
- var near = baseAlign === 'start' ? 'end' : 'start';
61
- var far = baseAlign === 'start' ? 'start' : 'end';
62
- return ["".concat(edgeKey, " span-").concat(crossAxis, "-").concat(near), edgeKey, "".concat(edgeKey, " span-").concat(crossAxis, "-").concat(far)];
63
- }
64
- if (align !== 'center') {
65
- // Aligned (start/end): try same-edge shifts, then single-axis flip,
66
- // then diagonal flip for corner overflow, then opposite-edge shifts.
67
- // Legacy Popper fallback ordering for e.g. bottom-start:
68
- // [bottom, bottom-end, top-start, top, top-end, auto].
69
- return [].concat(_toConsumableArray(shifts(align, sameEdge)), [flipKeyword, "".concat(flipKeyword, " ").concat(flipCrossKeyword)], _toConsumableArray(shifts(align, oppositeEdge))).join(', ');
70
- }
59
+ /**
60
+ * **Fallback algorithm**
61
+ *
62
+ * We have two things we can do to keep something visible:
63
+ *
64
+ * 1. _Slide_ along edges
65
+ * 2. _Flip_ to another edge
66
+ *
67
+ * _Centered popover_
68
+ *
69
+ * Desired: Sits in middle of main edge
70
+ *
71
+ * Fallbacks:
72
+ * 1: _Slide_ along main edge on the cross axis
73
+ * 2: _Flip_ on main axis to opposite edge (centered)
74
+ * 3: _Slide_ along opposite edge on the cross axis
75
+ *
76
+ * _Start or end aligned popover_
77
+ *
78
+ * Desired: Sits at start / end of main edge
79
+ *
80
+ * Fallbacks:
81
+ * 1: _Slide_ along main edge on the cross axis
82
+ * 2: _Flip_ on main axis to opposite edge
83
+ * 3: _Flip_ on the diagonal (flip main axis + flip cross axis) into the
84
+ * opposite corner. For start / end alignment, this is the clean escape
85
+ * when the popover would otherwise land offscreen on both axes (ie in a
86
+ * corner). Rule 4 gets the job done, but a slide drops the gap
87
+ * as named position-area values don't carry margins).
88
+ * The diagonal flip keeps the gap and the alignment.
89
+ * 4: _Slide_ along opposite edge on the cross axis
90
+ */
71
91
 
72
- // Centered: same-edge shifts, single-axis flip, opposite-edge shifts.
73
- // Diagonal flip is unnecessary because centered placements expand
74
- // equally in both cross-axis directions.
75
- return [].concat(_toConsumableArray(shifts('center', sameEdge)), [flipKeyword], _toConsumableArray(shifts('center', oppositeEdge))).join(', ');
92
+ return [slideOnEdge({
93
+ align: align,
94
+ edgeKey: sameEdgeArea,
95
+ crossAxis: crossAxis
96
+ }), flipOnMainAxis, align !== 'center' ? flipDiagonally({
97
+ axis: axis
98
+ }) : null, slideOnEdge({
99
+ align: align,
100
+ edgeKey: oppositeEdgeArea,
101
+ crossAxis: crossAxis
102
+ })].filter(Boolean).flat().join(', ');
76
103
  }
@@ -1,35 +1,12 @@
1
- import { type TPlacementOptions } from '../internal/resolve-placement';
1
+ import { type TPlacementOptions } from './resolve-placement';
2
2
  /**
3
- * Returns `position-try-fallbacks` value based on placement.
3
+ * Returns the `position-try-fallbacks` value for a placement.
4
4
  *
5
- * For centered placements, includes cross-axis aligned position-area
6
- * values so the browser can shift the popover along the cross-axis
7
- * when the centered position would overflow the viewport edge.
8
- *
9
- * Fallback order for centered placements (e.g. `block-end`):
10
- * 1. Same edge, start-aligned (shift for near-edge overflow)
11
- * 2. Same edge, end-aligned (shift for far-edge overflow)
12
- * 3. Flipped edge, centered
13
- * 4. Flipped edge, start-aligned
14
- * 5. Flipped edge, end-aligned
15
- *
16
- * For aligned placements (start/end), includes the same-edge centered
17
- * position as fallbacks so the browser can try centering when the aligned
18
- * position would overflow, before flipping to the opposite edge.
19
- *
20
- * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
21
- *
22
- * When a popup is in a viewport corner (e.g. inline-end align-end at the
23
- * top-right), flipping only the primary axis (`flip-inline`) moves the popup
24
- * to the left but keeps the same cross-axis span direction (e.g. upward),
25
- * which is still off-screen. The combined keyword `flip-inline flip-block`
26
- * mirrors the popup diagonally. It flips BOTH the position-area AND both
27
- * inline and block margins simultaneously, placing the popup at the
28
- * diagonally opposite corner where there is always space.
29
- *
30
- * Named `position-area` entries (e.g. `inline-start span-block-end`) in
31
- * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
32
- * tactic keywords correctly flip the gap margin along with the position.
5
+ * @example
6
+ * // Centered on the block-end edge (the default placement):
7
+ * placementToTryFallbacks({ placement: { axis: 'block', edge: 'end', align: 'center' } });
8
+ * // => 'block-end span-inline-end, block-end span-inline-start, flip-block,
9
+ * // block-start span-inline-end, block-start span-inline-start'
33
10
  */
34
11
  export declare function placementToTryFallbacks({ placement }: {
35
12
  placement: TPlacementOptions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/top-layer",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Low-level layering primitives based on popover and dialog",
5
5
  "homepage": "https://atlassian.design/components/top-layer",
6
6
  "repository": "https://bitbucket.org/atlassian/atlassian-frontend-mirror",
@@ -38,7 +38,8 @@
38
38
  "@atlaskit/css": "^1.0.0",
39
39
  "@atlaskit/ds-lib": "^8.0.0",
40
40
  "@atlaskit/layering": "^4.0.0",
41
- "@atlaskit/tokens": "^14.0.0",
41
+ "@atlaskit/tokens": "^15.0.0",
42
+ "@atlassian/react-compiler-gating": "^0.2.0",
42
43
  "@babel/runtime": "^7.0.0",
43
44
  "@compiled/react": "^0.20.0",
44
45
  "bind-event-listener": "^3.0.0",
@@ -57,7 +58,6 @@
57
58
  "@atlaskit/primitives": "^20.0.0",
58
59
  "@atlaskit/ssr": "workspace:^",
59
60
  "@atlaskit/textfield": "^9.0.0",
60
- "@atlassian/react-compiler-gating": "workspace:^",
61
61
  "@atlassian/ssr-tests": "workspace:^",
62
62
  "@atlassian/testing-library": "^0.6.0",
63
63
  "@testing-library/jest-dom": "^6.4.5",