@yahoo/uds 3.116.0-beta.2 → 3.116.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.
Files changed (187) hide show
  1. package/dist/automated-config/dist/generated/autoVariants.cjs +0 -10
  2. package/dist/automated-config/dist/generated/autoVariants.d.cts +0 -10
  3. package/dist/automated-config/dist/generated/autoVariants.d.ts +0 -10
  4. package/dist/automated-config/dist/generated/autoVariants.js +0 -10
  5. package/dist/automated-config/dist/generated/generatedConfigs.cjs +0 -1842
  6. package/dist/automated-config/dist/generated/generatedConfigs.d.cts +1 -194
  7. package/dist/automated-config/dist/generated/generatedConfigs.d.ts +1 -194
  8. package/dist/automated-config/dist/generated/generatedConfigs.js +1 -1842
  9. package/dist/automated-config/dist/generated/universalTokensConfigAuto.cjs +0 -78
  10. package/dist/automated-config/dist/generated/universalTokensConfigAuto.d.cts +1 -2
  11. package/dist/automated-config/dist/generated/universalTokensConfigAuto.d.ts +1 -2
  12. package/dist/automated-config/dist/generated/universalTokensConfigAuto.js +0 -78
  13. package/dist/cli/commands/sync.cjs +0 -6
  14. package/dist/cli/commands/sync.js +0 -6
  15. package/dist/components/client/Toast/Toast.cjs +3 -3
  16. package/dist/components/client/Toast/Toast.d.cts +1 -1
  17. package/dist/components/client/Toast/Toast.d.ts +1 -1
  18. package/dist/components/client/Toast/Toast.js +3 -3
  19. package/dist/components/client/Toast/UDSToastConfigProvider.d.cts +5 -5
  20. package/dist/components/client/Toast/UDSToastConfigProvider.d.ts +5 -5
  21. package/dist/components/client/Toast/index.d.cts +1 -1
  22. package/dist/components/client/Toast/index.d.ts +1 -1
  23. package/dist/components/client/Tooltip/Tooltip.cjs +6 -6
  24. package/dist/components/client/Tooltip/Tooltip.d.cts +1 -1
  25. package/dist/components/client/Tooltip/Tooltip.d.ts +1 -1
  26. package/dist/components/client/Tooltip/Tooltip.js +6 -6
  27. package/dist/components/client/Tooltip/TooltipContent.cjs +119 -55
  28. package/dist/components/client/Tooltip/TooltipContent.js +120 -56
  29. package/dist/components/client/Tooltip/tooltipContext.cjs +1 -0
  30. package/dist/components/client/Tooltip/tooltipContext.d.cts +2 -1
  31. package/dist/components/client/Tooltip/tooltipContext.d.ts +2 -1
  32. package/dist/components/client/Tooltip/tooltipContext.js +1 -0
  33. package/dist/{hooks/useSvgFloatingContent.cjs → components/client/Tooltip/useTooltipContent.cjs} +48 -81
  34. package/dist/components/client/Tooltip/useTooltipContent.d.cts +66 -0
  35. package/dist/components/client/Tooltip/useTooltipContent.d.ts +66 -0
  36. package/dist/{hooks/useSvgFloatingContent.js → components/client/Tooltip/useTooltipContent.js} +43 -76
  37. package/dist/components/client/Tooltip/util.cjs +248 -0
  38. package/dist/{utils/svgFloatingContentUtils.d.cts → components/client/Tooltip/util.d.cts} +62 -25
  39. package/dist/{utils/svgFloatingContentUtils.d.ts → components/client/Tooltip/util.d.ts} +62 -25
  40. package/dist/components/client/Tooltip/util.js +240 -0
  41. package/dist/components/client/index.cjs +0 -8
  42. package/dist/components/client/index.d.cts +5 -10
  43. package/dist/components/client/index.d.ts +5 -10
  44. package/dist/components/client/index.js +1 -5
  45. package/dist/components/client/providers/UDSConfigProvider.cjs +2 -6
  46. package/dist/components/client/providers/UDSConfigProvider.d.cts +1 -2
  47. package/dist/components/client/providers/UDSConfigProvider.d.ts +1 -2
  48. package/dist/components/client/providers/UDSConfigProvider.js +2 -6
  49. package/dist/components/experimental/client/{ExperimentalPopover.cjs → Popover.cjs} +1 -10
  50. package/dist/components/experimental/client/Popover.d.cts +29 -0
  51. package/dist/components/experimental/client/Popover.d.ts +29 -0
  52. package/dist/components/experimental/client/{ExperimentalPopover.js → Popover.js} +1 -10
  53. package/dist/components/experimental/client/index.cjs +10 -10
  54. package/dist/components/experimental/client/index.d.cts +2 -2
  55. package/dist/components/experimental/client/index.d.ts +2 -2
  56. package/dist/components/experimental/client/index.js +1 -1
  57. package/dist/components/experimental/index.cjs +19 -19
  58. package/dist/components/experimental/index.d.cts +2 -2
  59. package/dist/components/experimental/index.d.ts +2 -2
  60. package/dist/components/experimental/index.js +1 -1
  61. package/dist/components/index.cjs +0 -12
  62. package/dist/components/index.d.cts +5 -9
  63. package/dist/components/index.d.ts +5 -9
  64. package/dist/components/index.js +1 -9
  65. package/dist/config/dist/index.cjs +1 -79
  66. package/dist/config/dist/index.js +1 -79
  67. package/dist/index.cjs +10 -21
  68. package/dist/index.d.cts +10 -15
  69. package/dist/index.d.ts +10 -15
  70. package/dist/index.js +11 -16
  71. package/dist/runtime/index.cjs +0 -2
  72. package/dist/runtime/index.d.cts +2 -3
  73. package/dist/runtime/index.d.ts +2 -3
  74. package/dist/runtime/index.js +1 -2
  75. package/dist/runtime/udsConfig.cjs +1 -3
  76. package/dist/runtime/udsConfig.d.cts +1 -3
  77. package/dist/runtime/udsConfig.d.ts +1 -3
  78. package/dist/runtime/udsConfig.js +1 -3
  79. package/dist/styles/styler.d.cts +96 -106
  80. package/dist/styles/styler.d.ts +96 -106
  81. package/dist/styles/variants.d.cts +0 -30
  82. package/dist/styles/variants.d.ts +0 -30
  83. package/dist/tailwind/dist/commands/css.helpers.cjs +6 -2
  84. package/dist/tailwind/dist/commands/css.helpers.js +6 -2
  85. package/dist/tailwind/dist/commands/generateComponentData.cjs +2 -0
  86. package/dist/tailwind/dist/commands/generateComponentData.js +3 -1
  87. package/dist/tailwind/dist/commands/generatePurgeCSSData.cjs +3 -8
  88. package/dist/tailwind/dist/commands/generatePurgeCSSData.js +3 -8
  89. package/dist/tailwind/dist/commands/purge.cjs +2 -2
  90. package/dist/tailwind/dist/commands/purge.js +2 -2
  91. package/dist/tailwind/dist/css/generate.cjs +6 -4
  92. package/dist/tailwind/dist/css/generate.helpers.cjs +4 -1
  93. package/dist/tailwind/dist/css/generate.helpers.js +4 -1
  94. package/dist/tailwind/dist/css/generate.js +7 -5
  95. package/dist/tailwind/dist/css/nodeUtils.cjs +30 -2
  96. package/dist/tailwind/dist/css/nodeUtils.js +30 -3
  97. package/dist/tailwind/dist/css/runner.cjs +52 -19
  98. package/dist/tailwind/dist/css/runner.helpers.cjs +2 -2
  99. package/dist/tailwind/dist/css/runner.helpers.js +2 -2
  100. package/dist/tailwind/dist/css/runner.js +53 -20
  101. package/dist/tailwind/dist/css/theme.d.cts +2 -2
  102. package/dist/tailwind/dist/css/theme.d.ts +2 -2
  103. package/dist/tailwind/dist/purger/legacy/purgeCSS.cjs +19 -8
  104. package/dist/tailwind/dist/purger/legacy/purgeCSS.js +19 -8
  105. package/dist/tailwind/dist/purger/optimized/purge.cjs +2 -1
  106. package/dist/tailwind/dist/purger/optimized/purge.js +2 -1
  107. package/dist/tailwind/dist/purger/optimized/purgeFromCode.cjs +22 -2
  108. package/dist/tailwind/dist/purger/optimized/purgeFromCode.js +22 -2
  109. package/dist/tailwind/dist/purger/optimized/utils/componentAnalyzer.cjs +5 -4
  110. package/dist/tailwind/dist/purger/optimized/utils/componentAnalyzer.js +5 -4
  111. package/dist/tailwind/dist/purger/optimized/utils/files.cjs +12 -10
  112. package/dist/tailwind/dist/purger/optimized/utils/files.js +12 -9
  113. package/dist/tailwind/dist/tailwind/plugins/components.cjs +0 -1
  114. package/dist/tailwind/dist/tailwind/plugins/components.js +1 -2
  115. package/dist/tailwind/dist/tailwind/plugins/getTailwindAsUdsColors.cjs +294 -10
  116. package/dist/tailwind/dist/tailwind/plugins/getTailwindAsUdsColors.js +294 -9
  117. package/dist/tailwind/dist/utils/entryPoints.cjs +63 -0
  118. package/dist/tailwind/dist/utils/entryPoints.js +55 -0
  119. package/dist/tokens/automation/configs/index.cjs +0 -1
  120. package/dist/tokens/automation/configs/index.d.cts +2 -2
  121. package/dist/tokens/automation/configs/index.d.ts +2 -2
  122. package/dist/tokens/automation/configs/index.js +2 -2
  123. package/dist/tokens/automation/index.cjs +0 -1
  124. package/dist/tokens/automation/index.d.cts +2 -2
  125. package/dist/tokens/automation/index.d.ts +2 -2
  126. package/dist/tokens/automation/index.js +2 -2
  127. package/dist/tokens/index.cjs +1 -2
  128. package/dist/tokens/index.d.cts +3 -3
  129. package/dist/tokens/index.d.ts +3 -3
  130. package/dist/tokens/index.js +3 -3
  131. package/dist/tokens/types.d.cts +2 -2
  132. package/dist/tokens/types.d.ts +2 -2
  133. package/dist/types/dist/index.d.cts +1 -51
  134. package/dist/types/dist/index.d.ts +1 -51
  135. package/dist/uds/generated/componentData.cjs +887 -1029
  136. package/dist/uds/generated/componentData.js +840 -952
  137. package/dist/uds/generated/tailwindPurge.cjs +221 -247
  138. package/dist/uds/generated/tailwindPurge.js +221 -247
  139. package/dist/uds/package.cjs +1 -1
  140. package/dist/uds/package.js +1 -1
  141. package/generated/componentData.json +1195 -1337
  142. package/generated/tailwindPurge.ts +5 -4604
  143. package/package.json +2 -2
  144. package/dist/components/SvgFloatingOverlay.cjs +0 -122
  145. package/dist/components/SvgFloatingOverlay.d.cts +0 -42
  146. package/dist/components/SvgFloatingOverlay.d.ts +0 -42
  147. package/dist/components/SvgFloatingOverlay.js +0 -120
  148. package/dist/components/client/Popover/Popover.cjs +0 -96
  149. package/dist/components/client/Popover/Popover.d.cts +0 -55
  150. package/dist/components/client/Popover/Popover.d.ts +0 -55
  151. package/dist/components/client/Popover/Popover.js +0 -94
  152. package/dist/components/client/Popover/PopoverContent.cjs +0 -171
  153. package/dist/components/client/Popover/PopoverContent.d.cts +0 -26
  154. package/dist/components/client/Popover/PopoverContent.d.ts +0 -26
  155. package/dist/components/client/Popover/PopoverContent.js +0 -169
  156. package/dist/components/client/Popover/PopoverContext.cjs +0 -11
  157. package/dist/components/client/Popover/PopoverContext.d.cts +0 -21
  158. package/dist/components/client/Popover/PopoverContext.d.ts +0 -21
  159. package/dist/components/client/Popover/PopoverContext.js +0 -9
  160. package/dist/components/client/Popover/PopoverTrigger.cjs +0 -26
  161. package/dist/components/client/Popover/PopoverTrigger.d.cts +0 -14
  162. package/dist/components/client/Popover/PopoverTrigger.d.ts +0 -14
  163. package/dist/components/client/Popover/PopoverTrigger.js +0 -24
  164. package/dist/components/client/Popover/UDSPopoverConfigProvider.cjs +0 -40
  165. package/dist/components/client/Popover/UDSPopoverConfigProvider.d.cts +0 -28
  166. package/dist/components/client/Popover/UDSPopoverConfigProvider.d.ts +0 -28
  167. package/dist/components/client/Popover/UDSPopoverConfigProvider.js +0 -37
  168. package/dist/components/client/Popover/index.cjs +0 -12
  169. package/dist/components/client/Popover/index.d.cts +0 -7
  170. package/dist/components/client/Popover/index.d.ts +0 -7
  171. package/dist/components/client/Popover/index.js +0 -8
  172. package/dist/components/experimental/client/ExperimentalPopover.d.cts +0 -40
  173. package/dist/components/experimental/client/ExperimentalPopover.d.ts +0 -40
  174. package/dist/hooks/useSvgFloatingContent.d.cts +0 -74
  175. package/dist/hooks/useSvgFloatingContent.d.ts +0 -74
  176. package/dist/runtime/popoverConfig.cjs +0 -41
  177. package/dist/runtime/popoverConfig.d.cts +0 -24
  178. package/dist/runtime/popoverConfig.d.ts +0 -24
  179. package/dist/runtime/popoverConfig.js +0 -40
  180. package/dist/tailwind/dist/.prettierrc.cjs +0 -13
  181. package/dist/tailwind/dist/.prettierrc.js +0 -12
  182. package/dist/utils/parseShadow.cjs +0 -120
  183. package/dist/utils/parseShadow.d.cts +0 -33
  184. package/dist/utils/parseShadow.d.ts +0 -33
  185. package/dist/utils/parseShadow.js +0 -118
  186. package/dist/utils/svgFloatingContentUtils.cjs +0 -121
  187. package/dist/utils/svgFloatingContentUtils.js +0 -117
@@ -1,17 +1,21 @@
1
+ "use client";
1
2
  /*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
2
- import { DROP_SHADOW_PREFIX } from "../css-tokens/dist/index.js";
3
- import { parseShadow } from "../utils/parseShadow.js";
4
- import { generateSvgFloatingContentPath, getArrowClampDelta, getArrowSide } from "../utils/svgFloatingContentUtils.js";
3
+ import { DROP_SHADOW_PREFIX } from "../../../css-tokens/dist/index.js";
4
+ import { ARROW_HEIGHT, generateTooltipPath, getArrowClampDelta, getArrowSide, parseShadow } from "./util.js";
5
5
  import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
6
6
 
7
- //#region src/hooks/useSvgFloatingContent.ts
8
- function useSvgFloatingContent({ open, effectivePlacement, borderRadius, arrowRef, animationDuration, hideArrow = false, arrowWidth, arrowHeight, arrowTipRadiusFraction }) {
7
+ //#region src/components/client/Tooltip/useTooltipContent.ts
8
+ function useTooltipContent({ open, effectivePlacement, maxWidth, borderRadius, arrowRef, animationDuration }) {
9
9
  const internalRef = useRef(null);
10
10
  const shadowFilterId = useId();
11
11
  const [dimensions, setDimensions] = useState({
12
12
  width: 0,
13
13
  height: 0
14
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]);
15
19
  useEffect(() => {
16
20
  const el = internalRef.current;
17
21
  if (!el) return;
@@ -45,12 +49,12 @@ function useSvgFloatingContent({ open, effectivePlacement, borderRadius, arrowRe
45
49
  const [arrowCenter, setArrowCenter] = useState(void 0);
46
50
  const computeArrowCenter = useCallback(() => {
47
51
  const arrowEl = arrowRef.current;
48
- const el = internalRef.current;
49
- if (!arrowEl || !el) return;
52
+ const tooltipEl = internalRef.current;
53
+ if (!arrowEl || !tooltipEl) return;
50
54
  const arrowRect = arrowEl.getBoundingClientRect();
51
- const rect = el.getBoundingClientRect();
55
+ const tooltipRect = tooltipEl.getBoundingClientRect();
52
56
  const side = getArrowSide(effectivePlacement);
53
- const raw = side === "top" || side === "bottom" ? arrowRect.left + arrowRect.width / 2 - rect.left : arrowRect.top + arrowRect.height / 2 - rect.top;
57
+ const raw = side === "top" || side === "bottom" ? arrowRect.left + arrowRect.width / 2 - tooltipRect.left : arrowRect.top + arrowRect.height / 2 - tooltipRect.top;
54
58
  return Math.round(raw);
55
59
  }, [arrowRef, effectivePlacement]);
56
60
  const onPositionUpdate = useCallback(async ({ updatePosition }) => {
@@ -67,115 +71,81 @@ function useSvgFloatingContent({ open, effectivePlacement, borderRadius, arrowRe
67
71
  });
68
72
  readShadows();
69
73
  }
70
- if (!hideArrow) {
71
- const next = computeArrowCenter();
72
- if (next !== void 0) setArrowCenter((prev) => prev === next ? prev : next);
73
- }
74
- }, [
75
- computeArrowCenter,
76
- readShadows,
77
- hideArrow
78
- ]);
74
+ const next = computeArrowCenter();
75
+ if (next !== void 0) setArrowCenter((prev) => prev === next ? prev : next);
76
+ }, [computeArrowCenter, readShadows]);
79
77
  const svgPath = useMemo(() => {
80
- return dimensions.width > 0 && dimensions.height > 0 ? generateSvgFloatingContentPath({
78
+ return dimensions.width > 0 && dimensions.height > 0 ? generateTooltipPath({
81
79
  width: dimensions.width,
82
80
  height: dimensions.height,
83
81
  placement: effectivePlacement,
84
82
  borderRadius,
85
- arrowCenter: hideArrow ? void 0 : arrowCenter,
86
- arrowWidth,
87
- arrowHeight,
88
- arrowTipRadiusFraction,
89
- ...hideArrow && {
90
- arrowWidth: 0,
91
- arrowHeight: 0
92
- }
83
+ arrowCenter
93
84
  }) : null;
94
85
  }, [
95
86
  effectivePlacement,
96
87
  dimensions.width,
97
88
  dimensions.height,
98
89
  borderRadius,
99
- arrowCenter,
100
- hideArrow,
101
- arrowWidth,
102
- arrowHeight,
103
- arrowTipRadiusFraction
90
+ arrowCenter
104
91
  ]);
105
92
  const blurClipPath = useMemo(() => {
106
93
  if (dimensions.width <= 0 || dimensions.height <= 0) return null;
107
- if (hideArrow) return generateSvgFloatingContentPath({
108
- width: dimensions.width,
109
- height: dimensions.height,
110
- placement: effectivePlacement,
111
- borderRadius,
112
- arrowWidth: 0,
113
- arrowHeight: 0,
114
- arrowTipRadiusFraction
115
- });
116
94
  const arrowSide = getArrowSide(effectivePlacement);
117
- const offsetX = arrowSide === "left" ? arrowHeight : 0;
118
- const offsetY = arrowSide === "top" ? arrowHeight : 0;
119
- return generateSvgFloatingContentPath({
95
+ const offsetX = arrowSide === "left" ? ARROW_HEIGHT : 0;
96
+ const offsetY = arrowSide === "top" ? ARROW_HEIGHT : 0;
97
+ return generateTooltipPath({
120
98
  width: dimensions.width,
121
99
  height: dimensions.height,
122
100
  placement: effectivePlacement,
123
101
  borderRadius,
124
102
  arrowCenter,
125
103
  offsetX,
126
- offsetY,
127
- arrowWidth,
128
- arrowHeight,
129
- arrowTipRadiusFraction
104
+ offsetY
130
105
  });
131
106
  }, [
132
107
  effectivePlacement,
133
108
  dimensions.width,
134
109
  dimensions.height,
135
110
  borderRadius,
136
- arrowCenter,
137
- hideArrow,
138
- arrowHeight,
139
- arrowWidth,
140
- arrowTipRadiusFraction
111
+ arrowCenter
141
112
  ]);
142
113
  const blurStyle = useMemo(() => {
143
114
  const style = { clipPath: blurClipPath ? `path('${blurClipPath}')` : void 0 };
144
- if (!hideArrow) switch (getArrowSide(effectivePlacement)) {
115
+ switch (getArrowSide(effectivePlacement)) {
145
116
  case "top":
146
- style.height = `calc(100% + ${arrowHeight}px)`;
117
+ style.height = `calc(100% + ${ARROW_HEIGHT}px)`;
147
118
  style.top = "auto";
148
119
  style.bottom = "0";
149
120
  break;
150
121
  case "bottom":
151
- style.height = `calc(100% + ${arrowHeight}px)`;
122
+ style.height = `calc(100% + ${ARROW_HEIGHT}px)`;
152
123
  break;
153
124
  case "left":
154
- style.width = `calc(100% + ${arrowHeight}px)`;
125
+ style.width = `calc(100% + ${ARROW_HEIGHT}px)`;
155
126
  style.left = "auto";
156
127
  style.right = "0";
157
128
  break;
158
129
  case "right":
159
- style.width = `calc(100% + ${arrowHeight}px)`;
130
+ style.width = `calc(100% + ${ARROW_HEIGHT}px)`;
160
131
  break;
161
132
  }
162
133
  return style;
163
- }, [
164
- blurClipPath,
165
- effectivePlacement,
166
- hideArrow,
167
- arrowHeight
168
- ]);
134
+ }, [blurClipPath, effectivePlacement]);
169
135
  const [visible, setVisible] = useState(false);
136
+ if ((!open || !svgPath) && visible) setVisible(false);
170
137
  useEffect(() => {
171
- const raf = requestAnimationFrame(() => {
172
- setVisible(open && !!svgPath);
173
- });
174
- return () => cancelAnimationFrame(raf);
138
+ if (open && svgPath) {
139
+ const raf = requestAnimationFrame(() => {
140
+ setVisible(true);
141
+ });
142
+ return () => cancelAnimationFrame(raf);
143
+ }
175
144
  }, [open, svgPath]);
176
145
  return {
177
146
  internalRef,
178
147
  shadowFilterId,
148
+ maxWidthClass,
179
149
  dimensions,
180
150
  shadows,
181
151
  shadowPadding,
@@ -187,8 +157,8 @@ function useSvgFloatingContent({ open, effectivePlacement, borderRadius, arrowRe
187
157
  opacity: visible ? 1 : 0,
188
158
  transition: `opacity ${animationDuration}ms ease-in-out`
189
159
  },
190
- shift: useMemo(() => {
191
- if (hideArrow || arrowCenter === void 0 || dimensions.width <= 0 || dimensions.height <= 0) return {
160
+ tooltipShift: useMemo(() => {
161
+ if (arrowCenter === void 0 || dimensions.width <= 0 || dimensions.height <= 0) return {
192
162
  x: 0,
193
163
  y: 0
194
164
  };
@@ -197,21 +167,18 @@ function useSvgFloatingContent({ open, effectivePlacement, borderRadius, arrowRe
197
167
  height: dimensions.height,
198
168
  placement: effectivePlacement,
199
169
  borderRadius,
200
- arrowCenter,
201
- arrowWidth
170
+ arrowCenter
202
171
  });
203
172
  }, [
204
- hideArrow,
205
173
  arrowCenter,
206
174
  dimensions.width,
207
175
  dimensions.height,
208
176
  effectivePlacement,
209
- borderRadius,
210
- arrowWidth
177
+ borderRadius
211
178
  ]),
212
179
  onPositionUpdate
213
180
  };
214
181
  }
215
182
 
216
183
  //#endregion
217
- export { useSvgFloatingContent };
184
+ export { useTooltipContent };
@@ -0,0 +1,248 @@
1
+ "use client";
2
+ /*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ //#region src/components/client/Tooltip/util.ts
6
+ /**
7
+ * Splits a CSS value on whitespace, but keeps parenthesized groups
8
+ * (e.g. `rgb(0, 0, 0)`) together as single tokens.
9
+ */
10
+ function tokenizeCSSValue(value) {
11
+ const tokens = [];
12
+ let current = "";
13
+ let depth = 0;
14
+ for (const char of value) {
15
+ if (char === "(") depth++;
16
+ if (char === ")") depth--;
17
+ if (char === " " && depth === 0) {
18
+ if (current) tokens.push(current);
19
+ current = "";
20
+ } else current += char;
21
+ }
22
+ if (current) tokens.push(current);
23
+ return tokens;
24
+ }
25
+ /**
26
+ * Returns `true` if the token is a CSS color value.
27
+ *
28
+ * In a box-shadow context (after filtering `inset`), every token is either a
29
+ * length or a color. Colors always start with `#` (hex), a letter (named
30
+ * colors like `red`, `transparent`, `currentcolor`), or are a CSS function
31
+ * containing `(` (e.g. `rgb(…)`, `hsl(…)`, `oklch(…)`).
32
+ */
33
+ function isColorToken(token) {
34
+ const ch = token[0];
35
+ return ch !== "-" && ch !== "." && (ch < "0" || ch > "9");
36
+ }
37
+ /**
38
+ * Splits a CSS multi-shadow value (comma-separated) into individual
39
+ * shadow strings, correctly handling commas nested inside color functions
40
+ * like `rgb()`, `rgba()`, `hsl()`, etc.
41
+ */
42
+ function splitShadows(value) {
43
+ const shadows = [];
44
+ let current = "";
45
+ let depth = 0;
46
+ for (let i = 0; i < value.length; i++) {
47
+ const char = value[i];
48
+ if (char === "(") {
49
+ depth++;
50
+ current += char;
51
+ } else if (char === ")") {
52
+ depth--;
53
+ current += char;
54
+ } else if (char === "," && depth === 0) {
55
+ if (current.trim()) shadows.push(current.trim());
56
+ current = "";
57
+ } else current += char;
58
+ }
59
+ if (current.trim()) shadows.push(current.trim());
60
+ return shadows;
61
+ }
62
+ /**
63
+ * Parses a single CSS shadow value string into its constituent parts.
64
+ *
65
+ * Handles all standard CSS box-shadow / drop-shadow permutations:
66
+ * - Color before or after length values (`red 0 4px 8px` or `0 4px 8px red`)
67
+ * - Optional blur and spread radii (defaults to 0)
68
+ * - `inset` keyword at any position (silently ignored)
69
+ * - All color formats: named, hex (3/4/6/8-digit), rgb/rgba, hsl/hsla, oklch,
70
+ * oklab, lab, lch, color(), color-mix(), light-dark(), etc.
71
+ * - `none` / empty values → zeroed-out result with `transparent` color
72
+ */
73
+ function parseSingleShadow(shadow) {
74
+ const value = shadow.trim();
75
+ if (!value || value.toLowerCase() === "none") return {
76
+ x: 0,
77
+ y: 0,
78
+ blur: 0,
79
+ spread: 0,
80
+ color: "transparent"
81
+ };
82
+ const tokens = tokenizeCSSValue(value);
83
+ const lengths = [];
84
+ const colorParts = [];
85
+ for (const token of tokens) {
86
+ if (token.toLowerCase() === "inset") continue;
87
+ if (isColorToken(token)) colorParts.push(token);
88
+ else lengths.push(token);
89
+ }
90
+ return {
91
+ x: lengths.length > 0 ? parseFloat(lengths[0]) : 0,
92
+ y: lengths.length > 1 ? parseFloat(lengths[1]) : 0,
93
+ blur: lengths.length > 2 ? parseFloat(lengths[2]) : 0,
94
+ spread: lengths.length > 3 ? parseFloat(lengths[3]) : 0,
95
+ color: colorParts.length > 0 ? colorParts.join(" ") : "rgb(0 0 0 / 1)"
96
+ };
97
+ }
98
+ /**
99
+ * Parses a CSS shadow value — which may contain multiple comma-separated
100
+ * layers — into an array of {@link ParsedShadow} objects.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * parseShadow('0px 4px 8px 0px rgb(0 0 0 / 0.12)')
105
+ * // → [{ x: 0, y: 4, blur: 8, spread: 0, color: 'rgb(0 0 0 / 0.12)' }]
106
+ *
107
+ * parseShadow('0px 4px 8px rgb(0 0 0 / 0.12), 0px 1px 2px rgba(0, 0, 0, 0.08)')
108
+ * // → [
109
+ * // { x: 0, y: 4, blur: 8, spread: 0, color: 'rgb(0 0 0 / 0.12)' },
110
+ * // { x: 0, y: 1, blur: 2, spread: 0, color: 'rgba(0, 0, 0, 0.08)' },
111
+ * // ]
112
+ * ```
113
+ */
114
+ function parseShadow(shadowValue) {
115
+ const trimmed = shadowValue.trim();
116
+ if (!trimmed || trimmed.toLowerCase() === "none") return [];
117
+ return splitShadows(trimmed).map(parseSingleShadow);
118
+ }
119
+ /** Base width of the arrow triangle (px). */
120
+ const ARROW_WIDTH = 12;
121
+ /** Height (protrusion) of the arrow triangle from the edge (px). */
122
+ const ARROW_HEIGHT = 8;
123
+ /**
124
+ * Fraction of the container border-radius applied to round the arrow tip
125
+ * (0 = sharp point, 1 = same radius as the container corners).
126
+ */
127
+ const ARROW_TIP_RADIUS_FRACTION = .5;
128
+ /**
129
+ * Returns the side of the tooltip where the arrow should appear.
130
+ * The arrow points *toward* the trigger, so it lives on the opposite
131
+ * side of the placement direction.
132
+ */
133
+ function getArrowSide(placement) {
134
+ switch (placement.split("-")[0]) {
135
+ case "bottom": return "top";
136
+ case "top": return "bottom";
137
+ case "left": return "right";
138
+ case "right": return "left";
139
+ default: return "top";
140
+ }
141
+ }
142
+ /**
143
+ * Generates an SVG `<path>` string for a rounded rectangle with an arrow
144
+ * pointing toward the trigger element.
145
+ *
146
+ * The path is traced clockwise, inserting the arrow triangle on the
147
+ * appropriate edge. The arrow extends *outside* the 0,0 → width,height
148
+ * rectangle so the host `<svg>` must use `overflow: visible`.
149
+ */
150
+ function generateTooltipPath({ width, height, placement, borderRadius, arrowWidth = ARROW_WIDTH, arrowHeight = ARROW_HEIGHT, arrowCenter, offsetX: ox = 0, offsetY: oy = 0 }) {
151
+ const aw = arrowWidth / 2;
152
+ const ah = arrowHeight;
153
+ const arrowSide = getArrowSide(placement);
154
+ const arrowEdge = arrowSide === "top" || arrowSide === "bottom" ? width : height;
155
+ const otherEdge = arrowSide === "top" || arrowSide === "bottom" ? height : width;
156
+ const maxRadius = Math.min(otherEdge / 2, (arrowEdge - arrowWidth) / 2);
157
+ const r = Math.max(0, Math.min(borderRadius, maxRadius));
158
+ const minAc = r + aw;
159
+ const edgeLength = arrowSide === "top" || arrowSide === "bottom" ? width : height;
160
+ let ac = arrowCenter ?? edgeLength / 2;
161
+ ac = Math.max(minAc, Math.min(edgeLength - minAc, ac));
162
+ const edgeLen = Math.sqrt(aw * aw + ah * ah);
163
+ const tipR = r > 0 && edgeLen > 0 ? Math.min(r * ARROW_TIP_RADIUS_FRACTION, edgeLen / 2) : 0;
164
+ const daw = edgeLen > 0 ? aw / edgeLen : 0;
165
+ const dah = edgeLen > 0 ? ah / edgeLen : 0;
166
+ const d = [];
167
+ d.push(`M ${r + ox} ${oy}`);
168
+ if (arrowSide === "top") {
169
+ d.push(`L ${ac - aw + ox} ${oy}`);
170
+ if (tipR > 0) {
171
+ d.push(`L ${ac - tipR * daw + ox} ${-ah + tipR * dah + oy}`);
172
+ d.push(`Q ${ac + ox} ${-ah + oy} ${ac + tipR * daw + ox} ${-ah + tipR * dah + oy}`);
173
+ } else d.push(`L ${ac + ox} ${-ah + oy}`);
174
+ d.push(`L ${ac + aw + ox} ${oy}`);
175
+ }
176
+ d.push(`L ${width - r + ox} ${oy}`);
177
+ d.push(`A ${r} ${r} 0 0 1 ${width + ox} ${r + oy}`);
178
+ if (arrowSide === "right") {
179
+ d.push(`L ${width + ox} ${ac - aw + oy}`);
180
+ if (tipR > 0) {
181
+ d.push(`L ${width + ah - tipR * dah + ox} ${ac - tipR * daw + oy}`);
182
+ d.push(`Q ${width + ah + ox} ${ac + oy} ${width + ah - tipR * dah + ox} ${ac + tipR * daw + oy}`);
183
+ } else d.push(`L ${width + ah + ox} ${ac + oy}`);
184
+ d.push(`L ${width + ox} ${ac + aw + oy}`);
185
+ }
186
+ d.push(`L ${width + ox} ${height - r + oy}`);
187
+ d.push(`A ${r} ${r} 0 0 1 ${width - r + ox} ${height + oy}`);
188
+ if (arrowSide === "bottom") {
189
+ d.push(`L ${ac + aw + ox} ${height + oy}`);
190
+ if (tipR > 0) {
191
+ d.push(`L ${ac + tipR * daw + ox} ${height + ah - tipR * dah + oy}`);
192
+ d.push(`Q ${ac + ox} ${height + ah + oy} ${ac - tipR * daw + ox} ${height + ah - tipR * dah + oy}`);
193
+ } else d.push(`L ${ac + ox} ${height + ah + oy}`);
194
+ d.push(`L ${ac - aw + ox} ${height + oy}`);
195
+ }
196
+ d.push(`L ${r + ox} ${height + oy}`);
197
+ d.push(`A ${r} ${r} 0 0 1 ${ox} ${height - r + oy}`);
198
+ if (arrowSide === "left") {
199
+ d.push(`L ${ox} ${ac + aw + oy}`);
200
+ if (tipR > 0) {
201
+ d.push(`L ${-ah + tipR * dah + ox} ${ac + tipR * daw + oy}`);
202
+ d.push(`Q ${-ah + ox} ${ac + oy} ${-ah + tipR * dah + ox} ${ac - tipR * daw + oy}`);
203
+ } else d.push(`L ${-ah + ox} ${ac + oy}`);
204
+ d.push(`L ${ox} ${ac - aw + oy}`);
205
+ }
206
+ d.push(`L ${ox} ${r + oy}`);
207
+ d.push(`A ${r} ${r} 0 0 1 ${r + ox} ${oy}`);
208
+ d.push("Z");
209
+ return d.join(" ");
210
+ }
211
+ /**
212
+ * Computes the pixel offset the tooltip must shift so that the SVG arrow
213
+ * (after clamping) visually aligns with the Ariakit arrow's actual position.
214
+ *
215
+ * When the desired `arrowCenter` falls inside the safe zone the delta is 0.
216
+ * When it falls outside (e.g. a tiny trigger near a rounded corner), the
217
+ * returned delta tells the caller how far to translate the tooltip element
218
+ * so the clamped arrow ends up over the trigger center.
219
+ */
220
+ function getArrowClampDelta({ width, height, placement, borderRadius, arrowCenter, arrowWidth = ARROW_WIDTH }) {
221
+ const aw = arrowWidth / 2;
222
+ const side = getArrowSide(placement);
223
+ const arrowEdge = side === "top" || side === "bottom" ? width : height;
224
+ const otherEdge = side === "top" || side === "bottom" ? height : width;
225
+ const maxRadius = Math.min(otherEdge / 2, (arrowEdge - arrowWidth) / 2);
226
+ const minAc = Math.max(0, Math.min(borderRadius, maxRadius)) + aw;
227
+ const maxAc = arrowEdge - minAc;
228
+ let delta = 0;
229
+ if (arrowCenter < minAc) delta = arrowCenter - minAc;
230
+ else if (arrowCenter > maxAc) delta = arrowCenter - maxAc;
231
+ if (side === "top" || side === "bottom") return {
232
+ x: delta,
233
+ y: 0
234
+ };
235
+ return {
236
+ x: 0,
237
+ y: delta
238
+ };
239
+ }
240
+
241
+ //#endregion
242
+ exports.ARROW_HEIGHT = ARROW_HEIGHT;
243
+ exports.ARROW_TIP_RADIUS_FRACTION = ARROW_TIP_RADIUS_FRACTION;
244
+ exports.ARROW_WIDTH = ARROW_WIDTH;
245
+ exports.generateTooltipPath = generateTooltipPath;
246
+ exports.getArrowClampDelta = getArrowClampDelta;
247
+ exports.getArrowSide = getArrowSide;
248
+ exports.parseShadow = parseShadow;
@@ -1,17 +1,62 @@
1
1
 
2
- //#region src/utils/svgFloatingContentUtils.d.ts
3
- interface SVGFloatingContentPathOptions {
2
+ //#region src/components/client/Tooltip/util.d.ts
3
+ interface ParsedShadow {
4
+ /** Horizontal offset in px. */
5
+ x: number;
6
+ /** Vertical offset in px. */
7
+ y: number;
8
+ /** Blur radius in px. */
9
+ blur: number;
10
+ /** Spread radius in px (always 0 for drop-shadow filter functions). */
11
+ spread: number;
12
+ /** The raw CSS color string (e.g. `rgb(0 0 0 / 0.12)`, `#ff0000`, `red`). */
13
+ color: string;
14
+ }
15
+ /**
16
+ * Parses a CSS shadow value — which may contain multiple comma-separated
17
+ * layers — into an array of {@link ParsedShadow} objects.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * parseShadow('0px 4px 8px 0px rgb(0 0 0 / 0.12)')
22
+ * // → [{ x: 0, y: 4, blur: 8, spread: 0, color: 'rgb(0 0 0 / 0.12)' }]
23
+ *
24
+ * parseShadow('0px 4px 8px rgb(0 0 0 / 0.12), 0px 1px 2px rgba(0, 0, 0, 0.08)')
25
+ * // → [
26
+ * // { x: 0, y: 4, blur: 8, spread: 0, color: 'rgb(0 0 0 / 0.12)' },
27
+ * // { x: 0, y: 1, blur: 2, spread: 0, color: 'rgba(0, 0, 0, 0.08)' },
28
+ * // ]
29
+ * ```
30
+ */
31
+ declare function parseShadow(shadowValue: string): ParsedShadow[];
32
+ /** Base width of the arrow triangle (px). */
33
+ declare const ARROW_WIDTH = 12;
34
+ /** Height (protrusion) of the arrow triangle from the edge (px). */
35
+ declare const ARROW_HEIGHT = 8;
36
+ /**
37
+ * Fraction of the container border-radius applied to round the arrow tip
38
+ * (0 = sharp point, 1 = same radius as the container corners).
39
+ */
40
+ declare const ARROW_TIP_RADIUS_FRACTION = 0.5;
41
+ type ArrowSide = 'top' | 'bottom' | 'left' | 'right';
42
+ /**
43
+ * Returns the side of the tooltip where the arrow should appear.
44
+ * The arrow points *toward* the trigger, so it lives on the opposite
45
+ * side of the placement direction.
46
+ */
47
+ declare function getArrowSide(placement: string): ArrowSide;
48
+ interface TooltipPathOptions {
4
49
  width: number;
5
50
  height: number;
6
51
  placement: string;
7
52
  borderRadius: number;
8
- arrowWidth: number;
9
- arrowHeight: number;
10
- /** Fraction of the container border-radius applied to round the arrow tip (0 = sharp point, 1 = same radius as the container corners). */
11
- arrowTipRadiusFraction: number;
53
+ arrowWidth?: number;
54
+ arrowHeight?: number;
12
55
  /**
13
56
  * Position of the arrow center along the arrow's edge (px), measured from
14
57
  * the start of that edge (left for top/bottom sides, top for left/right).
58
+ * Typically derived from the Ariakit `TooltipArrow` element's position
59
+ * within the tooltip.
15
60
  *
16
61
  * Clamped so the arrow never collides with the border-radius curve
17
62
  * Falls back to the midpoint of the edge when omitted.
@@ -22,21 +67,6 @@ interface SVGFloatingContentPathOptions {
22
67
  /** Shift every coordinate in the path by this many pixels on the y-axis. */
23
68
  offsetY?: number;
24
69
  }
25
- interface ArrowClampDeltaOptions {
26
- width: number;
27
- height: number;
28
- placement: string;
29
- borderRadius: number;
30
- arrowCenter: number;
31
- arrowWidth: number;
32
- }
33
- type ArrowSide = 'top' | 'bottom' | 'left' | 'right';
34
- /**
35
- * Returns the side of the element where the arrow should appear.
36
- * The arrow points *toward* the trigger, so it lives on the opposite
37
- * side of the placement direction.
38
- */
39
- declare function getArrowSide(placement: string): ArrowSide;
40
70
  /**
41
71
  * Generates an SVG `<path>` string for a rounded rectangle with an arrow
42
72
  * pointing toward the trigger element.
@@ -45,18 +75,25 @@ declare function getArrowSide(placement: string): ArrowSide;
45
75
  * appropriate edge. The arrow extends *outside* the 0,0 → width,height
46
76
  * rectangle so the host `<svg>` must use `overflow: visible`.
47
77
  */
48
- declare function generateSvgFloatingContentPath({
78
+ declare function generateTooltipPath({
49
79
  width,
50
80
  height,
51
81
  placement,
52
82
  borderRadius,
53
83
  arrowWidth,
54
84
  arrowHeight,
55
- arrowTipRadiusFraction,
56
85
  arrowCenter,
57
86
  offsetX: ox,
58
87
  offsetY: oy
59
- }: SVGFloatingContentPathOptions): string;
88
+ }: TooltipPathOptions): string;
89
+ interface ArrowClampDeltaOptions {
90
+ width: number;
91
+ height: number;
92
+ placement: string;
93
+ borderRadius: number;
94
+ arrowCenter: number;
95
+ arrowWidth?: number;
96
+ }
60
97
  /**
61
98
  * Computes the pixel offset the tooltip must shift so that the SVG arrow
62
99
  * (after clamping) visually aligns with the Ariakit arrow's actual position.
@@ -78,4 +115,4 @@ declare function getArrowClampDelta({
78
115
  y: number;
79
116
  };
80
117
  //#endregion
81
- export { generateSvgFloatingContentPath, getArrowClampDelta, getArrowSide };
118
+ export { ARROW_HEIGHT, ARROW_TIP_RADIUS_FRACTION, ARROW_WIDTH, type ArrowClampDeltaOptions, type ArrowSide, type ParsedShadow, type TooltipPathOptions, generateTooltipPath, getArrowClampDelta, getArrowSide, parseShadow };