@sesionario/blocks 1.32.0 → 1.33.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/avatar.cjs CHANGED
@@ -64,8 +64,7 @@ function contrastingTextColor(backgroundHex) {
64
64
  function getInitials(name, max = 2) {
65
65
  const parts = name.trim().split(/\s+/).filter(Boolean);
66
66
  if (parts.length === 0) return "?";
67
- const letters = parts.slice(0, Math.max(1, max)).map((part) => part.charAt(0)).join("");
68
- return letters.toUpperCase() || "?";
67
+ return parts.slice(0, Math.max(1, max)).map((part) => part.charAt(0)).join("").toUpperCase();
69
68
  }
70
69
  function getAvatarColors(name) {
71
70
  const normalized = name.trim().toLowerCase();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/avatar.ts"],"names":[],"mappings":"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","file":"avatar.cjs","sourcesContent":["/** Neutral fallback when the name is empty. */\nconst EMPTY_COLORS = {\n\tbackgroundColor: \"#9ca3af\",\n\tcolor: \"#111111\",\n} as const;\n\n/**\n * Curated mid-lightness palette — professional, calm hues that stay\n * distinct when hashed by name and contrast well with black or white text.\n */\nconst AVATAR_PALETTE = [\n\t\"#4f6d8c\", // slate blue\n\t\"#3d7a6a\", // teal\n\t\"#6b5b8a\", // muted purple\n\t\"#8a5a4a\", // warm brown\n\t\"#4a7a8a\", // steel cyan\n\t\"#7a6b4a\", // olive\n\t\"#5a6b8a\", // periwinkle\n\t\"#8a4a5a\", // rose\n\t\"#4a8a6b\", // green\n\t\"#6b4a7a\", // plum\n\t\"#8a6b4a\", // amber brown\n\t\"#4a5a8a\", // indigo\n\t\"#7a4a6b\", // mauve\n\t\"#5a8a4a\", // leaf\n\t\"#8a5a7a\", // dusty pink\n\t\"#3d6b7a\", // deep teal\n] as const;\n\nexport type AvatarColors = {\n\tbackgroundColor: string;\n\tcolor: string;\n};\n\n/** FNV-1a 32-bit hash — stable across runtimes for the same string. */\nfunction hashString(input: string): number {\n\tlet hash = 0x811c9dc5;\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash ^= input.charCodeAt(i);\n\t\thash = Math.imul(hash, 0x01000193);\n\t}\n\treturn hash >>> 0;\n}\n\nfunction srgbToLinear(channel: number): number {\n\tconst c = channel / 255;\n\treturn c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n}\n\n/** Relative luminance (WCAG) for a hex color like `#rrggbb`. */\nfunction relativeLuminance(hex: string): number {\n\tconst normalized = hex.replace(\"#\", \"\");\n\tconst r = Number.parseInt(normalized.slice(0, 2), 16);\n\tconst g = Number.parseInt(normalized.slice(2, 4), 16);\n\tconst b = Number.parseInt(normalized.slice(4, 6), 16);\n\treturn (\n\t\t0.2126 * srgbToLinear(r) +\n\t\t0.7152 * srgbToLinear(g) +\n\t\t0.0722 * srgbToLinear(b)\n\t);\n}\n\nfunction contrastingTextColor(backgroundHex: string): \"#ffffff\" | \"#111111\" {\n\t// Threshold ~0.179 ≈ contrast preference for mid tones (WCAG-inspired).\n\treturn relativeLuminance(backgroundHex) > 0.179 ? \"#111111\" : \"#ffffff\";\n}\n\n/**\n * Word-based initials from a display name (max letters, default 2).\n * Empty / whitespace-only names yield `\"?\"`.\n */\nexport function getInitials(name: string, max = 2): string {\n\tconst parts = name.trim().split(/\\s+/).filter(Boolean);\n\tif (parts.length === 0) return \"?\";\n\tconst letters = parts\n\t\t.slice(0, Math.max(1, max))\n\t\t.map((part) => part.charAt(0))\n\t\t.join(\"\");\n\treturn letters.toUpperCase() || \"?\";\n}\n\n/**\n * Deterministic background + contrasting foreground from a full name.\n * Same name (case-insensitive) always maps to the same colors.\n */\nexport function getAvatarColors(name: string): AvatarColors {\n\tconst normalized = name.trim().toLowerCase();\n\tif (!normalized) {\n\t\treturn { ...EMPTY_COLORS };\n\t}\n\tconst backgroundColor =\n\t\tAVATAR_PALETTE[hashString(normalized) % AVATAR_PALETTE.length]!;\n\treturn {\n\t\tbackgroundColor,\n\t\tcolor: contrastingTextColor(backgroundColor),\n\t};\n}\n\n/** CSS style object for `AvatarFallback` (or any letter-avatar container). */\nexport function avatarFallbackStyle(\n\tname: string,\n): Pick<AvatarColors, \"backgroundColor\" | \"color\"> {\n\treturn getAvatarColors(name);\n}\n"]}
1
+ {"version":3,"sources":["../src/lib/avatar.ts"],"names":[],"mappings":"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","file":"avatar.cjs","sourcesContent":["/** Neutral fallback when the name is empty. */\nconst EMPTY_COLORS = {\n\tbackgroundColor: \"#9ca3af\",\n\tcolor: \"#111111\",\n} as const;\n\n/**\n * Curated mid-lightness palette — professional, calm hues that stay\n * distinct when hashed by name and contrast well with black or white text.\n */\nconst AVATAR_PALETTE = [\n\t\"#4f6d8c\", // slate blue\n\t\"#3d7a6a\", // teal\n\t\"#6b5b8a\", // muted purple\n\t\"#8a5a4a\", // warm brown\n\t\"#4a7a8a\", // steel cyan\n\t\"#7a6b4a\", // olive\n\t\"#5a6b8a\", // periwinkle\n\t\"#8a4a5a\", // rose\n\t\"#4a8a6b\", // green\n\t\"#6b4a7a\", // plum\n\t\"#8a6b4a\", // amber brown\n\t\"#4a5a8a\", // indigo\n\t\"#7a4a6b\", // mauve\n\t\"#5a8a4a\", // leaf\n\t\"#8a5a7a\", // dusty pink\n\t\"#3d6b7a\", // deep teal\n] as const;\n\nexport type AvatarColors = {\n\tbackgroundColor: string;\n\tcolor: string;\n};\n\n/** FNV-1a 32-bit hash — stable across runtimes for the same string. */\nfunction hashString(input: string): number {\n\tlet hash = 0x811c9dc5;\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash ^= input.charCodeAt(i);\n\t\thash = Math.imul(hash, 0x01000193);\n\t}\n\treturn hash >>> 0;\n}\n\nfunction srgbToLinear(channel: number): number {\n\tconst c = channel / 255;\n\treturn c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n}\n\n/** Relative luminance (WCAG) for a hex color like `#rrggbb`. */\nfunction relativeLuminance(hex: string): number {\n\tconst normalized = hex.replace(\"#\", \"\");\n\tconst r = Number.parseInt(normalized.slice(0, 2), 16);\n\tconst g = Number.parseInt(normalized.slice(2, 4), 16);\n\tconst b = Number.parseInt(normalized.slice(4, 6), 16);\n\treturn (\n\t\t0.2126 * srgbToLinear(r) +\n\t\t0.7152 * srgbToLinear(g) +\n\t\t0.0722 * srgbToLinear(b)\n\t);\n}\n\nfunction contrastingTextColor(backgroundHex: string): \"#ffffff\" | \"#111111\" {\n\t// Threshold ~0.179 ≈ contrast preference for mid tones (WCAG-inspired).\n\treturn relativeLuminance(backgroundHex) > 0.179 ? \"#111111\" : \"#ffffff\";\n}\n\n/**\n * Word-based initials from a display name (max letters, default 2).\n * Empty / whitespace-only names yield `\"?\"`.\n */\nexport function getInitials(name: string, max = 2): string {\n\tconst parts = name.trim().split(/\\s+/).filter(Boolean);\n\tif (parts.length === 0) return \"?\";\n\treturn parts\n\t\t.slice(0, Math.max(1, max))\n\t\t.map((part) => part.charAt(0))\n\t\t.join(\"\")\n\t\t.toUpperCase();\n}\n\n/**\n * Deterministic background + contrasting foreground from a full name.\n * Same name (case-insensitive) always maps to the same colors.\n */\nexport function getAvatarColors(name: string): AvatarColors {\n\tconst normalized = name.trim().toLowerCase();\n\tif (!normalized) {\n\t\treturn { ...EMPTY_COLORS };\n\t}\n\tconst backgroundColor =\n\t\tAVATAR_PALETTE[hashString(normalized) % AVATAR_PALETTE.length]!;\n\treturn {\n\t\tbackgroundColor,\n\t\tcolor: contrastingTextColor(backgroundColor),\n\t};\n}\n\n/** CSS style object for `AvatarFallback` (or any letter-avatar container). */\nexport function avatarFallbackStyle(\n\tname: string,\n): Pick<AvatarColors, \"backgroundColor\" | \"color\"> {\n\treturn getAvatarColors(name);\n}\n"]}
package/dist/avatar.js CHANGED
@@ -62,8 +62,7 @@ function contrastingTextColor(backgroundHex) {
62
62
  function getInitials(name, max = 2) {
63
63
  const parts = name.trim().split(/\s+/).filter(Boolean);
64
64
  if (parts.length === 0) return "?";
65
- const letters = parts.slice(0, Math.max(1, max)).map((part) => part.charAt(0)).join("");
66
- return letters.toUpperCase() || "?";
65
+ return parts.slice(0, Math.max(1, max)).map((part) => part.charAt(0)).join("").toUpperCase();
67
66
  }
68
67
  function getAvatarColors(name) {
69
68
  const normalized = name.trim().toLowerCase();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/avatar.ts"],"names":[],"mappings":"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","file":"avatar.js","sourcesContent":["/** Neutral fallback when the name is empty. */\nconst EMPTY_COLORS = {\n\tbackgroundColor: \"#9ca3af\",\n\tcolor: \"#111111\",\n} as const;\n\n/**\n * Curated mid-lightness palette — professional, calm hues that stay\n * distinct when hashed by name and contrast well with black or white text.\n */\nconst AVATAR_PALETTE = [\n\t\"#4f6d8c\", // slate blue\n\t\"#3d7a6a\", // teal\n\t\"#6b5b8a\", // muted purple\n\t\"#8a5a4a\", // warm brown\n\t\"#4a7a8a\", // steel cyan\n\t\"#7a6b4a\", // olive\n\t\"#5a6b8a\", // periwinkle\n\t\"#8a4a5a\", // rose\n\t\"#4a8a6b\", // green\n\t\"#6b4a7a\", // plum\n\t\"#8a6b4a\", // amber brown\n\t\"#4a5a8a\", // indigo\n\t\"#7a4a6b\", // mauve\n\t\"#5a8a4a\", // leaf\n\t\"#8a5a7a\", // dusty pink\n\t\"#3d6b7a\", // deep teal\n] as const;\n\nexport type AvatarColors = {\n\tbackgroundColor: string;\n\tcolor: string;\n};\n\n/** FNV-1a 32-bit hash — stable across runtimes for the same string. */\nfunction hashString(input: string): number {\n\tlet hash = 0x811c9dc5;\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash ^= input.charCodeAt(i);\n\t\thash = Math.imul(hash, 0x01000193);\n\t}\n\treturn hash >>> 0;\n}\n\nfunction srgbToLinear(channel: number): number {\n\tconst c = channel / 255;\n\treturn c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n}\n\n/** Relative luminance (WCAG) for a hex color like `#rrggbb`. */\nfunction relativeLuminance(hex: string): number {\n\tconst normalized = hex.replace(\"#\", \"\");\n\tconst r = Number.parseInt(normalized.slice(0, 2), 16);\n\tconst g = Number.parseInt(normalized.slice(2, 4), 16);\n\tconst b = Number.parseInt(normalized.slice(4, 6), 16);\n\treturn (\n\t\t0.2126 * srgbToLinear(r) +\n\t\t0.7152 * srgbToLinear(g) +\n\t\t0.0722 * srgbToLinear(b)\n\t);\n}\n\nfunction contrastingTextColor(backgroundHex: string): \"#ffffff\" | \"#111111\" {\n\t// Threshold ~0.179 ≈ contrast preference for mid tones (WCAG-inspired).\n\treturn relativeLuminance(backgroundHex) > 0.179 ? \"#111111\" : \"#ffffff\";\n}\n\n/**\n * Word-based initials from a display name (max letters, default 2).\n * Empty / whitespace-only names yield `\"?\"`.\n */\nexport function getInitials(name: string, max = 2): string {\n\tconst parts = name.trim().split(/\\s+/).filter(Boolean);\n\tif (parts.length === 0) return \"?\";\n\tconst letters = parts\n\t\t.slice(0, Math.max(1, max))\n\t\t.map((part) => part.charAt(0))\n\t\t.join(\"\");\n\treturn letters.toUpperCase() || \"?\";\n}\n\n/**\n * Deterministic background + contrasting foreground from a full name.\n * Same name (case-insensitive) always maps to the same colors.\n */\nexport function getAvatarColors(name: string): AvatarColors {\n\tconst normalized = name.trim().toLowerCase();\n\tif (!normalized) {\n\t\treturn { ...EMPTY_COLORS };\n\t}\n\tconst backgroundColor =\n\t\tAVATAR_PALETTE[hashString(normalized) % AVATAR_PALETTE.length]!;\n\treturn {\n\t\tbackgroundColor,\n\t\tcolor: contrastingTextColor(backgroundColor),\n\t};\n}\n\n/** CSS style object for `AvatarFallback` (or any letter-avatar container). */\nexport function avatarFallbackStyle(\n\tname: string,\n): Pick<AvatarColors, \"backgroundColor\" | \"color\"> {\n\treturn getAvatarColors(name);\n}\n"]}
1
+ {"version":3,"sources":["../src/lib/avatar.ts"],"names":[],"mappings":"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","file":"avatar.js","sourcesContent":["/** Neutral fallback when the name is empty. */\nconst EMPTY_COLORS = {\n\tbackgroundColor: \"#9ca3af\",\n\tcolor: \"#111111\",\n} as const;\n\n/**\n * Curated mid-lightness palette — professional, calm hues that stay\n * distinct when hashed by name and contrast well with black or white text.\n */\nconst AVATAR_PALETTE = [\n\t\"#4f6d8c\", // slate blue\n\t\"#3d7a6a\", // teal\n\t\"#6b5b8a\", // muted purple\n\t\"#8a5a4a\", // warm brown\n\t\"#4a7a8a\", // steel cyan\n\t\"#7a6b4a\", // olive\n\t\"#5a6b8a\", // periwinkle\n\t\"#8a4a5a\", // rose\n\t\"#4a8a6b\", // green\n\t\"#6b4a7a\", // plum\n\t\"#8a6b4a\", // amber brown\n\t\"#4a5a8a\", // indigo\n\t\"#7a4a6b\", // mauve\n\t\"#5a8a4a\", // leaf\n\t\"#8a5a7a\", // dusty pink\n\t\"#3d6b7a\", // deep teal\n] as const;\n\nexport type AvatarColors = {\n\tbackgroundColor: string;\n\tcolor: string;\n};\n\n/** FNV-1a 32-bit hash — stable across runtimes for the same string. */\nfunction hashString(input: string): number {\n\tlet hash = 0x811c9dc5;\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash ^= input.charCodeAt(i);\n\t\thash = Math.imul(hash, 0x01000193);\n\t}\n\treturn hash >>> 0;\n}\n\nfunction srgbToLinear(channel: number): number {\n\tconst c = channel / 255;\n\treturn c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n}\n\n/** Relative luminance (WCAG) for a hex color like `#rrggbb`. */\nfunction relativeLuminance(hex: string): number {\n\tconst normalized = hex.replace(\"#\", \"\");\n\tconst r = Number.parseInt(normalized.slice(0, 2), 16);\n\tconst g = Number.parseInt(normalized.slice(2, 4), 16);\n\tconst b = Number.parseInt(normalized.slice(4, 6), 16);\n\treturn (\n\t\t0.2126 * srgbToLinear(r) +\n\t\t0.7152 * srgbToLinear(g) +\n\t\t0.0722 * srgbToLinear(b)\n\t);\n}\n\nfunction contrastingTextColor(backgroundHex: string): \"#ffffff\" | \"#111111\" {\n\t// Threshold ~0.179 ≈ contrast preference for mid tones (WCAG-inspired).\n\treturn relativeLuminance(backgroundHex) > 0.179 ? \"#111111\" : \"#ffffff\";\n}\n\n/**\n * Word-based initials from a display name (max letters, default 2).\n * Empty / whitespace-only names yield `\"?\"`.\n */\nexport function getInitials(name: string, max = 2): string {\n\tconst parts = name.trim().split(/\\s+/).filter(Boolean);\n\tif (parts.length === 0) return \"?\";\n\treturn parts\n\t\t.slice(0, Math.max(1, max))\n\t\t.map((part) => part.charAt(0))\n\t\t.join(\"\")\n\t\t.toUpperCase();\n}\n\n/**\n * Deterministic background + contrasting foreground from a full name.\n * Same name (case-insensitive) always maps to the same colors.\n */\nexport function getAvatarColors(name: string): AvatarColors {\n\tconst normalized = name.trim().toLowerCase();\n\tif (!normalized) {\n\t\treturn { ...EMPTY_COLORS };\n\t}\n\tconst backgroundColor =\n\t\tAVATAR_PALETTE[hashString(normalized) % AVATAR_PALETTE.length]!;\n\treturn {\n\t\tbackgroundColor,\n\t\tcolor: contrastingTextColor(backgroundColor),\n\t};\n}\n\n/** CSS style object for `AvatarFallback` (or any letter-avatar container). */\nexport function avatarFallbackStyle(\n\tname: string,\n): Pick<AvatarColors, \"backgroundColor\" | \"color\"> {\n\treturn getAvatarColors(name);\n}\n"]}
package/dist/charts.cjs CHANGED
@@ -298,6 +298,7 @@ function ChartProvider({
298
298
  orientation: value.orientation,
299
299
  stacked: value.stacked,
300
300
  stackOffsets: value.stackOffsets,
301
+ squareSnap: value.squareSnap,
301
302
  composedBarDataKeys: value.composedBarDataKeys,
302
303
  composedBarSize: value.composedBarSize,
303
304
  composedMaxBarSize: value.composedMaxBarSize,
@@ -343,6 +344,7 @@ function ChartProvider({
343
344
  value.orientation,
344
345
  value.stacked,
345
346
  value.stackOffsets,
347
+ value.squareSnap,
346
348
  value.composedBarDataKeys,
347
349
  value.composedBarSize,
348
350
  value.composedMaxBarSize,
@@ -3863,11 +3865,6 @@ function useAnimatedSeriesPath({
3863
3865
  [renderData, xAccessor, xScale, yScale, dataKey]
3864
3866
  );
3865
3867
  const prevTransitionSignatureRef = react.useRef(transitionSignature);
3866
- react.useEffect(() => {
3867
- if (!animatingRef.current) {
3868
- displayedPointsRef.current = targetPoints;
3869
- }
3870
- }, [targetPoints]);
3871
3868
  react.useEffect(() => {
3872
3869
  const shouldAnimate = enabled && !reducedMotion && chartPhase === "ready" && durationMs > 0 && renderData.length > 0;
3873
3870
  if (!shouldAnimate) {
@@ -3930,6 +3927,11 @@ function useAnimatedSeriesPath({
3930
3927
  dataKey,
3931
3928
  targetPoints
3932
3929
  ]);
3930
+ react.useEffect(() => {
3931
+ if (!animatingRef.current) {
3932
+ displayedPointsRef.current = targetPoints;
3933
+ }
3934
+ }, [targetPoints]);
3933
3935
  const activePoints = animatedPoints ?? targetPoints;
3934
3936
  const pathD = react.useMemo(
3935
3937
  () => seriesPathFromPoints(activePoints, curve),
@@ -11999,7 +12001,6 @@ function PieCenterShell({
11999
12001
  return () => {
12000
12002
  cancelAnimationFrame(outerRaf);
12001
12003
  cancelAnimationFrame(innerRaf);
12002
- introStartedRef.current = false;
12003
12004
  };
12004
12005
  }
12005
12006
  setFlowTotal(centerValue);
@@ -12761,6 +12762,256 @@ function useRingHover() {
12761
12762
  function useRing() {
12762
12763
  return { ...useRingStable(), ...useRingHover() };
12763
12764
  }
12765
+ function generateArcPath(innerRadius, outerRadius, startAngle, endAngle, cornerRadius) {
12766
+ const generator = shape.arc({
12767
+ innerRadius,
12768
+ outerRadius,
12769
+ cornerRadius
12770
+ });
12771
+ return generator({ startAngle, endAngle }) || "";
12772
+ }
12773
+ function ringHoverScale(isHovered, isPushedOut) {
12774
+ if (isHovered) {
12775
+ return 1.03;
12776
+ }
12777
+ if (isPushedOut) {
12778
+ return 1.02;
12779
+ }
12780
+ return 1;
12781
+ }
12782
+ function RingProgressPath({
12783
+ progressComplete,
12784
+ progressPath,
12785
+ animatedProgressPath,
12786
+ color
12787
+ }) {
12788
+ if (progressComplete) {
12789
+ if (!progressPath) {
12790
+ return null;
12791
+ }
12792
+ return /* @__PURE__ */ jsxRuntime.jsx("path", { d: progressPath, fill: color });
12793
+ }
12794
+ return /* @__PURE__ */ jsxRuntime.jsx(react$1.motion.path, { d: animatedProgressPath, fill: color });
12795
+ }
12796
+ var Ring = react.memo(function Ring2({
12797
+ index,
12798
+ color: colorProp,
12799
+ animate: animate7 = true,
12800
+ showGlow = true,
12801
+ lineCap = "round"
12802
+ }) {
12803
+ const {
12804
+ data,
12805
+ getColor,
12806
+ getRingRadii,
12807
+ startAngle,
12808
+ endAngle,
12809
+ enterTransition,
12810
+ enterStaggerScale,
12811
+ animationKey
12812
+ } = useRingStable();
12813
+ const { hoveredIndex, setHoveredIndex } = useRingHover();
12814
+ const expandDelay = index * 0.08 * enterStaggerScale;
12815
+ const expandProgress = useMountProgress(
12816
+ enterTransition,
12817
+ expandDelay,
12818
+ `${animationKey}-expand-${index}`
12819
+ );
12820
+ const expandComplete = useEnterComplete(expandProgress);
12821
+ const progressDelay = (0.6 + index * 0.1) * enterStaggerScale;
12822
+ const progressMount = useMountProgress(
12823
+ enterTransition,
12824
+ progressDelay,
12825
+ `${animationKey}-progress-${index}`
12826
+ );
12827
+ const progressComplete = useEnterComplete(progressMount);
12828
+ const ringData = data[index];
12829
+ const progress = ringData ? ringData.value / ringData.maxValue : 0;
12830
+ const arcRange = endAngle - startAngle;
12831
+ const animatedProgressPath = react$1.useTransform(progressMount, (v) => {
12832
+ if (!ringData) {
12833
+ return "";
12834
+ }
12835
+ const currentEndAngle = startAngle + arcRange * progress * v;
12836
+ if (currentEndAngle <= startAngle + 0.01) {
12837
+ return "";
12838
+ }
12839
+ const radii = getRingRadii(index);
12840
+ const corner = lineCap === "round" ? (radii.outerRadius - radii.innerRadius) / 2 : 0;
12841
+ return generateArcPath(
12842
+ radii.innerRadius,
12843
+ radii.outerRadius,
12844
+ startAngle,
12845
+ currentEndAngle,
12846
+ corner
12847
+ );
12848
+ });
12849
+ const enterScale = react$1.useTransform(expandProgress, [0, 1], [0, 1]);
12850
+ const handleMouseEnter = react.useCallback(
12851
+ () => setHoveredIndex(index),
12852
+ [index, setHoveredIndex]
12853
+ );
12854
+ const handleMouseLeave = react.useCallback(
12855
+ () => setHoveredIndex(null),
12856
+ [setHoveredIndex]
12857
+ );
12858
+ if (!ringData) {
12859
+ return null;
12860
+ }
12861
+ const { innerRadius, outerRadius } = getRingRadii(index);
12862
+ const color = colorProp || getColor(index);
12863
+ const isHovered = hoveredIndex === index;
12864
+ const isFaded = hoveredIndex !== null && hoveredIndex !== index;
12865
+ const isPushedOut = hoveredIndex !== null && hoveredIndex < index;
12866
+ const cornerRadius = lineCap === "round" ? (outerRadius - innerRadius) / 2 : 0;
12867
+ const bgPath = generateArcPath(
12868
+ innerRadius,
12869
+ outerRadius,
12870
+ startAngle,
12871
+ endAngle,
12872
+ cornerRadius
12873
+ );
12874
+ const progressEndAngle = startAngle + arcRange * progress;
12875
+ const progressPath = progressEndAngle <= startAngle + 0.01 ? "" : generateArcPath(
12876
+ innerRadius,
12877
+ outerRadius,
12878
+ startAngle,
12879
+ progressEndAngle,
12880
+ cornerRadius
12881
+ );
12882
+ const hoverScale = ringHoverScale(isHovered, isPushedOut);
12883
+ const layerOpacity = isFaded ? 0.35 : 1;
12884
+ const enterDone = !animate7 || expandComplete && progressComplete;
12885
+ const glowStyle = {
12886
+ filter: showGlow && isHovered ? `drop-shadow(0 0 12px ${color})` : "none"
12887
+ };
12888
+ const groupStyle = {
12889
+ cursor: "pointer",
12890
+ transformOrigin: "0px 0px"
12891
+ };
12892
+ if (enterDone) {
12893
+ return /* @__PURE__ */ jsxRuntime.jsx(
12894
+ react$1.motion.g,
12895
+ {
12896
+ animate: { scale: hoverScale, opacity: layerOpacity },
12897
+ initial: { opacity: layerOpacity, scale: 1 },
12898
+ onMouseEnter: handleMouseEnter,
12899
+ onMouseLeave: handleMouseLeave,
12900
+ style: groupStyle,
12901
+ transition: {
12902
+ scale: { type: "spring", stiffness: 400, damping: 25 },
12903
+ opacity: { duration: 0.15 }
12904
+ },
12905
+ children: /* @__PURE__ */ jsxRuntime.jsxs("g", { style: glowStyle, children: [
12906
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: bgPath, fill: ringCssVars.ringBackground }),
12907
+ progressPath ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: progressPath, fill: color }) : null
12908
+ ] })
12909
+ }
12910
+ );
12911
+ }
12912
+ if (!expandComplete) {
12913
+ return /* @__PURE__ */ jsxRuntime.jsx(
12914
+ react$1.motion.g,
12915
+ {
12916
+ onMouseEnter: handleMouseEnter,
12917
+ onMouseLeave: handleMouseLeave,
12918
+ style: {
12919
+ ...groupStyle,
12920
+ scale: enterScale,
12921
+ opacity: layerOpacity
12922
+ },
12923
+ children: /* @__PURE__ */ jsxRuntime.jsx("g", { style: glowStyle, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: bgPath, fill: ringCssVars.ringBackground }) })
12924
+ }
12925
+ );
12926
+ }
12927
+ return /* @__PURE__ */ jsxRuntime.jsx(
12928
+ react$1.motion.g,
12929
+ {
12930
+ animate: { scale: hoverScale, opacity: layerOpacity },
12931
+ initial: { opacity: layerOpacity, scale: 1 },
12932
+ onMouseEnter: handleMouseEnter,
12933
+ onMouseLeave: handleMouseLeave,
12934
+ style: groupStyle,
12935
+ transition: {
12936
+ scale: { type: "spring", stiffness: 400, damping: 25 },
12937
+ opacity: { duration: 0.15 }
12938
+ },
12939
+ children: /* @__PURE__ */ jsxRuntime.jsxs("g", { style: glowStyle, children: [
12940
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: bgPath, fill: ringCssVars.ringBackground }),
12941
+ /* @__PURE__ */ jsxRuntime.jsx(
12942
+ RingProgressPath,
12943
+ {
12944
+ animatedProgressPath,
12945
+ color,
12946
+ progressComplete,
12947
+ progressPath
12948
+ }
12949
+ )
12950
+ ] })
12951
+ }
12952
+ );
12953
+ });
12954
+ Ring.displayName = "Ring";
12955
+ function RingCenter({
12956
+ defaultLabel = "Total",
12957
+ formatOptions = defaultChartStatFlowFormat,
12958
+ children,
12959
+ className = "",
12960
+ valueClassName = chartCenterValueClassName,
12961
+ labelClassName = chartCenterLabelClassName,
12962
+ prefix,
12963
+ suffix
12964
+ }) {
12965
+ const { data, totalValue, baseInnerRadius } = useRingStable();
12966
+ const { hoveredIndex } = useRingHover();
12967
+ const hoveredData = hoveredIndex === null ? null : data[hoveredIndex];
12968
+ const displayValue = hoveredData ? hoveredData.value : totalValue;
12969
+ const displayLabel = hoveredData ? hoveredData.label : defaultLabel;
12970
+ const centerSize = baseInnerRadius * 2 - 16;
12971
+ if (children && hoveredData) {
12972
+ return /* @__PURE__ */ jsxRuntime.jsx(
12973
+ "div",
12974
+ {
12975
+ className: cn(
12976
+ chartCenterContainerClassName,
12977
+ "flex items-center justify-center",
12978
+ className
12979
+ ),
12980
+ style: { width: centerSize, height: centerSize },
12981
+ children: children({
12982
+ value: displayValue,
12983
+ label: displayLabel,
12984
+ isHovered: hoveredIndex !== null,
12985
+ data: hoveredData
12986
+ })
12987
+ }
12988
+ );
12989
+ }
12990
+ return /* @__PURE__ */ jsxRuntime.jsx(
12991
+ "div",
12992
+ {
12993
+ className: cn(
12994
+ chartCenterContainerClassName,
12995
+ "flex flex-col items-center justify-center text-center",
12996
+ className
12997
+ ),
12998
+ style: { width: centerSize, height: centerSize },
12999
+ children: /* @__PURE__ */ jsxRuntime.jsx(
13000
+ ChartStatFlow,
13001
+ {
13002
+ formatOptions,
13003
+ label: displayLabel,
13004
+ labelClassName,
13005
+ prefix,
13006
+ suffix,
13007
+ value: displayValue,
13008
+ valueClassName
13009
+ }
13010
+ )
13011
+ }
13012
+ );
13013
+ }
13014
+ RingCenter.displayName = "RingCenter";
12764
13015
  function generateRingArcPath(innerRadius, outerRadius, startAngle, endAngle, cornerRadius) {
12765
13016
  const generator = shape.arc({
12766
13017
  innerRadius,
@@ -12770,10 +13021,10 @@ function generateRingArcPath(innerRadius, outerRadius, startAngle, endAngle, cor
12770
13021
  return generator({ startAngle, endAngle }) || "";
12771
13022
  }
12772
13023
  function isRing(child) {
12773
- return react.isValidElement(child) && typeof child.type === "function" && (child.type.displayName === "Ring" || child.type.name === "Ring");
13024
+ return react.isValidElement(child) && child.type === Ring;
12774
13025
  }
12775
13026
  function isRingCenter(child) {
12776
- return react.isValidElement(child) && typeof child.type === "function" && (child.type.displayName === "RingCenter" || child.type.name === "RingCenter");
13027
+ return react.isValidElement(child) && child.type === RingCenter;
12777
13028
  }
12778
13029
  function RingChartInner(props) {
12779
13030
  const size = Math.min(props.width, props.height);
@@ -13069,252 +13320,6 @@ function RingChart({
13069
13320
  }
13070
13321
  );
13071
13322
  }
13072
- function generateArcPath(innerRadius, outerRadius, startAngle, endAngle, cornerRadius) {
13073
- const generator = shape.arc({
13074
- innerRadius,
13075
- outerRadius,
13076
- cornerRadius
13077
- });
13078
- return generator({ startAngle, endAngle }) || "";
13079
- }
13080
- function ringHoverScale(isHovered, isPushedOut) {
13081
- if (isHovered) {
13082
- return 1.03;
13083
- }
13084
- if (isPushedOut) {
13085
- return 1.02;
13086
- }
13087
- return 1;
13088
- }
13089
- function RingProgressPath({
13090
- progressComplete,
13091
- progressPath,
13092
- animatedProgressPath,
13093
- color
13094
- }) {
13095
- if (progressComplete) {
13096
- if (!progressPath) {
13097
- return null;
13098
- }
13099
- return /* @__PURE__ */ jsxRuntime.jsx("path", { d: progressPath, fill: color });
13100
- }
13101
- return /* @__PURE__ */ jsxRuntime.jsx(react$1.motion.path, { d: animatedProgressPath, fill: color });
13102
- }
13103
- var Ring = react.memo(function Ring2({
13104
- index,
13105
- color: colorProp,
13106
- animate: animate7 = true,
13107
- showGlow = true,
13108
- lineCap = "round"
13109
- }) {
13110
- const {
13111
- data,
13112
- getColor,
13113
- getRingRadii,
13114
- startAngle,
13115
- endAngle,
13116
- enterTransition,
13117
- enterStaggerScale,
13118
- animationKey
13119
- } = useRingStable();
13120
- const { hoveredIndex, setHoveredIndex } = useRingHover();
13121
- const expandDelay = index * 0.08 * enterStaggerScale;
13122
- const expandProgress = useMountProgress(
13123
- enterTransition,
13124
- expandDelay,
13125
- `${animationKey}-expand-${index}`
13126
- );
13127
- const expandComplete = useEnterComplete(expandProgress);
13128
- const progressDelay = (0.6 + index * 0.1) * enterStaggerScale;
13129
- const progressMount = useMountProgress(
13130
- enterTransition,
13131
- progressDelay,
13132
- `${animationKey}-progress-${index}`
13133
- );
13134
- const progressComplete = useEnterComplete(progressMount);
13135
- const ringData = data[index];
13136
- const progress = ringData ? ringData.value / ringData.maxValue : 0;
13137
- const arcRange = endAngle - startAngle;
13138
- const animatedProgressPath = react$1.useTransform(progressMount, (v) => {
13139
- if (!ringData) {
13140
- return "";
13141
- }
13142
- const currentEndAngle = startAngle + arcRange * progress * v;
13143
- if (currentEndAngle <= startAngle + 0.01) {
13144
- return "";
13145
- }
13146
- const radii = getRingRadii(index);
13147
- const corner = lineCap === "round" ? (radii.outerRadius - radii.innerRadius) / 2 : 0;
13148
- return generateArcPath(
13149
- radii.innerRadius,
13150
- radii.outerRadius,
13151
- startAngle,
13152
- currentEndAngle,
13153
- corner
13154
- );
13155
- });
13156
- const enterScale = react$1.useTransform(expandProgress, [0, 1], [0, 1]);
13157
- const handleMouseEnter = react.useCallback(
13158
- () => setHoveredIndex(index),
13159
- [index, setHoveredIndex]
13160
- );
13161
- const handleMouseLeave = react.useCallback(
13162
- () => setHoveredIndex(null),
13163
- [setHoveredIndex]
13164
- );
13165
- if (!ringData) {
13166
- return null;
13167
- }
13168
- const { innerRadius, outerRadius } = getRingRadii(index);
13169
- const color = colorProp || getColor(index);
13170
- const isHovered = hoveredIndex === index;
13171
- const isFaded = hoveredIndex !== null && hoveredIndex !== index;
13172
- const isPushedOut = hoveredIndex !== null && hoveredIndex < index;
13173
- const cornerRadius = lineCap === "round" ? (outerRadius - innerRadius) / 2 : 0;
13174
- const bgPath = generateArcPath(
13175
- innerRadius,
13176
- outerRadius,
13177
- startAngle,
13178
- endAngle,
13179
- cornerRadius
13180
- );
13181
- const progressEndAngle = startAngle + arcRange * progress;
13182
- const progressPath = progressEndAngle <= startAngle + 0.01 ? "" : generateArcPath(
13183
- innerRadius,
13184
- outerRadius,
13185
- startAngle,
13186
- progressEndAngle,
13187
- cornerRadius
13188
- );
13189
- const hoverScale = ringHoverScale(isHovered, isPushedOut);
13190
- const layerOpacity = isFaded ? 0.35 : 1;
13191
- const enterDone = !animate7 || expandComplete && progressComplete;
13192
- const groupStyle = {
13193
- cursor: "pointer",
13194
- transformOrigin: "0px 0px",
13195
- filter: showGlow && isHovered ? `drop-shadow(0 0 12px ${color})` : "none"
13196
- };
13197
- if (enterDone) {
13198
- return /* @__PURE__ */ jsxRuntime.jsxs(
13199
- react$1.motion.g,
13200
- {
13201
- animate: { scale: hoverScale, opacity: layerOpacity },
13202
- onMouseEnter: handleMouseEnter,
13203
- onMouseLeave: handleMouseLeave,
13204
- style: groupStyle,
13205
- transition: {
13206
- scale: { type: "spring", stiffness: 400, damping: 25 },
13207
- opacity: { duration: 0.15 }
13208
- },
13209
- children: [
13210
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: bgPath, fill: ringCssVars.ringBackground }),
13211
- progressPath ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: progressPath, fill: color }) : null
13212
- ]
13213
- }
13214
- );
13215
- }
13216
- if (!expandComplete) {
13217
- return /* @__PURE__ */ jsxRuntime.jsx(
13218
- react$1.motion.g,
13219
- {
13220
- onMouseEnter: handleMouseEnter,
13221
- onMouseLeave: handleMouseLeave,
13222
- style: {
13223
- ...groupStyle,
13224
- scale: enterScale,
13225
- opacity: layerOpacity
13226
- },
13227
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: bgPath, fill: ringCssVars.ringBackground })
13228
- }
13229
- );
13230
- }
13231
- return /* @__PURE__ */ jsxRuntime.jsxs(
13232
- react$1.motion.g,
13233
- {
13234
- animate: { scale: hoverScale, opacity: layerOpacity },
13235
- onMouseEnter: handleMouseEnter,
13236
- onMouseLeave: handleMouseLeave,
13237
- style: groupStyle,
13238
- transition: {
13239
- scale: { type: "spring", stiffness: 400, damping: 25 },
13240
- opacity: { duration: 0.15 }
13241
- },
13242
- children: [
13243
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: bgPath, fill: ringCssVars.ringBackground }),
13244
- /* @__PURE__ */ jsxRuntime.jsx(
13245
- RingProgressPath,
13246
- {
13247
- animatedProgressPath,
13248
- color,
13249
- progressComplete,
13250
- progressPath
13251
- }
13252
- )
13253
- ]
13254
- }
13255
- );
13256
- });
13257
- Ring.displayName = "Ring";
13258
- function RingCenter({
13259
- defaultLabel = "Total",
13260
- formatOptions = defaultChartStatFlowFormat,
13261
- children,
13262
- className = "",
13263
- valueClassName = chartCenterValueClassName,
13264
- labelClassName = chartCenterLabelClassName,
13265
- prefix,
13266
- suffix
13267
- }) {
13268
- const { data, totalValue, baseInnerRadius } = useRingStable();
13269
- const { hoveredIndex } = useRingHover();
13270
- const hoveredData = hoveredIndex === null ? null : data[hoveredIndex];
13271
- const displayValue = hoveredData ? hoveredData.value : totalValue;
13272
- const displayLabel = hoveredData ? hoveredData.label : defaultLabel;
13273
- const centerSize = baseInnerRadius * 2 - 16;
13274
- if (children && hoveredData) {
13275
- return /* @__PURE__ */ jsxRuntime.jsx(
13276
- "div",
13277
- {
13278
- className: cn(
13279
- chartCenterContainerClassName,
13280
- "flex items-center justify-center",
13281
- className
13282
- ),
13283
- style: { width: centerSize, height: centerSize },
13284
- children: children({
13285
- value: displayValue,
13286
- label: displayLabel,
13287
- isHovered: hoveredIndex !== null,
13288
- data: hoveredData
13289
- })
13290
- }
13291
- );
13292
- }
13293
- return /* @__PURE__ */ jsxRuntime.jsx(
13294
- "div",
13295
- {
13296
- className: cn(
13297
- chartCenterContainerClassName,
13298
- "flex flex-col items-center justify-center text-center",
13299
- className
13300
- ),
13301
- style: { width: centerSize, height: centerSize },
13302
- children: /* @__PURE__ */ jsxRuntime.jsx(
13303
- ChartStatFlow,
13304
- {
13305
- formatOptions,
13306
- label: displayLabel,
13307
- labelClassName,
13308
- prefix,
13309
- suffix,
13310
- value: displayValue,
13311
- valueClassName
13312
- }
13313
- )
13314
- }
13315
- );
13316
- }
13317
- RingCenter.displayName = "RingCenter";
13318
13323
  function Card({ className, ...props }) {
13319
13324
  return /* @__PURE__ */ jsxRuntime.jsx(
13320
13325
  "div",