@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
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
|
+
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; }
|
|
4
|
+
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) { _defineProperty(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; }
|
|
1
5
|
/**
|
|
2
6
|
* Legacy Popper.js placement values (used by `@atlaskit/popper`, `@atlaskit/popup`,
|
|
3
7
|
* `@atlaskit/tooltip`, etc.).
|
|
@@ -128,11 +132,34 @@ var placementMapping = {
|
|
|
128
132
|
};
|
|
129
133
|
|
|
130
134
|
/**
|
|
131
|
-
* Convert a legacy Popper.js placement to the new
|
|
135
|
+
* Convert a legacy Popper.js placement to the new `position-area`-based Placement.
|
|
136
|
+
* Optional `offset` is the legacy Popper `[along, away]` tuple (also known as
|
|
137
|
+
* `[skidding, distance]`); negative `along` becomes `direction: 'backwards'`.
|
|
138
|
+
*
|
|
139
|
+
* The tuple keeps the historical popper names so call sites that already pass
|
|
140
|
+
* `[along, away]` migrate without thinking; the new internal field names
|
|
141
|
+
* (`gap` / `crossAxisShift`) are produced inside this adapter.
|
|
132
142
|
*/
|
|
133
143
|
export function fromLegacyPlacement(_ref) {
|
|
134
|
-
var legacy = _ref.legacy
|
|
135
|
-
|
|
144
|
+
var legacy = _ref.legacy,
|
|
145
|
+
offset = _ref.offset;
|
|
146
|
+
var basePlacement = placementMapping[legacy];
|
|
147
|
+
if (!offset) {
|
|
148
|
+
return basePlacement;
|
|
149
|
+
}
|
|
150
|
+
var _offset = _slicedToArray(offset, 2),
|
|
151
|
+
along = _offset[0],
|
|
152
|
+
away = _offset[1];
|
|
153
|
+
return _objectSpread(_objectSpread({}, basePlacement), {}, {
|
|
154
|
+
offset: {
|
|
155
|
+
gap: away,
|
|
156
|
+
crossAxisShift: {
|
|
157
|
+
// Sign is captured in `direction`; `value` is the magnitude.
|
|
158
|
+
value: Math.abs(along),
|
|
159
|
+
direction: along >= 0 ? 'forwards' : 'backwards'
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
136
163
|
}
|
|
137
164
|
|
|
138
165
|
/**
|
|
@@ -32,7 +32,6 @@ export var PopupContent = /*#__PURE__*/forwardRef(function PopupContent(_ref, re
|
|
|
32
32
|
placementProp = _ref.placement,
|
|
33
33
|
onCloseProp = _ref.onClose,
|
|
34
34
|
testIdProp = _ref.testId,
|
|
35
|
-
offsetProp = _ref.offset,
|
|
36
35
|
forceFallbackPositioningProp = _ref.forceFallbackPositioning;
|
|
37
36
|
// When inside <Popup>, context provides defaults. Props always win.
|
|
38
37
|
var ctx = useMaybePopupContext();
|
|
@@ -129,7 +128,6 @@ export var PopupContent = /*#__PURE__*/forwardRef(function PopupContent(_ref, re
|
|
|
129
128
|
},
|
|
130
129
|
popoverRef: popoverRef,
|
|
131
130
|
placement: placement,
|
|
132
|
-
offset: offsetProp,
|
|
133
131
|
forceFallbackPositioning: forceFallbackPositioning,
|
|
134
132
|
arrow: arrowPreset !== null && arrowPreset !== void 0 ? arrowPreset : undefined
|
|
135
133
|
});
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { type TPlacement } from './resolve-placement';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Computes popover position from trigger rect and viewport, flipping to
|
|
4
|
+
* the side with more space when needed. Re-runs on scroll/resize.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* - "auto" placement: show on the edge with the most available space
|
|
9
|
-
*
|
|
10
|
-
* Re-runs on scroll (capture on window) and resize events.
|
|
6
|
+
* `gap` and `crossAxisShift` are pre-resolved to pixels by the
|
|
7
|
+
* caller (see `resolveCssLengthToPixels`), so this function stays purely
|
|
8
|
+
* numeric.
|
|
11
9
|
*/
|
|
12
|
-
export declare function computeFallbackPosition({ triggerRect, popoverEl, placement, viewport,
|
|
10
|
+
export declare function computeFallbackPosition({ triggerRect, popoverEl, placement, viewport, gap, crossAxisShift, }: {
|
|
13
11
|
triggerRect: DOMRect;
|
|
14
12
|
popoverEl: HTMLElement;
|
|
15
13
|
placement: TPlacement;
|
|
@@ -17,7 +15,11 @@ export declare function computeFallbackPosition({ triggerRect, popoverEl, placem
|
|
|
17
15
|
width: number;
|
|
18
16
|
height: number;
|
|
19
17
|
};
|
|
20
|
-
|
|
18
|
+
gap: number;
|
|
19
|
+
crossAxisShift: {
|
|
20
|
+
value: number;
|
|
21
|
+
direction: 'forwards' | 'backwards';
|
|
22
|
+
};
|
|
21
23
|
}): {
|
|
22
24
|
top: number;
|
|
23
25
|
left: number;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a CSS length value to a pixel number using a hidden DOM probe.
|
|
3
|
+
*
|
|
4
|
+
* Used by the JS positioning fallback: consumer offsets can be numbers,
|
|
5
|
+
* `${n}px` strings, tokenised `var(--ds-space-100, 8px)` strings, `calc()`
|
|
6
|
+
* expressions, viewport units, etc. Parsing arbitrary CSS in JS is fragile
|
|
7
|
+
* (and impossible for `calc(var(...))` without a layout context), so we let
|
|
8
|
+
* the browser do the math.
|
|
9
|
+
*
|
|
10
|
+
* The probe is appended to `container` so it inherits the same containing
|
|
11
|
+
* block, font size, and custom-property scope as the popover. We use `width`
|
|
12
|
+
* because it accepts any CSS length, including negative `calc()` results
|
|
13
|
+
* (negative widths are clamped to 0 — see note below).
|
|
14
|
+
*
|
|
15
|
+
* Cost: one synchronous reflow per call. The fallback only resolves on
|
|
16
|
+
* placement/offset changes, not on every scroll/resize update, so this is
|
|
17
|
+
* not a hot path.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveCssLengthToPixels({ value, container, }: {
|
|
20
|
+
value: number | string;
|
|
21
|
+
container: HTMLElement;
|
|
22
|
+
}): number;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes an offset to a CSS length string. Numbers become `${n}px`;
|
|
3
|
+
* strings pass through. Apply at the API boundary so internal code only
|
|
4
|
+
* deals with strings.
|
|
5
|
+
*/
|
|
6
|
+
export declare function toCssLengthString({ value }: {
|
|
7
|
+
value: number | string;
|
|
8
|
+
}): string;
|
|
@@ -1,16 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Cross-axis shift. `value` is a CSS length string (consumer numbers are
|
|
3
|
+
* normalized to `${n}px`). `direction` is `'forwards'` (toward end) or
|
|
4
|
+
* `'backwards'` (toward start).
|
|
5
|
+
*/
|
|
6
|
+
export type TCrossAxisShiftOffset = {
|
|
7
|
+
value: string;
|
|
8
|
+
direction: 'forwards' | 'backwards';
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Fully-resolved placement (internal). Use `getPlacement` for partial input.
|
|
12
|
+
* `offset.gap` and `offset.crossAxisShift.value` are always CSS
|
|
13
|
+
* length strings.
|
|
4
14
|
*/
|
|
5
15
|
export type TPlacement = {
|
|
6
16
|
axis: 'block' | 'inline';
|
|
7
17
|
edge: 'start' | 'end';
|
|
8
18
|
align: 'start' | 'center' | 'end';
|
|
19
|
+
offset: {
|
|
20
|
+
gap: string;
|
|
21
|
+
crossAxisShift: {
|
|
22
|
+
value: string;
|
|
23
|
+
direction: 'forwards' | 'backwards';
|
|
24
|
+
};
|
|
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
|
+
export type TPlacementOptions = {
|
|
37
|
+
axis?: 'block' | 'inline';
|
|
38
|
+
edge?: 'start' | 'end';
|
|
39
|
+
align?: 'start' | 'center' | 'end';
|
|
40
|
+
offset?: {
|
|
41
|
+
gap?: number | string;
|
|
42
|
+
crossAxisShift?: {
|
|
43
|
+
value?: number | string;
|
|
44
|
+
direction?: 'forwards' | 'backwards';
|
|
45
|
+
};
|
|
46
|
+
};
|
|
9
47
|
};
|
|
10
48
|
/**
|
|
11
|
-
* Resolves a partial placement to its fully-specified form.
|
|
12
|
-
*
|
|
49
|
+
* Resolves a partial placement to its fully-specified form. Number offsets
|
|
50
|
+
* are normalized to `${n}px` strings.
|
|
51
|
+
*
|
|
52
|
+
* Defaults: `axis: 'block'`, `edge: 'end'`, `align: 'center'`,
|
|
53
|
+
* `offset.gap: token('space.100', '8px')`,
|
|
54
|
+
* `offset.crossAxisShift: { value: '0px', direction: 'forwards' }`.
|
|
13
55
|
*/
|
|
14
56
|
export declare function getPlacement({ placement }: {
|
|
15
|
-
placement:
|
|
57
|
+
placement: TPlacementOptions;
|
|
16
58
|
}): TPlacement;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor positioning for top-layer popovers. See
|
|
3
|
+
* `notes/architecture/positioning.md` for the full model.
|
|
4
|
+
*
|
|
5
|
+
* Two runtime paths: CSS Anchor Positioning (modern browsers) and a JS
|
|
6
|
+
* fallback that measures the trigger and writes `top`/`left`.
|
|
7
|
+
*
|
|
8
|
+
* Both paths honour `offset.gap` and `offset.crossAxisShift`. The
|
|
9
|
+
* CSS path passes the values through as strings; the JS fallback resolves
|
|
10
|
+
* them to pixels via a hidden DOM probe (see `resolveCssLengthToPixels`)
|
|
11
|
+
* so tokens, `calc()`, `var()`, etc all work. The JS fallback hides the
|
|
12
|
+
* popover with `opacity: 0` until the first measurement completes, so it
|
|
13
|
+
* is never painted at the wrong location.
|
|
14
|
+
*/
|
|
1
15
|
import { type RefObject } from 'react';
|
|
2
16
|
import { type TArrowPreset } from '../arrow/types';
|
|
3
|
-
import { type TPlacementOptions } from '../
|
|
17
|
+
import { type TPlacementOptions } from '../internal/resolve-placement';
|
|
4
18
|
export { getPlacement } from './resolve-placement';
|
|
5
19
|
/**
|
|
6
20
|
* Resolves placement options to CSS `position-area` syntax.
|
|
@@ -59,7 +73,7 @@ export declare function placementToTryFallbacks({ placement }: {
|
|
|
59
73
|
* `position: fixed` with measured coordinates, re-running on scroll (capture)
|
|
60
74
|
* and resize events.
|
|
61
75
|
*/
|
|
62
|
-
export declare function useAnchorPosition({ anchorRef, popoverRef, placement,
|
|
76
|
+
export declare function useAnchorPosition({ anchorRef, popoverRef, placement, forceFallbackPositioning, arrow, }: {
|
|
63
77
|
/**
|
|
64
78
|
* Element to position relative to.
|
|
65
79
|
*/
|
|
@@ -70,13 +84,10 @@ export declare function useAnchorPosition({ anchorRef, popoverRef, placement, of
|
|
|
70
84
|
popoverRef: RefObject<HTMLElement | null>;
|
|
71
85
|
/**
|
|
72
86
|
* Where to place the element relative to the anchor.
|
|
87
|
+
* `offset.gap` and `offset.crossAxisShift` are part of the
|
|
88
|
+
* placement object.
|
|
73
89
|
*/
|
|
74
90
|
placement: TPlacementOptions;
|
|
75
|
-
/**
|
|
76
|
-
* Gap between the positioned element and the anchor, in pixels.
|
|
77
|
-
* Defaults to 8 (`space.100`). Tooltip uses 4.
|
|
78
|
-
*/
|
|
79
|
-
offset?: number;
|
|
80
91
|
/**
|
|
81
92
|
* Forces the JavaScript positioning fallback even when the browser
|
|
82
93
|
* supports CSS Anchor Positioning. Useful for testing fallback
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type TPlacementOptions } from '../popup/types';
|
|
1
|
+
import { type TPlacementOptions } from '../internal/resolve-placement';
|
|
3
2
|
/**
|
|
4
3
|
* Legacy Popper.js placement values (used by `@atlaskit/popper`, `@atlaskit/popup`,
|
|
5
4
|
* `@atlaskit/tooltip`, etc.).
|
|
@@ -41,12 +40,19 @@ export type TLegacyPlacement = 'auto' | 'auto-start' | 'auto-end' | 'top' | 'top
|
|
|
41
40
|
* // newPlacement === { axis: 'block', edge: 'end', align: 'start' }
|
|
42
41
|
* ```
|
|
43
42
|
*/
|
|
44
|
-
declare const placementMapping: Record<TLegacyPlacement,
|
|
43
|
+
declare const placementMapping: Record<TLegacyPlacement, TPlacementOptions>;
|
|
45
44
|
/**
|
|
46
|
-
* Convert a legacy Popper.js placement to the new
|
|
45
|
+
* Convert a legacy Popper.js placement to the new `position-area`-based Placement.
|
|
46
|
+
* Optional `offset` is the legacy Popper `[along, away]` tuple (also known as
|
|
47
|
+
* `[skidding, distance]`); negative `along` becomes `direction: 'backwards'`.
|
|
48
|
+
*
|
|
49
|
+
* The tuple keeps the historical popper names so call sites that already pass
|
|
50
|
+
* `[along, away]` migrate without thinking; the new internal field names
|
|
51
|
+
* (`gap` / `crossAxisShift`) are produced inside this adapter.
|
|
47
52
|
*/
|
|
48
|
-
export declare function fromLegacyPlacement({ legacy }: {
|
|
53
|
+
export declare function fromLegacyPlacement({ legacy, offset, }: {
|
|
49
54
|
legacy: TLegacyPlacement;
|
|
55
|
+
offset?: [along: number, away: number];
|
|
50
56
|
}): TPlacementOptions;
|
|
51
57
|
/**
|
|
52
58
|
* The full mapping record, exposed for consumers that need to iterate or introspect.
|
|
@@ -2,39 +2,30 @@ import { type ReactElement, type ReactNode, type Ref, type RefObject } from 'rea
|
|
|
2
2
|
import { type StrictXCSSProp } from '@atlaskit/css';
|
|
3
3
|
import { type TAnimationPreset } from '../animations/types';
|
|
4
4
|
import { type TArrowPreset } from '../arrow/types';
|
|
5
|
-
import { type
|
|
5
|
+
import { type TPlacementOptions } from '../internal/resolve-placement';
|
|
6
6
|
import { type TRoleRequiringAccessibleName, type TRoleWithImplicitName } from '../internal/role-types';
|
|
7
7
|
import { type TPopoverCloseReason } from '../popover/types';
|
|
8
8
|
/**
|
|
9
|
-
* Describes where to position a popover relative to its trigger.
|
|
9
|
+
* Describes where to position a popover relative to its trigger. All fields
|
|
10
|
+
* are optional. The default `{}` means "below the trigger, centered, with a
|
|
11
|
+
* `space.100` token gap" (equivalent to Popper.js `'bottom'`).
|
|
10
12
|
*
|
|
11
|
-
* - `axis
|
|
12
|
-
*
|
|
13
|
-
* - `
|
|
14
|
-
*
|
|
15
|
-
* - `
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* All fields are optional. The default `{}` means "below the trigger, centered"
|
|
19
|
-
* (equivalent to Popper.js `'bottom'`).
|
|
13
|
+
* - `axis`: `'block'` (above/below, default) or `'inline'` (left/right)
|
|
14
|
+
* - `edge`: `'start'` or `'end'` (default)
|
|
15
|
+
* - `align`: `'start'`, `'center'` (default), or `'end'`
|
|
16
|
+
* - `offset.gap`: distance from the trigger toward the popover (default `token('space.100', '8px')`, accepts number or CSS string)
|
|
17
|
+
* - `offset.crossAxisShift.value`: cross-axis shift (default `0`)
|
|
18
|
+
* - `offset.crossAxisShift.direction`: `'forwards'` (default) or `'backwards'`
|
|
20
19
|
*
|
|
21
20
|
* @example
|
|
22
21
|
* ```ts
|
|
23
|
-
* // Below trigger,
|
|
24
|
-
* placement={{}}
|
|
25
|
-
* placement={{
|
|
26
|
-
*
|
|
27
|
-
* // Below trigger, aligned to the start (left in LTR)
|
|
28
|
-
* placement={{ align: 'start' }}
|
|
29
|
-
*
|
|
30
|
-
* // Above trigger, aligned to the end (right in LTR)
|
|
31
|
-
* placement={{ edge: 'start', align: 'end' }}
|
|
32
|
-
*
|
|
33
|
-
* // Right of trigger, centered
|
|
34
|
-
* placement={{ axis: 'inline' }}
|
|
22
|
+
* placement={{ align: 'start' }} // Below trigger, aligned to start
|
|
23
|
+
* placement={{ axis: 'inline' }} // Right of trigger, centered
|
|
24
|
+
* placement={{ offset: { gap: 4 } }} // Tooltip-like gap
|
|
25
|
+
* placement={{ offset: { crossAxisShift: { value: 4, direction: 'backwards' } } }}
|
|
35
26
|
* ```
|
|
36
27
|
*/
|
|
37
|
-
export type TPlacementOptions
|
|
28
|
+
export { type TPlacementOptions } from '../internal/resolve-placement';
|
|
38
29
|
export type TPopupProps = {
|
|
39
30
|
/**
|
|
40
31
|
* Position of the popup relative to the trigger. Only the Popup compound uses
|
|
@@ -176,11 +167,6 @@ type TPopupContentBaseProps = {
|
|
|
176
167
|
* Test ID applied to the popover content element.
|
|
177
168
|
*/
|
|
178
169
|
testId?: string;
|
|
179
|
-
/**
|
|
180
|
-
* Gap between the popover and its trigger, in pixels.
|
|
181
|
-
* Defaults to 8 (design token `space.100`). Tooltip uses 4.
|
|
182
|
-
*/
|
|
183
|
-
offset?: number;
|
|
184
170
|
/**
|
|
185
171
|
* Forces the JavaScript positioning fallback even when the browser
|
|
186
172
|
* supports CSS Anchor Positioning. Useful for testing fallback
|
|
@@ -302,4 +288,3 @@ export type TPopupContentProps = TPopupContentBaseProps & (({
|
|
|
302
288
|
export type TPopupSurfaceProps = {
|
|
303
289
|
children: ReactNode;
|
|
304
290
|
};
|
|
305
|
-
export {};
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { type TPlacement } from './resolve-placement';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Computes popover position from trigger rect and viewport, flipping to
|
|
4
|
+
* the side with more space when needed. Re-runs on scroll/resize.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* - "auto" placement: show on the edge with the most available space
|
|
9
|
-
*
|
|
10
|
-
* Re-runs on scroll (capture on window) and resize events.
|
|
6
|
+
* `gap` and `crossAxisShift` are pre-resolved to pixels by the
|
|
7
|
+
* caller (see `resolveCssLengthToPixels`), so this function stays purely
|
|
8
|
+
* numeric.
|
|
11
9
|
*/
|
|
12
|
-
export declare function computeFallbackPosition({ triggerRect, popoverEl, placement, viewport,
|
|
10
|
+
export declare function computeFallbackPosition({ triggerRect, popoverEl, placement, viewport, gap, crossAxisShift, }: {
|
|
13
11
|
triggerRect: DOMRect;
|
|
14
12
|
popoverEl: HTMLElement;
|
|
15
13
|
placement: TPlacement;
|
|
@@ -17,7 +15,11 @@ export declare function computeFallbackPosition({ triggerRect, popoverEl, placem
|
|
|
17
15
|
width: number;
|
|
18
16
|
height: number;
|
|
19
17
|
};
|
|
20
|
-
|
|
18
|
+
gap: number;
|
|
19
|
+
crossAxisShift: {
|
|
20
|
+
value: number;
|
|
21
|
+
direction: 'forwards' | 'backwards';
|
|
22
|
+
};
|
|
21
23
|
}): {
|
|
22
24
|
top: number;
|
|
23
25
|
left: number;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a CSS length value to a pixel number using a hidden DOM probe.
|
|
3
|
+
*
|
|
4
|
+
* Used by the JS positioning fallback: consumer offsets can be numbers,
|
|
5
|
+
* `${n}px` strings, tokenised `var(--ds-space-100, 8px)` strings, `calc()`
|
|
6
|
+
* expressions, viewport units, etc. Parsing arbitrary CSS in JS is fragile
|
|
7
|
+
* (and impossible for `calc(var(...))` without a layout context), so we let
|
|
8
|
+
* the browser do the math.
|
|
9
|
+
*
|
|
10
|
+
* The probe is appended to `container` so it inherits the same containing
|
|
11
|
+
* block, font size, and custom-property scope as the popover. We use `width`
|
|
12
|
+
* because it accepts any CSS length, including negative `calc()` results
|
|
13
|
+
* (negative widths are clamped to 0 — see note below).
|
|
14
|
+
*
|
|
15
|
+
* Cost: one synchronous reflow per call. The fallback only resolves on
|
|
16
|
+
* placement/offset changes, not on every scroll/resize update, so this is
|
|
17
|
+
* not a hot path.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveCssLengthToPixels({ value, container, }: {
|
|
20
|
+
value: number | string;
|
|
21
|
+
container: HTMLElement;
|
|
22
|
+
}): number;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes an offset to a CSS length string. Numbers become `${n}px`;
|
|
3
|
+
* strings pass through. Apply at the API boundary so internal code only
|
|
4
|
+
* deals with strings.
|
|
5
|
+
*/
|
|
6
|
+
export declare function toCssLengthString({ value }: {
|
|
7
|
+
value: number | string;
|
|
8
|
+
}): string;
|
|
@@ -1,16 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Cross-axis shift. `value` is a CSS length string (consumer numbers are
|
|
3
|
+
* normalized to `${n}px`). `direction` is `'forwards'` (toward end) or
|
|
4
|
+
* `'backwards'` (toward start).
|
|
5
|
+
*/
|
|
6
|
+
export type TCrossAxisShiftOffset = {
|
|
7
|
+
value: string;
|
|
8
|
+
direction: 'forwards' | 'backwards';
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Fully-resolved placement (internal). Use `getPlacement` for partial input.
|
|
12
|
+
* `offset.gap` and `offset.crossAxisShift.value` are always CSS
|
|
13
|
+
* length strings.
|
|
4
14
|
*/
|
|
5
15
|
export type TPlacement = {
|
|
6
16
|
axis: 'block' | 'inline';
|
|
7
17
|
edge: 'start' | 'end';
|
|
8
18
|
align: 'start' | 'center' | 'end';
|
|
19
|
+
offset: {
|
|
20
|
+
gap: string;
|
|
21
|
+
crossAxisShift: {
|
|
22
|
+
value: string;
|
|
23
|
+
direction: 'forwards' | 'backwards';
|
|
24
|
+
};
|
|
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
|
+
export type TPlacementOptions = {
|
|
37
|
+
axis?: 'block' | 'inline';
|
|
38
|
+
edge?: 'start' | 'end';
|
|
39
|
+
align?: 'start' | 'center' | 'end';
|
|
40
|
+
offset?: {
|
|
41
|
+
gap?: number | string;
|
|
42
|
+
crossAxisShift?: {
|
|
43
|
+
value?: number | string;
|
|
44
|
+
direction?: 'forwards' | 'backwards';
|
|
45
|
+
};
|
|
46
|
+
};
|
|
9
47
|
};
|
|
10
48
|
/**
|
|
11
|
-
* Resolves a partial placement to its fully-specified form.
|
|
12
|
-
*
|
|
49
|
+
* Resolves a partial placement to its fully-specified form. Number offsets
|
|
50
|
+
* are normalized to `${n}px` strings.
|
|
51
|
+
*
|
|
52
|
+
* Defaults: `axis: 'block'`, `edge: 'end'`, `align: 'center'`,
|
|
53
|
+
* `offset.gap: token('space.100', '8px')`,
|
|
54
|
+
* `offset.crossAxisShift: { value: '0px', direction: 'forwards' }`.
|
|
13
55
|
*/
|
|
14
56
|
export declare function getPlacement({ placement }: {
|
|
15
|
-
placement:
|
|
57
|
+
placement: TPlacementOptions;
|
|
16
58
|
}): TPlacement;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor positioning for top-layer popovers. See
|
|
3
|
+
* `notes/architecture/positioning.md` for the full model.
|
|
4
|
+
*
|
|
5
|
+
* Two runtime paths: CSS Anchor Positioning (modern browsers) and a JS
|
|
6
|
+
* fallback that measures the trigger and writes `top`/`left`.
|
|
7
|
+
*
|
|
8
|
+
* Both paths honour `offset.gap` and `offset.crossAxisShift`. The
|
|
9
|
+
* CSS path passes the values through as strings; the JS fallback resolves
|
|
10
|
+
* them to pixels via a hidden DOM probe (see `resolveCssLengthToPixels`)
|
|
11
|
+
* so tokens, `calc()`, `var()`, etc all work. The JS fallback hides the
|
|
12
|
+
* popover with `opacity: 0` until the first measurement completes, so it
|
|
13
|
+
* is never painted at the wrong location.
|
|
14
|
+
*/
|
|
1
15
|
import { type RefObject } from 'react';
|
|
2
16
|
import { type TArrowPreset } from '../arrow/types';
|
|
3
|
-
import { type TPlacementOptions } from '../
|
|
17
|
+
import { type TPlacementOptions } from '../internal/resolve-placement';
|
|
4
18
|
export { getPlacement } from './resolve-placement';
|
|
5
19
|
/**
|
|
6
20
|
* Resolves placement options to CSS `position-area` syntax.
|
|
@@ -59,7 +73,7 @@ export declare function placementToTryFallbacks({ placement }: {
|
|
|
59
73
|
* `position: fixed` with measured coordinates, re-running on scroll (capture)
|
|
60
74
|
* and resize events.
|
|
61
75
|
*/
|
|
62
|
-
export declare function useAnchorPosition({ anchorRef, popoverRef, placement,
|
|
76
|
+
export declare function useAnchorPosition({ anchorRef, popoverRef, placement, forceFallbackPositioning, arrow, }: {
|
|
63
77
|
/**
|
|
64
78
|
* Element to position relative to.
|
|
65
79
|
*/
|
|
@@ -70,13 +84,10 @@ export declare function useAnchorPosition({ anchorRef, popoverRef, placement, of
|
|
|
70
84
|
popoverRef: RefObject<HTMLElement | null>;
|
|
71
85
|
/**
|
|
72
86
|
* Where to place the element relative to the anchor.
|
|
87
|
+
* `offset.gap` and `offset.crossAxisShift` are part of the
|
|
88
|
+
* placement object.
|
|
73
89
|
*/
|
|
74
90
|
placement: TPlacementOptions;
|
|
75
|
-
/**
|
|
76
|
-
* Gap between the positioned element and the anchor, in pixels.
|
|
77
|
-
* Defaults to 8 (`space.100`). Tooltip uses 4.
|
|
78
|
-
*/
|
|
79
|
-
offset?: number;
|
|
80
91
|
/**
|
|
81
92
|
* Forces the JavaScript positioning fallback even when the browser
|
|
82
93
|
* supports CSS Anchor Positioning. Useful for testing fallback
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type TPlacementOptions } from '../popup/types';
|
|
1
|
+
import { type TPlacementOptions } from '../internal/resolve-placement';
|
|
3
2
|
/**
|
|
4
3
|
* Legacy Popper.js placement values (used by `@atlaskit/popper`, `@atlaskit/popup`,
|
|
5
4
|
* `@atlaskit/tooltip`, etc.).
|
|
@@ -41,12 +40,22 @@ export type TLegacyPlacement = 'auto' | 'auto-start' | 'auto-end' | 'top' | 'top
|
|
|
41
40
|
* // newPlacement === { axis: 'block', edge: 'end', align: 'start' }
|
|
42
41
|
* ```
|
|
43
42
|
*/
|
|
44
|
-
declare const placementMapping: Record<TLegacyPlacement,
|
|
43
|
+
declare const placementMapping: Record<TLegacyPlacement, TPlacementOptions>;
|
|
45
44
|
/**
|
|
46
|
-
* Convert a legacy Popper.js placement to the new
|
|
45
|
+
* Convert a legacy Popper.js placement to the new `position-area`-based Placement.
|
|
46
|
+
* Optional `offset` is the legacy Popper `[along, away]` tuple (also known as
|
|
47
|
+
* `[skidding, distance]`); negative `along` becomes `direction: 'backwards'`.
|
|
48
|
+
*
|
|
49
|
+
* The tuple keeps the historical popper names so call sites that already pass
|
|
50
|
+
* `[along, away]` migrate without thinking; the new internal field names
|
|
51
|
+
* (`gap` / `crossAxisShift`) are produced inside this adapter.
|
|
47
52
|
*/
|
|
48
|
-
export declare function fromLegacyPlacement({ legacy }: {
|
|
53
|
+
export declare function fromLegacyPlacement({ legacy, offset, }: {
|
|
49
54
|
legacy: TLegacyPlacement;
|
|
55
|
+
offset?: [
|
|
56
|
+
along: number,
|
|
57
|
+
away: number
|
|
58
|
+
];
|
|
50
59
|
}): TPlacementOptions;
|
|
51
60
|
/**
|
|
52
61
|
* The full mapping record, exposed for consumers that need to iterate or introspect.
|
|
@@ -2,39 +2,30 @@ import { type ReactElement, type ReactNode, type Ref, type RefObject } from 'rea
|
|
|
2
2
|
import { type StrictXCSSProp } from '@atlaskit/css';
|
|
3
3
|
import { type TAnimationPreset } from '../animations/types';
|
|
4
4
|
import { type TArrowPreset } from '../arrow/types';
|
|
5
|
-
import { type
|
|
5
|
+
import { type TPlacementOptions } from '../internal/resolve-placement';
|
|
6
6
|
import { type TRoleRequiringAccessibleName, type TRoleWithImplicitName } from '../internal/role-types';
|
|
7
7
|
import { type TPopoverCloseReason } from '../popover/types';
|
|
8
8
|
/**
|
|
9
|
-
* Describes where to position a popover relative to its trigger.
|
|
9
|
+
* Describes where to position a popover relative to its trigger. All fields
|
|
10
|
+
* are optional. The default `{}` means "below the trigger, centered, with a
|
|
11
|
+
* `space.100` token gap" (equivalent to Popper.js `'bottom'`).
|
|
10
12
|
*
|
|
11
|
-
* - `axis
|
|
12
|
-
*
|
|
13
|
-
* - `
|
|
14
|
-
*
|
|
15
|
-
* - `
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* All fields are optional. The default `{}` means "below the trigger, centered"
|
|
19
|
-
* (equivalent to Popper.js `'bottom'`).
|
|
13
|
+
* - `axis`: `'block'` (above/below, default) or `'inline'` (left/right)
|
|
14
|
+
* - `edge`: `'start'` or `'end'` (default)
|
|
15
|
+
* - `align`: `'start'`, `'center'` (default), or `'end'`
|
|
16
|
+
* - `offset.gap`: distance from the trigger toward the popover (default `token('space.100', '8px')`, accepts number or CSS string)
|
|
17
|
+
* - `offset.crossAxisShift.value`: cross-axis shift (default `0`)
|
|
18
|
+
* - `offset.crossAxisShift.direction`: `'forwards'` (default) or `'backwards'`
|
|
20
19
|
*
|
|
21
20
|
* @example
|
|
22
21
|
* ```ts
|
|
23
|
-
* // Below trigger,
|
|
24
|
-
* placement={{}}
|
|
25
|
-
* placement={{
|
|
26
|
-
*
|
|
27
|
-
* // Below trigger, aligned to the start (left in LTR)
|
|
28
|
-
* placement={{ align: 'start' }}
|
|
29
|
-
*
|
|
30
|
-
* // Above trigger, aligned to the end (right in LTR)
|
|
31
|
-
* placement={{ edge: 'start', align: 'end' }}
|
|
32
|
-
*
|
|
33
|
-
* // Right of trigger, centered
|
|
34
|
-
* placement={{ axis: 'inline' }}
|
|
22
|
+
* placement={{ align: 'start' }} // Below trigger, aligned to start
|
|
23
|
+
* placement={{ axis: 'inline' }} // Right of trigger, centered
|
|
24
|
+
* placement={{ offset: { gap: 4 } }} // Tooltip-like gap
|
|
25
|
+
* placement={{ offset: { crossAxisShift: { value: 4, direction: 'backwards' } } }}
|
|
35
26
|
* ```
|
|
36
27
|
*/
|
|
37
|
-
export type TPlacementOptions
|
|
28
|
+
export { type TPlacementOptions } from '../internal/resolve-placement';
|
|
38
29
|
export type TPopupProps = {
|
|
39
30
|
/**
|
|
40
31
|
* Position of the popup relative to the trigger. Only the Popup compound uses
|
|
@@ -176,11 +167,6 @@ type TPopupContentBaseProps = {
|
|
|
176
167
|
* Test ID applied to the popover content element.
|
|
177
168
|
*/
|
|
178
169
|
testId?: string;
|
|
179
|
-
/**
|
|
180
|
-
* Gap between the popover and its trigger, in pixels.
|
|
181
|
-
* Defaults to 8 (design token `space.100`). Tooltip uses 4.
|
|
182
|
-
*/
|
|
183
|
-
offset?: number;
|
|
184
170
|
/**
|
|
185
171
|
* Forces the JavaScript positioning fallback even when the browser
|
|
186
172
|
* supports CSS Anchor Positioning. Useful for testing fallback
|
|
@@ -302,4 +288,3 @@ export type TPopupContentProps = TPopupContentBaseProps & (({
|
|
|
302
288
|
export type TPopupSurfaceProps = {
|
|
303
289
|
children: ReactNode;
|
|
304
290
|
};
|
|
305
|
-
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/top-layer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.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",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@af/visual-regression": "workspace:^",
|
|
53
53
|
"@atlaskit/button": "^23.11.0",
|
|
54
54
|
"@atlaskit/heading": "^5.4.0",
|
|
55
|
-
"@atlaskit/lozenge": "^13.
|
|
55
|
+
"@atlaskit/lozenge": "^13.7.0",
|
|
56
56
|
"@atlaskit/primitives": "^19.0.0",
|
|
57
57
|
"@atlaskit/ssr": "workspace:^",
|
|
58
58
|
"@atlaskit/textfield": "^8.3.0",
|