@cloudflare/kumo 2.5.1 → 2.6.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 (193) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/ai/component-registry.json +176 -124
  3. package/ai/component-registry.md +171 -51
  4. package/ai/schemas.ts +23 -12
  5. package/dist/.build-complete +1 -1
  6. package/dist/ai/schemas.d.ts +75 -48
  7. package/dist/ai/schemas.d.ts.map +1 -1
  8. package/dist/ai/schemas.js +207 -197
  9. package/dist/ai/schemas.js.map +1 -1
  10. package/dist/chunks/SankeyChart-g1tng405ml2e0qg2.js +890 -0
  11. package/dist/chunks/SankeyChart-g1tng405ml2e0qg2.js.map +1 -0
  12. package/dist/chunks/{autocomplete-d0w42h1frdu03df6.js → autocomplete-hgprlcuf0ixbbo6d.js} +18 -18
  13. package/dist/chunks/{autocomplete-d0w42h1frdu03df6.js.map → autocomplete-hgprlcuf0ixbbo6d.js.map} +1 -1
  14. package/dist/chunks/{breadcrumbs-j214mimk5zj4ffp4.js → breadcrumbs-lyj8ljudrm2owx5y.js} +2 -2
  15. package/dist/chunks/{breadcrumbs-j214mimk5zj4ffp4.js.map → breadcrumbs-lyj8ljudrm2owx5y.js.map} +1 -1
  16. package/dist/chunks/button-gtdhvogt5rlrf1is.js +237 -0
  17. package/dist/chunks/button-gtdhvogt5rlrf1is.js.map +1 -0
  18. package/dist/chunks/{checkbox-dqih8tzzt3vhp870.js → checkbox-byg8t8r9vbmif696.js} +3 -3
  19. package/dist/chunks/{checkbox-dqih8tzzt3vhp870.js.map → checkbox-byg8t8r9vbmif696.js.map} +1 -1
  20. package/dist/chunks/{clipboard-text-mrut8z3dt1w0efxz.js → clipboard-text-lf909phvldd8rfk8.js} +4 -4
  21. package/dist/chunks/{clipboard-text-mrut8z3dt1w0efxz.js.map → clipboard-text-lf909phvldd8rfk8.js.map} +1 -1
  22. package/dist/chunks/{collapsible-nzqcf9zwnjkxqzr6.js → collapsible-dl61f8gd4j897hmv.js} +4 -4
  23. package/dist/chunks/{collapsible-nzqcf9zwnjkxqzr6.js.map → collapsible-dl61f8gd4j897hmv.js.map} +1 -1
  24. package/dist/chunks/{combobox-msvukodjsqzlvpqc.js → combobox-dxff22zxzq846nec.js} +4 -4
  25. package/dist/chunks/{combobox-msvukodjsqzlvpqc.js.map → combobox-dxff22zxzq846nec.js.map} +1 -1
  26. package/dist/chunks/{command-palette-fqhyacp33fhyf696.js → command-palette-i4r0402b838wiy0j.js} +21 -21
  27. package/dist/chunks/{command-palette-fqhyacp33fhyf696.js.map → command-palette-i4r0402b838wiy0j.js.map} +1 -1
  28. package/dist/chunks/{dialog-3mpu1i1wssrsz8i6.js → dialog-g1b8161nbyixdit0.js} +7 -7
  29. package/dist/chunks/{dialog-3mpu1i1wssrsz8i6.js.map → dialog-g1b8161nbyixdit0.js.map} +1 -1
  30. package/dist/chunks/{dropdown-g4sb4cw9ffqaw5gx.js → dropdown-irp18txvgz8590e9.js} +27 -27
  31. package/dist/chunks/{dropdown-g4sb4cw9ffqaw5gx.js.map → dropdown-irp18txvgz8590e9.js.map} +1 -1
  32. package/dist/chunks/{empty-n17inn1z67bpohkw.js → empty-daa6d7u9oleaw24a.js} +2 -2
  33. package/dist/chunks/{empty-n17inn1z67bpohkw.js.map → empty-daa6d7u9oleaw24a.js.map} +1 -1
  34. package/dist/chunks/{field-c8o7h3rlam4c9pcx.js → field-f1hy08um3jf9jos6.js} +3 -3
  35. package/dist/chunks/{field-c8o7h3rlam4c9pcx.js.map → field-f1hy08um3jf9jos6.js.map} +1 -1
  36. package/dist/chunks/{input-area-eurk3seud30ricwn.js → input-area-bwyujceeulpfkpxv.js} +4 -4
  37. package/dist/chunks/{input-area-eurk3seud30ricwn.js.map → input-area-bwyujceeulpfkpxv.js.map} +1 -1
  38. package/dist/chunks/{input-en8hhb14mmt3tfwn.js → input-f2ct7obgdzypjmp2.js} +3 -3
  39. package/dist/chunks/{input-en8hhb14mmt3tfwn.js.map → input-f2ct7obgdzypjmp2.js.map} +1 -1
  40. package/dist/chunks/{input-group-d09ocmjcbdai0gze.js → input-group-kcd3jin5pbdijmw8.js} +5 -5
  41. package/dist/chunks/{input-group-d09ocmjcbdai0gze.js.map → input-group-kcd3jin5pbdijmw8.js.map} +1 -1
  42. package/dist/chunks/{label-c8rz453pti66slki.js → label-himqjkdhh0hgfdsa.js} +3 -3
  43. package/dist/chunks/{label-c8rz453pti66slki.js.map → label-himqjkdhh0hgfdsa.js.map} +1 -1
  44. package/dist/chunks/{layer-card-er4flkcxmzfug8jw.js → layer-card-cshi5vydqg3phyfx.js} +2 -2
  45. package/dist/chunks/{layer-card-er4flkcxmzfug8jw.js.map → layer-card-cshi5vydqg3phyfx.js.map} +1 -1
  46. package/dist/chunks/{link-i6vnwyjcwvjz5btm.js → link-bw21ofmgg58igq5n.js} +4 -4
  47. package/dist/chunks/{link-i6vnwyjcwvjz5btm.js.map → link-bw21ofmgg58igq5n.js.map} +1 -1
  48. package/dist/chunks/{menubar-ng5if56amh1tto4j.js → menubar-m12wcbbucuszspw4.js} +2 -2
  49. package/dist/chunks/{menubar-ng5if56amh1tto4j.js.map → menubar-m12wcbbucuszspw4.js.map} +1 -1
  50. package/dist/chunks/{meter-d5igshkjqttl1fdj.js → meter-dn8vgc0smpk0du75.js} +4 -4
  51. package/dist/chunks/{meter-d5igshkjqttl1fdj.js.map → meter-dn8vgc0smpk0du75.js.map} +1 -1
  52. package/dist/chunks/{pagination-bw7vwca4wrfjm8vb.js → pagination-oafyxvdndm9m8250.js} +3 -3
  53. package/dist/chunks/{pagination-bw7vwca4wrfjm8vb.js.map → pagination-oafyxvdndm9m8250.js.map} +1 -1
  54. package/dist/chunks/{popover-ozf1j7oi7pxiudyz.js → popover-bbxr39l1lx175hum.js} +18 -18
  55. package/dist/chunks/{popover-ozf1j7oi7pxiudyz.js.map → popover-bbxr39l1lx175hum.js.map} +1 -1
  56. package/dist/chunks/radio-ffx05ih9nc764evh.js +226 -0
  57. package/dist/chunks/radio-ffx05ih9nc764evh.js.map +1 -0
  58. package/dist/chunks/{select-dw9iw35ug7yer3o3.js → select-kl1skfh3pmwc33rp.js} +6 -6
  59. package/dist/chunks/{select-dw9iw35ug7yer3o3.js.map → select-kl1skfh3pmwc33rp.js.map} +1 -1
  60. package/dist/chunks/{sensitive-input-dgoxjtoxl4zqa51v.js → sensitive-input-izmbyk1t7r56ciiq.js} +4 -4
  61. package/dist/chunks/{sensitive-input-dgoxjtoxl4zqa51v.js.map → sensitive-input-izmbyk1t7r56ciiq.js.map} +1 -1
  62. package/dist/chunks/{sidebar-nbdw4rgvuabxp5nj.js → sidebar-ior8rnhsd7gy5am5.js} +49 -49
  63. package/dist/chunks/sidebar-ior8rnhsd7gy5am5.js.map +1 -0
  64. package/dist/chunks/{surface-iyejjbqogjbo7ise.js → surface-g5a1buofz4erjov2.js} +2 -2
  65. package/dist/chunks/{surface-iyejjbqogjbo7ise.js.map → surface-g5a1buofz4erjov2.js.map} +1 -1
  66. package/dist/chunks/{switch-g8f77h69h34xld06.js → switch-kh8a6l3l0hszm9h4.js} +3 -3
  67. package/dist/chunks/{switch-g8f77h69h34xld06.js.map → switch-kh8a6l3l0hszm9h4.js.map} +1 -1
  68. package/dist/chunks/{table-e1te1im2tt2ez05y.js → table-dz2k55oab66h2vi9.js} +2 -2
  69. package/dist/chunks/{table-e1te1im2tt2ez05y.js.map → table-dz2k55oab66h2vi9.js.map} +1 -1
  70. package/dist/chunks/{tabs-ho9t1gkq22jb855l.js → tabs-kcw98wibdz4mhpkc.js} +2 -2
  71. package/dist/chunks/{tabs-ho9t1gkq22jb855l.js.map → tabs-kcw98wibdz4mhpkc.js.map} +1 -1
  72. package/dist/chunks/{toast-kvbgct0jvfmn4mas.js → toast-dkdo1lu72tnefya6.js} +7 -7
  73. package/dist/chunks/{toast-kvbgct0jvfmn4mas.js.map → toast-dkdo1lu72tnefya6.js.map} +1 -1
  74. package/dist/chunks/toolbar-o7xe6pd189evdd53.js +172 -0
  75. package/dist/chunks/toolbar-o7xe6pd189evdd53.js.map +1 -0
  76. package/dist/chunks/{tooltip-ken77ixya0qpidie.js → tooltip-eqnhjdbvwapy8gj4.js} +4 -4
  77. package/dist/chunks/{tooltip-ken77ixya0qpidie.js.map → tooltip-eqnhjdbvwapy8gj4.js.map} +1 -1
  78. package/dist/chunks/{vendor-base-ui-knphx7dts1vm1x37.js → vendor-base-ui-f9z44m829vvptrg0.js} +2209 -2207
  79. package/dist/chunks/{vendor-base-ui-knphx7dts1vm1x37.js.map → vendor-base-ui-f9z44m829vvptrg0.js.map} +1 -1
  80. package/dist/code.js +1 -1
  81. package/dist/components/autocomplete.js +1 -1
  82. package/dist/components/breadcrumbs.js +1 -1
  83. package/dist/components/button.js +1 -1
  84. package/dist/components/chart.js +1 -1
  85. package/dist/components/checkbox.js +1 -1
  86. package/dist/components/clipboard-text.js +1 -1
  87. package/dist/components/collapsible.js +1 -1
  88. package/dist/components/combobox.js +1 -1
  89. package/dist/components/command-palette.js +1 -1
  90. package/dist/components/dialog.js +1 -1
  91. package/dist/components/dropdown.js +1 -1
  92. package/dist/components/empty.js +1 -1
  93. package/dist/components/field.js +1 -1
  94. package/dist/components/input-group.js +1 -1
  95. package/dist/components/input.js +3 -3
  96. package/dist/components/label.js +1 -1
  97. package/dist/components/layer-card.js +1 -1
  98. package/dist/components/link.js +1 -1
  99. package/dist/components/menubar.js +1 -1
  100. package/dist/components/meter.js +1 -1
  101. package/dist/components/pagination.js +1 -1
  102. package/dist/components/popover.js +1 -1
  103. package/dist/components/radio.js +1 -1
  104. package/dist/components/select.js +1 -1
  105. package/dist/components/sensitive-input.js +1 -1
  106. package/dist/components/sidebar.js +1 -1
  107. package/dist/components/surface.js +1 -1
  108. package/dist/components/switch.js +1 -1
  109. package/dist/components/table.js +1 -1
  110. package/dist/components/tabs.js +1 -1
  111. package/dist/components/toast.js +2 -2
  112. package/dist/components/toolbar.js +8 -0
  113. package/dist/components/toolbar.js.map +1 -0
  114. package/dist/components/tooltip.js +1 -1
  115. package/dist/index.js +199 -195
  116. package/dist/index.js.map +1 -1
  117. package/dist/primitives/accordion.js +1 -1
  118. package/dist/primitives/alert-dialog.js +1 -1
  119. package/dist/primitives/autocomplete.js +1 -1
  120. package/dist/primitives/avatar.js +1 -1
  121. package/dist/primitives/button.js +1 -1
  122. package/dist/primitives/checkbox-group.js +1 -1
  123. package/dist/primitives/checkbox.js +1 -1
  124. package/dist/primitives/collapsible.js +1 -1
  125. package/dist/primitives/combobox.js +1 -1
  126. package/dist/primitives/context-menu.js +1 -1
  127. package/dist/primitives/csp-provider.js +1 -1
  128. package/dist/primitives/dialog.js +1 -1
  129. package/dist/primitives/direction-provider.js +1 -1
  130. package/dist/primitives/drawer.js +1 -1
  131. package/dist/primitives/field.js +1 -1
  132. package/dist/primitives/fieldset.js +1 -1
  133. package/dist/primitives/form.js +1 -1
  134. package/dist/primitives/input.js +1 -1
  135. package/dist/primitives/menu.js +1 -1
  136. package/dist/primitives/menubar.js +1 -1
  137. package/dist/primitives/meter.js +1 -1
  138. package/dist/primitives/navigation-menu.js +1 -1
  139. package/dist/primitives/number-field.js +1 -1
  140. package/dist/primitives/otp-field.js +1 -1
  141. package/dist/primitives/popover.js +1 -1
  142. package/dist/primitives/preview-card.js +1 -1
  143. package/dist/primitives/progress.js +1 -1
  144. package/dist/primitives/radio-group.js +1 -1
  145. package/dist/primitives/radio.js +1 -1
  146. package/dist/primitives/scroll-area.js +1 -1
  147. package/dist/primitives/select.js +1 -1
  148. package/dist/primitives/separator.js +1 -1
  149. package/dist/primitives/slider.js +1 -1
  150. package/dist/primitives/switch.js +1 -1
  151. package/dist/primitives/tabs.js +1 -1
  152. package/dist/primitives/toast.js +1 -1
  153. package/dist/primitives/toggle-group.js +1 -1
  154. package/dist/primitives/toggle.js +1 -1
  155. package/dist/primitives/toolbar.js +1 -1
  156. package/dist/primitives/tooltip.js +1 -1
  157. package/dist/primitives.js +1 -1
  158. package/dist/scripts/theme-generator/config.d.ts.map +1 -1
  159. package/dist/scripts/theme-generator/config.js +13 -2
  160. package/dist/scripts/theme-generator/config.js.map +1 -1
  161. package/dist/src/components/button/button.d.ts +5 -5
  162. package/dist/src/components/button/button.d.ts.map +1 -1
  163. package/dist/src/components/chart/EChart.d.ts +12 -4
  164. package/dist/src/components/chart/EChart.d.ts.map +1 -1
  165. package/dist/src/components/chart/Legend.d.ts +11 -2
  166. package/dist/src/components/chart/Legend.d.ts.map +1 -1
  167. package/dist/src/components/chart/TimeseriesChart.d.ts +15 -1
  168. package/dist/src/components/chart/TimeseriesChart.d.ts.map +1 -1
  169. package/dist/src/components/radio/index.d.ts +1 -1
  170. package/dist/src/components/radio/index.d.ts.map +1 -1
  171. package/dist/src/components/radio/radio.d.ts +49 -10
  172. package/dist/src/components/radio/radio.d.ts.map +1 -1
  173. package/dist/src/components/radio/radio.type-spec.d.ts +12 -0
  174. package/dist/src/components/radio/radio.type-spec.d.ts.map +1 -0
  175. package/dist/src/components/toolbar/index.d.ts +2 -0
  176. package/dist/src/components/toolbar/index.d.ts.map +1 -0
  177. package/dist/src/components/toolbar/toolbar.d.ts +50 -0
  178. package/dist/src/components/toolbar/toolbar.d.ts.map +1 -0
  179. package/dist/src/index.d.ts +2 -1
  180. package/dist/src/index.d.ts.map +1 -1
  181. package/dist/styles/kumo-standalone.css +1 -1
  182. package/dist/styles/theme-kumo.css +11 -4
  183. package/package.json +5 -1
  184. package/scripts/component-registry/discovery.ts +16 -11
  185. package/scripts/component-registry/metadata.ts +30 -0
  186. package/scripts/theme-generator/config.ts +14 -2
  187. package/dist/chunks/SankeyChart-i1m7zv0lys3j0iq6.js +0 -775
  188. package/dist/chunks/SankeyChart-i1m7zv0lys3j0iq6.js.map +0 -1
  189. package/dist/chunks/button-mnrxu6dud2x5js5b.js +0 -210
  190. package/dist/chunks/button-mnrxu6dud2x5js5b.js.map +0 -1
  191. package/dist/chunks/radio-gpg6kmzonr2cayq1.js +0 -218
  192. package/dist/chunks/radio-gpg6kmzonr2cayq1.js.map +0 -1
  193. package/dist/chunks/sidebar-nbdw4rgvuabxp5nj.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SankeyChart-g1tng405ml2e0qg2.js","sources":["../../src/components/chart/Color.ts","../../src/components/chart/EChart.tsx","../../src/components/chart/TimeseriesChart.tsx","../../src/components/chart/Legend.tsx","../../src/components/chart/SankeyChart.tsx"],"sourcesContent":["/**\n * Categorical colors for light mode — used when assigning colors to data series\n * by index (e.g. the first series gets Blue, the second gets Violet, etc.).\n */\nenum ChartCategoricalLightColors {\n Blue = \"#4290F0\",\n Yellow = \"#F5B647\",\n Pink = \"#E8649D\",\n Purple = \"#8D58EE\",\n Teal = \"#50C3B6\",\n Orange = \"#D37536\",\n}\n\n/**\n * Categorical colors for dark mode\n */\nenum ChartCategoricalDarkColors {\n Blue = \"#4290F0\",\n Yellow = \"#EEB720\",\n Pink = \"#E8649D\",\n Purple = \"#8D58EE\",\n Teal = \"#50C3B6\",\n Orange = \"#D37536\",\n}\n\n/**\n * Semantic colors for light mode — used to convey meaning (status, severity)\n * rather than just distinguishing series. Use via `ChartPalette.semantic()`.\n */\nenum ChartSemanticLightColors {\n Attention = \"#FC574A\",\n Warning = \"#F8A054\",\n Success = \"#00A63E\",\n Neutral = \"#B9D6FF\",\n Disabled = \"#CBCBCB\",\n Skeleton = \"#DDDDDD\",\n}\n\n/**\n * Semantic colors for dark mode\n */\nenum ChartSemanticDarkColors {\n Attention = \"#FC574A\",\n Warning = \"#F8A054\",\n Success = \"#00A63E\",\n Neutral = \"#8EC5FF\",\n Disabled = \"#878787\",\n Skeleton = \"#5C5C5C\",\n}\n\nexport type ChartSemanticColorName =\n | \"Attention\"\n | \"Warning\"\n | \"Success\"\n | \"Neutral\"\n | \"Disabled\"\n | \"Skeleton\";\n\n/**\n * Sequential color palettes for light mode with the colour in position #2 of the array as the base.\n */\nconst sequentialLight = {\n blues: [\"#E1EAF4\", \"#8EBCF6\", \"#4290F0\", \"#0E58B4\", \"#03254F\"],\n};\n\n/**\n * Sequential color palettes for dark mode. These are the reverse of the light mode palettes using the same base color (position 2).\n */\nconst sequentialDark = {\n blues: [\"#03254F\", \"#0E58B4\", \"#4290F0\", \"#A6BFDD\", \"#E1EAF4\"],\n};\n\n/**\n * Ordered list of categorical colors for light mode, indexed by series position.\n * Used as the default ECharts color palette when `isDarkMode` is `false`.\n */\nexport const CHART_LIGHT_COLORS = [\n ChartCategoricalLightColors.Blue,\n ChartCategoricalLightColors.Yellow,\n ChartCategoricalLightColors.Pink,\n ChartCategoricalLightColors.Purple,\n ChartCategoricalLightColors.Teal,\n ChartCategoricalLightColors.Orange,\n];\n\n/**\n * Ordered list of categorical colors for dark mode, indexed by series position.\n * Used as the default ECharts color palette when `isDarkMode` is `true`.\n */\nexport const CHART_DARK_COLORS = [\n ChartCategoricalDarkColors.Blue,\n ChartCategoricalDarkColors.Yellow,\n ChartCategoricalDarkColors.Pink,\n ChartCategoricalDarkColors.Purple,\n ChartCategoricalDarkColors.Teal,\n ChartCategoricalDarkColors.Orange,\n];\n\n/**\n * Utilities for resolving Kumo chart colors by semantic name or series index.\n * All functions accept an `isDarkMode` flag and return the appropriate color string.\n */\nexport namespace ChartPalette {\n /**\n * Returns the hex color for a named semantic value (status, severity, etc.).\n *\n * @example\n * ```ts\n * ChartPalette.semantic(\"Attention\") // \"#FC574A\" (light)\n * ChartPalette.semantic(\"Warning\", true) // \"#F8A054\" (dark)\n * ```\n */\n export function semantic(\n name: ChartSemanticColorName,\n isDarkMode = false,\n ): string {\n return isDarkMode\n ? ChartSemanticDarkColors[name]\n : ChartSemanticLightColors[name];\n }\n\n /**\n * Returns the categorical color for a given series index.\n * Wraps around via modulo when `index` exceeds the palette length (6 colors).\n *\n * @example\n * ```ts\n * ChartPalette.categorical(0) // Blue (light)\n * ChartPalette.categorical(0, true) // Blue (dark)\n * ChartPalette.categorical(6) // wraps back to Blue\n * ```\n */\n export function categorical(index: number, isDarkMode = false): string {\n return isDarkMode\n ? CHART_DARK_COLORS[index % CHART_DARK_COLORS.length]\n : CHART_LIGHT_COLORS[index % CHART_LIGHT_COLORS.length];\n }\n\n /**\n * Returns all steps of a named sequential palette as an array.\n *\n * @example\n * ```ts\n * ChartPalette.sequential(\"blues\") // 5-step array (light)\n * ChartPalette.sequential(\"blues\", true) // 5-step array (dark)\n * ```\n */\n export function sequential(\n palette: keyof typeof sequentialLight,\n isDarkMode = false,\n ): string[] {\n return isDarkMode\n ? [...sequentialDark[palette]]\n : [...sequentialLight[palette]];\n }\n\n /**\n * Returns the hex color for chart text/labels.\n *\n * @example\n * ```ts\n * ChartPalette.text(\"primary\") // \"#6B7280\" (light)\n * ChartPalette.text(\"primary\", true) // \"#9CA3AF\" (dark)\n * ChartPalette.text(\"secondary\") // \"#9CA3AF\" (light)\n * ```\n */\n export function text(variant: \"primary\" | \"secondary\", isDarkMode = false) {\n const colors = {\n light: { primary: \"#6B7280\", secondary: \"#9CA3AF\" },\n dark: { primary: \"#9CA3AF\", secondary: \"#6B7280\" },\n };\n return isDarkMode ? colors.dark[variant] : colors.light[variant];\n }\n}\n","import type * as echarts from \"echarts/core\";\nimport type {\n EChartsOption,\n SetOptionOpts,\n TooltipComponentOption,\n} from \"echarts\";\nimport { forwardRef, useEffect, useRef } from \"react\";\nimport { cn } from \"../../utils\";\nimport { CHART_DARK_COLORS, CHART_LIGHT_COLORS } from \"./Color\";\n\n/** Parameters passed to mouse event handlers on chart elements */\ntype EChartsMouseEventParams = {\n /** The type of component that triggered the event (e.g. \"series\", \"markPoint\") */\n componentType: string;\n /** Series type (e.g. \"line\", \"bar\") — present when componentType is \"series\" */\n seriesType?: string;\n /** Zero-based index of the series in the option.series array */\n seriesIndex?: number;\n /** Name of the series */\n seriesName?: string;\n /** Name of the data item */\n name?: string;\n /** Zero-based index of the data item within its series */\n dataIndex?: number;\n /** Raw data item value */\n data?: any;\n /** Sub-type of data (e.g. \"node\", \"edge\" for graph series) */\n dataType?: string;\n /** Numeric or array value of the data item */\n value?: number | any[];\n /** Resolved color of the series or data item */\n color?: string;\n};\n\n/**\n * Tooltip options with the `formatter` property removed and replaced with\n * `dangerousHtmlFormatter` to make the security implications more explicit.\n */\nexport type SafeTooltipOption = Omit<TooltipComponentOption, \"formatter\"> & {\n /**\n * USE WITH CAUTION: Use this only for trusted HTML content.\n * When building tooltip HTML with user-provided data, always sanitize\n * the input to prevent XSS vulnerabilities. Recommended: use\n * `encodeHTML` from `echarts/format` to escape HTML special characters.\n */\n dangerousHtmlFormatter?: TooltipComponentOption[\"formatter\"];\n};\n\nexport type KumoChartOption = {\n [K in keyof EChartsOption]: K extends \"tooltip\"\n ? SafeTooltipOption | SafeTooltipOption[] | undefined\n : EChartsOption[K];\n};\n\n/**\n * ECharts event handlers that can be attached to a `Chart`.\n * Pass a subset via the `onEvents` prop; handlers are registered lazily and\n * cleaned up automatically when removed or when the chart is unmounted.\n */\nexport interface ChartEvents {\n // Mouse events — fired on chart elements (series, marks, etc.)\n click: (params: EChartsMouseEventParams) => void;\n dblclick: (params: EChartsMouseEventParams) => void;\n mousedown: (params: EChartsMouseEventParams) => void;\n mousemove: (params: EChartsMouseEventParams) => void;\n mouseup: (params: EChartsMouseEventParams) => void;\n mouseover: (params: EChartsMouseEventParams) => void;\n mouseout: (params: EChartsMouseEventParams) => void;\n /** Fired when the pointer leaves the chart canvas entirely */\n globalout: (params: any) => void;\n contextmenu: (params: any) => void;\n\n // Legend events\n /** Map of series name → selected state for all legend items */\n /** Fired on legend toggle (`legendToggleSelect` action or a legend UI click) */\n legendselectchanged: (params: {\n name: string;\n selected: Record<string, boolean>;\n }) => void;\n /** Fired by the `legendSelect` action. Carries the full `selected` map. */\n legendselected: (params: {\n name: string;\n selected: Record<string, boolean>;\n }) => void;\n /** Fired by the `legendUnSelect` action. Carries the full `selected` map. */\n legendunselected: (params: {\n name: string;\n selected: Record<string, boolean>;\n }) => void;\n legendscroll: (params: any) => void;\n\n // Data zoom / timeline events\n datazoom: (params: any) => void;\n datarangeselected: (params: any) => void;\n timelinechanged: (params: any) => void;\n timelineplaychanged: (params: any) => void;\n\n // Toolbox events\n restore: (params: any) => void;\n dataviewchanged: (params: any) => void;\n magictypechanged: (params: any) => void;\n\n // Pie chart selection events\n pieselectchanged: (params: any) => void;\n pieselected: (params: any) => void;\n pieunselected: (params: any) => void;\n\n // Map / geo selection events\n mapselectchanged: (params: any) => void;\n mapselected: (params: any) => void;\n mapunselected: (params: any) => void;\n geoselectchanged: (params: any) => void;\n geoselected: (params: any) => void;\n geounselected: (params: any) => void;\n\n axisareaselected: (params: any) => void;\n\n // Brush / selection events\n brush: (params: any) => void;\n brushselected: (params: any) => void;\n /** Fired when the user finishes drawing a brush selection */\n brushend: (params: {\n areas: Array<{\n /** Coordinate range covered by the brush — interpretation depends on axis type */\n coordRange: any;\n brushType?: string;\n panelId?: string;\n range?: any;\n }>;\n }) => void;\n}\n\n/** Props for the low-level `Chart` wrapper around Apache ECharts */\nexport interface ChartProps {\n /**\n * The ECharts core instance imported by the consumer.\n * Passed in rather than imported directly so the consumer controls which\n * ECharts modules are bundled (tree-shaking).\n */\n echarts: typeof echarts;\n /** ECharts option object — passed through to `chart.setOption()` */\n options: KumoChartOption;\n /**\n * Additional options passed as the second argument to `chart.setOption()`.\n * Defaults to `{ notMerge: false, lazyUpdate: true }`.\n */\n optionUpdateBehavior?: SetOptionOpts;\n /** Additional CSS classes applied to the chart container `<div>` */\n className?: string;\n /**\n * When `true`, initialises ECharts with its built-in dark theme.\n * Changing this value after mount destroys and re-creates the chart instance.\n */\n isDarkMode?: boolean;\n /** Height of the chart container in pixels. Defaults to `350`. */\n height?: number;\n /** Subset of ECharts events to listen for. Handlers are bound/unbound reactively. */\n onEvents?: Partial<ChartEvents>;\n}\n\nconst transformTooltip = (tooltipObj: SafeTooltipOption) => {\n const { dangerousHtmlFormatter, ...restOfTooltip } = tooltipObj;\n return {\n ...restOfTooltip,\n formatter: dangerousHtmlFormatter,\n };\n};\n\nconst prepareChartOptions = ({\n options,\n isDarkMode,\n}: {\n options: KumoChartOption;\n isDarkMode?: boolean;\n}): EChartsOption => {\n const withDefaults: EChartsOption = {\n backgroundColor: \"transparent\",\n color: isDarkMode ? CHART_DARK_COLORS : CHART_LIGHT_COLORS,\n ...options,\n };\n\n if (!withDefaults.tooltip) return withDefaults;\n\n return {\n ...withDefaults,\n tooltip: Array.isArray(withDefaults.tooltip)\n ? withDefaults.tooltip.map(transformTooltip)\n : transformTooltip(withDefaults.tooltip as SafeTooltipOption),\n };\n};\n\n/**\n * Chart — a low-level wrapper around [Apache ECharts](https://echarts.apache.org).\n *\n * Manages the ECharts instance lifecycle (init, option updates, event binding,\n * resize observation, and disposal). Exposes the raw `echarts.ECharts` instance\n * via `ref` for imperative access when needed.\n *\n * Prefer `TimeseriesChart` for time-series data; use this component when you\n * need full control over the ECharts option object.\n *\n * @example\n * ```tsx\n * import * as echarts from \"echarts/core\";\n * import { BarChart } from \"echarts/charts\";\n * import { GridComponent } from \"echarts/components\";\n * import { CanvasRenderer } from \"echarts/renderers\";\n *\n * echarts.use([BarChart, GridComponent, CanvasRenderer]);\n *\n * <Chart\n * echarts={echarts}\n * options={{ xAxis: { data: [\"A\", \"B\"] }, yAxis: {}, series: [{ type: \"bar\", data: [1, 2] }] }}\n * />\n * ```\n */\nexport const Chart = forwardRef<echarts.ECharts, ChartProps>(function Chart(\n {\n echarts,\n options,\n optionUpdateBehavior,\n className,\n isDarkMode,\n height = 350,\n onEvents,\n }: ChartProps,\n ref,\n) {\n // Ref to the container DOM node that ECharts renders into\n const elRef = useRef<HTMLDivElement | null>(null);\n // Ref to the active ECharts instance\n const chartRef = useRef<echarts.ECharts | null>(null);\n // Keeps the latest onEvents object without triggering re-binding on every render\n const handlersRef = useRef<Partial<ChartEvents>>({});\n // Stable wrapper functions per event name — avoids creating new closures on re-render\n const wrappersRef = useRef<Record<string, (params: any) => void>>({});\n // Tracks which event names are currently bound to the chart instance\n const boundEventsRef = useRef<Set<string>>(new Set());\n\n // Init and cleanup\n useEffect(() => {\n if (!elRef.current) return;\n\n const chart = echarts.init(elRef.current, isDarkMode ? \"dark\" : undefined);\n chartRef.current = chart;\n\n if (typeof ref === \"function\") ref(chart);\n else if (ref) ref.current = chart;\n\n return () => {\n for (const event of boundEventsRef.current) {\n const wrapper = wrappersRef.current[event];\n if (wrapper) chart.off(event, wrapper);\n }\n boundEventsRef.current.clear();\n if (typeof ref === \"function\") ref(null);\n else if (ref) ref.current = null;\n chartRef.current = null;\n chart.dispose();\n };\n }, [elRef, isDarkMode]);\n\n // Update options\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart) return;\n\n chart.setOption(prepareChartOptions({ options, isDarkMode }), {\n notMerge: false,\n lazyUpdate: true,\n ...optionUpdateBehavior,\n });\n }, [isDarkMode, optionUpdateBehavior, options]);\n\n // Keep handlersRef in sync so wrapper closures always call the latest handler\n // without needing to re-bind listeners on every render\n useEffect(() => {\n handlersRef.current = onEvents ?? {};\n }, [onEvents]);\n\n // Reactively bind and unbind event listeners when onEvents changes.\n // Uses stable wrapper functions (wrappersRef) so the same function reference\n // is passed to both chart.on() and chart.off(), which ECharts requires.\n useEffect(() => {\n const chart = chartRef.current;\n if (!chart) return;\n\n const nextBound = new Set<string>();\n\n for (const [event, handler] of Object.entries(onEvents ?? {})) {\n if (typeof handler !== \"function\") continue;\n nextBound.add(event);\n\n if (!wrappersRef.current[event]) {\n wrappersRef.current[event] = (params: any) => {\n const current = handlersRef.current as Record<\n string,\n ((p: any) => void) | undefined\n >;\n current[event]?.(params);\n };\n }\n\n if (!boundEventsRef.current.has(event)) {\n chart.on(event, wrappersRef.current[event]);\n }\n }\n\n for (const event of boundEventsRef.current) {\n if (nextBound.has(event)) continue;\n const wrapper = wrappersRef.current[event];\n if (wrapper) {\n chart.off(event, wrapper);\n }\n }\n\n boundEventsRef.current = nextBound;\n }, [echarts, isDarkMode, onEvents]);\n\n // Resize handling\n useEffect(() => {\n const chart = chartRef.current;\n const el = elRef.current;\n if (!chart || !el) return;\n\n // Flag to skip the very first trigger\n let isInitial = true;\n\n const ro = new ResizeObserver(() => {\n if (isInitial) {\n isInitial = false;\n return; // Skip the first resize to let the animation play\n }\n chart.resize();\n });\n\n ro.observe(el);\n\n return () => ro.disconnect();\n }, []);\n\n return (\n <div\n ref={elRef}\n className={cn(\"w-full\", className)}\n style={{ height }}\n tabIndex={options.aria?.enabled ? 0 : undefined}\n role={options.aria?.enabled ? \"img\" : undefined}\n />\n );\n});\n\nChart.displayName = \"Chart\";\n","import type * as echarts from \"echarts/core\";\nimport type { LineSeriesOption, BarSeriesOption } from \"echarts/charts\";\nimport type { EChartsOption, SeriesOption, SetOptionOpts } from \"echarts\";\nimport {\n forwardRef,\n memo,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\nimport { Chart, ChartEvents, KumoChartOption } from \"./EChart\";\n\n/** A single data series rendered on a `TimeseriesChart` */\nexport interface TimeseriesData {\n /** Display name shown in tooltips and legends */\n name: string;\n /** Array of `[timestamp_ms, value]` tuples ordered by time */\n data: [number, number][];\n /** Hex color string used for this series' line, bars, and legend dot */\n color: string;\n}\n\n/** Props for `TimeseriesChart` */\nexport interface TimeseriesChartProps {\n /**\n * The ECharts core instance imported by the consumer.\n * Passed in rather than imported directly so the consumer controls which\n * ECharts modules are bundled (tree-shaking).\n */\n echarts: typeof echarts;\n /** Visual style of each series. Defaults to `\"line\"`. */\n type?: \"line\" | \"bar\";\n /** Array of time series data to display on the chart */\n data: TimeseriesData[];\n /** Label for the x-axis (time axis) */\n xAxisName?: string;\n /** Number of ticks to display on the x-axis */\n xAxisTickCount?: number;\n /**\n * Custom formatter for x-axis tick labels.\n * Receives the raw timestamp in milliseconds and returns a display string,\n * overriding ECharts' built-in time formatting.\n */\n xAxisTickFormat?: (value: number) => string;\n /**\n * Custom formatter for y-axis tick labels.\n * Receives the raw value and returns a display string.\n * When omitted, ECharts' built-in formatter is used.\n */\n yAxisTickFormat?: (value: number) => string;\n /**\n * @deprecated Use `tooltipValueFormat` instead. This prop formats tooltip\n * values, not y-axis tick labels. It will be removed in a future major version.\n */\n yAxisTickLabelFormat?: (value: number) => string;\n /** Label for the y-axis (value axis) */\n yAxisName?: string;\n /** Number of ticks to display on the y-axis */\n yAxisTickCount?: number;\n /**\n * Custom formatter for tooltip values.\n * Receives the raw y-value and returns a display string.\n * When omitted, the raw value is shown. Takes precedence over the\n * deprecated `yAxisTickLabelFormat` prop.\n */\n tooltipValueFormat?: (value: number) => string;\n /**\n * Controls which series are shown in the tooltip.\n * - `\"all\"` — show all series at the hovered timestamp (default)\n * - `\"single\"` — show only the series whose value is closest to the cursor\n */\n tooltipMode?: \"all\" | \"single\";\n /**\n * Maximum number of series rows shown in the tooltip when `tooltipMode` is `\"all\"`.\n * Additional series are hidden with a `+N more` footer. Defaults to `10`.\n */\n tooltipMaxItems?: number;\n /**\n * Constrains the tooltip to stay within a specific element or region.\n * By default the tooltip avoids overflowing any clipping ancestor\n * (scroll containers, viewports, etc.).\n *\n * Pass an `Element` or array of elements to restrict the tooltip to a\n * specific container.\n *\n * @default \"clipping-ancestors\"\n */\n tooltipBoundary?: \"clipping-ancestors\" | Element | Element[];\n /**\n * Which axis the tooltip follows the cursor on.\n *\n * - `\"both\"` — tooltip tracks the cursor on both axes, staying near the\n * pointer at all times. This is the default and matches the behaviour of\n * ECharts' built-in tooltip.\n * - `\"x\"` — tooltip follows the cursor horizontally but is locked to a\n * fixed vertical position relative to the chart. This keeps the tooltip\n * out of the way of the data and avoids vertical jitter as series values\n * change — the same approach used by Recharts and many dashboard UIs.\n *\n * Only these two modes are offered because the x-axis is always time in a\n * `TimeseriesChart`: y-only tracking and fully-fixed positioning don't\n * produce useful tooltip behaviour for time-series data.\n *\n * Powered by Base UI Tooltip's `trackCursorAxis` under the hood.\n *\n * @default \"both\"\n */\n tooltipFollowCursor?: \"both\" | \"x\";\n /** Indicates incomplete data periods with optional before/after timestamps in ms */\n incomplete?: { before?: number; after?: number };\n /**\n * When `true`, adds a hidden ECharts legend so consumers can drive series\n * visibility imperatively via the `legendSelect` / `legendUnSelect` /\n * `legendToggleSelect` actions (e.g. to build a custom interactive legend).\n * Toggled-off series are also excluded from the tooltip.\n *\n * Requires the consumer to register ECharts' `LegendComponent`\n * (`echarts.use([LegendComponent])`); otherwise the legend actions no-op and,\n * in development, ECharts logs a \"component legend is used but not imported\"\n * warning.\n *\n * @default false\n */\n enableLegendSelection?: boolean;\n /** Height of the chart in pixels. Defaults to `350`. */\n height?: number;\n /** Callback fired when user selects a time range via brush selection */\n onTimeRangeChange?: (from: number, to: number) => void;\n /** When `true`, switches the chart to ECharts' built-in dark theme */\n isDarkMode?: boolean;\n /**\n * When `true`, renders a vertical gradient fill beneath each line series.\n * The gradient fades from the series' color at the top to transparent at the bottom.\n * Has no effect when `type` is `\"bar\"`.\n */\n gradient?: boolean;\n /**\n * When `true`, hides the chart and displays an animated sine-wave skeleton\n * that oscillates back and forth to indicate that data is being fetched.\n */\n loading?: boolean;\n /**\n * Accessible description for screen readers. When provided, it is passed to\n * ECharts' `aria.label.description` and announced when the chart receives\n * focus. Consumers are responsible for writing a meaningful description —\n * see the W3C guidance on complex images for recommendations.\n *\n * @see https://www.w3.org/WAI/tutorials/images/complex/\n * @see https://echarts.apache.org/handbook/en/best-practices/aria/\n */\n ariaDescription?: string;\n /**\n * Additional options passed as the second argument to `chart.setOption()`.\n * Defaults to `{ notMerge: false, lazyUpdate: true }`.\n */\n optionUpdateBehavior?: SetOptionOpts;\n}\n\ninterface TooltipRow {\n name: string;\n value: number;\n color: string;\n}\n\ninterface TooltipState {\n ts: number;\n rows: TooltipRow[];\n hiddenCount: number;\n}\n\n/**\n * TimeseriesChart — a time-series line or bar chart.\n *\n * Built on `Chart` (Apache ECharts) with opinionated defaults for time-series data:\n * a time-typed x-axis, dashed lines for incomplete data periods, brush-based\n * time range selection, and automatic tooltip deduplication.\n *\n * @example\n * ```tsx\n * import * as echarts from \"echarts/core\";\n * import { LineChart } from \"echarts/charts\";\n * import { GridComponent, TooltipComponent, BrushComponent, ToolboxComponent } from \"echarts/components\";\n * import { CanvasRenderer } from \"echarts/renderers\";\n *\n * echarts.use([LineChart, GridComponent, TooltipComponent, BrushComponent, ToolboxComponent, CanvasRenderer]);\n *\n * const [range, setRange] = useState<[number, number]>();\n *\n * <TimeseriesChart\n * echarts={echarts}\n * data={[{ name: \"Requests\", data: [[Date.now(), 42]], color: \"#086FFF\" }]}\n * xAxisName=\"Time\"\n * xAxisTickFormat={(ts) => new Date(ts).toLocaleTimeString()}\n * yAxisName=\"Count\"\n * yAxisTickFormat={(value) => `${value / 1000}k`}\n * tooltipValueFormat={(value) => `${value.toFixed(2)} req/s`}\n * onTimeRangeChange={(from, to) => setRange([from, to])}\n * />\n * ```\n */\nexport const TimeseriesChart = forwardRef<\n echarts.ECharts | null,\n TimeseriesChartProps\n>(function TimeseriesChart(\n {\n echarts,\n type = \"line\",\n data,\n xAxisName,\n xAxisTickCount,\n xAxisTickFormat,\n yAxisTickFormat,\n yAxisTickLabelFormat,\n yAxisName,\n yAxisTickCount,\n tooltipValueFormat,\n onTimeRangeChange,\n height = 350,\n incomplete,\n enableLegendSelection = false,\n isDarkMode,\n gradient,\n loading,\n ariaDescription,\n optionUpdateBehavior,\n tooltipMode = \"all\",\n tooltipMaxItems = 10,\n tooltipFollowCursor = \"both\",\n tooltipBoundary,\n },\n ref,\n) {\n const chartRef = useRef<echarts.ECharts | null>(null);\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n const mergedRef = useCallback(\n (instance: echarts.ECharts | null) => {\n chartRef.current = instance;\n if (typeof ref === \"function\") {\n ref(instance);\n } else if (ref) {\n ref.current = instance;\n }\n },\n [ref],\n );\n\n // Keep latest props accessible inside event handlers without stale closures\n const dataRef = useRef(data);\n dataRef.current = data;\n // Tracks legend selection (series name → visible) so the tooltip can skip toggled-off series\n const legendSelectedRef = useRef<Record<string, boolean> | null>(null);\n // Clear stale selection so it can't keep filtering the tooltip when:\n // - legend selection is disabled (hidden legend removed), or\n // - the theme toggles (`isDarkMode` change re-inits the ECharts instance,\n // which resets legend selection to all-visible).\n // Done in an effect (not during render) to stay safe under concurrent rendering.\n useEffect(() => {\n legendSelectedRef.current = null;\n }, [enableLegendSelection, isDarkMode]);\n\n const tooltipModeRef = useRef(tooltipMode);\n tooltipModeRef.current = tooltipMode;\n const tooltipMaxItemsRef = useRef(tooltipMaxItems);\n tooltipMaxItemsRef.current = tooltipMaxItems;\n\n const [tooltipState, setTooltipState] = useState<TooltipState | null>(null);\n\n // Track cursor position for single-mode y lookup (convertFromPixel needs relative coords)\n const mousePosRef = useRef({ x: 0, y: 0 });\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const onMove = (e: MouseEvent) => {\n const rect = container.getBoundingClientRect();\n mousePosRef.current = {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top,\n };\n };\n container.addEventListener(\"mousemove\", onMove);\n return () => container.removeEventListener(\"mousemove\", onMove);\n }, []);\n\n const incompleteBefore = incomplete?.before;\n const incompleteAfter = incomplete?.after;\n\n const options = useMemo(() => {\n const transformSeries: Array<LineSeriesOption | BarSeriesOption> = [];\n\n const seriesType =\n type === \"bar\"\n ? ({ type: \"bar\", stack: \"total\" } as const)\n : ({ type: \"line\", showSymbol: false } as const);\n\n for (const s of data) {\n const incompleteBeforePoints =\n incompleteBefore && type === \"line\"\n ? s.data.filter((point) => point[0] <= incompleteBefore)\n : [];\n\n const incompleteAfterPoints =\n incompleteAfter && type === \"line\"\n ? s.data.filter((point) => point[0] >= incompleteAfter)\n : [];\n\n const completePoints =\n incompleteBeforePoints.length > 0 || incompleteAfterPoints.length > 0\n ? s.data.slice(\n Math.max(0, incompleteBeforePoints.length - 1),\n Math.max(0, s.data.length - incompleteAfterPoints.length + 1),\n )\n : s.data;\n\n // Main complete data series\n const areaStyle =\n gradient && type === \"line\"\n ? {\n color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [\n { offset: 0, color: colorWithOpacity(s.color, 0.4) },\n { offset: 1, color: colorWithOpacity(s.color, 0) },\n ]),\n }\n : undefined;\n\n transformSeries.push({\n data: completePoints,\n color: s.color,\n name: s.name,\n emphasis: { focus: \"series\" },\n ...(areaStyle ? { areaStyle } : {}),\n ...seriesType,\n });\n\n // Incomplete data series with dashed lines\n const incompleteSeriesConfig = {\n color: s.color,\n name: s.name,\n type: \"line\" as const,\n lineStyle: { type: \"dashed\" as const },\n showSymbol: false,\n emphasis: { focus: \"series\" as const },\n };\n\n if (incompleteBeforePoints.length > 0) {\n transformSeries.push({\n ...incompleteSeriesConfig,\n data: incompleteBeforePoints,\n });\n }\n\n if (incompleteAfterPoints.length > 0) {\n transformSeries.push({\n ...incompleteSeriesConfig,\n data: incompleteAfterPoints,\n });\n }\n }\n\n return {\n aria: {\n enabled: true,\n ...(ariaDescription && { label: { description: ariaDescription } }),\n },\n brush: {\n xAxisIndex: \"all\" as const,\n brushType: \"lineX\" as const,\n brushMode: \"single\" as const,\n outOfBrush: {\n colorAlpha: 0.3,\n },\n brushStyle: {\n borderWidth: 1,\n color: \"rgba(120,140,180,0.3)\",\n borderColor: \"rgba(120,140,180,0.8)\",\n },\n },\n tooltip: {\n trigger: \"axis\" as const,\n showContent: false,\n axisPointer: { type: \"shadow\" as const },\n },\n backgroundColor: \"transparent\",\n toolbox: { show: false },\n ...(enableLegendSelection ? { legend: { show: false } } : {}),\n xAxis: {\n name: xAxisName,\n nameLocation: \"middle\" as const,\n nameGap: 30,\n type: \"time\" as const,\n splitLine: {\n show: false,\n },\n axisLine: { show: false },\n splitNumber: xAxisTickCount ?? 5,\n ...(xAxisTickFormat && {\n axisLabel: {\n formatter: (value: number) => xAxisTickFormat(value),\n },\n }),\n },\n yAxis: {\n name: yAxisName,\n nameLocation: \"middle\" as const,\n nameGap: 40,\n type: \"value\" as const,\n axisTick: { show: true },\n axisLabel: {\n margin: 15,\n ...(yAxisTickFormat && {\n formatter: (value: number) => yAxisTickFormat(value),\n }),\n },\n splitLine: {\n show: true,\n lineStyle: { type: \"dashed\" as const, width: 1 },\n },\n splitNumber: yAxisTickCount,\n },\n grid: {\n left: yAxisName ? 30 : 24,\n right: 24,\n top: 24,\n bottom: xAxisName ? 30 : 24,\n },\n series: transformSeries as SeriesOption[],\n } satisfies KumoChartOption;\n }, [\n data,\n xAxisName,\n xAxisTickCount,\n xAxisTickFormat,\n yAxisTickFormat,\n yAxisName,\n yAxisTickCount,\n incompleteBefore,\n incompleteAfter,\n type,\n gradient,\n enableLegendSelection,\n echarts,\n ariaDescription,\n ]);\n\n const events = useMemo<Partial<ChartEvents>>(() => {\n return {\n updateaxispointer: (params: any) => {\n const ts: number | undefined = params?.axesInfo?.[0]?.value;\n if (ts == null) return;\n\n const seenNames = new Set<string>();\n const allRows: TooltipRow[] = [];\n\n // Respect legend selection: series toggled off via the legend\n // (legendUnSelect / legendToggleSelect) should not appear in the tooltip.\n // Read from a ref kept in sync by `legendselectchanged` — avoids the\n // expensive `getOption()` deep-clone on every pointer move.\n const legendSelected = legendSelectedRef.current;\n\n for (const s of dataRef.current) {\n if (seenNames.has(s.name)) continue;\n if (legendSelected && legendSelected[s.name] === false) continue;\n seenNames.add(s.name);\n const value = findNearest(s.data, ts);\n if (value != null)\n allRows.push({ name: s.name, value, color: s.color });\n }\n\n // Sort by value descending so highest series appears first\n allRows.sort((a, b) => b.value - a.value);\n\n let rows: TooltipRow[];\n let hiddenCount = 0;\n\n if (tooltipModeRef.current === \"single\") {\n // Find the series whose value is closest to the cursor's y position\n const chart = chartRef.current;\n const cursorValue = chart\n ? (\n chart.convertFromPixel(\"grid\", [0, mousePosRef.current.y]) as [\n number,\n number,\n ]\n )?.[1]\n : null;\n if (cursorValue != null && allRows.length > 0) {\n const nearest = allRows.reduce((best, row) =>\n Math.abs(row.value - cursorValue) <\n Math.abs(best.value - cursorValue)\n ? row\n : best,\n );\n rows = [nearest];\n } else {\n rows = allRows.slice(0, 1);\n }\n } else {\n const max = tooltipMaxItemsRef.current;\n rows = allRows.slice(0, max);\n hiddenCount = Math.max(0, allRows.length - max);\n }\n\n const nextState: TooltipState = { ts, rows, hiddenCount };\n setTooltipState((prev) => {\n if (isSameTooltipState(prev, nextState)) return prev;\n return nextState;\n });\n },\n globalout: () => {\n setTooltipState(null);\n },\n // Keep the tooltip in sync with legend selection. Each action fires a\n // different event — `legendToggleSelect` → `legendselectchanged`,\n // `legendSelect` → `legendselected`, `legendUnSelect` → `legendunselected`\n // — and all three carry the full `selected` map, so we listen to all of\n // them (params type inferred from `ChartEvents`).\n legendselectchanged: (params) => {\n legendSelectedRef.current = params.selected;\n },\n legendselected: (params) => {\n legendSelectedRef.current = params.selected;\n },\n legendunselected: (params) => {\n legendSelectedRef.current = params.selected;\n },\n ...(onTimeRangeChange && {\n brushend: (params: any) => {\n const range = params.areas[0].coordRange;\n onTimeRangeChange(range[0], range[1]);\n chartRef.current?.dispatchAction({ type: \"brush\", areas: [] });\n },\n }),\n };\n }, [onTimeRangeChange]);\n\n // Activate the lineX brush cursor when a time-range callback is provided,\n // and deactivate it on cleanup so the cursor resets when the prop is removed.\n const hasTimeRangeCallback = !!onTimeRangeChange;\n useEffect(() => {\n const chart = chartRef.current;\n if (chart && hasTimeRangeCallback) {\n chart.dispatchAction({\n type: \"takeGlobalCursor\",\n key: \"brush\",\n brushOption: {\n brushType: \"lineX\" as const,\n brushMode: \"single\" as const,\n },\n });\n\n return () => {\n chart.dispatchAction({\n type: \"takeGlobalCursor\",\n key: \"brush\",\n brushOption: {\n brushType: false,\n },\n });\n };\n }\n // `loading` controls whether <Chart> is mounted. When it flips to false,\n // chartRef.current becomes available and the brush cursor must be activated.\n // Without this dep, the effect won't re-run after Chart mounts.\n }, [chartRef, hasTimeRangeCallback, loading]);\n\n const formatFn = tooltipValueFormat ?? yAxisTickLabelFormat;\n const tooltipOpen = tooltipState !== null;\n\n return (\n <TooltipPrimitive.Root\n open={tooltipOpen}\n trackCursorAxis={tooltipFollowCursor}\n >\n <TooltipPrimitive.Trigger\n render={\n <div\n ref={containerRef}\n className=\"relative w-full\"\n style={{ height }}\n />\n }\n >\n {loading && <ChartWaveLoader height={height} isDarkMode={isDarkMode} />}\n {!loading && (\n <Chart\n echarts={echarts}\n ref={mergedRef}\n options={options as EChartsOption}\n height={height}\n isDarkMode={isDarkMode}\n onEvents={events}\n optionUpdateBehavior={optionUpdateBehavior}\n />\n )}\n </TooltipPrimitive.Trigger>\n {tooltipOpen && (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Positioner\n side=\"right\"\n align=\"start\"\n sideOffset={12}\n collisionAvoidance={{ side: \"flip\", align: \"shift\" }}\n collisionBoundary={tooltipBoundary}\n collisionPadding={8}\n >\n <TooltipPrimitive.Popup\n data-mode={isDarkMode ? \"dark\" : \"light\"}\n className=\"bg-kumo-base rounded-lg shadow-lg shadow-kumo-tip-shadow outline outline-1 outline-kumo-fill p-2 min-w-[150px] max-w-xs\"\n >\n <TooltipContent state={tooltipState} formatValue={formatFn} />\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n )}\n </TooltipPrimitive.Root>\n );\n});\n\nTimeseriesChart.displayName = \"TimeseriesChart\";\n\n// ─── Tooltip content ──────────────────────────────────────────────────────────\n//\n// Memoized so React skips reconciliation when the cursor moves within the same\n// data point. The timestamp dedup in updateAxisPointer already prevents most\n// unnecessary state updates; this is a safety net for when the parent re-renders\n// for unrelated reasons (e.g. a prop change on TimeseriesChart).\n\ninterface TooltipContentProps {\n state: TooltipState;\n formatValue?: (v: number) => string;\n}\n\nconst TooltipContent = memo(function TooltipContent({\n state,\n formatValue,\n}: TooltipContentProps) {\n const { ts, rows, hiddenCount } = state;\n\n return (\n <>\n <div className=\"text-xs font-semibold text-kumo-default mb-1\">\n {formatTimestamp(ts)}\n </div>\n {rows.map((row) => (\n <div\n key={row.name}\n className=\"flex items-center justify-between gap-4 py-0.5\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span\n className=\"w-3 h-3 rounded-full shrink-0\"\n style={{ backgroundColor: row.color }}\n />\n <span\n className=\"text-xs font-medium text-kumo-default truncate\"\n title={row.name}\n >\n {row.name}\n </span>\n </div>\n <span className=\"text-xs font-semibold text-kumo-default shrink-0\">\n {formatValue\n ? formatValue(row.value)\n : formatDefaultValue(row.value)}\n </span>\n </div>\n ))}\n {hiddenCount > 0 && (\n <div className=\"text-xs text-kumo-subtle mt-1\">+{hiddenCount} more</div>\n )}\n </>\n );\n});\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\n/** Binary search for the value in `data` whose timestamp is closest to `ts`. */\nfunction findNearest(data: [number, number][], ts: number): number | null {\n if (data.length === 0) return null;\n let lo = 0,\n hi = data.length - 1;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (data[mid][0] < ts) lo = mid + 1;\n else hi = mid;\n }\n // Check both neighbours and return the closer one\n if (lo > 0 && Math.abs(data[lo - 1][0] - ts) < Math.abs(data[lo][0] - ts))\n lo--;\n return data[lo][1];\n}\n\n/** Shallow-compare two tooltip states so React can skip renders when nothing changed. */\nfunction isSameTooltipState(a: TooltipState | null, b: TooltipState): boolean {\n if (\n !a ||\n a.ts !== b.ts ||\n a.hiddenCount !== b.hiddenCount ||\n a.rows.length !== b.rows.length\n ) {\n return false;\n }\n return a.rows.every((row, i) => {\n const next = b.rows[i];\n return (\n row.name === next.name &&\n row.value === next.value &&\n row.color === next.color\n );\n });\n}\n\nconst defaultNumberFormat = new Intl.NumberFormat(undefined, {\n maximumFractionDigits: 3,\n});\n\n/** Fallback value formatter — avoids floating point noise without scientific notation. */\nfunction formatDefaultValue(value: number): string {\n if (Number.isInteger(value)) return String(value);\n return defaultNumberFormat.format(value);\n}\n\n/**\n * Animated sine-wave skeleton shown while `TimeseriesChart` is in `loading` state.\n * Renders multiple staggered wave paths that sweep continuously left-to-right,\n * mimicking the motion of live time-series data being drawn.\n */\nfunction ChartWaveLoader({\n height,\n isDarkMode,\n}: {\n height: number;\n isDarkMode?: boolean;\n}) {\n const mid = height / 2;\n const amp = Math.min(height * 0.12, 28);\n const period = 400;\n const steps = 120;\n\n const points: string[] = [];\n for (let i = 0; i <= steps; i++) {\n const x = -period + (i / steps) * period * 3;\n const y = mid + Math.sin((i / steps) * 2 * Math.PI * 3) * amp;\n points.push(`${i === 0 ? \"M\" : \"L\"}${x.toFixed(2)},${y.toFixed(2)}`);\n }\n const d = points.join(\" \");\n\n const strokeColor = isDarkMode ? \"rgba(255,255,255,0.5)\" : \"rgba(0,0,0,0.2)\";\n\n return (\n <div\n aria-hidden=\"true\"\n className=\"absolute inset-0 overflow-hidden\"\n style={{ height }}\n >\n <svg\n width=\"100%\"\n height={height}\n viewBox={`0 0 ${period} ${height}`}\n preserveAspectRatio=\"none\"\n className=\"w-full animate-pulse\"\n >\n <path\n d={d}\n fill=\"none\"\n stroke={strokeColor}\n strokeWidth=\"2\"\n style={{\n animation: `kumo-chart-wave 2.4s linear infinite`,\n transformOrigin: \"0 0\",\n }}\n />\n </svg>\n </div>\n );\n}\n\n/**\n * Returns an `rgba(r, g, b, alpha)` string for any hex or rgb(a) color input,\n * replacing whatever opacity was already present with the given `alpha` (0–1).\n *\n * Handles:\n * - 6-digit hex: `#RRGGBB`\n * - 8-digit hex: `#RRGGBBAA` ← strips existing alpha\n * - 3-digit hex: `#RGB`\n * - `rgb(r, g, b)`\n * - `rgba(r, g, b, a)` ← replaces existing alpha\n */\nfunction colorWithOpacity(color: string, alpha: number): string {\n const a = Math.max(0, Math.min(1, alpha));\n\n // rgb / rgba\n const rgbMatch = color.match(\n /rgba?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*,\\s*([\\d.]+)/i,\n );\n if (rgbMatch) {\n return `rgba(${rgbMatch[1]}, ${rgbMatch[2]}, ${rgbMatch[3]}, ${a})`;\n }\n\n // hex — strip leading #\n let hex = color.replace(/^#/, \"\");\n\n // expand 3-digit → 6-digit\n if (hex.length === 3) {\n hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n }\n\n // strip 8-digit alpha → keep only 6\n if (hex.length === 8) {\n hex = hex.slice(0, 6);\n }\n\n const r = parseInt(hex.slice(0, 2), 16);\n const g = parseInt(hex.slice(2, 4), 16);\n const b = parseInt(hex.slice(4, 6), 16);\n\n return `rgba(${r}, ${g}, ${b}, ${a})`;\n}\n\nconst tooltipDateFormat = new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hour12: false,\n});\n\n/**\n * Formats a timestamp for use in chart tooltips using the browser's locale.\n * Accepts a Unix timestamp in milliseconds, an ISO date string, or a `Date` object.\n */\nfunction formatTimestamp(ts: number | string | Date): string {\n return tooltipDateFormat.format(new Date(ts));\n}\n","import type {\n KeyboardEventHandler,\n MouseEventHandler,\n PointerEventHandler,\n} from \"react\";\nimport { cn } from \"../../utils\";\n\nconst onInteractiveKeyDown: KeyboardEventHandler<HTMLDivElement> = (event) => {\n if (event.key !== \"Enter\" && event.key !== \" \") return;\n event.preventDefault();\n event.currentTarget.click();\n};\n\n/** Shared props for both legend item variants */\ninterface LegendItemProps {\n /** Series name shown as a label */\n name: string;\n /** Hex color string for the series indicator dot */\n color: string;\n /** Formatted value string to display */\n value: string;\n /** Optional unit label shown after the value (e.g. `\"ms\"`, `\"%\"`) */\n unit?: string;\n /** When `true`, renders the item at 50% opacity to indicate a deselected state */\n inactive?: boolean;\n /** Fired when a pointer enters the legend item — useful for highlighting the corresponding chart series */\n onPointerEnter?: PointerEventHandler<HTMLDivElement>;\n /** Fired when a pointer leaves the legend item — useful for resetting chart series emphasis */\n onPointerLeave?: PointerEventHandler<HTMLDivElement>;\n /** Fired when the legend item is clicked — useful for toggling series visibility */\n onClick?: MouseEventHandler<HTMLDivElement>;\n /** Optional className to customize legend item presentation */\n className?: string;\n}\n\n/**\n * Large legend item — stacked layout with a colored dot + series name on top\n * and a large value with an optional small unit below. Use for prominent\n * single-metric displays such as dashboard cards.\n */\nfunction LargeItem({\n color,\n value,\n name,\n unit,\n inactive,\n onPointerEnter,\n onPointerLeave,\n onClick,\n className,\n}: LegendItemProps) {\n return (\n <div\n // oxlint-disable-next-line prefer-tag-over-role\n role=\"button\"\n tabIndex={onClick ? 0 : -1}\n className={cn(\n \"inline-flex flex-col gap-2 min-w-42 py-2\",\n { \"cursor-pointer\": !!onClick },\n className,\n )}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onClick={onClick}\n onKeyDown={onClick ? onInteractiveKeyDown : undefined}\n >\n <div className=\"flex items-center gap-2\">\n <span\n className={cn(\"size-2 rounded-full inline-block\", {\n \"opacity-50\": inactive,\n })}\n style={{ backgroundColor: color }}\n />\n <span className={cn(\"text-xs\", { \"opacity-50\": inactive })}>\n {name}\n </span>\n </div>\n <div className=\"flex items-baseline gap-0.5\">\n <span\n className={cn(\"text-lg font-medium leading-none\", {\n \"opacity-50\": inactive,\n })}\n >\n {value}\n </span>\n {unit && (\n <span\n className={cn(\"text-xs text-kumo-subtle leading-none\", {\n \"opacity-50\": inactive,\n })}\n >\n {unit}\n </span>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Small legend item — inline layout with a colored dot, series name, and value\n * on a single row. Use for compact legends below or beside a chart.\n */\nfunction SmallItem({\n color,\n value,\n name,\n inactive,\n onPointerEnter,\n onPointerLeave,\n onClick,\n className,\n}: LegendItemProps) {\n return (\n <div\n // oxlint-disable-next-line prefer-tag-over-role\n role=\"button\"\n tabIndex={onClick ? 0 : -1}\n className={cn(\n \"inline-flex items-center gap-2\",\n { \"cursor-pointer\": !!onClick },\n className,\n )}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onClick={onClick}\n onKeyDown={onClick ? onInteractiveKeyDown : undefined}\n >\n <span\n className={cn(\"size-2 rounded-full inline-block\", {\n \"opacity-50\": inactive,\n })}\n style={{ backgroundColor: color }}\n />\n <span className={cn(\"text-xs\", { \"opacity-50\": inactive })}>{name}</span>\n <span className={cn(\"text-xs font-medium\", { \"opacity-50\": inactive })}>\n {value}\n </span>\n </div>\n );\n}\n\n/**\n * ChartLegend — pre-built legend item components for use alongside a chart.\n *\n * - `ChartLegend.SmallItem` — compact inline layout; suited for multi-series legends\n * - `ChartLegend.LargeItem` — stacked layout with a large value; suited for single-metric cards\n *\n * @example\n * ```tsx\n * <ChartLegend.SmallItem name=\"Requests\" color=\"#086FFF\" value=\"1,234\" />\n * <ChartLegend.LargeItem name=\"Latency\" color=\"#CF7EE9\" value=\"42\" unit=\"ms\" inactive />\n * ```\n */\nexport const ChartLegend = {\n SmallItem,\n LargeItem,\n};\n","import type * as echarts from \"echarts/core\";\nimport type { EChartsOption } from \"echarts\";\nimport { useMemo, useCallback } from \"react\";\nimport { Chart, type ChartEvents } from \"./EChart\";\nimport { ChartPalette } from \"./Color\";\n\nexport interface SankeyNodeData {\n id?: string;\n name: string;\n color?: string;\n /** Optional value/count to display above the node label */\n value?: number;\n /** Additional data to show in tooltip (e.g., { Apps: 166, Sessions: 122600 }) */\n tooltipData?: Record<string, number | string>;\n isDrillable?: boolean;\n childCount?: number;\n}\n\nexport interface SankeyLinkData {\n id?: string;\n source: number;\n target: number;\n value: number;\n isDrillable?: boolean;\n}\n\nexport type DrillTarget =\n | { type: \"node\"; nodeId: string }\n | { type: \"link\"; sourceId: string; targetId: string };\n\nexport interface DrillSelection {\n id: string;\n type: \"node\" | \"link\";\n label: string;\n depth: number;\n}\n\nexport interface DrillDownContext {\n selections: DrillSelection[];\n isMultiSelect: boolean;\n}\n\nexport interface SankeyData {\n nodes: SankeyNodeData[];\n links: SankeyLinkData[];\n}\n\n/** Parameters passed to the tooltip formatter */\nexport interface SankeyTooltipParams {\n type: \"node\" | \"link\";\n name: string;\n node?: SankeyNodeData;\n link?: { source: string; target: string; value: number };\n color?: string;\n}\n\nexport interface SankeyChartProps {\n /**\n * The ECharts core instance imported by the consumer.\n * Passed in rather than imported directly so the consumer controls which\n * ECharts modules are bundled (tree-shaking).\n */\n echarts: typeof echarts;\n /** Array of nodes in the Sankey diagram */\n nodes: SankeyNodeData[];\n /** Array of links connecting nodes by index */\n links: SankeyLinkData[];\n /** Height of the chart in pixels */\n height?: number;\n /** Show node values above labels (default: true if any node has a value) */\n showNodeValues?: boolean;\n /** Layout for node labels when showNodeValues is true.\n * - 'stacked': value on top, name below (default)\n * - 'inline': \"value name\" on a single line (better for small nodes)\n */\n nodeLabelLayout?: \"stacked\" | \"inline\";\n /** Format function for node values (default: toLocaleString) */\n formatValue?: (value: number) => string;\n /** Custom tooltip formatter. Return HTML string or empty string to hide tooltip. */\n tooltipFormatter?: (params: SankeyTooltipParams) => string;\n nodeWidth?: number;\n nodePadding?: number;\n showTooltip?: boolean;\n defaultNodeColor?: string;\n /** Left padding of the Sankey layout within the chart container. Accepts a number (px) or percentage string. ECharts default: '5%'. */\n left?: number | string;\n /** Right padding of the Sankey layout within the chart container. Accepts a number (px) or percentage string. ECharts default: '5%'. */\n right?: number | string;\n /** Link fill style: 'gradient' blends source to target colors, 'gray' uses flat gray */\n linkColor?: \"gradient\" | \"gray\";\n linkOpacity?: number;\n className?: string;\n isDarkMode?: boolean;\n onNodeClick?: (node: SankeyNodeData) => void;\n onLinkClick?: (link: SankeyLinkData) => void;\n}\n\nconst defaultFormatValue = (value: number) => value.toLocaleString();\n\n/** Type guard for ECharts tooltip params */\ninterface TooltipParams {\n dataType?: string;\n name?: string;\n data?: { source?: string; target?: string; value?: number };\n value?: number | number[];\n color?: string;\n}\n\nfunction isTooltipParams(params: unknown): params is TooltipParams {\n return typeof params === \"object\" && params !== null;\n}\n\n/** Escape HTML special characters to prevent XSS in tooltips */\nconst escapeHtml = (str: string): string =>\n str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n\n/**\n * Escape ECharts rich text metacharacters to prevent formatting issues.\n * Rich text syntax uses {styleName|text}, so | and } must be escaped.\n */\nconst escapeRichText = (str: string): string =>\n str.replace(/[{}|]/g, (char) => `\\\\${char}`);\n\n/**\n * Sanitize a CSS color value to prevent injection attacks.\n * Only allows valid hex colors, rgb/rgba, hsl/hsla, and named colors.\n */\nconst sanitizeColor = (color: string): string => {\n const fallback = \"#666\";\n if (!color || typeof color !== \"string\") return fallback;\n\n // Hex colors: #RGB, #RRGGBB, #RRGGBBAA\n if (/^#(?:[0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(color)) {\n return color;\n }\n\n // rgb/rgba: rgb(0,0,0) or rgba(0,0,0,0.5)\n if (\n /^rgba?\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*(?:,\\s*[\\d.]+\\s*)?\\)$/i.test(\n color,\n )\n ) {\n return color;\n }\n\n // hsl/hsla: hsl(0,0%,0%) or hsla(0,0%,0%,0.5)\n if (\n /^hsla?\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}%\\s*,\\s*\\d{1,3}%\\s*(?:,\\s*[\\d.]+\\s*)?\\)$/i.test(\n color,\n )\n ) {\n return color;\n }\n\n // Named colors (basic set) - only alphanumeric, no special chars\n if (/^[a-z]{3,20}$/i.test(color)) {\n return color;\n }\n\n return fallback;\n};\n\nexport function SankeyChart({\n echarts,\n nodes,\n links,\n height = 400,\n nodeWidth = 8,\n nodePadding = 10,\n showTooltip: enableTooltip = true,\n showNodeValues,\n nodeLabelLayout = \"stacked\",\n formatValue = defaultFormatValue,\n tooltipFormatter,\n defaultNodeColor,\n left,\n right,\n linkColor = \"gradient\",\n linkOpacity = 0.5,\n className,\n isDarkMode,\n onNodeClick,\n onLinkClick,\n}: SankeyChartProps) {\n const hasNodeValues = nodes.some((n) => n.value !== undefined);\n const shouldShowValues = showNodeValues ?? hasNodeValues;\n const isInlineLayout = nodeLabelLayout === \"inline\";\n const options = useMemo<EChartsOption>(() => {\n const labelColor = ChartPalette.text(\"primary\", isDarkMode);\n const secondaryColor = ChartPalette.text(\"secondary\", isDarkMode);\n\n // Compute colors for each node (explicit color > default > categorical)\n const nodeColors = nodes.map(\n (node, index) =>\n node.color ??\n defaultNodeColor ??\n ChartPalette.categorical(index, isDarkMode),\n );\n\n // Build a map of node name to original node data + computed color for tooltip access\n const nodeDataMap = new Map(\n nodes.map((n, i) => [n.name, { ...n, computedColor: nodeColors[i] }]),\n );\n\n const echartsNodes = nodes.map((node, index) => ({\n name: node.name,\n value: node.value,\n itemStyle: {\n color: nodeColors[index],\n },\n }));\n\n const echartsLinks = links.map((link) => ({\n source: nodes[link.source]?.name ?? \"\",\n target: nodes[link.target]?.name ?? \"\",\n value: link.value,\n }));\n\n return {\n backgroundColor: \"transparent\",\n animation: true,\n animationDuration: 500,\n animationDurationUpdate: 300,\n animationEasingUpdate: \"cubicInOut\",\n tooltip: enableTooltip\n ? {\n trigger: \"item\",\n triggerOn: \"mousemove\",\n dangerousHtmlFormatter: (params: unknown) => {\n if (!isTooltipParams(params)) return \"\";\n\n if (params.dataType === \"node\" && params.name) {\n const nodeData = nodeDataMap.get(params.name);\n const color = sanitizeColor(\n nodeData?.computedColor ?? params.color ?? \"#666\",\n );\n\n // Use custom formatter if provided\n if (tooltipFormatter) {\n return tooltipFormatter({\n type: \"node\",\n name: params.name,\n node: nodeData,\n color,\n });\n }\n\n // Default node tooltip\n const safeName = escapeHtml(params.name);\n return `<div style=\"display:flex;align-items:center;gap:6px;\"><span style=\"display:inline-block;width:10px;height:10px;border-radius:50%;background:${color}\"></span><strong>${safeName}</strong></div>`;\n }\n\n if (params.dataType === \"edge\" && params.data) {\n const { source, target, value } = params.data;\n\n // Use custom formatter if provided\n if (tooltipFormatter) {\n return tooltipFormatter({\n type: \"link\",\n name: `${source} → ${target}`,\n link: {\n source: source ?? \"\",\n target: target ?? \"\",\n value: value ?? 0,\n },\n });\n }\n\n // Get colors for source and target nodes\n const sourceNode = nodeDataMap.get(source ?? \"\");\n const targetNode = nodeDataMap.get(target ?? \"\");\n const sourceColor = sanitizeColor(\n sourceNode?.computedColor ?? \"#666\",\n );\n const targetColor = sanitizeColor(\n targetNode?.computedColor ?? \"#666\",\n );\n\n // Default link tooltip with colored dots\n const safeSource = escapeHtml(source ?? \"\");\n const safeTarget = escapeHtml(target ?? \"\");\n return `<div style=\"display:flex;align-items:center;gap:6px;margin-bottom:4px;\">\n <span style=\"display:inline-block;width:10px;height:10px;border-radius:50%;background:${sourceColor}\"></span>\n <strong>${safeSource}</strong>\n <span style=\"color:${secondaryColor}\">→</span>\n <span style=\"display:inline-block;width:10px;height:10px;border-radius:50%;background:${targetColor}\"></span>\n <strong>${safeTarget}</strong>\n </div>\n <strong>${value !== undefined ? escapeHtml(formatValue(value)) : \"\"}</strong>`;\n }\n\n return \"\";\n },\n }\n : undefined,\n series: [\n {\n type: \"sankey\",\n ...(left !== undefined && { left }),\n ...(right !== undefined && { right }),\n data: echartsNodes,\n links: echartsLinks,\n draggable: false,\n emphasis: {\n focus: \"adjacency\",\n },\n nodeWidth,\n nodeGap: nodePadding,\n lineStyle: {\n color: linkColor === \"gradient\" ? \"source\" : \"#d1d5db\",\n opacity: linkColor === \"gradient\" ? linkOpacity : 0.4,\n curveness: 0.5,\n },\n label: {\n show: true,\n color: labelColor,\n fontSize: 12,\n formatter: shouldShowValues\n ? (params: { name?: string }) => {\n const name = params.name ?? \"\";\n const nodeData = nodeDataMap.get(name);\n const safeName = escapeRichText(name);\n if (nodeData?.value !== undefined) {\n const formattedValue = escapeRichText(\n formatValue(nodeData.value),\n );\n // Inline: \"name value\" on single line; Stacked: value above name\n return isInlineLayout\n ? `{name|${safeName}} {value|${formattedValue}}`\n : `{value|${formattedValue}}\\n{name|${safeName}}`;\n }\n return safeName;\n }\n : undefined,\n rich: shouldShowValues\n ? {\n value: {\n fontSize: 11,\n color: labelColor,\n lineHeight: isInlineLayout ? undefined : 16,\n },\n name: {\n fontSize: 12,\n color: labelColor,\n fontWeight: 700,\n },\n }\n : undefined,\n },\n },\n ],\n };\n }, [\n nodes,\n links,\n enableTooltip,\n nodeWidth,\n nodePadding,\n defaultNodeColor,\n left,\n right,\n isDarkMode,\n linkColor,\n linkOpacity,\n shouldShowValues,\n isInlineLayout,\n formatValue,\n tooltipFormatter,\n ]);\n\n const handleClick = useCallback(\n (params: Parameters<ChartEvents[\"click\"]>[0]) => {\n if (params.dataType === \"node\" && onNodeClick && params.name) {\n const nodeIndex = nodes.findIndex((n) => n.name === params.name);\n const originalNode = nodeIndex >= 0 ? nodes[nodeIndex] : null;\n\n const nodeData: SankeyNodeData = {\n ...originalNode,\n name: params.name,\n };\n onNodeClick(nodeData);\n } else if (params.dataType === \"edge\" && onLinkClick && params.data) {\n const data = params.data;\n const source =\n typeof data === \"object\" && data !== null && \"source\" in data\n ? String(data.source)\n : \"\";\n const target =\n typeof data === \"object\" && data !== null && \"target\" in data\n ? String(data.target)\n : \"\";\n const sourceIndex = nodes.findIndex((n) => n.name === source);\n const targetIndex = nodes.findIndex((n) => n.name === target);\n\n if (sourceIndex === -1 || targetIndex === -1) return;\n\n const rawValue = params.value;\n const value =\n typeof rawValue === \"number\"\n ? rawValue\n : Array.isArray(rawValue) && typeof rawValue[0] === \"number\"\n ? rawValue[0]\n : 0;\n\n // Find original link to preserve id and isDrillable properties\n const originalLink = links.find(\n (l) => l.source === sourceIndex && l.target === targetIndex,\n );\n onLinkClick({\n ...originalLink,\n source: sourceIndex,\n target: targetIndex,\n value,\n });\n }\n },\n [nodes, links, onNodeClick, onLinkClick],\n );\n\n const onEvents = useMemo<Partial<ChartEvents>>(\n () => ({\n click: handleClick,\n }),\n [handleClick],\n );\n\n return (\n <Chart\n echarts={echarts}\n options={options}\n className={className}\n isDarkMode={isDarkMode}\n height={height}\n onEvents={onEvents}\n />\n );\n}\n\nSankeyChart.displayName = \"SankeyChart\";\n"],"names":["ChartSemanticLightColors","ChartSemanticDarkColors","sequentialLight","sequentialDark","CHART_LIGHT_COLORS","CHART_DARK_COLORS","ChartPalette","semantic","name","isDarkMode","categorical","index","sequential","palette","text","variant","colors","transformTooltip","tooltipObj","dangerousHtmlFormatter","restOfTooltip","prepareChartOptions","options","withDefaults","Chart","forwardRef","echarts","optionUpdateBehavior","className","height","onEvents","ref","elRef","useRef","chartRef","handlersRef","wrappersRef","boundEventsRef","useEffect","chart","event","wrapper","nextBound","handler","params","el","isInitial","ro","jsx","cn","TimeseriesChart","type","data","xAxisName","xAxisTickCount","xAxisTickFormat","yAxisTickFormat","yAxisTickLabelFormat","yAxisName","yAxisTickCount","tooltipValueFormat","onTimeRangeChange","incomplete","enableLegendSelection","gradient","loading","ariaDescription","tooltipMode","tooltipMaxItems","tooltipFollowCursor","tooltipBoundary","containerRef","mergedRef","useCallback","instance","dataRef","legendSelectedRef","tooltipModeRef","tooltipMaxItemsRef","tooltipState","setTooltipState","useState","mousePosRef","container","onMove","e","rect","incompleteBefore","incompleteAfter","useMemo","transformSeries","seriesType","s","incompleteBeforePoints","point","incompleteAfterPoints","completePoints","areaStyle","colorWithOpacity","incompleteSeriesConfig","value","events","ts","seenNames","allRows","legendSelected","findNearest","a","b","rows","hiddenCount","cursorValue","best","row","max","nextState","prev","isSameTooltipState","range","hasTimeRangeCallback","formatFn","tooltipOpen","jsxs","TooltipPrimitive.Root","TooltipPrimitive.Trigger","ChartWaveLoader","TooltipPrimitive.Portal","TooltipPrimitive.Positioner","TooltipPrimitive.Popup","TooltipContent","memo","state","formatValue","Fragment","formatTimestamp","formatDefaultValue","lo","hi","mid","i","next","defaultNumberFormat","amp","period","steps","points","x","y","d","strokeColor","color","alpha","rgbMatch","hex","r","g","tooltipDateFormat","onInteractiveKeyDown","LargeItem","unit","inactive","onPointerEnter","onPointerLeave","onClick","SmallItem","ChartLegend","defaultFormatValue","isTooltipParams","escapeHtml","str","escapeRichText","char","sanitizeColor","fallback","SankeyChart","nodes","links","nodeWidth","nodePadding","enableTooltip","showNodeValues","nodeLabelLayout","tooltipFormatter","defaultNodeColor","left","right","linkColor","linkOpacity","onNodeClick","onLinkClick","hasNodeValues","n","shouldShowValues","isInlineLayout","labelColor","secondaryColor","nodeColors","node","nodeDataMap","echartsNodes","echartsLinks","link","nodeData","safeName","source","target","sourceNode","targetNode","sourceColor","targetColor","safeSource","safeTarget","formattedValue","handleClick","nodeIndex","sourceIndex","targetIndex","rawValue","originalLink","l"],"mappings":"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"}
@@ -2,11 +2,11 @@
2
2
  import { jsx as t, jsxs as C } from "react/jsx-runtime";
3
3
  import { CheckIcon as y } from "@phosphor-icons/react";
4
4
  import { createContext as v, useContext as I } from "react";
5
- import { K as u, i as k } from "./input-en8hhb14mmt3tfwn.js";
5
+ import { K as u, i as k } from "./input-f2ct7obgdzypjmp2.js";
6
6
  import { c as r } from "./cn-ct4n7r74mh8y0f48.js";
7
7
  import { r as E } from "./resolve-variant-gw6eh7fa4st8ej7m.js";
8
- import { F as T } from "./field-c8o7h3rlam4c9pcx.js";
9
- import { by as w, aa as z, af as G, bx as L, ac as O, S as P, ad as _, ae as S, bw as U, an as R, ao as V, ap as F, ag as K } from "./vendor-base-ui-knphx7dts1vm1x37.js";
8
+ import { F as z } from "./field-f1hy08um3jf9jos6.js";
9
+ import { bB as T, aa as G, af as L, bA as O, ac as P, S as _, ad as w, ae as S, bz as U, an as R, ao as V, ap as F, ag as K } from "./vendor-base-ui-f9z44m829vvptrg0.js";
10
10
  const p = v({
11
11
  hasError: !1
12
12
  }), W = {
@@ -34,9 +34,9 @@ function d({
34
34
  children: m,
35
35
  ...i
36
36
  }) {
37
- const g = i, c = /* @__PURE__ */ t(p.Provider, { value: { hasError: !!a }, children: /* @__PURE__ */ t(L, { ...g, children: m }) });
37
+ const g = i, c = /* @__PURE__ */ t(p.Provider, { value: { hasError: !!a }, children: /* @__PURE__ */ t(O, { ...g, children: m }) });
38
38
  return o ? /* @__PURE__ */ t(
39
- T,
39
+ z,
40
40
  {
41
41
  label: o,
42
42
  required: e,
@@ -107,7 +107,7 @@ function M({
107
107
  ...e
108
108
  }) {
109
109
  return /* @__PURE__ */ t(
110
- O,
110
+ P,
111
111
  {
112
112
  ...e,
113
113
  className: r(
@@ -144,18 +144,18 @@ function h(o) {
144
144
  }
145
145
  );
146
146
  }
147
- function N(o) {
147
+ function A(o) {
148
148
  return /* @__PURE__ */ t(
149
- _,
149
+ w,
150
150
  {
151
151
  ...o,
152
152
  className: "border-t border-kumo-line mt-2 pt-2 first:border-t-0 first:mt-0 first:pt-0"
153
153
  }
154
154
  );
155
155
  }
156
- function A(o) {
156
+ function N(o) {
157
157
  return /* @__PURE__ */ t(
158
- P,
158
+ _,
159
159
  {
160
160
  ...o,
161
161
  className: r("mx-0 my-1 h-px bg-kumo-line", o.className)
@@ -167,22 +167,22 @@ b.displayName = "Autocomplete.InputGroup";
167
167
  f.displayName = "Autocomplete.Content";
168
168
  x.displayName = "Autocomplete.Item";
169
169
  h.displayName = "Autocomplete.GroupLabel";
170
- N.displayName = "Autocomplete.Group";
171
- A.displayName = "Autocomplete.Separator";
170
+ A.displayName = "Autocomplete.Group";
171
+ N.displayName = "Autocomplete.Separator";
172
172
  const Y = Object.assign(d, {
173
173
  // Styled compound sub-components
174
174
  InputGroup: b,
175
175
  Content: f,
176
176
  Item: x,
177
177
  GroupLabel: h,
178
- Group: N,
179
- Separator: A,
178
+ Group: A,
179
+ Separator: N,
180
180
  List: M,
181
181
  // Pass-through Base UI sub-components
182
- Empty: G,
183
- Collection: z,
182
+ Empty: L,
183
+ Collection: G,
184
184
  // Filtering
185
- useFilter: w
185
+ useFilter: T
186
186
  });
187
187
  export {
188
188
  Y as A,
@@ -190,4 +190,4 @@ export {
190
190
  X as a,
191
191
  l as b
192
192
  };
193
- //# sourceMappingURL=autocomplete-d0w42h1frdu03df6.js.map
193
+ //# sourceMappingURL=autocomplete-hgprlcuf0ixbbo6d.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"autocomplete-d0w42h1frdu03df6.js","sources":["../../src/components/autocomplete/autocomplete.tsx"],"sourcesContent":["import { Autocomplete as AutocompleteBase } from \"@base-ui/react/autocomplete\";\nimport { CheckIcon } from \"@phosphor-icons/react\";\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport { inputVariants, KUMO_INPUT_VARIANTS } from \"../input/input\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant } from \"../../utils/resolve-variant\";\nimport { Field, type FieldErrorMatch } from \"../field/field\";\n\nconst AutocompleteContext = createContext<{ hasError: boolean }>({\n hasError: false,\n});\n\n/** Autocomplete variant definitions. */\nexport const KUMO_AUTOCOMPLETE_VARIANTS = {\n size: KUMO_INPUT_VARIANTS.size,\n} as const;\n\nexport const KUMO_AUTOCOMPLETE_DEFAULT_VARIANTS = {\n size: \"base\",\n} as const;\n\n// Derived types from KUMO_AUTOCOMPLETE_VARIANTS\nexport type KumoAutocompleteSize = keyof typeof KUMO_AUTOCOMPLETE_VARIANTS.size;\n\nexport interface KumoAutocompleteVariantsProps {\n /**\n * Size of the autocomplete input. Matches Input component sizes.\n * - `\"xs\"` — Extra small for compact UIs (h-5 / 20px)\n * - `\"sm\"` — Small for secondary fields (h-6.5 / 26px)\n * - `\"base\"` — Default size (h-9 / 36px)\n * - `\"lg\"` — Large for prominent fields (h-10 / 40px)\n * @default \"base\"\n */\n size?: KumoAutocompleteSize;\n}\n\nexport function autocompleteVariants({\n size = KUMO_AUTOCOMPLETE_DEFAULT_VARIANTS.size,\n}: KumoAutocompleteVariantsProps = {}) {\n return cn(\n resolveVariant(\n KUMO_INPUT_VARIANTS.size,\n size,\n KUMO_AUTOCOMPLETE_DEFAULT_VARIANTS.size,\n ).classes,\n );\n}\n\n/**\n * Autocomplete component props.\n *\n * Autocomplete provides a free-form text input with optional suggestions in a\n * filterable dropdown. Unlike Combobox, the input value is not constrained to\n * the suggestion list items.\n *\n * @example\n * ```tsx\n * <Autocomplete label=\"Country\" items={countries}>\n * <Autocomplete.InputGroup />\n * <Autocomplete.Content>\n * <Autocomplete.List>\n * {(item) => <Autocomplete.Item value={item}>{item}</Autocomplete.Item>}\n * </Autocomplete.List>\n * </Autocomplete.Content>\n * </Autocomplete>\n * ```\n */\nexport interface AutocompleteProps {\n /** Array of items to display in the dropdown */\n items: unknown[];\n /** The controlled input value */\n value?: string | number | string[];\n /** The uncontrolled default input value */\n defaultValue?: string | number | string[];\n /** Callback when the input value changes */\n onValueChange?: AutocompleteBase.Root.Props<unknown>[\"onValueChange\"];\n /** Whether the popup is open (controlled) */\n open?: boolean;\n /** Callback when the popup opens or closes */\n onOpenChange?: AutocompleteBase.Root.Props<unknown>[\"onOpenChange\"];\n /** Autocomplete content (input group, popup content) */\n children: ReactNode;\n /** Additional CSS classes */\n className?: string;\n /** Label content (enables Field wrapper) */\n label?: ReactNode;\n /** Whether the field is required */\n required?: boolean;\n /** Tooltip content to display next to the label */\n labelTooltip?: ReactNode;\n /** Helper text displayed below the field */\n description?: ReactNode;\n /** Error message or validation error object */\n error?: string | { message: ReactNode; match: FieldErrorMatch };\n}\n\nfunction Root<ItemValue>({\n label,\n required,\n labelTooltip,\n description,\n error,\n children,\n ...props\n}: AutocompleteBase.Root.Props<ItemValue> & {\n label?: ReactNode;\n required?: boolean;\n labelTooltip?: ReactNode;\n description?: ReactNode;\n error?: string | { message: ReactNode; match: FieldErrorMatch };\n}) {\n const rootProps = props as Omit<\n AutocompleteBase.Root.Props<ItemValue>,\n \"items\"\n > & {\n items?: readonly ItemValue[];\n };\n const control = (\n <AutocompleteContext.Provider value={{ hasError: Boolean(error) }}>\n <AutocompleteBase.Root {...rootProps}>{children}</AutocompleteBase.Root>\n </AutocompleteContext.Provider>\n );\n\n if (label) {\n return (\n <Field\n label={label}\n required={required}\n labelTooltip={labelTooltip}\n description={description}\n error={\n error\n ? typeof error === \"string\"\n ? { message: error, match: true }\n : error\n : undefined\n }\n >\n {control}\n </Field>\n );\n }\n\n return control;\n}\n\nfunction InputGroup({\n className,\n size = KUMO_AUTOCOMPLETE_DEFAULT_VARIANTS.size,\n placeholder,\n}: {\n className?: string;\n size?: KumoAutocompleteSize;\n placeholder?: string;\n}) {\n const { hasError } = useContext(AutocompleteContext);\n return (\n <AutocompleteBase.Input\n className={cn(\n inputVariants({\n size,\n variant: hasError ? \"error\" : \"default\",\n focusIndicator: true,\n }),\n \"w-full\",\n className,\n )}\n placeholder={placeholder}\n />\n );\n}\n\nfunction Content({\n children,\n className,\n align = \"start\",\n sideOffset = 4,\n alignOffset,\n side,\n}: {\n children?: ReactNode;\n className?: string;\n align?: AutocompleteBase.Positioner.Props[\"align\"];\n alignOffset?: AutocompleteBase.Positioner.Props[\"alignOffset\"];\n side?: AutocompleteBase.Positioner.Props[\"side\"];\n sideOffset?: AutocompleteBase.Positioner.Props[\"sideOffset\"];\n}) {\n return (\n <AutocompleteBase.Portal>\n <AutocompleteBase.Positioner\n className=\"outline-none\"\n align={align}\n sideOffset={sideOffset}\n alignOffset={alignOffset}\n side={side}\n >\n <AutocompleteBase.Popup\n className={(state: AutocompleteBase.Popup.State) =>\n cn(\n \"flex flex-col\",\n \"max-h-[min(var(--available-height),24rem)] max-w-(--available-width) min-w-(--anchor-width) py-1.5\",\n \"bg-kumo-control text-kumo-default\",\n \"rounded-lg shadow-lg ring ring-kumo-line\",\n state.empty && \"hidden\",\n className,\n )\n }\n >\n {children}\n </AutocompleteBase.Popup>\n </AutocompleteBase.Positioner>\n </AutocompleteBase.Portal>\n );\n}\n\nfunction List({\n className,\n ...props\n}: AutocompleteBase.List.Props & { className?: string }) {\n return (\n <AutocompleteBase.List\n {...props}\n className={cn(\n \"min-h-0 flex-1 overflow-y-auto overscroll-contain scroll-pt-2 scroll-pb-2\",\n className,\n )}\n />\n );\n}\n\nfunction Item({ children, ...props }: AutocompleteBase.Item.Props) {\n return (\n <AutocompleteBase.Item\n data-kumo-component=\"Autocomplete\"\n data-kumo-part=\"item\"\n {...props}\n className=\"group mx-1.5 grid cursor-pointer grid-cols-[1fr_16px] gap-2 rounded px-2 py-1.5 text-base data-highlighted:bg-kumo-overlay data-selected:font-medium\"\n >\n <div className=\"col-start-1\">{children}</div>\n <span className=\"col-start-2 hidden items-center group-data-selected:flex\">\n <CheckIcon size={14} />\n </span>\n </AutocompleteBase.Item>\n );\n}\n\nfunction GroupLabel(props: AutocompleteBase.GroupLabel.Props) {\n return (\n <AutocompleteBase.GroupLabel\n {...props}\n className={cn(\n \"mx-1.5 px-2 py-1.5 text-sm text-kumo-strong\",\n props.className,\n )}\n />\n );\n}\n\nfunction Group(props: AutocompleteBase.Group.Props) {\n return (\n <AutocompleteBase.Group\n {...props}\n className=\"border-t border-kumo-line mt-2 pt-2 first:border-t-0 first:mt-0 first:pt-0\"\n />\n );\n}\n\nfunction Separator(props: AutocompleteBase.Separator.Props) {\n return (\n <AutocompleteBase.Separator\n {...props}\n className={cn(\"mx-0 my-1 h-px bg-kumo-line\", props.className)}\n />\n );\n}\n\nRoot.displayName = \"Autocomplete.Root\";\nInputGroup.displayName = \"Autocomplete.InputGroup\";\nContent.displayName = \"Autocomplete.Content\";\nItem.displayName = \"Autocomplete.Item\";\nGroupLabel.displayName = \"Autocomplete.GroupLabel\";\nGroup.displayName = \"Autocomplete.Group\";\nSeparator.displayName = \"Autocomplete.Separator\";\n\n/**\n * Autocomplete — free-form text input with an optional filtered suggestion list.\n *\n * Unlike Combobox, the input value is not restricted to items in the list.\n * Use Combobox when the selected value must come from the list.\n *\n * Compound component: `Autocomplete` (Root), `.InputGroup`, `.Content`, `.Item`,\n * `.GroupLabel`, `.Group`, `.Separator`, `.List`, `.Collection`.\n *\n * `InputGroup` renders the text input with Input component styling.\n * Pass a `size` prop to `InputGroup` to match the Input component sizes.\n *\n * @example\n * ```tsx\n * <Autocomplete items={fruits} label=\"Fruit\">\n * <Autocomplete.InputGroup size=\"base\" />\n * <Autocomplete.Content>\n * <Autocomplete.List>\n * {(item) => <Autocomplete.Item value={item}>{item}</Autocomplete.Item>}\n * </Autocomplete.List>\n * </Autocomplete.Content>\n * </Autocomplete>\n * ```\n *\n * @see https://base-ui.com/react/components/autocomplete\n */\nexport const Autocomplete = Object.assign(Root, {\n // Styled compound sub-components\n InputGroup,\n Content,\n Item,\n GroupLabel,\n Group,\n Separator,\n List,\n\n // Pass-through Base UI sub-components\n Empty: AutocompleteBase.Empty,\n Collection: AutocompleteBase.Collection,\n\n // Filtering\n useFilter: AutocompleteBase.useFilter,\n});\n"],"names":["AutocompleteContext","createContext","KUMO_AUTOCOMPLETE_VARIANTS","KUMO_INPUT_VARIANTS","KUMO_AUTOCOMPLETE_DEFAULT_VARIANTS","autocompleteVariants","size","cn","resolveVariant","Root","label","required","labelTooltip","description","error","children","props","rootProps","control","jsx","AutocompleteBase.Root","Field","InputGroup","className","placeholder","hasError","useContext","AutocompleteBase.Input","inputVariants","Content","align","sideOffset","alignOffset","side","AutocompleteBase.Portal","AutocompleteBase.Positioner","AutocompleteBase.Popup","state","List","AutocompleteBase.List","Item","jsxs","AutocompleteBase.Item","CheckIcon","GroupLabel","AutocompleteBase.GroupLabel","Group","AutocompleteBase.Group","Separator","AutocompleteBase.Separator","Autocomplete","AutocompleteBase.Empty","AutocompleteBase.Collection","AutocompleteBase.useFilter"],"mappings":"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"}
1
+ {"version":3,"file":"autocomplete-hgprlcuf0ixbbo6d.js","sources":["../../src/components/autocomplete/autocomplete.tsx"],"sourcesContent":["import { Autocomplete as AutocompleteBase } from \"@base-ui/react/autocomplete\";\nimport { CheckIcon } from \"@phosphor-icons/react\";\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport { inputVariants, KUMO_INPUT_VARIANTS } from \"../input/input\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant } from \"../../utils/resolve-variant\";\nimport { Field, type FieldErrorMatch } from \"../field/field\";\n\nconst AutocompleteContext = createContext<{ hasError: boolean }>({\n hasError: false,\n});\n\n/** Autocomplete variant definitions. */\nexport const KUMO_AUTOCOMPLETE_VARIANTS = {\n size: KUMO_INPUT_VARIANTS.size,\n} as const;\n\nexport const KUMO_AUTOCOMPLETE_DEFAULT_VARIANTS = {\n size: \"base\",\n} as const;\n\n// Derived types from KUMO_AUTOCOMPLETE_VARIANTS\nexport type KumoAutocompleteSize = keyof typeof KUMO_AUTOCOMPLETE_VARIANTS.size;\n\nexport interface KumoAutocompleteVariantsProps {\n /**\n * Size of the autocomplete input. Matches Input component sizes.\n * - `\"xs\"` — Extra small for compact UIs (h-5 / 20px)\n * - `\"sm\"` — Small for secondary fields (h-6.5 / 26px)\n * - `\"base\"` — Default size (h-9 / 36px)\n * - `\"lg\"` — Large for prominent fields (h-10 / 40px)\n * @default \"base\"\n */\n size?: KumoAutocompleteSize;\n}\n\nexport function autocompleteVariants({\n size = KUMO_AUTOCOMPLETE_DEFAULT_VARIANTS.size,\n}: KumoAutocompleteVariantsProps = {}) {\n return cn(\n resolveVariant(\n KUMO_INPUT_VARIANTS.size,\n size,\n KUMO_AUTOCOMPLETE_DEFAULT_VARIANTS.size,\n ).classes,\n );\n}\n\n/**\n * Autocomplete component props.\n *\n * Autocomplete provides a free-form text input with optional suggestions in a\n * filterable dropdown. Unlike Combobox, the input value is not constrained to\n * the suggestion list items.\n *\n * @example\n * ```tsx\n * <Autocomplete label=\"Country\" items={countries}>\n * <Autocomplete.InputGroup />\n * <Autocomplete.Content>\n * <Autocomplete.List>\n * {(item) => <Autocomplete.Item value={item}>{item}</Autocomplete.Item>}\n * </Autocomplete.List>\n * </Autocomplete.Content>\n * </Autocomplete>\n * ```\n */\nexport interface AutocompleteProps {\n /** Array of items to display in the dropdown */\n items: unknown[];\n /** The controlled input value */\n value?: string | number | string[];\n /** The uncontrolled default input value */\n defaultValue?: string | number | string[];\n /** Callback when the input value changes */\n onValueChange?: AutocompleteBase.Root.Props<unknown>[\"onValueChange\"];\n /** Whether the popup is open (controlled) */\n open?: boolean;\n /** Callback when the popup opens or closes */\n onOpenChange?: AutocompleteBase.Root.Props<unknown>[\"onOpenChange\"];\n /** Autocomplete content (input group, popup content) */\n children: ReactNode;\n /** Additional CSS classes */\n className?: string;\n /** Label content (enables Field wrapper) */\n label?: ReactNode;\n /** Whether the field is required */\n required?: boolean;\n /** Tooltip content to display next to the label */\n labelTooltip?: ReactNode;\n /** Helper text displayed below the field */\n description?: ReactNode;\n /** Error message or validation error object */\n error?: string | { message: ReactNode; match: FieldErrorMatch };\n}\n\nfunction Root<ItemValue>({\n label,\n required,\n labelTooltip,\n description,\n error,\n children,\n ...props\n}: AutocompleteBase.Root.Props<ItemValue> & {\n label?: ReactNode;\n required?: boolean;\n labelTooltip?: ReactNode;\n description?: ReactNode;\n error?: string | { message: ReactNode; match: FieldErrorMatch };\n}) {\n const rootProps = props as Omit<\n AutocompleteBase.Root.Props<ItemValue>,\n \"items\"\n > & {\n items?: readonly ItemValue[];\n };\n const control = (\n <AutocompleteContext.Provider value={{ hasError: Boolean(error) }}>\n <AutocompleteBase.Root {...rootProps}>{children}</AutocompleteBase.Root>\n </AutocompleteContext.Provider>\n );\n\n if (label) {\n return (\n <Field\n label={label}\n required={required}\n labelTooltip={labelTooltip}\n description={description}\n error={\n error\n ? typeof error === \"string\"\n ? { message: error, match: true }\n : error\n : undefined\n }\n >\n {control}\n </Field>\n );\n }\n\n return control;\n}\n\nfunction InputGroup({\n className,\n size = KUMO_AUTOCOMPLETE_DEFAULT_VARIANTS.size,\n placeholder,\n}: {\n className?: string;\n size?: KumoAutocompleteSize;\n placeholder?: string;\n}) {\n const { hasError } = useContext(AutocompleteContext);\n return (\n <AutocompleteBase.Input\n className={cn(\n inputVariants({\n size,\n variant: hasError ? \"error\" : \"default\",\n focusIndicator: true,\n }),\n \"w-full\",\n className,\n )}\n placeholder={placeholder}\n />\n );\n}\n\nfunction Content({\n children,\n className,\n align = \"start\",\n sideOffset = 4,\n alignOffset,\n side,\n}: {\n children?: ReactNode;\n className?: string;\n align?: AutocompleteBase.Positioner.Props[\"align\"];\n alignOffset?: AutocompleteBase.Positioner.Props[\"alignOffset\"];\n side?: AutocompleteBase.Positioner.Props[\"side\"];\n sideOffset?: AutocompleteBase.Positioner.Props[\"sideOffset\"];\n}) {\n return (\n <AutocompleteBase.Portal>\n <AutocompleteBase.Positioner\n className=\"outline-none\"\n align={align}\n sideOffset={sideOffset}\n alignOffset={alignOffset}\n side={side}\n >\n <AutocompleteBase.Popup\n className={(state: AutocompleteBase.Popup.State) =>\n cn(\n \"flex flex-col\",\n \"max-h-[min(var(--available-height),24rem)] max-w-(--available-width) min-w-(--anchor-width) py-1.5\",\n \"bg-kumo-control text-kumo-default\",\n \"rounded-lg shadow-lg ring ring-kumo-line\",\n state.empty && \"hidden\",\n className,\n )\n }\n >\n {children}\n </AutocompleteBase.Popup>\n </AutocompleteBase.Positioner>\n </AutocompleteBase.Portal>\n );\n}\n\nfunction List({\n className,\n ...props\n}: AutocompleteBase.List.Props & { className?: string }) {\n return (\n <AutocompleteBase.List\n {...props}\n className={cn(\n \"min-h-0 flex-1 overflow-y-auto overscroll-contain scroll-pt-2 scroll-pb-2\",\n className,\n )}\n />\n );\n}\n\nfunction Item({ children, ...props }: AutocompleteBase.Item.Props) {\n return (\n <AutocompleteBase.Item\n data-kumo-component=\"Autocomplete\"\n data-kumo-part=\"item\"\n {...props}\n className=\"group mx-1.5 grid cursor-pointer grid-cols-[1fr_16px] gap-2 rounded px-2 py-1.5 text-base data-highlighted:bg-kumo-overlay data-selected:font-medium\"\n >\n <div className=\"col-start-1\">{children}</div>\n <span className=\"col-start-2 hidden items-center group-data-selected:flex\">\n <CheckIcon size={14} />\n </span>\n </AutocompleteBase.Item>\n );\n}\n\nfunction GroupLabel(props: AutocompleteBase.GroupLabel.Props) {\n return (\n <AutocompleteBase.GroupLabel\n {...props}\n className={cn(\n \"mx-1.5 px-2 py-1.5 text-sm text-kumo-strong\",\n props.className,\n )}\n />\n );\n}\n\nfunction Group(props: AutocompleteBase.Group.Props) {\n return (\n <AutocompleteBase.Group\n {...props}\n className=\"border-t border-kumo-line mt-2 pt-2 first:border-t-0 first:mt-0 first:pt-0\"\n />\n );\n}\n\nfunction Separator(props: AutocompleteBase.Separator.Props) {\n return (\n <AutocompleteBase.Separator\n {...props}\n className={cn(\"mx-0 my-1 h-px bg-kumo-line\", props.className)}\n />\n );\n}\n\nRoot.displayName = \"Autocomplete.Root\";\nInputGroup.displayName = \"Autocomplete.InputGroup\";\nContent.displayName = \"Autocomplete.Content\";\nItem.displayName = \"Autocomplete.Item\";\nGroupLabel.displayName = \"Autocomplete.GroupLabel\";\nGroup.displayName = \"Autocomplete.Group\";\nSeparator.displayName = \"Autocomplete.Separator\";\n\n/**\n * Autocomplete — free-form text input with an optional filtered suggestion list.\n *\n * Unlike Combobox, the input value is not restricted to items in the list.\n * Use Combobox when the selected value must come from the list.\n *\n * Compound component: `Autocomplete` (Root), `.InputGroup`, `.Content`, `.Item`,\n * `.GroupLabel`, `.Group`, `.Separator`, `.List`, `.Collection`.\n *\n * `InputGroup` renders the text input with Input component styling.\n * Pass a `size` prop to `InputGroup` to match the Input component sizes.\n *\n * @example\n * ```tsx\n * <Autocomplete items={fruits} label=\"Fruit\">\n * <Autocomplete.InputGroup size=\"base\" />\n * <Autocomplete.Content>\n * <Autocomplete.List>\n * {(item) => <Autocomplete.Item value={item}>{item}</Autocomplete.Item>}\n * </Autocomplete.List>\n * </Autocomplete.Content>\n * </Autocomplete>\n * ```\n *\n * @see https://base-ui.com/react/components/autocomplete\n */\nexport const Autocomplete = Object.assign(Root, {\n // Styled compound sub-components\n InputGroup,\n Content,\n Item,\n GroupLabel,\n Group,\n Separator,\n List,\n\n // Pass-through Base UI sub-components\n Empty: AutocompleteBase.Empty,\n Collection: AutocompleteBase.Collection,\n\n // Filtering\n useFilter: AutocompleteBase.useFilter,\n});\n"],"names":["AutocompleteContext","createContext","KUMO_AUTOCOMPLETE_VARIANTS","KUMO_INPUT_VARIANTS","KUMO_AUTOCOMPLETE_DEFAULT_VARIANTS","autocompleteVariants","size","cn","resolveVariant","Root","label","required","labelTooltip","description","error","children","props","rootProps","control","jsx","AutocompleteBase.Root","Field","InputGroup","className","placeholder","hasError","useContext","AutocompleteBase.Input","inputVariants","Content","align","sideOffset","alignOffset","side","AutocompleteBase.Portal","AutocompleteBase.Positioner","AutocompleteBase.Popup","state","List","AutocompleteBase.List","Item","jsxs","AutocompleteBase.Item","CheckIcon","GroupLabel","AutocompleteBase.GroupLabel","Group","AutocompleteBase.Group","Separator","AutocompleteBase.Separator","Autocomplete","AutocompleteBase.Empty","AutocompleteBase.Collection","AutocompleteBase.useFilter"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  import { jsxs as l, jsx as r } from "react/jsx-runtime";
3
3
  import { Children as k, cloneElement as d, isValidElement as x, useState as C, useEffect as g } from "react";
4
4
  import { CheckIcon as w, CopyIcon as N } from "@phosphor-icons/react";
5
- import { B as y } from "./button-mnrxu6dud2x5js5b.js";
5
+ import { B as y } from "./button-gtdhvogt5rlrf1is.js";
6
6
  import { S as v } from "./skeleton-line-epxenksfesr2fkcv.js";
7
7
  import { u as B } from "./link-provider-mn2voeohon7cj9o4.js";
8
8
  import { c as f } from "./cn-ct4n7r74mh8y0f48.js";
@@ -166,4 +166,4 @@ export {
166
166
  b as a,
167
167
  A as b
168
168
  };
169
- //# sourceMappingURL=breadcrumbs-j214mimk5zj4ffp4.js.map
169
+ //# sourceMappingURL=breadcrumbs-lyj8ljudrm2owx5y.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumbs-j214mimk5zj4ffp4.js","sources":["../../src/components/breadcrumbs/breadcrumbs.tsx"],"sourcesContent":["import {\n Children,\n cloneElement,\n isValidElement,\n useEffect,\n useState,\n type PropsWithChildren,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { CheckIcon, CopyIcon } from \"@phosphor-icons/react\";\nimport { Button } from \"../../components/button\";\nimport { SkeletonLine } from \"../../components/loader/skeleton-line\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant } from \"../../utils/resolve-variant\";\n\n/** Breadcrumbs size variant definitions. */\nexport const KUMO_BREADCRUMBS_VARIANTS = {\n size: {\n sm: {\n classes: \"text-sm h-10 gap-0.5\",\n description: \"Compact breadcrumbs for dense UIs\",\n },\n base: {\n classes: \"text-base h-12 gap-1\",\n description: \"Default breadcrumbs size\",\n },\n },\n} as const;\n\nexport const KUMO_BREADCRUMBS_DEFAULT_VARIANTS = {\n size: \"base\",\n} as const;\n\nexport type KumoBreadcrumbsSize = keyof typeof KUMO_BREADCRUMBS_VARIANTS.size;\n\nexport interface KumoBreadcrumbsVariantsProps {\n /**\n * Size of the breadcrumbs.\n * - `\"sm\"` — Compact breadcrumbs for dense UIs\n * - `\"base\"` — Default breadcrumbs size\n * @default \"base\"\n */\n size?: KumoBreadcrumbsSize;\n}\n\nexport function breadcrumbsVariants({\n size = KUMO_BREADCRUMBS_DEFAULT_VARIANTS.size,\n}: KumoBreadcrumbsVariantsProps = {}) {\n return cn(\n \"group mr-4 flex min-w-0 grow items-center overflow-hidden whitespace-nowrap\",\n resolveVariant(KUMO_BREADCRUMBS_VARIANTS.size, size, KUMO_BREADCRUMBS_DEFAULT_VARIANTS.size).classes,\n );\n}\n\nexport interface BreadcrumbsItemProps {\n href: string;\n icon?: React.ReactNode;\n}\n\nconst Link = ({\n href,\n icon,\n children,\n}: PropsWithChildren<BreadcrumbsItemProps>) => {\n const LinkComponent = useLinkComponent();\n\n return (\n <LinkComponent\n data-kumo-component=\"Breadcrumbs\"\n data-kumo-part=\"link\"\n to={href}\n className=\"flex min-w-0 max-w-full items-center gap-1 text-kumo-subtle no-underline\"\n >\n {!!icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n <span className=\"truncate\">{children}</span>\n </LinkComponent>\n );\n};\n\ninterface BreadcrumbsCurrentProps {\n loading?: boolean;\n icon?: React.ReactNode;\n}\n\nfunction Current({\n children,\n icon,\n loading,\n}: PropsWithChildren<BreadcrumbsCurrentProps>) {\n if (loading) {\n return (\n <div className=\"flex w-[125px] min-w-0 items-center gap-1\">\n {icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n <SkeletonLine />\n </div>\n );\n }\n\n return (\n <div\n className=\"flex min-w-0 max-w-full items-center gap-1 font-medium\"\n aria-current=\"page\"\n >\n {icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n <span className=\"truncate\">{children}</span>\n </div>\n );\n}\n\nfunction Separator() {\n return (\n <span\n className=\"flex shrink-0 items-center text-kumo-inactive\"\n aria-hidden=\"true\"\n >\n <svg width=\"24\" height=\"24\" fill=\"none\" viewBox=\"0 0 24 24\">\n <path\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"1.5\"\n d=\"M10.75 8.75L14.25 12L10.75 15.25\"\n />\n </svg>\n </span>\n );\n}\n\nfunction MobileEllipsis() {\n return (\n <span className=\"flex shrink-0 items-center text-kumo-subtle\" aria-hidden>\n ...\n </span>\n );\n}\n\nfunction Clipboard({ text }: { text: string }) {\n const [isCopied, setIsCopied] = useState(false);\n\n useEffect(() => {\n if (!isCopied) return;\n\n const timeoutId = setTimeout(() => setIsCopied(false), 2000);\n return () => clearTimeout(timeoutId);\n }, [isCopied]);\n\n const handleCopyDeeplink = async () => {\n if (!text) return;\n\n try {\n await navigator.clipboard.writeText(text);\n setIsCopied(true);\n } catch (err) {\n console.error(\"Failed to copy deeplink:\", err);\n }\n };\n\n return (\n <Button\n variant=\"ghost\"\n shape=\"square\"\n size=\"sm\"\n className=\"opacity-0 transition-[opacity] group-hover:opacity-100\"\n onClick={handleCopyDeeplink}\n title=\"Click to copy\"\n aria-label=\"Copy\"\n >\n {isCopied ? (\n <CheckIcon weight=\"bold\" className=\"text-kumo-success\" />\n ) : (\n <CopyIcon weight=\"regular\" />\n )}\n </Button>\n );\n}\n\n/**\n * Breadcrumbs component props.\n *\n * @example\n * ```tsx\n * <Breadcrumbs>\n * <Breadcrumbs.Link href=\"/\">Home</Breadcrumbs.Link>\n * <Breadcrumbs.Separator />\n * <Breadcrumbs.Link href=\"/docs\">Docs</Breadcrumbs.Link>\n * <Breadcrumbs.Separator />\n * <Breadcrumbs.Current>Current Page</Breadcrumbs.Current>\n * </Breadcrumbs>\n * ```\n */\nexport interface BreadcrumbsProps\n extends PropsWithChildren,\n KumoBreadcrumbsVariantsProps {\n /** Additional CSS classes merged via `cn()`. */\n className?: string;\n}\n\n/**\n * Navigation breadcrumb trail showing the current page's location in a hierarchy.\n * Compound component with `Breadcrumbs.Link`, `Breadcrumbs.Current`, `Breadcrumbs.Separator`, and `Breadcrumbs.Clipboard`.\n *\n * @example\n * ```tsx\n * <Breadcrumbs>\n * <Breadcrumbs.Link href=\"/\">Home</Breadcrumbs.Link>\n * <Breadcrumbs.Separator />\n * <Breadcrumbs.Current>Dashboard</Breadcrumbs.Current>\n * </Breadcrumbs>\n * ```\n */\nexport function Breadcrumb({\n children,\n size = \"base\",\n className,\n}: BreadcrumbsProps) {\n const childArray = Children.toArray(children);\n const mobileChildren = getMobileBreadcrumbChildren(childArray);\n\n return (\n <nav\n className={cn(breadcrumbsVariants({ size }), className)}\n aria-label=\"breadcrumb\"\n >\n <div className=\"contents sm:hidden\">{mobileChildren}</div>\n <div className=\"hidden sm:contents\">{childArray}</div>\n </nav>\n );\n}\n\nfunction isComponentElement(\n child: ReactNode,\n component: unknown,\n): child is ReactElement {\n return isValidElement(child) && child.type === component;\n}\n\nfunction getMobileBreadcrumbChildren(children: ReactNode[]): ReactNode[] {\n const breadcrumbItems = children.filter(\n (child) =>\n isComponentElement(child, Link) || isComponentElement(child, Current),\n ) as ReactElement[];\n\n if (breadcrumbItems.length <= 2) {\n return children;\n }\n\n const [parentItem, currentItem] = breadcrumbItems.slice(-2);\n const trailingItems: ReactNode[] = [\n <MobileEllipsis key=\"kumo-breadcrumb-mobile-ellipsis\" />,\n <Separator key=\"kumo-breadcrumb-mobile-separator-leading\" />,\n cloneElement(parentItem, { key: \"kumo-breadcrumb-mobile-parent\" }),\n <Separator key=\"kumo-breadcrumb-mobile-separator-trailing\" />,\n cloneElement(currentItem, { key: \"kumo-breadcrumb-mobile-current\" }),\n ];\n\n const extras = children.filter(\n (child) =>\n !isComponentElement(child, Link) &&\n !isComponentElement(child, Current) &&\n !isComponentElement(child, Separator),\n );\n\n return [...trailingItems, ...extras];\n}\n\nBreadcrumb.Link = Link;\nBreadcrumb.Current = Current;\nBreadcrumb.Separator = Separator;\nBreadcrumb.Clipboard = Clipboard;\n"],"names":["KUMO_BREADCRUMBS_VARIANTS","KUMO_BREADCRUMBS_DEFAULT_VARIANTS","breadcrumbsVariants","size","cn","resolveVariant","Link","href","icon","children","LinkComponent","useLinkComponent","jsxs","jsx","Current","loading","SkeletonLine","Separator","MobileEllipsis","Clipboard","text","isCopied","setIsCopied","useState","useEffect","timeoutId","Button","err","CheckIcon","CopyIcon","Breadcrumb","className","childArray","Children","mobileChildren","getMobileBreadcrumbChildren","isComponentElement","child","component","isValidElement","breadcrumbItems","parentItem","currentItem","trailingItems","cloneElement","extras"],"mappings":"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"}
1
+ {"version":3,"file":"breadcrumbs-lyj8ljudrm2owx5y.js","sources":["../../src/components/breadcrumbs/breadcrumbs.tsx"],"sourcesContent":["import {\n Children,\n cloneElement,\n isValidElement,\n useEffect,\n useState,\n type PropsWithChildren,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { CheckIcon, CopyIcon } from \"@phosphor-icons/react\";\nimport { Button } from \"../../components/button\";\nimport { SkeletonLine } from \"../../components/loader/skeleton-line\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant } from \"../../utils/resolve-variant\";\n\n/** Breadcrumbs size variant definitions. */\nexport const KUMO_BREADCRUMBS_VARIANTS = {\n size: {\n sm: {\n classes: \"text-sm h-10 gap-0.5\",\n description: \"Compact breadcrumbs for dense UIs\",\n },\n base: {\n classes: \"text-base h-12 gap-1\",\n description: \"Default breadcrumbs size\",\n },\n },\n} as const;\n\nexport const KUMO_BREADCRUMBS_DEFAULT_VARIANTS = {\n size: \"base\",\n} as const;\n\nexport type KumoBreadcrumbsSize = keyof typeof KUMO_BREADCRUMBS_VARIANTS.size;\n\nexport interface KumoBreadcrumbsVariantsProps {\n /**\n * Size of the breadcrumbs.\n * - `\"sm\"` — Compact breadcrumbs for dense UIs\n * - `\"base\"` — Default breadcrumbs size\n * @default \"base\"\n */\n size?: KumoBreadcrumbsSize;\n}\n\nexport function breadcrumbsVariants({\n size = KUMO_BREADCRUMBS_DEFAULT_VARIANTS.size,\n}: KumoBreadcrumbsVariantsProps = {}) {\n return cn(\n \"group mr-4 flex min-w-0 grow items-center overflow-hidden whitespace-nowrap\",\n resolveVariant(KUMO_BREADCRUMBS_VARIANTS.size, size, KUMO_BREADCRUMBS_DEFAULT_VARIANTS.size).classes,\n );\n}\n\nexport interface BreadcrumbsItemProps {\n href: string;\n icon?: React.ReactNode;\n}\n\nconst Link = ({\n href,\n icon,\n children,\n}: PropsWithChildren<BreadcrumbsItemProps>) => {\n const LinkComponent = useLinkComponent();\n\n return (\n <LinkComponent\n data-kumo-component=\"Breadcrumbs\"\n data-kumo-part=\"link\"\n to={href}\n className=\"flex min-w-0 max-w-full items-center gap-1 text-kumo-subtle no-underline\"\n >\n {!!icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n <span className=\"truncate\">{children}</span>\n </LinkComponent>\n );\n};\n\ninterface BreadcrumbsCurrentProps {\n loading?: boolean;\n icon?: React.ReactNode;\n}\n\nfunction Current({\n children,\n icon,\n loading,\n}: PropsWithChildren<BreadcrumbsCurrentProps>) {\n if (loading) {\n return (\n <div className=\"flex w-[125px] min-w-0 items-center gap-1\">\n {icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n <SkeletonLine />\n </div>\n );\n }\n\n return (\n <div\n className=\"flex min-w-0 max-w-full items-center gap-1 font-medium\"\n aria-current=\"page\"\n >\n {icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n <span className=\"truncate\">{children}</span>\n </div>\n );\n}\n\nfunction Separator() {\n return (\n <span\n className=\"flex shrink-0 items-center text-kumo-inactive\"\n aria-hidden=\"true\"\n >\n <svg width=\"24\" height=\"24\" fill=\"none\" viewBox=\"0 0 24 24\">\n <path\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"1.5\"\n d=\"M10.75 8.75L14.25 12L10.75 15.25\"\n />\n </svg>\n </span>\n );\n}\n\nfunction MobileEllipsis() {\n return (\n <span className=\"flex shrink-0 items-center text-kumo-subtle\" aria-hidden>\n ...\n </span>\n );\n}\n\nfunction Clipboard({ text }: { text: string }) {\n const [isCopied, setIsCopied] = useState(false);\n\n useEffect(() => {\n if (!isCopied) return;\n\n const timeoutId = setTimeout(() => setIsCopied(false), 2000);\n return () => clearTimeout(timeoutId);\n }, [isCopied]);\n\n const handleCopyDeeplink = async () => {\n if (!text) return;\n\n try {\n await navigator.clipboard.writeText(text);\n setIsCopied(true);\n } catch (err) {\n console.error(\"Failed to copy deeplink:\", err);\n }\n };\n\n return (\n <Button\n variant=\"ghost\"\n shape=\"square\"\n size=\"sm\"\n className=\"opacity-0 transition-[opacity] group-hover:opacity-100\"\n onClick={handleCopyDeeplink}\n title=\"Click to copy\"\n aria-label=\"Copy\"\n >\n {isCopied ? (\n <CheckIcon weight=\"bold\" className=\"text-kumo-success\" />\n ) : (\n <CopyIcon weight=\"regular\" />\n )}\n </Button>\n );\n}\n\n/**\n * Breadcrumbs component props.\n *\n * @example\n * ```tsx\n * <Breadcrumbs>\n * <Breadcrumbs.Link href=\"/\">Home</Breadcrumbs.Link>\n * <Breadcrumbs.Separator />\n * <Breadcrumbs.Link href=\"/docs\">Docs</Breadcrumbs.Link>\n * <Breadcrumbs.Separator />\n * <Breadcrumbs.Current>Current Page</Breadcrumbs.Current>\n * </Breadcrumbs>\n * ```\n */\nexport interface BreadcrumbsProps\n extends PropsWithChildren,\n KumoBreadcrumbsVariantsProps {\n /** Additional CSS classes merged via `cn()`. */\n className?: string;\n}\n\n/**\n * Navigation breadcrumb trail showing the current page's location in a hierarchy.\n * Compound component with `Breadcrumbs.Link`, `Breadcrumbs.Current`, `Breadcrumbs.Separator`, and `Breadcrumbs.Clipboard`.\n *\n * @example\n * ```tsx\n * <Breadcrumbs>\n * <Breadcrumbs.Link href=\"/\">Home</Breadcrumbs.Link>\n * <Breadcrumbs.Separator />\n * <Breadcrumbs.Current>Dashboard</Breadcrumbs.Current>\n * </Breadcrumbs>\n * ```\n */\nexport function Breadcrumb({\n children,\n size = \"base\",\n className,\n}: BreadcrumbsProps) {\n const childArray = Children.toArray(children);\n const mobileChildren = getMobileBreadcrumbChildren(childArray);\n\n return (\n <nav\n className={cn(breadcrumbsVariants({ size }), className)}\n aria-label=\"breadcrumb\"\n >\n <div className=\"contents sm:hidden\">{mobileChildren}</div>\n <div className=\"hidden sm:contents\">{childArray}</div>\n </nav>\n );\n}\n\nfunction isComponentElement(\n child: ReactNode,\n component: unknown,\n): child is ReactElement {\n return isValidElement(child) && child.type === component;\n}\n\nfunction getMobileBreadcrumbChildren(children: ReactNode[]): ReactNode[] {\n const breadcrumbItems = children.filter(\n (child) =>\n isComponentElement(child, Link) || isComponentElement(child, Current),\n ) as ReactElement[];\n\n if (breadcrumbItems.length <= 2) {\n return children;\n }\n\n const [parentItem, currentItem] = breadcrumbItems.slice(-2);\n const trailingItems: ReactNode[] = [\n <MobileEllipsis key=\"kumo-breadcrumb-mobile-ellipsis\" />,\n <Separator key=\"kumo-breadcrumb-mobile-separator-leading\" />,\n cloneElement(parentItem, { key: \"kumo-breadcrumb-mobile-parent\" }),\n <Separator key=\"kumo-breadcrumb-mobile-separator-trailing\" />,\n cloneElement(currentItem, { key: \"kumo-breadcrumb-mobile-current\" }),\n ];\n\n const extras = children.filter(\n (child) =>\n !isComponentElement(child, Link) &&\n !isComponentElement(child, Current) &&\n !isComponentElement(child, Separator),\n );\n\n return [...trailingItems, ...extras];\n}\n\nBreadcrumb.Link = Link;\nBreadcrumb.Current = Current;\nBreadcrumb.Separator = Separator;\nBreadcrumb.Clipboard = Clipboard;\n"],"names":["KUMO_BREADCRUMBS_VARIANTS","KUMO_BREADCRUMBS_DEFAULT_VARIANTS","breadcrumbsVariants","size","cn","resolveVariant","Link","href","icon","children","LinkComponent","useLinkComponent","jsxs","jsx","Current","loading","SkeletonLine","Separator","MobileEllipsis","Clipboard","text","isCopied","setIsCopied","useState","useEffect","timeoutId","Button","err","CheckIcon","CopyIcon","Breadcrumb","className","childArray","Children","mobileChildren","getMobileBreadcrumbChildren","isComponentElement","child","component","isValidElement","breadcrumbItems","parentItem","currentItem","trailingItems","cloneElement","extras"],"mappings":"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"}