@yahoo/uds 3.99.0 → 3.100.0-beta.1
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/dist/automated-config/dist/generated/autoVariants.cjs +9 -1
- package/dist/automated-config/dist/generated/autoVariants.d.cts +8 -0
- package/dist/automated-config/dist/generated/autoVariants.d.ts +8 -0
- package/dist/automated-config/dist/generated/autoVariants.js +9 -1
- package/dist/automated-config/dist/generated/generatedConfigs.cjs +1588 -1
- package/dist/automated-config/dist/generated/generatedConfigs.d.cts +378 -189
- package/dist/automated-config/dist/generated/generatedConfigs.d.ts +378 -189
- package/dist/automated-config/dist/generated/generatedConfigs.js +1587 -1
- package/dist/automated-config/dist/generated/universalTokensConfigAuto.cjs +82 -0
- package/dist/automated-config/dist/generated/universalTokensConfigAuto.d.cts +2 -1
- package/dist/automated-config/dist/generated/universalTokensConfigAuto.d.ts +2 -1
- package/dist/automated-config/dist/generated/universalTokensConfigAuto.js +82 -0
- package/dist/automated-config/dist/properties.cjs +141 -89
- package/dist/automated-config/dist/properties.d.cts +18 -3
- package/dist/automated-config/dist/properties.d.ts +18 -3
- package/dist/automated-config/dist/properties.js +142 -90
- package/dist/automated-config/dist/utils/buildConfigSchema.cjs +5 -1
- package/dist/automated-config/dist/utils/buildConfigSchema.d.cts +2 -1
- package/dist/automated-config/dist/utils/buildConfigSchema.d.ts +2 -1
- package/dist/automated-config/dist/utils/buildConfigSchema.js +5 -1
- package/dist/automated-config/dist/utils/getConfigVariantProperties.d.cts +2 -2
- package/dist/automated-config/dist/utils/getConfigVariantProperties.d.ts +2 -2
- package/dist/automated-config/dist/utils/index.d.cts +2 -1
- package/dist/automated-config/dist/utils/index.d.ts +2 -1
- package/dist/cli/commands/sync.cjs +5 -1
- package/dist/cli/commands/sync.js +5 -1
- package/dist/components/client/Button.js +2 -2
- package/dist/components/client/Tooltip/Tooltip.cjs +37 -0
- package/dist/components/client/Tooltip/Tooltip.d.cts +16 -0
- package/dist/components/client/Tooltip/Tooltip.d.ts +16 -0
- package/dist/components/client/Tooltip/Tooltip.js +35 -0
- package/dist/components/client/Tooltip/TooltipContent.cjs +171 -0
- package/dist/components/client/Tooltip/TooltipContent.d.cts +8 -0
- package/dist/components/client/Tooltip/TooltipContent.d.ts +8 -0
- package/dist/components/client/Tooltip/TooltipContent.js +169 -0
- package/dist/components/client/Tooltip/TooltipTrigger.cjs +20 -0
- package/dist/components/client/Tooltip/TooltipTrigger.d.cts +13 -0
- package/dist/components/client/Tooltip/TooltipTrigger.d.ts +13 -0
- package/dist/components/client/Tooltip/TooltipTrigger.js +18 -0
- package/dist/components/client/Tooltip/UDSTooltipConfigProvider.cjs +41 -0
- package/dist/components/client/Tooltip/UDSTooltipConfigProvider.d.cts +29 -0
- package/dist/components/client/Tooltip/UDSTooltipConfigProvider.d.ts +29 -0
- package/dist/components/client/Tooltip/UDSTooltipConfigProvider.js +38 -0
- package/dist/components/client/Tooltip/index.cjs +12 -0
- package/dist/components/client/Tooltip/index.d.cts +7 -0
- package/dist/components/client/Tooltip/index.d.ts +7 -0
- package/dist/components/client/Tooltip/index.js +8 -0
- package/dist/components/client/Tooltip/tooltipContext.cjs +12 -0
- package/dist/components/client/Tooltip/tooltipContext.d.cts +12 -0
- package/dist/components/client/Tooltip/tooltipContext.d.ts +12 -0
- package/dist/components/client/Tooltip/tooltipContext.js +10 -0
- package/dist/components/client/Tooltip/useTooltipContent.cjs +186 -0
- package/dist/components/client/Tooltip/useTooltipContent.d.cts +63 -0
- package/dist/components/client/Tooltip/useTooltipContent.d.ts +63 -0
- package/dist/components/client/Tooltip/useTooltipContent.js +184 -0
- package/dist/components/client/Tooltip/util.cjs +248 -0
- package/dist/components/client/Tooltip/util.d.cts +118 -0
- package/dist/components/client/Tooltip/util.d.ts +118 -0
- package/dist/components/client/Tooltip/util.js +240 -0
- package/dist/components/client/index.cjs +8 -0
- package/dist/components/client/index.d.cts +7 -1
- package/dist/components/client/index.d.ts +7 -1
- package/dist/components/client/index.js +5 -1
- package/dist/components/client/providers/UDSConfigProvider.cjs +6 -2
- package/dist/components/client/providers/UDSConfigProvider.d.cts +2 -1
- package/dist/components/client/providers/UDSConfigProvider.d.ts +2 -1
- package/dist/components/client/providers/UDSConfigProvider.js +6 -2
- package/dist/components/index.cjs +8 -0
- package/dist/components/index.d.cts +6 -1
- package/dist/components/index.d.ts +6 -1
- package/dist/components/index.js +5 -1
- package/dist/config/dist/index.cjs +83 -1
- package/dist/config/dist/index.d.cts +123 -1
- package/dist/config/dist/index.d.ts +123 -1
- package/dist/config/dist/index.js +83 -1
- package/dist/css-tokens/dist/index.cjs +2 -0
- package/dist/css-tokens/dist/index.d.cts +2 -1
- package/dist/css-tokens/dist/index.d.ts +2 -1
- package/dist/css-tokens/dist/index.js +2 -1
- package/dist/fixtures/dist/arbitrary.d.cts +11 -0
- package/dist/fixtures/dist/arbitrary.d.ts +11 -0
- package/dist/fixtures/dist/index.cjs +27 -1
- package/dist/fixtures/dist/index.d.cts +17 -3
- package/dist/fixtures/dist/index.d.ts +17 -3
- package/dist/fixtures/dist/index.js +26 -2
- package/dist/fixtures/index.cjs +6 -1
- package/dist/fixtures/index.d.cts +4 -2
- package/dist/fixtures/index.d.ts +4 -2
- package/dist/fixtures/index.js +3 -2
- package/dist/fixtures/src/arbitrary.cjs +23 -0
- package/dist/fixtures/src/arbitrary.d.cts +15 -0
- package/dist/fixtures/src/arbitrary.d.ts +15 -0
- package/dist/fixtures/src/arbitrary.js +18 -0
- package/dist/fixtures/src/util.cjs +26 -0
- package/dist/fixtures/src/util.d.cts +9 -0
- package/dist/fixtures/src/util.d.ts +9 -0
- package/dist/fixtures/src/util.js +25 -0
- package/dist/index.cjs +12 -0
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +8 -3
- package/dist/runtime/index.cjs +2 -0
- package/dist/runtime/index.d.cts +2 -1
- package/dist/runtime/index.d.ts +2 -1
- package/dist/runtime/index.js +2 -1
- package/dist/runtime/tooltipConfig.cjs +36 -0
- package/dist/runtime/tooltipConfig.d.cts +20 -0
- package/dist/runtime/tooltipConfig.d.ts +20 -0
- package/dist/runtime/tooltipConfig.js +35 -0
- package/dist/runtime/udsConfig.cjs +3 -1
- package/dist/runtime/udsConfig.d.cts +2 -0
- package/dist/runtime/udsConfig.d.ts +2 -0
- package/dist/runtime/udsConfig.js +3 -1
- package/dist/styles/styler.d.cts +51 -43
- package/dist/styles/styler.d.ts +51 -43
- package/dist/styles/variants.d.cts +24 -0
- package/dist/styles/variants.d.ts +24 -0
- package/dist/tailwind/plugins/blurBgFallback.cjs +30 -0
- package/dist/tailwind/plugins/blurBgFallback.d.cts +14 -0
- package/dist/tailwind/plugins/blurBgFallback.d.ts +14 -0
- package/dist/tailwind/plugins/blurBgFallback.js +27 -0
- package/dist/tailwind/plugins/components.cjs +1 -0
- package/dist/tailwind/plugins/components.js +2 -1
- package/dist/tailwind/tailwindPlugin.cjs +2 -1
- package/dist/tailwind/tailwindPlugin.js +2 -1
- package/dist/tailwind/utils/getShadowStyles.d.cts +4 -4
- package/dist/tailwind/utils/getShadowStyles.d.ts +4 -4
- package/dist/tailwind/utils/getTailwindAsUdsColors.d.cts +1 -1
- package/dist/tailwind/utils/getTailwindAsUdsColors.d.ts +1 -1
- package/dist/tokens/automation/configs/index.cjs +2 -1
- package/dist/tokens/automation/configs/index.d.cts +2 -2
- package/dist/tokens/automation/configs/index.d.ts +2 -2
- package/dist/tokens/automation/configs/index.js +2 -2
- package/dist/tokens/automation/index.cjs +1 -0
- package/dist/tokens/automation/index.d.cts +2 -2
- package/dist/tokens/automation/index.d.ts +2 -2
- package/dist/tokens/automation/index.js +2 -2
- package/dist/tokens/automation/properties.d.cts +2 -2
- package/dist/tokens/automation/properties.d.ts +2 -2
- package/dist/tokens/consts/cssTokens.cjs +1 -0
- package/dist/tokens/consts/cssTokens.d.cts +2 -2
- package/dist/tokens/consts/cssTokens.d.ts +2 -2
- package/dist/tokens/consts/cssTokens.js +2 -2
- package/dist/tokens/index.cjs +2 -0
- package/dist/tokens/index.d.cts +4 -4
- package/dist/tokens/index.d.ts +4 -4
- package/dist/tokens/index.js +3 -3
- package/dist/tokens/types.d.cts +2 -2
- package/dist/tokens/types.d.ts +2 -2
- package/dist/types/dist/index.d.cts +25 -2
- package/dist/types/dist/index.d.ts +25 -2
- package/dist/uds/generated/tailwindPurge.cjs +30 -2
- package/dist/uds/generated/tailwindPurge.js +30 -2
- package/package.json +1 -2
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
|
|
3
|
+
import { createContext } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/components/client/Tooltip/tooltipContext.tsx
|
|
6
|
+
/** When true, tooltip content should hide when pointer leaves anchor/tooltip. */
|
|
7
|
+
const TooltipInternalContext = createContext(null);
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { TooltipInternalContext };
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
|
|
5
|
+
const require_index = require('../../../css-tokens/dist/index.cjs');
|
|
6
|
+
const require_components_client_Tooltip_util = require('./util.cjs');
|
|
7
|
+
let react = require("react");
|
|
8
|
+
|
|
9
|
+
//#region src/components/client/Tooltip/useTooltipContent.ts
|
|
10
|
+
function useTooltipContent({ open, effectivePlacement, maxWidth, borderRadius, arrowRef }) {
|
|
11
|
+
const internalRef = (0, react.useRef)(null);
|
|
12
|
+
const shadowFilterId = (0, react.useId)();
|
|
13
|
+
const [dimensions, setDimensions] = (0, react.useState)({
|
|
14
|
+
width: 0,
|
|
15
|
+
height: 0
|
|
16
|
+
});
|
|
17
|
+
const maxWidthClass = (0, react.useMemo)(() => {
|
|
18
|
+
if (maxWidth !== void 0) return typeof maxWidth === "number" ? `max-w-[${maxWidth}px]` : `max-w-[${maxWidth}]`;
|
|
19
|
+
return "max-w-lg";
|
|
20
|
+
}, [maxWidth]);
|
|
21
|
+
(0, react.useEffect)(() => {
|
|
22
|
+
const el = internalRef.current;
|
|
23
|
+
if (!el) return;
|
|
24
|
+
const observer = new ResizeObserver(() => {
|
|
25
|
+
setDimensions({
|
|
26
|
+
width: el.offsetWidth,
|
|
27
|
+
height: el.offsetHeight
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
observer.observe(el);
|
|
31
|
+
return () => observer.disconnect();
|
|
32
|
+
}, [open]);
|
|
33
|
+
const [shadows, setShadows] = (0, react.useState)([]);
|
|
34
|
+
const shadowValueRef = (0, react.useRef)("");
|
|
35
|
+
const readShadows = (0, react.useCallback)(() => {
|
|
36
|
+
if (!internalRef.current) return;
|
|
37
|
+
const shadowValue = getComputedStyle(internalRef.current).getPropertyValue(`--${require_index.DROP_SHADOW_PREFIX}`);
|
|
38
|
+
if (shadowValue !== shadowValueRef.current) {
|
|
39
|
+
shadowValueRef.current = shadowValue;
|
|
40
|
+
setShadows(require_components_client_Tooltip_util.parseShadow(shadowValue));
|
|
41
|
+
}
|
|
42
|
+
}, []);
|
|
43
|
+
const shadowPadding = (0, react.useMemo)(() => {
|
|
44
|
+
if (shadows.length === 0) return 0;
|
|
45
|
+
return shadows.reduce((max, s) => {
|
|
46
|
+
const extentX = Math.abs(s.x) + s.blur + Math.abs(s.spread);
|
|
47
|
+
const extentY = Math.abs(s.y) + s.blur + Math.abs(s.spread);
|
|
48
|
+
return Math.max(max, extentX, extentY);
|
|
49
|
+
}, 0);
|
|
50
|
+
}, [shadows]);
|
|
51
|
+
const [arrowCenter, setArrowCenter] = (0, react.useState)(void 0);
|
|
52
|
+
const computeArrowCenter = (0, react.useCallback)(() => {
|
|
53
|
+
const arrowEl = arrowRef.current;
|
|
54
|
+
const tooltipEl = internalRef.current;
|
|
55
|
+
if (!arrowEl || !tooltipEl) return;
|
|
56
|
+
const arrowRect = arrowEl.getBoundingClientRect();
|
|
57
|
+
const tooltipRect = tooltipEl.getBoundingClientRect();
|
|
58
|
+
const side = require_components_client_Tooltip_util.getArrowSide(effectivePlacement);
|
|
59
|
+
const raw = side === "top" || side === "bottom" ? arrowRect.left + arrowRect.width / 2 - tooltipRect.left : arrowRect.top + arrowRect.height / 2 - tooltipRect.top;
|
|
60
|
+
return Math.round(raw);
|
|
61
|
+
}, [arrowRef, effectivePlacement]);
|
|
62
|
+
const onPositionUpdate = (0, react.useCallback)(async ({ updatePosition }) => {
|
|
63
|
+
await updatePosition();
|
|
64
|
+
const el = internalRef.current;
|
|
65
|
+
if (el) {
|
|
66
|
+
const { offsetWidth, offsetHeight } = el;
|
|
67
|
+
if (offsetWidth > 0 && offsetHeight > 0) setDimensions((prev) => {
|
|
68
|
+
if (prev.width === offsetWidth && prev.height === offsetHeight) return prev;
|
|
69
|
+
return {
|
|
70
|
+
width: offsetWidth,
|
|
71
|
+
height: offsetHeight
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
readShadows();
|
|
75
|
+
}
|
|
76
|
+
const next = computeArrowCenter();
|
|
77
|
+
if (next !== void 0) setArrowCenter((prev) => prev === next ? prev : next);
|
|
78
|
+
}, [computeArrowCenter, readShadows]);
|
|
79
|
+
const svgPath = (0, react.useMemo)(() => {
|
|
80
|
+
return dimensions.width > 0 && dimensions.height > 0 ? require_components_client_Tooltip_util.generateTooltipPath({
|
|
81
|
+
width: dimensions.width,
|
|
82
|
+
height: dimensions.height,
|
|
83
|
+
placement: effectivePlacement,
|
|
84
|
+
borderRadius,
|
|
85
|
+
arrowCenter
|
|
86
|
+
}) : null;
|
|
87
|
+
}, [
|
|
88
|
+
effectivePlacement,
|
|
89
|
+
dimensions.width,
|
|
90
|
+
dimensions.height,
|
|
91
|
+
borderRadius,
|
|
92
|
+
arrowCenter
|
|
93
|
+
]);
|
|
94
|
+
const blurClipPath = (0, react.useMemo)(() => {
|
|
95
|
+
if (dimensions.width <= 0 || dimensions.height <= 0) return null;
|
|
96
|
+
const arrowSide = require_components_client_Tooltip_util.getArrowSide(effectivePlacement);
|
|
97
|
+
const offsetX = arrowSide === "left" ? require_components_client_Tooltip_util.ARROW_HEIGHT : 0;
|
|
98
|
+
const offsetY = arrowSide === "top" ? require_components_client_Tooltip_util.ARROW_HEIGHT : 0;
|
|
99
|
+
return require_components_client_Tooltip_util.generateTooltipPath({
|
|
100
|
+
width: dimensions.width,
|
|
101
|
+
height: dimensions.height,
|
|
102
|
+
placement: effectivePlacement,
|
|
103
|
+
borderRadius,
|
|
104
|
+
arrowCenter,
|
|
105
|
+
offsetX,
|
|
106
|
+
offsetY
|
|
107
|
+
});
|
|
108
|
+
}, [
|
|
109
|
+
effectivePlacement,
|
|
110
|
+
dimensions.width,
|
|
111
|
+
dimensions.height,
|
|
112
|
+
borderRadius,
|
|
113
|
+
arrowCenter
|
|
114
|
+
]);
|
|
115
|
+
const blurStyle = (0, react.useMemo)(() => {
|
|
116
|
+
const style = { clipPath: blurClipPath ? `path('${blurClipPath}')` : void 0 };
|
|
117
|
+
switch (require_components_client_Tooltip_util.getArrowSide(effectivePlacement)) {
|
|
118
|
+
case "top":
|
|
119
|
+
style.height = `calc(100% + ${require_components_client_Tooltip_util.ARROW_HEIGHT}px)`;
|
|
120
|
+
style.top = "auto";
|
|
121
|
+
style.bottom = "0";
|
|
122
|
+
break;
|
|
123
|
+
case "bottom":
|
|
124
|
+
style.height = `calc(100% + ${require_components_client_Tooltip_util.ARROW_HEIGHT}px)`;
|
|
125
|
+
break;
|
|
126
|
+
case "left":
|
|
127
|
+
style.width = `calc(100% + ${require_components_client_Tooltip_util.ARROW_HEIGHT}px)`;
|
|
128
|
+
style.left = "auto";
|
|
129
|
+
style.right = "0";
|
|
130
|
+
break;
|
|
131
|
+
case "right":
|
|
132
|
+
style.width = `calc(100% + ${require_components_client_Tooltip_util.ARROW_HEIGHT}px)`;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
return style;
|
|
136
|
+
}, [blurClipPath, effectivePlacement]);
|
|
137
|
+
const [visible, setVisible] = (0, react.useState)(false);
|
|
138
|
+
if ((!open || !svgPath) && visible) setVisible(false);
|
|
139
|
+
(0, react.useEffect)(() => {
|
|
140
|
+
if (open && svgPath) {
|
|
141
|
+
const raf = requestAnimationFrame(() => {
|
|
142
|
+
setVisible(true);
|
|
143
|
+
});
|
|
144
|
+
return () => cancelAnimationFrame(raf);
|
|
145
|
+
}
|
|
146
|
+
}, [open, svgPath]);
|
|
147
|
+
return {
|
|
148
|
+
internalRef,
|
|
149
|
+
shadowFilterId,
|
|
150
|
+
maxWidthClass,
|
|
151
|
+
dimensions,
|
|
152
|
+
shadows,
|
|
153
|
+
shadowPadding,
|
|
154
|
+
svgPath,
|
|
155
|
+
blurClipPath,
|
|
156
|
+
blurStyle,
|
|
157
|
+
visible,
|
|
158
|
+
childTransitionStyle: {
|
|
159
|
+
opacity: visible ? 1 : 0,
|
|
160
|
+
transition: "opacity 200ms ease-in-out"
|
|
161
|
+
},
|
|
162
|
+
tooltipShift: (0, react.useMemo)(() => {
|
|
163
|
+
if (arrowCenter === void 0 || dimensions.width <= 0 || dimensions.height <= 0) return {
|
|
164
|
+
x: 0,
|
|
165
|
+
y: 0
|
|
166
|
+
};
|
|
167
|
+
return require_components_client_Tooltip_util.getArrowClampDelta({
|
|
168
|
+
width: dimensions.width,
|
|
169
|
+
height: dimensions.height,
|
|
170
|
+
placement: effectivePlacement,
|
|
171
|
+
borderRadius,
|
|
172
|
+
arrowCenter
|
|
173
|
+
});
|
|
174
|
+
}, [
|
|
175
|
+
arrowCenter,
|
|
176
|
+
dimensions.width,
|
|
177
|
+
dimensions.height,
|
|
178
|
+
effectivePlacement,
|
|
179
|
+
borderRadius
|
|
180
|
+
]),
|
|
181
|
+
onPositionUpdate
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
exports.useTooltipContent = useTooltipContent;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
|
|
2
|
+
import { ParsedShadow } from "./util.cjs";
|
|
3
|
+
import { CSSProperties, RefObject } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/components/client/Tooltip/useTooltipContent.d.ts
|
|
6
|
+
interface UseTooltipContentOptions {
|
|
7
|
+
/** Whether the tooltip is currently open. */
|
|
8
|
+
open: boolean;
|
|
9
|
+
/** Resolved placement after Ariakit positioning (e.g. `'top'`, `'bottom-start'`). */
|
|
10
|
+
effectivePlacement: string;
|
|
11
|
+
/** Optional max-width override (number = px, string = CSS value). */
|
|
12
|
+
maxWidth?: number | string;
|
|
13
|
+
/** Border-radius from the tooltip config (px). */
|
|
14
|
+
borderRadius: number;
|
|
15
|
+
/**
|
|
16
|
+
* Ref to the Ariakit `TooltipArrow` element. Its position (set by
|
|
17
|
+
* floating-ui) is read inside the `updatePosition` callback so the
|
|
18
|
+
* SVG arrow always mirrors where floating-ui places the native arrow.
|
|
19
|
+
*/
|
|
20
|
+
arrowRef: RefObject<HTMLDivElement | null>;
|
|
21
|
+
}
|
|
22
|
+
interface UseTooltipContentReturn {
|
|
23
|
+
internalRef: RefObject<HTMLElement | null>;
|
|
24
|
+
shadowFilterId: string;
|
|
25
|
+
maxWidthClass: string;
|
|
26
|
+
dimensions: {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
shadows: ParsedShadow[];
|
|
31
|
+
shadowPadding: number;
|
|
32
|
+
svgPath: string | null;
|
|
33
|
+
blurClipPath: string | null;
|
|
34
|
+
blurStyle: CSSProperties;
|
|
35
|
+
visible: boolean;
|
|
36
|
+
childTransitionStyle: CSSProperties;
|
|
37
|
+
/**
|
|
38
|
+
* Pixel offset to apply as a CSS transform on the tooltip element so that
|
|
39
|
+
* the (clamped) SVG arrow aligns with the trigger center even when the
|
|
40
|
+
* trigger is too small / close to a rounded corner for the arrow to reach.
|
|
41
|
+
*/
|
|
42
|
+
tooltipShift: {
|
|
43
|
+
x: number;
|
|
44
|
+
y: number;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Pass as the `updatePosition` prop to the Ariakit `<Tooltip>` component.
|
|
48
|
+
* This hooks into floating-ui's positioning lifecycle so the SVG arrow
|
|
49
|
+
* center is read after every `computePosition`
|
|
50
|
+
*/
|
|
51
|
+
onPositionUpdate: (props: {
|
|
52
|
+
updatePosition: () => Promise<void>;
|
|
53
|
+
}) => Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
declare function useTooltipContent({
|
|
56
|
+
open,
|
|
57
|
+
effectivePlacement,
|
|
58
|
+
maxWidth,
|
|
59
|
+
borderRadius,
|
|
60
|
+
arrowRef
|
|
61
|
+
}: UseTooltipContentOptions): UseTooltipContentReturn;
|
|
62
|
+
//#endregion
|
|
63
|
+
export { type UseTooltipContentOptions, type UseTooltipContentReturn, useTooltipContent };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
|
|
2
|
+
import { ParsedShadow } from "./util.js";
|
|
3
|
+
import { CSSProperties, RefObject } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/components/client/Tooltip/useTooltipContent.d.ts
|
|
6
|
+
interface UseTooltipContentOptions {
|
|
7
|
+
/** Whether the tooltip is currently open. */
|
|
8
|
+
open: boolean;
|
|
9
|
+
/** Resolved placement after Ariakit positioning (e.g. `'top'`, `'bottom-start'`). */
|
|
10
|
+
effectivePlacement: string;
|
|
11
|
+
/** Optional max-width override (number = px, string = CSS value). */
|
|
12
|
+
maxWidth?: number | string;
|
|
13
|
+
/** Border-radius from the tooltip config (px). */
|
|
14
|
+
borderRadius: number;
|
|
15
|
+
/**
|
|
16
|
+
* Ref to the Ariakit `TooltipArrow` element. Its position (set by
|
|
17
|
+
* floating-ui) is read inside the `updatePosition` callback so the
|
|
18
|
+
* SVG arrow always mirrors where floating-ui places the native arrow.
|
|
19
|
+
*/
|
|
20
|
+
arrowRef: RefObject<HTMLDivElement | null>;
|
|
21
|
+
}
|
|
22
|
+
interface UseTooltipContentReturn {
|
|
23
|
+
internalRef: RefObject<HTMLElement | null>;
|
|
24
|
+
shadowFilterId: string;
|
|
25
|
+
maxWidthClass: string;
|
|
26
|
+
dimensions: {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
shadows: ParsedShadow[];
|
|
31
|
+
shadowPadding: number;
|
|
32
|
+
svgPath: string | null;
|
|
33
|
+
blurClipPath: string | null;
|
|
34
|
+
blurStyle: CSSProperties;
|
|
35
|
+
visible: boolean;
|
|
36
|
+
childTransitionStyle: CSSProperties;
|
|
37
|
+
/**
|
|
38
|
+
* Pixel offset to apply as a CSS transform on the tooltip element so that
|
|
39
|
+
* the (clamped) SVG arrow aligns with the trigger center even when the
|
|
40
|
+
* trigger is too small / close to a rounded corner for the arrow to reach.
|
|
41
|
+
*/
|
|
42
|
+
tooltipShift: {
|
|
43
|
+
x: number;
|
|
44
|
+
y: number;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Pass as the `updatePosition` prop to the Ariakit `<Tooltip>` component.
|
|
48
|
+
* This hooks into floating-ui's positioning lifecycle so the SVG arrow
|
|
49
|
+
* center is read after every `computePosition`
|
|
50
|
+
*/
|
|
51
|
+
onPositionUpdate: (props: {
|
|
52
|
+
updatePosition: () => Promise<void>;
|
|
53
|
+
}) => Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
declare function useTooltipContent({
|
|
56
|
+
open,
|
|
57
|
+
effectivePlacement,
|
|
58
|
+
maxWidth,
|
|
59
|
+
borderRadius,
|
|
60
|
+
arrowRef
|
|
61
|
+
}: UseTooltipContentOptions): UseTooltipContentReturn;
|
|
62
|
+
//#endregion
|
|
63
|
+
export { type UseTooltipContentOptions, type UseTooltipContentReturn, useTooltipContent };
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
|
|
3
|
+
import { DROP_SHADOW_PREFIX } from "../../../css-tokens/dist/index.js";
|
|
4
|
+
import { ARROW_HEIGHT, generateTooltipPath, getArrowClampDelta, getArrowSide, parseShadow } from "./util.js";
|
|
5
|
+
import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
6
|
+
|
|
7
|
+
//#region src/components/client/Tooltip/useTooltipContent.ts
|
|
8
|
+
function useTooltipContent({ open, effectivePlacement, maxWidth, borderRadius, arrowRef }) {
|
|
9
|
+
const internalRef = useRef(null);
|
|
10
|
+
const shadowFilterId = useId();
|
|
11
|
+
const [dimensions, setDimensions] = useState({
|
|
12
|
+
width: 0,
|
|
13
|
+
height: 0
|
|
14
|
+
});
|
|
15
|
+
const maxWidthClass = useMemo(() => {
|
|
16
|
+
if (maxWidth !== void 0) return typeof maxWidth === "number" ? `max-w-[${maxWidth}px]` : `max-w-[${maxWidth}]`;
|
|
17
|
+
return "max-w-lg";
|
|
18
|
+
}, [maxWidth]);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const el = internalRef.current;
|
|
21
|
+
if (!el) return;
|
|
22
|
+
const observer = new ResizeObserver(() => {
|
|
23
|
+
setDimensions({
|
|
24
|
+
width: el.offsetWidth,
|
|
25
|
+
height: el.offsetHeight
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
observer.observe(el);
|
|
29
|
+
return () => observer.disconnect();
|
|
30
|
+
}, [open]);
|
|
31
|
+
const [shadows, setShadows] = useState([]);
|
|
32
|
+
const shadowValueRef = useRef("");
|
|
33
|
+
const readShadows = useCallback(() => {
|
|
34
|
+
if (!internalRef.current) return;
|
|
35
|
+
const shadowValue = getComputedStyle(internalRef.current).getPropertyValue(`--${DROP_SHADOW_PREFIX}`);
|
|
36
|
+
if (shadowValue !== shadowValueRef.current) {
|
|
37
|
+
shadowValueRef.current = shadowValue;
|
|
38
|
+
setShadows(parseShadow(shadowValue));
|
|
39
|
+
}
|
|
40
|
+
}, []);
|
|
41
|
+
const shadowPadding = useMemo(() => {
|
|
42
|
+
if (shadows.length === 0) return 0;
|
|
43
|
+
return shadows.reduce((max, s) => {
|
|
44
|
+
const extentX = Math.abs(s.x) + s.blur + Math.abs(s.spread);
|
|
45
|
+
const extentY = Math.abs(s.y) + s.blur + Math.abs(s.spread);
|
|
46
|
+
return Math.max(max, extentX, extentY);
|
|
47
|
+
}, 0);
|
|
48
|
+
}, [shadows]);
|
|
49
|
+
const [arrowCenter, setArrowCenter] = useState(void 0);
|
|
50
|
+
const computeArrowCenter = useCallback(() => {
|
|
51
|
+
const arrowEl = arrowRef.current;
|
|
52
|
+
const tooltipEl = internalRef.current;
|
|
53
|
+
if (!arrowEl || !tooltipEl) return;
|
|
54
|
+
const arrowRect = arrowEl.getBoundingClientRect();
|
|
55
|
+
const tooltipRect = tooltipEl.getBoundingClientRect();
|
|
56
|
+
const side = getArrowSide(effectivePlacement);
|
|
57
|
+
const raw = side === "top" || side === "bottom" ? arrowRect.left + arrowRect.width / 2 - tooltipRect.left : arrowRect.top + arrowRect.height / 2 - tooltipRect.top;
|
|
58
|
+
return Math.round(raw);
|
|
59
|
+
}, [arrowRef, effectivePlacement]);
|
|
60
|
+
const onPositionUpdate = useCallback(async ({ updatePosition }) => {
|
|
61
|
+
await updatePosition();
|
|
62
|
+
const el = internalRef.current;
|
|
63
|
+
if (el) {
|
|
64
|
+
const { offsetWidth, offsetHeight } = el;
|
|
65
|
+
if (offsetWidth > 0 && offsetHeight > 0) setDimensions((prev) => {
|
|
66
|
+
if (prev.width === offsetWidth && prev.height === offsetHeight) return prev;
|
|
67
|
+
return {
|
|
68
|
+
width: offsetWidth,
|
|
69
|
+
height: offsetHeight
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
readShadows();
|
|
73
|
+
}
|
|
74
|
+
const next = computeArrowCenter();
|
|
75
|
+
if (next !== void 0) setArrowCenter((prev) => prev === next ? prev : next);
|
|
76
|
+
}, [computeArrowCenter, readShadows]);
|
|
77
|
+
const svgPath = useMemo(() => {
|
|
78
|
+
return dimensions.width > 0 && dimensions.height > 0 ? generateTooltipPath({
|
|
79
|
+
width: dimensions.width,
|
|
80
|
+
height: dimensions.height,
|
|
81
|
+
placement: effectivePlacement,
|
|
82
|
+
borderRadius,
|
|
83
|
+
arrowCenter
|
|
84
|
+
}) : null;
|
|
85
|
+
}, [
|
|
86
|
+
effectivePlacement,
|
|
87
|
+
dimensions.width,
|
|
88
|
+
dimensions.height,
|
|
89
|
+
borderRadius,
|
|
90
|
+
arrowCenter
|
|
91
|
+
]);
|
|
92
|
+
const blurClipPath = useMemo(() => {
|
|
93
|
+
if (dimensions.width <= 0 || dimensions.height <= 0) return null;
|
|
94
|
+
const arrowSide = getArrowSide(effectivePlacement);
|
|
95
|
+
const offsetX = arrowSide === "left" ? ARROW_HEIGHT : 0;
|
|
96
|
+
const offsetY = arrowSide === "top" ? ARROW_HEIGHT : 0;
|
|
97
|
+
return generateTooltipPath({
|
|
98
|
+
width: dimensions.width,
|
|
99
|
+
height: dimensions.height,
|
|
100
|
+
placement: effectivePlacement,
|
|
101
|
+
borderRadius,
|
|
102
|
+
arrowCenter,
|
|
103
|
+
offsetX,
|
|
104
|
+
offsetY
|
|
105
|
+
});
|
|
106
|
+
}, [
|
|
107
|
+
effectivePlacement,
|
|
108
|
+
dimensions.width,
|
|
109
|
+
dimensions.height,
|
|
110
|
+
borderRadius,
|
|
111
|
+
arrowCenter
|
|
112
|
+
]);
|
|
113
|
+
const blurStyle = useMemo(() => {
|
|
114
|
+
const style = { clipPath: blurClipPath ? `path('${blurClipPath}')` : void 0 };
|
|
115
|
+
switch (getArrowSide(effectivePlacement)) {
|
|
116
|
+
case "top":
|
|
117
|
+
style.height = `calc(100% + ${ARROW_HEIGHT}px)`;
|
|
118
|
+
style.top = "auto";
|
|
119
|
+
style.bottom = "0";
|
|
120
|
+
break;
|
|
121
|
+
case "bottom":
|
|
122
|
+
style.height = `calc(100% + ${ARROW_HEIGHT}px)`;
|
|
123
|
+
break;
|
|
124
|
+
case "left":
|
|
125
|
+
style.width = `calc(100% + ${ARROW_HEIGHT}px)`;
|
|
126
|
+
style.left = "auto";
|
|
127
|
+
style.right = "0";
|
|
128
|
+
break;
|
|
129
|
+
case "right":
|
|
130
|
+
style.width = `calc(100% + ${ARROW_HEIGHT}px)`;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
return style;
|
|
134
|
+
}, [blurClipPath, effectivePlacement]);
|
|
135
|
+
const [visible, setVisible] = useState(false);
|
|
136
|
+
if ((!open || !svgPath) && visible) setVisible(false);
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (open && svgPath) {
|
|
139
|
+
const raf = requestAnimationFrame(() => {
|
|
140
|
+
setVisible(true);
|
|
141
|
+
});
|
|
142
|
+
return () => cancelAnimationFrame(raf);
|
|
143
|
+
}
|
|
144
|
+
}, [open, svgPath]);
|
|
145
|
+
return {
|
|
146
|
+
internalRef,
|
|
147
|
+
shadowFilterId,
|
|
148
|
+
maxWidthClass,
|
|
149
|
+
dimensions,
|
|
150
|
+
shadows,
|
|
151
|
+
shadowPadding,
|
|
152
|
+
svgPath,
|
|
153
|
+
blurClipPath,
|
|
154
|
+
blurStyle,
|
|
155
|
+
visible,
|
|
156
|
+
childTransitionStyle: {
|
|
157
|
+
opacity: visible ? 1 : 0,
|
|
158
|
+
transition: "opacity 200ms ease-in-out"
|
|
159
|
+
},
|
|
160
|
+
tooltipShift: useMemo(() => {
|
|
161
|
+
if (arrowCenter === void 0 || dimensions.width <= 0 || dimensions.height <= 0) return {
|
|
162
|
+
x: 0,
|
|
163
|
+
y: 0
|
|
164
|
+
};
|
|
165
|
+
return getArrowClampDelta({
|
|
166
|
+
width: dimensions.width,
|
|
167
|
+
height: dimensions.height,
|
|
168
|
+
placement: effectivePlacement,
|
|
169
|
+
borderRadius,
|
|
170
|
+
arrowCenter
|
|
171
|
+
});
|
|
172
|
+
}, [
|
|
173
|
+
arrowCenter,
|
|
174
|
+
dimensions.width,
|
|
175
|
+
dimensions.height,
|
|
176
|
+
effectivePlacement,
|
|
177
|
+
borderRadius
|
|
178
|
+
]),
|
|
179
|
+
onPositionUpdate
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
//#endregion
|
|
184
|
+
export { useTooltipContent };
|