braid-design-system 33.12.3 → 33.12.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 +9 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/lib/components/TooltipRenderer/TooltipRenderer.cjs +64 -73
- package/dist/lib/components/TooltipRenderer/TooltipRenderer.css.cjs +7 -6
- package/dist/lib/components/TooltipRenderer/TooltipRenderer.css.mjs +7 -6
- package/dist/lib/components/TooltipRenderer/TooltipRenderer.mjs +65 -74
- package/dist/lib/components/private/Popover/Popover.cjs +90 -125
- package/dist/lib/components/private/Popover/Popover.css.cjs +0 -21
- package/dist/lib/components/private/Popover/Popover.css.mjs +2 -23
- package/dist/lib/components/private/Popover/Popover.mjs +92 -127
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# braid-design-system
|
|
2
2
|
|
|
3
|
+
## 33.12.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- **Autosuggest, MenuRenderer, OverflowMenu, TooltipRenderer**: Ensure `TooltipRenderer` is correctly positioned on Android devices ([#1926](https://github.com/seek-oss/braid-design-system/pull/1926))
|
|
8
|
+
|
|
9
|
+
Additionally, adjust `TooltipRenderer` positioning at screen edges, removing extra edge spacing.
|
|
10
|
+
This ensures the tooltip arrow is more closely aligned with the trigger when the trigger is near the edge of the screen.
|
|
11
|
+
|
|
3
12
|
## 33.12.3
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -3421,6 +3421,13 @@ interface LoaderProps {
|
|
|
3421
3421
|
declare const Loader: ({ size, "aria-label": ariaLabel, delayVisibility, data, ...restProps }: LoaderProps) => react.JSX.Element;
|
|
3422
3422
|
|
|
3423
3423
|
type Placement = 'top' | 'bottom';
|
|
3424
|
+
interface PopoverPlacementData {
|
|
3425
|
+
placement: Placement;
|
|
3426
|
+
arrow?: {
|
|
3427
|
+
x?: number;
|
|
3428
|
+
y?: number;
|
|
3429
|
+
};
|
|
3430
|
+
}
|
|
3424
3431
|
interface PopoverProps {
|
|
3425
3432
|
id?: string;
|
|
3426
3433
|
role: NonNullable<AllHTMLAttributes<HTMLElement>['role'] | false>;
|
|
@@ -3433,8 +3440,10 @@ interface PopoverProps {
|
|
|
3433
3440
|
modal?: boolean;
|
|
3434
3441
|
open: boolean;
|
|
3435
3442
|
onClose?: () => void;
|
|
3443
|
+
onPlacementChange?: (data: PopoverPlacementData) => void;
|
|
3436
3444
|
triggerRef: RefObject<HTMLElement | null>;
|
|
3437
3445
|
enterFocusRef?: RefObject<HTMLElement | null>;
|
|
3446
|
+
arrowRef?: RefObject<HTMLElement | null>;
|
|
3438
3447
|
children: ReactNode;
|
|
3439
3448
|
}
|
|
3440
3449
|
|
package/dist/index.d.ts
CHANGED
|
@@ -3421,6 +3421,13 @@ interface LoaderProps {
|
|
|
3421
3421
|
declare const Loader: ({ size, "aria-label": ariaLabel, delayVisibility, data, ...restProps }: LoaderProps) => react.JSX.Element;
|
|
3422
3422
|
|
|
3423
3423
|
type Placement = 'top' | 'bottom';
|
|
3424
|
+
interface PopoverPlacementData {
|
|
3425
|
+
placement: Placement;
|
|
3426
|
+
arrow?: {
|
|
3427
|
+
x?: number;
|
|
3428
|
+
y?: number;
|
|
3429
|
+
};
|
|
3430
|
+
}
|
|
3424
3431
|
interface PopoverProps {
|
|
3425
3432
|
id?: string;
|
|
3426
3433
|
role: NonNullable<AllHTMLAttributes<HTMLElement>['role'] | false>;
|
|
@@ -3433,8 +3440,10 @@ interface PopoverProps {
|
|
|
3433
3440
|
modal?: boolean;
|
|
3434
3441
|
open: boolean;
|
|
3435
3442
|
onClose?: () => void;
|
|
3443
|
+
onPlacementChange?: (data: PopoverPlacementData) => void;
|
|
3436
3444
|
triggerRef: RefObject<HTMLElement | null>;
|
|
3437
3445
|
enterFocusRef?: RefObject<HTMLElement | null>;
|
|
3446
|
+
arrowRef?: RefObject<HTMLElement | null>;
|
|
3438
3447
|
children: ReactNode;
|
|
3439
3448
|
}
|
|
3440
3449
|
|
|
@@ -7,16 +7,15 @@ const lib_hooks_useFallbackId_cjs = require("../../hooks/useFallbackId.cjs");
|
|
|
7
7
|
const lib_hooks_useIsomorphicLayoutEffect_cjs = require("../../hooks/useIsomorphicLayoutEffect.cjs");
|
|
8
8
|
const lib_components_Box_Box_cjs = require("../Box/Box.cjs");
|
|
9
9
|
const lib_components_private_Popover_Popover_cjs = require("../private/Popover/Popover.cjs");
|
|
10
|
-
const lib_components_private_animationTimeout_cjs = require("../private/animationTimeout.cjs");
|
|
11
10
|
const lib_components_private_defaultTextProps_cjs = require("../private/defaultTextProps.cjs");
|
|
12
11
|
const lib_components_useSpace_useSpace_cjs = require("../useSpace/useSpace.cjs");
|
|
13
12
|
const lib_components_useThemeName_useThemeName_cjs = require("../useThemeName/useThemeName.cjs");
|
|
14
13
|
const lib_components_TooltipRenderer_TooltipRenderer_css_cjs = require("./TooltipRenderer.css.cjs");
|
|
15
14
|
const _interopDefaultCompat = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
|
|
16
15
|
const isMobile__default = /* @__PURE__ */ _interopDefaultCompat(isMobile);
|
|
17
|
-
const edgeOffset = "xxsmall";
|
|
18
16
|
const offsetSpace = "small";
|
|
19
17
|
const StaticTooltipContext = react.createContext(false);
|
|
18
|
+
const clamp = (min, value, max) => Math.max(min, Math.min(value, max));
|
|
20
19
|
const TooltipTextDefaultsProvider = ({
|
|
21
20
|
children
|
|
22
21
|
}) => {
|
|
@@ -31,35 +30,59 @@ const TooltipTextDefaultsProvider = ({
|
|
|
31
30
|
);
|
|
32
31
|
};
|
|
33
32
|
const TooltipContent = ({
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
placement,
|
|
34
|
+
arrowPosition,
|
|
35
|
+
arrowRef,
|
|
36
36
|
children
|
|
37
|
-
}) =>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
37
|
+
}) => {
|
|
38
|
+
const arrowX = arrowPosition?.x;
|
|
39
|
+
const arrowY = arrowPosition?.y;
|
|
40
|
+
const { space, grid } = lib_components_useSpace_useSpace_cjs.useSpace();
|
|
41
|
+
const edgeOffsetInPx = grid * space.xsmall;
|
|
42
|
+
const arrowWidthOffset = parseFloat(lib_components_TooltipRenderer_TooltipRenderer_css_cjs.constants.arrowSize) * 2;
|
|
43
|
+
const [tooltipWidth, setTooltipWidth] = react.useState(0);
|
|
44
|
+
const tooltipContainerRef = react.useRef(null);
|
|
45
|
+
lib_hooks_useIsomorphicLayoutEffect_cjs.useIsomorphicLayoutEffect(() => {
|
|
46
|
+
if (!tooltipContainerRef.current) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const { width } = tooltipContainerRef.current.getBoundingClientRect();
|
|
50
|
+
setTooltipWidth(width);
|
|
51
|
+
}, [children]);
|
|
52
|
+
const clampedArrowX = arrowX !== void 0 && tooltipWidth > 0 ? clamp(
|
|
53
|
+
edgeOffsetInPx,
|
|
54
|
+
arrowX,
|
|
55
|
+
tooltipWidth - edgeOffsetInPx - arrowWidthOffset
|
|
56
|
+
) : arrowX;
|
|
57
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
58
|
+
lib_components_Box_Box_cjs.Box,
|
|
59
|
+
{
|
|
60
|
+
ref: tooltipContainerRef,
|
|
61
|
+
textAlign: "left",
|
|
62
|
+
boxShadow: "large",
|
|
63
|
+
background: "neutral",
|
|
64
|
+
borderRadius: "large",
|
|
65
|
+
padding: "small",
|
|
66
|
+
className: [lib_components_TooltipRenderer_TooltipRenderer_css_cjs.maxWidth, lib_components_TooltipRenderer_TooltipRenderer_css_cjs.translateZ0],
|
|
67
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(TooltipTextDefaultsProvider, { children: [
|
|
68
|
+
/* @__PURE__ */ jsxRuntime.jsx(lib_components_Box_Box_cjs.Box, { className: lib_components_TooltipRenderer_TooltipRenderer_css_cjs.overflowWrap, zIndex: 1, position: "relative", children }),
|
|
69
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
70
|
+
lib_components_Box_Box_cjs.Box,
|
|
71
|
+
{
|
|
72
|
+
ref: arrowRef,
|
|
73
|
+
position: "fixed",
|
|
74
|
+
background: "neutral",
|
|
75
|
+
className: lib_components_TooltipRenderer_TooltipRenderer_css_cjs.arrow[placement ?? "top"],
|
|
76
|
+
style: dynamic.assignInlineVars({
|
|
77
|
+
[lib_components_TooltipRenderer_TooltipRenderer_css_cjs.arrowX]: clampedArrowX !== void 0 ? `${clampedArrowX}px` : void 0,
|
|
78
|
+
[lib_components_TooltipRenderer_TooltipRenderer_css_cjs.arrowY]: arrowY !== void 0 ? `${arrowY}px` : void 0
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
] })
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
};
|
|
63
86
|
const TooltipRenderer = ({
|
|
64
87
|
id,
|
|
65
88
|
tooltip,
|
|
@@ -67,16 +90,11 @@ const TooltipRenderer = ({
|
|
|
67
90
|
children
|
|
68
91
|
}) => {
|
|
69
92
|
const resolvedId = lib_hooks_useFallbackId_cjs.useFallbackId(id);
|
|
70
|
-
const tooltipRef = react.useRef(null);
|
|
71
93
|
const triggerRef = react.useRef(null);
|
|
94
|
+
const arrowRef = react.useRef(null);
|
|
72
95
|
const [open, setOpen] = react.useState(false);
|
|
73
|
-
const [
|
|
74
|
-
|
|
75
|
-
);
|
|
76
|
-
const [tooltipPosition, setTooltipPosition] = react.useState(
|
|
77
|
-
void 0
|
|
78
|
-
);
|
|
79
|
-
const { grid, space } = lib_components_useSpace_useSpace_cjs.useSpace();
|
|
96
|
+
const [resolvedPlacement, setResolvedPlacement] = react.useState(placement);
|
|
97
|
+
const [arrowPosition, setArrowPosition] = react.useState();
|
|
80
98
|
const isStatic = react.useContext(StaticTooltipContext);
|
|
81
99
|
const isMobileDevice = react.useRef(isMobile__default.default()).current;
|
|
82
100
|
const onScreen = react.useRef(null);
|
|
@@ -136,38 +154,6 @@ const TooltipRenderer = ({
|
|
|
136
154
|
}
|
|
137
155
|
};
|
|
138
156
|
}, [open, isMobileDevice]);
|
|
139
|
-
const handleTooltipPosition = () => {
|
|
140
|
-
const setPositions = () => {
|
|
141
|
-
if (tooltipRef.current) {
|
|
142
|
-
setTooltipPosition(tooltipRef.current.getBoundingClientRect());
|
|
143
|
-
}
|
|
144
|
-
if (triggerRef.current) {
|
|
145
|
-
setTriggerPosition(triggerRef.current.getBoundingClientRect());
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
setTimeout(() => {
|
|
149
|
-
const frameId = requestAnimationFrame(setPositions);
|
|
150
|
-
return () => cancelAnimationFrame(frameId);
|
|
151
|
-
}, lib_components_private_animationTimeout_cjs.animationTimeout / 2);
|
|
152
|
-
};
|
|
153
|
-
lib_hooks_useIsomorphicLayoutEffect_cjs.useIsomorphicLayoutEffect(() => {
|
|
154
|
-
if (!showTooltip) {
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
handleTooltipPosition();
|
|
158
|
-
window.addEventListener("resize", handleTooltipPosition);
|
|
159
|
-
return () => {
|
|
160
|
-
window.removeEventListener("resize", handleTooltipPosition);
|
|
161
|
-
};
|
|
162
|
-
}, [showTooltip]);
|
|
163
|
-
let inferredPlacement = placement;
|
|
164
|
-
let arrowLeftOffset = 0;
|
|
165
|
-
if (tooltipPosition && triggerPosition) {
|
|
166
|
-
inferredPlacement = tooltipPosition.top > triggerPosition.top ? "bottom" : "top";
|
|
167
|
-
const edgeOffsetInPx = space[edgeOffset] * grid;
|
|
168
|
-
const tooltipLeftToTriggerLeft = triggerPosition.left - tooltipPosition.left - edgeOffsetInPx;
|
|
169
|
-
arrowLeftOffset = tooltipLeftToTriggerLeft + triggerPosition.width / 2;
|
|
170
|
-
}
|
|
171
157
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
172
158
|
children({
|
|
173
159
|
triggerProps: {
|
|
@@ -183,7 +169,6 @@ const TooltipRenderer = ({
|
|
|
183
169
|
{
|
|
184
170
|
id: resolvedId,
|
|
185
171
|
role: "tooltip",
|
|
186
|
-
ref: tooltipRef,
|
|
187
172
|
offsetSpace,
|
|
188
173
|
align: "center",
|
|
189
174
|
placement,
|
|
@@ -192,12 +177,18 @@ const TooltipRenderer = ({
|
|
|
192
177
|
modal: false,
|
|
193
178
|
open: showTooltip,
|
|
194
179
|
onClose: !isStatic ? () => setOpen(false) : void 0,
|
|
180
|
+
onPlacementChange: ({ placement: newPlacement, arrow }) => {
|
|
181
|
+
setResolvedPlacement(newPlacement);
|
|
182
|
+
setArrowPosition(arrow);
|
|
183
|
+
},
|
|
195
184
|
triggerRef,
|
|
185
|
+
arrowRef,
|
|
196
186
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
197
187
|
TooltipContent,
|
|
198
188
|
{
|
|
199
|
-
|
|
200
|
-
|
|
189
|
+
placement: resolvedPlacement,
|
|
190
|
+
arrowPosition,
|
|
191
|
+
arrowRef,
|
|
201
192
|
children: tooltip
|
|
202
193
|
}
|
|
203
194
|
)
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
const fileScope = require("@vanilla-extract/css/fileScope");
|
|
3
3
|
const css = require("@vanilla-extract/css");
|
|
4
4
|
const cssUtils = require("@vanilla-extract/css-utils");
|
|
5
|
-
const lib_css_atoms_atomicProperties_cjs = require("../../css/atoms/atomicProperties.cjs");
|
|
6
5
|
const lib_themes_vars_css_cjs = require("../../themes/vars.css.cjs");
|
|
7
6
|
fileScope.setFileScope("src/lib/components/TooltipRenderer/TooltipRenderer.css.ts", "braid-design-system");
|
|
8
7
|
const constants = {
|
|
@@ -21,11 +20,11 @@ const translateZ0 = css.style({
|
|
|
21
20
|
}, "translateZ0");
|
|
22
21
|
const borderRadius = lib_themes_vars_css_cjs.vars.borderRadius.small;
|
|
23
22
|
const offset = cssUtils.calc(constants.arrowSize).divide(2).negate().toString();
|
|
24
|
-
const
|
|
25
|
-
const
|
|
23
|
+
const arrowX = css.createVar("arrowX");
|
|
24
|
+
const arrowY = css.createVar("arrowY");
|
|
26
25
|
const baseArrow = css.style({
|
|
27
|
-
left:
|
|
28
|
-
|
|
26
|
+
left: arrowX,
|
|
27
|
+
top: arrowY,
|
|
29
28
|
visibility: "hidden",
|
|
30
29
|
":before": {
|
|
31
30
|
visibility: "visible",
|
|
@@ -52,7 +51,9 @@ const arrow = css.styleVariants({
|
|
|
52
51
|
}, "arrow");
|
|
53
52
|
fileScope.endFileScope();
|
|
54
53
|
exports.arrow = arrow;
|
|
55
|
-
exports.
|
|
54
|
+
exports.arrowX = arrowX;
|
|
55
|
+
exports.arrowY = arrowY;
|
|
56
|
+
exports.constants = constants;
|
|
56
57
|
exports.maxWidth = maxWidth;
|
|
57
58
|
exports.overflowWrap = overflowWrap;
|
|
58
59
|
exports.translateZ0 = translateZ0;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { setFileScope, endFileScope } from "@vanilla-extract/css/fileScope";
|
|
2
2
|
import { style, styleVariants, createVar } from "@vanilla-extract/css";
|
|
3
3
|
import { calc } from "@vanilla-extract/css-utils";
|
|
4
|
-
import { space } from "../../css/atoms/atomicProperties.mjs";
|
|
5
4
|
import { vars } from "../../themes/vars.css.mjs";
|
|
6
5
|
setFileScope("src/lib/components/TooltipRenderer/TooltipRenderer.css.ts", "braid-design-system");
|
|
7
6
|
const constants = {
|
|
@@ -20,11 +19,11 @@ const translateZ0 = style({
|
|
|
20
19
|
}, "translateZ0");
|
|
21
20
|
const borderRadius = vars.borderRadius.small;
|
|
22
21
|
const offset = calc(constants.arrowSize).divide(2).negate().toString();
|
|
23
|
-
const
|
|
24
|
-
const
|
|
22
|
+
const arrowX = createVar("arrowX");
|
|
23
|
+
const arrowY = createVar("arrowY");
|
|
25
24
|
const baseArrow = style({
|
|
26
|
-
left:
|
|
27
|
-
|
|
25
|
+
left: arrowX,
|
|
26
|
+
top: arrowY,
|
|
28
27
|
visibility: "hidden",
|
|
29
28
|
":before": {
|
|
30
29
|
visibility: "visible",
|
|
@@ -52,7 +51,9 @@ const arrow = styleVariants({
|
|
|
52
51
|
endFileScope();
|
|
53
52
|
export {
|
|
54
53
|
arrow,
|
|
55
|
-
|
|
54
|
+
arrowX,
|
|
55
|
+
arrowY,
|
|
56
|
+
constants,
|
|
56
57
|
maxWidth,
|
|
57
58
|
overflowWrap,
|
|
58
59
|
translateZ0
|
|
@@ -6,14 +6,13 @@ import { useFallbackId } from "../../hooks/useFallbackId.mjs";
|
|
|
6
6
|
import { useIsomorphicLayoutEffect } from "../../hooks/useIsomorphicLayoutEffect.mjs";
|
|
7
7
|
import { Box } from "../Box/Box.mjs";
|
|
8
8
|
import { Popover } from "../private/Popover/Popover.mjs";
|
|
9
|
-
import { animationTimeout } from "../private/animationTimeout.mjs";
|
|
10
9
|
import { DefaultTextPropsProvider } from "../private/defaultTextProps.mjs";
|
|
11
10
|
import { useSpace } from "../useSpace/useSpace.mjs";
|
|
12
11
|
import { useThemeName } from "../useThemeName/useThemeName.mjs";
|
|
13
|
-
import { maxWidth, translateZ0, overflowWrap, arrow,
|
|
14
|
-
const edgeOffset = "xxsmall";
|
|
12
|
+
import { maxWidth, translateZ0, overflowWrap, arrow, arrowY, arrowX, constants } from "./TooltipRenderer.css.mjs";
|
|
15
13
|
const offsetSpace = "small";
|
|
16
14
|
const StaticTooltipContext = createContext(false);
|
|
15
|
+
const clamp = (min, value, max) => Math.max(min, Math.min(value, max));
|
|
17
16
|
const TooltipTextDefaultsProvider = ({
|
|
18
17
|
children
|
|
19
18
|
}) => {
|
|
@@ -28,35 +27,59 @@ const TooltipTextDefaultsProvider = ({
|
|
|
28
27
|
);
|
|
29
28
|
};
|
|
30
29
|
const TooltipContent = ({
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
placement,
|
|
31
|
+
arrowPosition,
|
|
32
|
+
arrowRef,
|
|
33
33
|
children
|
|
34
|
-
}) =>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
34
|
+
}) => {
|
|
35
|
+
const arrowX$1 = arrowPosition?.x;
|
|
36
|
+
const arrowY$1 = arrowPosition?.y;
|
|
37
|
+
const { space, grid } = useSpace();
|
|
38
|
+
const edgeOffsetInPx = grid * space.xsmall;
|
|
39
|
+
const arrowWidthOffset = parseFloat(constants.arrowSize) * 2;
|
|
40
|
+
const [tooltipWidth, setTooltipWidth] = useState(0);
|
|
41
|
+
const tooltipContainerRef = useRef(null);
|
|
42
|
+
useIsomorphicLayoutEffect(() => {
|
|
43
|
+
if (!tooltipContainerRef.current) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const { width } = tooltipContainerRef.current.getBoundingClientRect();
|
|
47
|
+
setTooltipWidth(width);
|
|
48
|
+
}, [children]);
|
|
49
|
+
const clampedArrowX = arrowX$1 !== void 0 && tooltipWidth > 0 ? clamp(
|
|
50
|
+
edgeOffsetInPx,
|
|
51
|
+
arrowX$1,
|
|
52
|
+
tooltipWidth - edgeOffsetInPx - arrowWidthOffset
|
|
53
|
+
) : arrowX$1;
|
|
54
|
+
return /* @__PURE__ */ jsx(
|
|
55
|
+
Box,
|
|
56
|
+
{
|
|
57
|
+
ref: tooltipContainerRef,
|
|
58
|
+
textAlign: "left",
|
|
59
|
+
boxShadow: "large",
|
|
60
|
+
background: "neutral",
|
|
61
|
+
borderRadius: "large",
|
|
62
|
+
padding: "small",
|
|
63
|
+
className: [maxWidth, translateZ0],
|
|
64
|
+
children: /* @__PURE__ */ jsxs(TooltipTextDefaultsProvider, { children: [
|
|
65
|
+
/* @__PURE__ */ jsx(Box, { className: overflowWrap, zIndex: 1, position: "relative", children }),
|
|
66
|
+
/* @__PURE__ */ jsx(
|
|
67
|
+
Box,
|
|
68
|
+
{
|
|
69
|
+
ref: arrowRef,
|
|
70
|
+
position: "fixed",
|
|
71
|
+
background: "neutral",
|
|
72
|
+
className: arrow[placement ?? "top"],
|
|
73
|
+
style: assignInlineVars({
|
|
74
|
+
[arrowX]: clampedArrowX !== void 0 ? `${clampedArrowX}px` : void 0,
|
|
75
|
+
[arrowY]: arrowY$1 !== void 0 ? `${arrowY$1}px` : void 0
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
] })
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
};
|
|
60
83
|
const TooltipRenderer = ({
|
|
61
84
|
id,
|
|
62
85
|
tooltip,
|
|
@@ -64,16 +87,11 @@ const TooltipRenderer = ({
|
|
|
64
87
|
children
|
|
65
88
|
}) => {
|
|
66
89
|
const resolvedId = useFallbackId(id);
|
|
67
|
-
const tooltipRef = useRef(null);
|
|
68
90
|
const triggerRef = useRef(null);
|
|
91
|
+
const arrowRef = useRef(null);
|
|
69
92
|
const [open, setOpen] = useState(false);
|
|
70
|
-
const [
|
|
71
|
-
|
|
72
|
-
);
|
|
73
|
-
const [tooltipPosition, setTooltipPosition] = useState(
|
|
74
|
-
void 0
|
|
75
|
-
);
|
|
76
|
-
const { grid, space } = useSpace();
|
|
93
|
+
const [resolvedPlacement, setResolvedPlacement] = useState(placement);
|
|
94
|
+
const [arrowPosition, setArrowPosition] = useState();
|
|
77
95
|
const isStatic = useContext(StaticTooltipContext);
|
|
78
96
|
const isMobileDevice = useRef(isMobile()).current;
|
|
79
97
|
const onScreen = useRef(null);
|
|
@@ -133,38 +151,6 @@ const TooltipRenderer = ({
|
|
|
133
151
|
}
|
|
134
152
|
};
|
|
135
153
|
}, [open, isMobileDevice]);
|
|
136
|
-
const handleTooltipPosition = () => {
|
|
137
|
-
const setPositions = () => {
|
|
138
|
-
if (tooltipRef.current) {
|
|
139
|
-
setTooltipPosition(tooltipRef.current.getBoundingClientRect());
|
|
140
|
-
}
|
|
141
|
-
if (triggerRef.current) {
|
|
142
|
-
setTriggerPosition(triggerRef.current.getBoundingClientRect());
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
setTimeout(() => {
|
|
146
|
-
const frameId = requestAnimationFrame(setPositions);
|
|
147
|
-
return () => cancelAnimationFrame(frameId);
|
|
148
|
-
}, animationTimeout / 2);
|
|
149
|
-
};
|
|
150
|
-
useIsomorphicLayoutEffect(() => {
|
|
151
|
-
if (!showTooltip) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
handleTooltipPosition();
|
|
155
|
-
window.addEventListener("resize", handleTooltipPosition);
|
|
156
|
-
return () => {
|
|
157
|
-
window.removeEventListener("resize", handleTooltipPosition);
|
|
158
|
-
};
|
|
159
|
-
}, [showTooltip]);
|
|
160
|
-
let inferredPlacement = placement;
|
|
161
|
-
let arrowLeftOffset = 0;
|
|
162
|
-
if (tooltipPosition && triggerPosition) {
|
|
163
|
-
inferredPlacement = tooltipPosition.top > triggerPosition.top ? "bottom" : "top";
|
|
164
|
-
const edgeOffsetInPx = space[edgeOffset] * grid;
|
|
165
|
-
const tooltipLeftToTriggerLeft = triggerPosition.left - tooltipPosition.left - edgeOffsetInPx;
|
|
166
|
-
arrowLeftOffset = tooltipLeftToTriggerLeft + triggerPosition.width / 2;
|
|
167
|
-
}
|
|
168
154
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
169
155
|
children({
|
|
170
156
|
triggerProps: {
|
|
@@ -180,7 +166,6 @@ const TooltipRenderer = ({
|
|
|
180
166
|
{
|
|
181
167
|
id: resolvedId,
|
|
182
168
|
role: "tooltip",
|
|
183
|
-
ref: tooltipRef,
|
|
184
169
|
offsetSpace,
|
|
185
170
|
align: "center",
|
|
186
171
|
placement,
|
|
@@ -189,12 +174,18 @@ const TooltipRenderer = ({
|
|
|
189
174
|
modal: false,
|
|
190
175
|
open: showTooltip,
|
|
191
176
|
onClose: !isStatic ? () => setOpen(false) : void 0,
|
|
177
|
+
onPlacementChange: ({ placement: newPlacement, arrow: arrow2 }) => {
|
|
178
|
+
setResolvedPlacement(newPlacement);
|
|
179
|
+
setArrowPosition(arrow2);
|
|
180
|
+
},
|
|
192
181
|
triggerRef,
|
|
182
|
+
arrowRef,
|
|
193
183
|
children: /* @__PURE__ */ jsx(
|
|
194
184
|
TooltipContent,
|
|
195
185
|
{
|
|
196
|
-
|
|
197
|
-
|
|
186
|
+
placement: resolvedPlacement,
|
|
187
|
+
arrowPosition,
|
|
188
|
+
arrowRef,
|
|
198
189
|
children: tooltip
|
|
199
190
|
}
|
|
200
191
|
)
|
|
@@ -1,37 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const jsxRuntime = require("react/jsx-runtime");
|
|
3
|
-
const
|
|
3
|
+
const reactDom = require("@floating-ui/react-dom");
|
|
4
4
|
const dedent = require("dedent");
|
|
5
5
|
const react = require("react");
|
|
6
|
-
const lib_hooks_useIsomorphicLayoutEffect_cjs = require("../../../hooks/useIsomorphicLayoutEffect.cjs");
|
|
7
6
|
const lib_components_Box_Box_cjs = require("../../Box/Box.cjs");
|
|
8
7
|
const lib_components_BraidPortal_BraidPortal_cjs = require("../../BraidPortal/BraidPortal.cjs");
|
|
8
|
+
const lib_components_useResponsiveValue_useResponsiveValue_cjs = require("../../useResponsiveValue/useResponsiveValue.cjs");
|
|
9
9
|
const lib_components_useSpace_useSpace_cjs = require("../../useSpace/useSpace.cjs");
|
|
10
10
|
const lib_components_private_animationTimeout_cjs = require("../animationTimeout.cjs");
|
|
11
11
|
const lib_components_private_Popover_Popover_css_cjs = require("./Popover.css.cjs");
|
|
12
|
+
const lib_css_atoms_sprinkles_css_cjs = require("../../../css/atoms/sprinkles.css.cjs");
|
|
12
13
|
const _interopDefaultCompat = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
|
|
13
14
|
const dedent__default = /* @__PURE__ */ _interopDefaultCompat(dedent);
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const positionMap = {
|
|
16
|
+
top: {
|
|
17
|
+
left: "top-start",
|
|
18
|
+
center: "top",
|
|
19
|
+
right: "top-end"
|
|
20
|
+
},
|
|
21
|
+
bottom: {
|
|
22
|
+
left: "bottom-start",
|
|
23
|
+
center: "bottom",
|
|
24
|
+
right: "bottom-end"
|
|
18
25
|
}
|
|
19
|
-
const rect = element.getBoundingClientRect();
|
|
20
|
-
const { top, bottom, left, right, width } = rect;
|
|
21
|
-
const { scrollX: scrollX2, scrollY, innerWidth } = window;
|
|
22
|
-
return {
|
|
23
|
-
// For `top`, we subtract this from the dynamic viewport height in `Popover.css.ts`
|
|
24
|
-
// which can't be accessed from Javascript.
|
|
25
|
-
top: top + scrollY,
|
|
26
|
-
bottom: bottom + scrollY,
|
|
27
|
-
left: left + scrollX2,
|
|
28
|
-
right: innerWidth - right - scrollX2,
|
|
29
|
-
width
|
|
30
|
-
};
|
|
31
26
|
};
|
|
32
|
-
function
|
|
33
|
-
return
|
|
27
|
+
function getFloatingUiPosition(placement, align) {
|
|
28
|
+
return positionMap[placement][align];
|
|
34
29
|
}
|
|
30
|
+
const zIndex = "notification";
|
|
31
|
+
const PopoverContext = react.createContext(null);
|
|
35
32
|
const PopoverContent = react.forwardRef(
|
|
36
33
|
({
|
|
37
34
|
id,
|
|
@@ -45,18 +42,59 @@ const PopoverContent = react.forwardRef(
|
|
|
45
42
|
modal = true,
|
|
46
43
|
open,
|
|
47
44
|
onClose,
|
|
45
|
+
onPlacementChange,
|
|
48
46
|
triggerRef,
|
|
49
47
|
enterFocusRef,
|
|
48
|
+
arrowRef,
|
|
50
49
|
children
|
|
51
50
|
}, forwardedRef) => {
|
|
52
|
-
const [triggerPosition, setTriggerPosition] = react.useState(void 0);
|
|
53
51
|
const ref = react.useRef(null);
|
|
54
52
|
react.useImperativeHandle(forwardedRef, () => ref.current);
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
53
|
+
const normalized = lib_css_atoms_sprinkles_css_cjs.normalizeResponsiveValue(offsetSpace);
|
|
54
|
+
const mobile = normalized.mobile ?? "none";
|
|
55
|
+
const tablet = normalized.tablet ?? mobile;
|
|
56
|
+
const desktop = normalized.desktop ?? tablet;
|
|
57
|
+
const wide = normalized.wide ?? desktop;
|
|
58
|
+
const resolvedOffsetSpace = lib_components_useResponsiveValue_useResponsiveValue_cjs.useResponsiveValue()({ mobile, tablet, desktop, wide }) ?? mobile;
|
|
59
|
+
const spaceScale = lib_components_useSpace_useSpace_cjs.useSpace();
|
|
60
|
+
let offsetSpacePx = 0;
|
|
61
|
+
if (resolvedOffsetSpace !== "none") {
|
|
62
|
+
offsetSpacePx = spaceScale.space[resolvedOffsetSpace] * spaceScale.grid;
|
|
63
|
+
}
|
|
64
|
+
const floatingUiRequestedPosition = getFloatingUiPosition(placement, align);
|
|
65
|
+
const middleware = [
|
|
66
|
+
reactDom.offset(offsetSpacePx),
|
|
67
|
+
!lockPlacement && reactDom.flip(),
|
|
68
|
+
width === "full" ? reactDom.size({
|
|
69
|
+
apply({ rects, elements }) {
|
|
70
|
+
Object.assign(elements.floating.style, {
|
|
71
|
+
width: `${rects.reference.width}px`
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}) : reactDom.shift({
|
|
75
|
+
crossAxis: align === "center"
|
|
76
|
+
}),
|
|
77
|
+
arrowRef && reactDom.arrow({ element: arrowRef })
|
|
78
|
+
].filter(Boolean);
|
|
79
|
+
const {
|
|
80
|
+
refs,
|
|
81
|
+
floatingStyles,
|
|
82
|
+
middlewareData,
|
|
83
|
+
placement: floatingUiEvaluatedPosition,
|
|
84
|
+
isPositioned
|
|
85
|
+
} = reactDom.useFloating({
|
|
86
|
+
placement: floatingUiRequestedPosition,
|
|
87
|
+
middleware,
|
|
88
|
+
whileElementsMounted: reactDom.autoUpdate
|
|
89
|
+
});
|
|
90
|
+
react.useEffect(() => {
|
|
91
|
+
refs.setReference(triggerRef.current);
|
|
92
|
+
}, [triggerRef, refs]);
|
|
93
|
+
react.useEffect(() => {
|
|
94
|
+
if (ref.current) {
|
|
95
|
+
refs.setFloating(ref.current);
|
|
96
|
+
}
|
|
97
|
+
}, [refs]);
|
|
60
98
|
react.useEffect(() => {
|
|
61
99
|
const handleKeydown = (event) => {
|
|
62
100
|
if (event.key === "Escape" || event.key === "Tab") {
|
|
@@ -81,9 +119,6 @@ const PopoverContent = react.forwardRef(
|
|
|
81
119
|
window.removeEventListener("keydown", handleKeydown);
|
|
82
120
|
};
|
|
83
121
|
}, [onClose, triggerRef]);
|
|
84
|
-
react.useEffect(() => {
|
|
85
|
-
setTriggerPosition(getPosition(triggerRef.current));
|
|
86
|
-
}, [triggerRef]);
|
|
87
122
|
react.useEffect(() => {
|
|
88
123
|
setTimeout(() => {
|
|
89
124
|
if (!enterFocusRef) {
|
|
@@ -101,95 +136,24 @@ const PopoverContent = react.forwardRef(
|
|
|
101
136
|
}
|
|
102
137
|
}
|
|
103
138
|
}, lib_components_private_animationTimeout_cjs.animationTimeout);
|
|
104
|
-
}, [open, enterFocusRef
|
|
139
|
+
}, [open, enterFocusRef]);
|
|
140
|
+
const resolvedPlacement = floatingUiEvaluatedPosition?.startsWith("top") ? "top" : "bottom";
|
|
105
141
|
react.useEffect(() => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
resizeObserver.observe(document.body);
|
|
112
|
-
return () => {
|
|
113
|
-
window.removeEventListener("resize", handleResize);
|
|
114
|
-
resizeObserver.disconnect();
|
|
115
|
-
};
|
|
116
|
-
}, [triggerRef]);
|
|
117
|
-
const handlePlacement = () => {
|
|
118
|
-
const popoverBoundingRect = ref?.current?.getBoundingClientRect();
|
|
119
|
-
if (!popoverBoundingRect) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
const triggerBoundingRect = triggerRef.current?.getBoundingClientRect();
|
|
123
|
-
if (!triggerBoundingRect) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const { height: popoverHeight } = popoverBoundingRect;
|
|
127
|
-
const heightRequired = popoverHeight + transitionThresholdInPx;
|
|
128
|
-
const fitsAbove = triggerBoundingRect.top >= heightRequired;
|
|
129
|
-
const fitsBelow = window.innerHeight - triggerBoundingRect.bottom >= heightRequired;
|
|
130
|
-
if (!fitsAbove && fitsBelow) {
|
|
131
|
-
setActualPlacement("bottom");
|
|
132
|
-
} else if (!fitsBelow && fitsAbove) {
|
|
133
|
-
setActualPlacement("top");
|
|
134
|
-
} else {
|
|
135
|
-
setActualPlacement(placement);
|
|
142
|
+
if (onPlacementChange) {
|
|
143
|
+
onPlacementChange({
|
|
144
|
+
placement: resolvedPlacement,
|
|
145
|
+
arrow: middlewareData.arrow
|
|
146
|
+
});
|
|
136
147
|
}
|
|
148
|
+
}, [resolvedPlacement, middlewareData.arrow, onPlacementChange]);
|
|
149
|
+
const combinedStyles = {
|
|
150
|
+
...floatingStyles,
|
|
151
|
+
...!isPositioned ? { opacity: 0, pointerEvents: "none" } : {}
|
|
137
152
|
};
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
const popoverBoundingRect = ref?.current?.getBoundingClientRect();
|
|
143
|
-
if (!popoverBoundingRect) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
const { width: popoverWidth } = popoverBoundingRect;
|
|
147
|
-
const triggerCenter = triggerPosition.width && triggerPosition.left + triggerPosition.width / 2;
|
|
148
|
-
const popoverLeft = align === "center" && triggerCenter ? triggerCenter - popoverWidth / 2 : triggerPosition.left;
|
|
149
|
-
const clampedPopoverLeft = clamp(
|
|
150
|
-
scrollX,
|
|
151
|
-
popoverLeft,
|
|
152
|
-
window.innerWidth + scrollX - popoverWidth
|
|
153
|
-
);
|
|
154
|
-
const triggerRightFromLeft = window.innerWidth - triggerPosition.right;
|
|
155
|
-
const clampedTriggerRightFromLeft = clamp(
|
|
156
|
-
scrollX + popoverWidth,
|
|
157
|
-
triggerRightFromLeft,
|
|
158
|
-
scrollX + window.innerWidth
|
|
159
|
-
);
|
|
160
|
-
if (alignmentAnchor === "right" && clampedTriggerRightFromLeft !== triggerPosition.right + horizontalOffset) {
|
|
161
|
-
setHorizontalOffset(
|
|
162
|
-
window.innerWidth - clampedTriggerRightFromLeft - triggerPosition.right
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
if (alignmentAnchor === "left" && clampedPopoverLeft !== triggerPosition.left + horizontalOffset) {
|
|
166
|
-
setHorizontalOffset(clampedPopoverLeft - triggerPosition.left);
|
|
167
|
-
}
|
|
168
|
-
return;
|
|
169
|
-
};
|
|
170
|
-
lib_hooks_useIsomorphicLayoutEffect_cjs.useIsomorphicLayoutEffect(() => {
|
|
171
|
-
if (!showPopover) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
if (width !== "full") {
|
|
175
|
-
handleHorizontalShift();
|
|
176
|
-
}
|
|
177
|
-
if (!lockPlacement) {
|
|
178
|
-
handlePlacement();
|
|
179
|
-
}
|
|
180
|
-
}, [showPopover]);
|
|
181
|
-
const triggerPositionVars = triggerPosition && {
|
|
182
|
-
// Vertical positioning
|
|
183
|
-
[lib_components_private_Popover_Popover_css_cjs.triggerVars[actualPlacement]]: `${triggerPosition[actualPlacement]}`,
|
|
184
|
-
// Horizontal positioning
|
|
185
|
-
[lib_components_private_Popover_Popover_css_cjs.triggerVars.left]: width === "full" || alignmentAnchor === "left" ? `${triggerPosition?.left}` : void 0,
|
|
186
|
-
[lib_components_private_Popover_Popover_css_cjs.triggerVars.right]: width === "full" || alignmentAnchor === "right" ? `${triggerPosition?.right}` : void 0,
|
|
187
|
-
// Horizontal scroll offset
|
|
188
|
-
[lib_components_private_Popover_Popover_css_cjs.horizontalOffset]: width !== "full" ? `${horizontalOffset}` : "0"
|
|
153
|
+
const popoverContextValue = {
|
|
154
|
+
arrow: middlewareData.arrow,
|
|
155
|
+
resolvedPlacement
|
|
189
156
|
};
|
|
190
|
-
if (!showPopover) {
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
157
|
return /* @__PURE__ */ jsxRuntime.jsxs(lib_components_BraidPortal_BraidPortal_cjs.BraidPortal, { children: [
|
|
194
158
|
modal && /* @__PURE__ */ jsxRuntime.jsx(
|
|
195
159
|
lib_components_Box_Box_cjs.Box,
|
|
@@ -217,17 +181,18 @@ const PopoverContent = react.forwardRef(
|
|
|
217
181
|
role: role || void 0,
|
|
218
182
|
tabIndex: -1,
|
|
219
183
|
zIndex,
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
184
|
+
style: combinedStyles,
|
|
185
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
186
|
+
lib_components_Box_Box_cjs.Box,
|
|
187
|
+
{
|
|
188
|
+
className: {
|
|
189
|
+
[lib_components_private_Popover_Popover_css_cjs.animation]: true,
|
|
190
|
+
[lib_components_private_Popover_Popover_css_cjs.invertPlacement]: resolvedPlacement === "bottom",
|
|
191
|
+
[lib_components_private_Popover_Popover_css_cjs.delayVisibility]: delayVisibility
|
|
192
|
+
},
|
|
193
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(PopoverContext.Provider, { value: popoverContextValue, children })
|
|
194
|
+
}
|
|
195
|
+
)
|
|
231
196
|
}
|
|
232
197
|
)
|
|
233
198
|
] });
|
|
@@ -9,23 +9,6 @@ const backdrop = css.style({
|
|
|
9
9
|
width: "100vw",
|
|
10
10
|
height: "100vh"
|
|
11
11
|
}, "backdrop");
|
|
12
|
-
const triggerVars = {
|
|
13
|
-
top: css.createVar("triggerVars_top"),
|
|
14
|
-
left: css.createVar("triggerVars_left"),
|
|
15
|
-
bottom: css.createVar("triggerVars_bottom"),
|
|
16
|
-
right: css.createVar("triggerVars_right")
|
|
17
|
-
};
|
|
18
|
-
const horizontalOffset = css.createVar("horizontalOffset");
|
|
19
|
-
const dynamicHeight = css.createVar("dynamicHeight");
|
|
20
|
-
const popoverPosition = css.style({
|
|
21
|
-
vars: {
|
|
22
|
-
[dynamicHeight]: "100svh"
|
|
23
|
-
},
|
|
24
|
-
top: cssUtils.calc(triggerVars.bottom).multiply("1px").toString(),
|
|
25
|
-
bottom: cssUtils.calc(css.fallbackVar(dynamicHeight, "100vh")).subtract(cssUtils.calc(triggerVars.top).multiply("1px")).toString(),
|
|
26
|
-
left: cssUtils.calc(triggerVars.left).add(horizontalOffset).multiply("1px").toString(),
|
|
27
|
-
right: cssUtils.calc(triggerVars.right).add(horizontalOffset).multiply("1px").toString()
|
|
28
|
-
}, "popoverPosition");
|
|
29
12
|
const placementModifier = css.createVar("placementModifier");
|
|
30
13
|
const invertPlacement = css.style({
|
|
31
14
|
vars: {
|
|
@@ -53,8 +36,4 @@ fileScope.endFileScope();
|
|
|
53
36
|
exports.animation = animation;
|
|
54
37
|
exports.backdrop = backdrop;
|
|
55
38
|
exports.delayVisibility = delayVisibility;
|
|
56
|
-
exports.horizontalOffset = horizontalOffset;
|
|
57
39
|
exports.invertPlacement = invertPlacement;
|
|
58
|
-
exports.popoverPosition = popoverPosition;
|
|
59
|
-
exports.transitionThreshold = transitionThreshold;
|
|
60
|
-
exports.triggerVars = triggerVars;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { setFileScope, endFileScope } from "@vanilla-extract/css/fileScope";
|
|
2
|
-
import {
|
|
2
|
+
import { style, keyframes, createVar, fallbackVar } from "@vanilla-extract/css";
|
|
3
3
|
import { calc } from "@vanilla-extract/css-utils";
|
|
4
4
|
import { animationTimeout } from "../animationTimeout.mjs";
|
|
5
5
|
import { vars } from "../../../themes/vars.css.mjs";
|
|
@@ -8,23 +8,6 @@ const backdrop = style({
|
|
|
8
8
|
width: "100vw",
|
|
9
9
|
height: "100vh"
|
|
10
10
|
}, "backdrop");
|
|
11
|
-
const triggerVars = {
|
|
12
|
-
top: createVar("triggerVars_top"),
|
|
13
|
-
left: createVar("triggerVars_left"),
|
|
14
|
-
bottom: createVar("triggerVars_bottom"),
|
|
15
|
-
right: createVar("triggerVars_right")
|
|
16
|
-
};
|
|
17
|
-
const horizontalOffset = createVar("horizontalOffset");
|
|
18
|
-
const dynamicHeight = createVar("dynamicHeight");
|
|
19
|
-
const popoverPosition = style({
|
|
20
|
-
vars: {
|
|
21
|
-
[dynamicHeight]: "100svh"
|
|
22
|
-
},
|
|
23
|
-
top: calc(triggerVars.bottom).multiply("1px").toString(),
|
|
24
|
-
bottom: calc(fallbackVar(dynamicHeight, "100vh")).subtract(calc(triggerVars.top).multiply("1px")).toString(),
|
|
25
|
-
left: calc(triggerVars.left).add(horizontalOffset).multiply("1px").toString(),
|
|
26
|
-
right: calc(triggerVars.right).add(horizontalOffset).multiply("1px").toString()
|
|
27
|
-
}, "popoverPosition");
|
|
28
11
|
const placementModifier = createVar("placementModifier");
|
|
29
12
|
const invertPlacement = style({
|
|
30
13
|
vars: {
|
|
@@ -53,9 +36,5 @@ export {
|
|
|
53
36
|
animation,
|
|
54
37
|
backdrop,
|
|
55
38
|
delayVisibility,
|
|
56
|
-
|
|
57
|
-
invertPlacement,
|
|
58
|
-
popoverPosition,
|
|
59
|
-
transitionThreshold,
|
|
60
|
-
triggerVars
|
|
39
|
+
invertPlacement
|
|
61
40
|
};
|
|
@@ -1,34 +1,31 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { offset, flip, size, shift, arrow, useFloating, autoUpdate } from "@floating-ui/react-dom";
|
|
3
3
|
import dedent from "dedent";
|
|
4
|
-
import { forwardRef,
|
|
5
|
-
import { useIsomorphicLayoutEffect } from "../../../hooks/useIsomorphicLayoutEffect.mjs";
|
|
4
|
+
import { forwardRef, useRef, useImperativeHandle, useEffect, createContext } from "react";
|
|
6
5
|
import { Box } from "../../Box/Box.mjs";
|
|
7
6
|
import { BraidPortal } from "../../BraidPortal/BraidPortal.mjs";
|
|
7
|
+
import { useResponsiveValue } from "../../useResponsiveValue/useResponsiveValue.mjs";
|
|
8
8
|
import { useSpace } from "../../useSpace/useSpace.mjs";
|
|
9
9
|
import { animationTimeout } from "../animationTimeout.mjs";
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
import { backdrop, delayVisibility, invertPlacement, animation } from "./Popover.css.mjs";
|
|
11
|
+
import { normalizeResponsiveValue } from "../../../css/atoms/sprinkles.css.mjs";
|
|
12
|
+
const positionMap = {
|
|
13
|
+
top: {
|
|
14
|
+
left: "top-start",
|
|
15
|
+
center: "top",
|
|
16
|
+
right: "top-end"
|
|
17
|
+
},
|
|
18
|
+
bottom: {
|
|
19
|
+
left: "bottom-start",
|
|
20
|
+
center: "bottom",
|
|
21
|
+
right: "bottom-end"
|
|
15
22
|
}
|
|
16
|
-
const rect = element.getBoundingClientRect();
|
|
17
|
-
const { top, bottom, left, right, width } = rect;
|
|
18
|
-
const { scrollX: scrollX2, scrollY, innerWidth } = window;
|
|
19
|
-
return {
|
|
20
|
-
// For `top`, we subtract this from the dynamic viewport height in `Popover.css.ts`
|
|
21
|
-
// which can't be accessed from Javascript.
|
|
22
|
-
top: top + scrollY,
|
|
23
|
-
bottom: bottom + scrollY,
|
|
24
|
-
left: left + scrollX2,
|
|
25
|
-
right: innerWidth - right - scrollX2,
|
|
26
|
-
width
|
|
27
|
-
};
|
|
28
23
|
};
|
|
29
|
-
function
|
|
30
|
-
return
|
|
24
|
+
function getFloatingUiPosition(placement, align) {
|
|
25
|
+
return positionMap[placement][align];
|
|
31
26
|
}
|
|
27
|
+
const zIndex = "notification";
|
|
28
|
+
const PopoverContext = createContext(null);
|
|
32
29
|
const PopoverContent = forwardRef(
|
|
33
30
|
({
|
|
34
31
|
id,
|
|
@@ -42,18 +39,59 @@ const PopoverContent = forwardRef(
|
|
|
42
39
|
modal = true,
|
|
43
40
|
open,
|
|
44
41
|
onClose,
|
|
42
|
+
onPlacementChange,
|
|
45
43
|
triggerRef,
|
|
46
44
|
enterFocusRef,
|
|
45
|
+
arrowRef,
|
|
47
46
|
children
|
|
48
47
|
}, forwardedRef) => {
|
|
49
|
-
const [triggerPosition, setTriggerPosition] = useState(void 0);
|
|
50
48
|
const ref = useRef(null);
|
|
51
49
|
useImperativeHandle(forwardedRef, () => ref.current);
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const
|
|
50
|
+
const normalized = normalizeResponsiveValue(offsetSpace);
|
|
51
|
+
const mobile = normalized.mobile ?? "none";
|
|
52
|
+
const tablet = normalized.tablet ?? mobile;
|
|
53
|
+
const desktop = normalized.desktop ?? tablet;
|
|
54
|
+
const wide = normalized.wide ?? desktop;
|
|
55
|
+
const resolvedOffsetSpace = useResponsiveValue()({ mobile, tablet, desktop, wide }) ?? mobile;
|
|
56
|
+
const spaceScale = useSpace();
|
|
57
|
+
let offsetSpacePx = 0;
|
|
58
|
+
if (resolvedOffsetSpace !== "none") {
|
|
59
|
+
offsetSpacePx = spaceScale.space[resolvedOffsetSpace] * spaceScale.grid;
|
|
60
|
+
}
|
|
61
|
+
const floatingUiRequestedPosition = getFloatingUiPosition(placement, align);
|
|
62
|
+
const middleware = [
|
|
63
|
+
offset(offsetSpacePx),
|
|
64
|
+
!lockPlacement && flip(),
|
|
65
|
+
width === "full" ? size({
|
|
66
|
+
apply({ rects, elements }) {
|
|
67
|
+
Object.assign(elements.floating.style, {
|
|
68
|
+
width: `${rects.reference.width}px`
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}) : shift({
|
|
72
|
+
crossAxis: align === "center"
|
|
73
|
+
}),
|
|
74
|
+
arrowRef && arrow({ element: arrowRef })
|
|
75
|
+
].filter(Boolean);
|
|
76
|
+
const {
|
|
77
|
+
refs,
|
|
78
|
+
floatingStyles,
|
|
79
|
+
middlewareData,
|
|
80
|
+
placement: floatingUiEvaluatedPosition,
|
|
81
|
+
isPositioned
|
|
82
|
+
} = useFloating({
|
|
83
|
+
placement: floatingUiRequestedPosition,
|
|
84
|
+
middleware,
|
|
85
|
+
whileElementsMounted: autoUpdate
|
|
86
|
+
});
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
refs.setReference(triggerRef.current);
|
|
89
|
+
}, [triggerRef, refs]);
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (ref.current) {
|
|
92
|
+
refs.setFloating(ref.current);
|
|
93
|
+
}
|
|
94
|
+
}, [refs]);
|
|
57
95
|
useEffect(() => {
|
|
58
96
|
const handleKeydown = (event) => {
|
|
59
97
|
if (event.key === "Escape" || event.key === "Tab") {
|
|
@@ -78,9 +116,6 @@ const PopoverContent = forwardRef(
|
|
|
78
116
|
window.removeEventListener("keydown", handleKeydown);
|
|
79
117
|
};
|
|
80
118
|
}, [onClose, triggerRef]);
|
|
81
|
-
useEffect(() => {
|
|
82
|
-
setTriggerPosition(getPosition(triggerRef.current));
|
|
83
|
-
}, [triggerRef]);
|
|
84
119
|
useEffect(() => {
|
|
85
120
|
setTimeout(() => {
|
|
86
121
|
if (!enterFocusRef) {
|
|
@@ -98,95 +133,24 @@ const PopoverContent = forwardRef(
|
|
|
98
133
|
}
|
|
99
134
|
}
|
|
100
135
|
}, animationTimeout);
|
|
101
|
-
}, [open, enterFocusRef
|
|
136
|
+
}, [open, enterFocusRef]);
|
|
137
|
+
const resolvedPlacement = floatingUiEvaluatedPosition?.startsWith("top") ? "top" : "bottom";
|
|
102
138
|
useEffect(() => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
resizeObserver.observe(document.body);
|
|
109
|
-
return () => {
|
|
110
|
-
window.removeEventListener("resize", handleResize);
|
|
111
|
-
resizeObserver.disconnect();
|
|
112
|
-
};
|
|
113
|
-
}, [triggerRef]);
|
|
114
|
-
const handlePlacement = () => {
|
|
115
|
-
const popoverBoundingRect = ref?.current?.getBoundingClientRect();
|
|
116
|
-
if (!popoverBoundingRect) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const triggerBoundingRect = triggerRef.current?.getBoundingClientRect();
|
|
120
|
-
if (!triggerBoundingRect) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const { height: popoverHeight } = popoverBoundingRect;
|
|
124
|
-
const heightRequired = popoverHeight + transitionThresholdInPx;
|
|
125
|
-
const fitsAbove = triggerBoundingRect.top >= heightRequired;
|
|
126
|
-
const fitsBelow = window.innerHeight - triggerBoundingRect.bottom >= heightRequired;
|
|
127
|
-
if (!fitsAbove && fitsBelow) {
|
|
128
|
-
setActualPlacement("bottom");
|
|
129
|
-
} else if (!fitsBelow && fitsAbove) {
|
|
130
|
-
setActualPlacement("top");
|
|
131
|
-
} else {
|
|
132
|
-
setActualPlacement(placement);
|
|
139
|
+
if (onPlacementChange) {
|
|
140
|
+
onPlacementChange({
|
|
141
|
+
placement: resolvedPlacement,
|
|
142
|
+
arrow: middlewareData.arrow
|
|
143
|
+
});
|
|
133
144
|
}
|
|
145
|
+
}, [resolvedPlacement, middlewareData.arrow, onPlacementChange]);
|
|
146
|
+
const combinedStyles = {
|
|
147
|
+
...floatingStyles,
|
|
148
|
+
...!isPositioned ? { opacity: 0, pointerEvents: "none" } : {}
|
|
134
149
|
};
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
const popoverBoundingRect = ref?.current?.getBoundingClientRect();
|
|
140
|
-
if (!popoverBoundingRect) {
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
const { width: popoverWidth } = popoverBoundingRect;
|
|
144
|
-
const triggerCenter = triggerPosition.width && triggerPosition.left + triggerPosition.width / 2;
|
|
145
|
-
const popoverLeft = align === "center" && triggerCenter ? triggerCenter - popoverWidth / 2 : triggerPosition.left;
|
|
146
|
-
const clampedPopoverLeft = clamp(
|
|
147
|
-
scrollX,
|
|
148
|
-
popoverLeft,
|
|
149
|
-
window.innerWidth + scrollX - popoverWidth
|
|
150
|
-
);
|
|
151
|
-
const triggerRightFromLeft = window.innerWidth - triggerPosition.right;
|
|
152
|
-
const clampedTriggerRightFromLeft = clamp(
|
|
153
|
-
scrollX + popoverWidth,
|
|
154
|
-
triggerRightFromLeft,
|
|
155
|
-
scrollX + window.innerWidth
|
|
156
|
-
);
|
|
157
|
-
if (alignmentAnchor === "right" && clampedTriggerRightFromLeft !== triggerPosition.right + horizontalOffset$1) {
|
|
158
|
-
setHorizontalOffset(
|
|
159
|
-
window.innerWidth - clampedTriggerRightFromLeft - triggerPosition.right
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
if (alignmentAnchor === "left" && clampedPopoverLeft !== triggerPosition.left + horizontalOffset$1) {
|
|
163
|
-
setHorizontalOffset(clampedPopoverLeft - triggerPosition.left);
|
|
164
|
-
}
|
|
165
|
-
return;
|
|
166
|
-
};
|
|
167
|
-
useIsomorphicLayoutEffect(() => {
|
|
168
|
-
if (!showPopover) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
if (width !== "full") {
|
|
172
|
-
handleHorizontalShift();
|
|
173
|
-
}
|
|
174
|
-
if (!lockPlacement) {
|
|
175
|
-
handlePlacement();
|
|
176
|
-
}
|
|
177
|
-
}, [showPopover]);
|
|
178
|
-
const triggerPositionVars = triggerPosition && {
|
|
179
|
-
// Vertical positioning
|
|
180
|
-
[triggerVars[actualPlacement]]: `${triggerPosition[actualPlacement]}`,
|
|
181
|
-
// Horizontal positioning
|
|
182
|
-
[triggerVars.left]: width === "full" || alignmentAnchor === "left" ? `${triggerPosition?.left}` : void 0,
|
|
183
|
-
[triggerVars.right]: width === "full" || alignmentAnchor === "right" ? `${triggerPosition?.right}` : void 0,
|
|
184
|
-
// Horizontal scroll offset
|
|
185
|
-
[horizontalOffset]: width !== "full" ? `${horizontalOffset$1}` : "0"
|
|
150
|
+
const popoverContextValue = {
|
|
151
|
+
arrow: middlewareData.arrow,
|
|
152
|
+
resolvedPlacement
|
|
186
153
|
};
|
|
187
|
-
if (!showPopover) {
|
|
188
|
-
return null;
|
|
189
|
-
}
|
|
190
154
|
return /* @__PURE__ */ jsxs(BraidPortal, { children: [
|
|
191
155
|
modal && /* @__PURE__ */ jsx(
|
|
192
156
|
Box,
|
|
@@ -214,17 +178,18 @@ const PopoverContent = forwardRef(
|
|
|
214
178
|
role: role || void 0,
|
|
215
179
|
tabIndex: -1,
|
|
216
180
|
zIndex,
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
181
|
+
style: combinedStyles,
|
|
182
|
+
children: /* @__PURE__ */ jsx(
|
|
183
|
+
Box,
|
|
184
|
+
{
|
|
185
|
+
className: {
|
|
186
|
+
[animation]: true,
|
|
187
|
+
[invertPlacement]: resolvedPlacement === "bottom",
|
|
188
|
+
[delayVisibility]: delayVisibility$1
|
|
189
|
+
},
|
|
190
|
+
children: /* @__PURE__ */ jsx(PopoverContext.Provider, { value: popoverContextValue, children })
|
|
191
|
+
}
|
|
192
|
+
)
|
|
228
193
|
}
|
|
229
194
|
)
|
|
230
195
|
] });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "braid-design-system",
|
|
3
|
-
"version": "33.12.
|
|
3
|
+
"version": "33.12.4",
|
|
4
4
|
"description": "Themeable design system for the SEEK Group",
|
|
5
5
|
"homepage": "https://seek-oss.github.io/braid-design-system/",
|
|
6
6
|
"bugs": {
|
|
@@ -164,6 +164,7 @@
|
|
|
164
164
|
"@capsizecss/core": "^4.1.2",
|
|
165
165
|
"@capsizecss/metrics": "^3.0.0",
|
|
166
166
|
"@capsizecss/vanilla-extract": "^2.0.4",
|
|
167
|
+
"@floating-ui/react-dom": "^2.1.6",
|
|
167
168
|
"@vanilla-extract/css": "^1.9.2",
|
|
168
169
|
"@vanilla-extract/css-utils": "^0.1.3",
|
|
169
170
|
"@vanilla-extract/dynamic": "^2.1.2",
|