@epilot/spark-ui 0.20.1 → 0.20.2

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 (270) hide show
  1. package/dist/components/accordion.cjs +5 -5
  2. package/dist/components/accordion.cjs.map +1 -1
  3. package/dist/components/alert-dialog.cjs +9 -9
  4. package/dist/components/alert-dialog.cjs.map +1 -1
  5. package/dist/components/attachment.cjs +10 -10
  6. package/dist/components/attachment.cjs.map +1 -1
  7. package/dist/components/attachment.d.cts +2 -2
  8. package/dist/components/attachment.d.ts +2 -2
  9. package/dist/components/autocomplete.cjs +12 -12
  10. package/dist/components/autocomplete.cjs.map +1 -1
  11. package/dist/components/avatar.cjs +2 -2
  12. package/dist/components/avatar.cjs.map +1 -1
  13. package/dist/components/avatar.js +1 -1
  14. package/dist/components/badge.cjs +2 -2
  15. package/dist/components/badge.cjs.map +1 -1
  16. package/dist/components/badge.js +2 -2
  17. package/dist/components/badge.js.map +1 -1
  18. package/dist/components/bar-chart.cjs +3 -3
  19. package/dist/components/bar-chart.cjs.map +1 -1
  20. package/dist/components/bar-chart.js.map +1 -1
  21. package/dist/components/box.cjs +2 -2
  22. package/dist/components/box.cjs.map +1 -1
  23. package/dist/components/box.js +1 -1
  24. package/dist/components/breadcrumbs.cjs +7 -7
  25. package/dist/components/breadcrumbs.cjs.map +1 -1
  26. package/dist/components/bubble.cjs +5 -5
  27. package/dist/components/bubble.cjs.map +1 -1
  28. package/dist/components/bubble.d.cts +1 -1
  29. package/dist/components/bubble.d.ts +1 -1
  30. package/dist/components/button-group.cjs +5 -5
  31. package/dist/components/button-group.cjs.map +1 -1
  32. package/dist/components/button-group.js +1 -1
  33. package/dist/components/button.cjs +2 -2
  34. package/dist/components/button.cjs.map +1 -1
  35. package/dist/components/button.d.cts +3 -3
  36. package/dist/components/button.d.ts +3 -3
  37. package/dist/components/button.js +1 -1
  38. package/dist/components/button.js.map +1 -1
  39. package/dist/components/calendar.cjs +11 -10
  40. package/dist/components/calendar.cjs.map +1 -1
  41. package/dist/components/calendar.js +4 -3
  42. package/dist/components/calendar.js.map +1 -1
  43. package/dist/components/callout.cjs +7 -7
  44. package/dist/components/callout.cjs.map +1 -1
  45. package/dist/components/callout.d.cts +1 -1
  46. package/dist/components/callout.d.ts +1 -1
  47. package/dist/components/card.cjs +16 -16
  48. package/dist/components/card.cjs.map +1 -1
  49. package/dist/components/card.js +2 -2
  50. package/dist/components/card.js.map +1 -1
  51. package/dist/components/chart.cjs +2 -2
  52. package/dist/components/chart.cjs.map +1 -1
  53. package/dist/components/checkbox.cjs +2 -2
  54. package/dist/components/checkbox.cjs.map +1 -1
  55. package/dist/components/checkbox.js +1 -1
  56. package/dist/components/checkbox.js.map +1 -1
  57. package/dist/components/circular-gauge.cjs +3 -3
  58. package/dist/components/circular-gauge.cjs.map +1 -1
  59. package/dist/components/circular-gauge.js +1 -1
  60. package/dist/components/circular-gauge.js.map +1 -1
  61. package/dist/components/day-of-week-picker.cjs +4 -4
  62. package/dist/components/day-of-week-picker.cjs.map +1 -1
  63. package/dist/components/dialog.cjs +8 -8
  64. package/dist/components/dialog.cjs.map +1 -1
  65. package/dist/components/donut-chart.cjs.map +1 -1
  66. package/dist/components/donut-chart.js.map +1 -1
  67. package/dist/components/drawer.cjs +8 -8
  68. package/dist/components/drawer.cjs.map +1 -1
  69. package/dist/components/drawer.js +2 -2
  70. package/dist/components/drawer.js.map +1 -1
  71. package/dist/components/dropdown-menu.cjs +10 -10
  72. package/dist/components/dropdown-menu.cjs.map +1 -1
  73. package/dist/components/energy-breakdown.cjs +1 -1
  74. package/dist/components/energy-breakdown.cjs.map +1 -1
  75. package/dist/components/energy-breakdown.js +1 -1
  76. package/dist/components/energy-breakdown.js.map +1 -1
  77. package/dist/components/entity-card.cjs +11 -11
  78. package/dist/components/entity-card.cjs.map +1 -1
  79. package/dist/components/field.cjs +16 -16
  80. package/dist/components/field.cjs.map +1 -1
  81. package/dist/components/field.js +1 -1
  82. package/dist/components/field.js.map +1 -1
  83. package/dist/components/hero-metric.cjs +4 -4
  84. package/dist/components/hero-metric.cjs.map +1 -1
  85. package/dist/components/icon.cjs +6 -6
  86. package/dist/components/icon.cjs.map +1 -1
  87. package/dist/components/icon.js +5 -5
  88. package/dist/components/icon.js.map +1 -1
  89. package/dist/components/info-block.cjs +9 -9
  90. package/dist/components/info-block.cjs.map +1 -1
  91. package/dist/components/info-block.d.cts +1 -1
  92. package/dist/components/info-block.d.ts +1 -1
  93. package/dist/components/input-date.cjs +4 -3
  94. package/dist/components/input-date.cjs.map +1 -1
  95. package/dist/components/input-date.d.cts +3 -1
  96. package/dist/components/input-date.d.ts +3 -1
  97. package/dist/components/input-date.js +2 -1
  98. package/dist/components/input-date.js.map +1 -1
  99. package/dist/components/input-group.cjs +5 -5
  100. package/dist/components/input-group.cjs.map +1 -1
  101. package/dist/components/input-group.d.cts +1 -1
  102. package/dist/components/input-group.d.ts +1 -1
  103. package/dist/components/input-otp.cjs +3 -3
  104. package/dist/components/input-otp.cjs.map +1 -1
  105. package/dist/components/input-otp.js +1 -1
  106. package/dist/components/input.cjs +3 -3
  107. package/dist/components/input.cjs.map +1 -1
  108. package/dist/components/input.js +1 -1
  109. package/dist/components/label.cjs +2 -2
  110. package/dist/components/label.cjs.map +1 -1
  111. package/dist/components/layout.cjs +2 -2
  112. package/dist/components/layout.cjs.map +1 -1
  113. package/dist/components/line-chart.cjs +6 -6
  114. package/dist/components/line-chart.cjs.map +1 -1
  115. package/dist/components/line-chart.js +3 -3
  116. package/dist/components/line-chart.js.map +1 -1
  117. package/dist/components/list.cjs +11 -11
  118. package/dist/components/list.cjs.map +1 -1
  119. package/dist/components/list.d.cts +7 -2
  120. package/dist/components/list.d.ts +7 -2
  121. package/dist/components/list.js +2 -2
  122. package/dist/components/list.js.map +1 -1
  123. package/dist/components/marker.cjs +4 -4
  124. package/dist/components/marker.cjs.map +1 -1
  125. package/dist/components/marker.d.cts +1 -1
  126. package/dist/components/marker.d.ts +1 -1
  127. package/dist/components/message-scroller.cjs +7 -7
  128. package/dist/components/message-scroller.cjs.map +1 -1
  129. package/dist/components/message-scroller.js +2 -2
  130. package/dist/components/message-scroller.js.map +1 -1
  131. package/dist/components/message.cjs +7 -7
  132. package/dist/components/message.cjs.map +1 -1
  133. package/dist/components/page-header.cjs +5 -5
  134. package/dist/components/page-header.cjs.map +1 -1
  135. package/dist/components/period-tabs.cjs +6 -6
  136. package/dist/components/period-tabs.cjs.map +1 -1
  137. package/dist/components/pill.cjs +3 -3
  138. package/dist/components/pill.cjs.map +1 -1
  139. package/dist/components/pill.js +3 -3
  140. package/dist/components/pill.js.map +1 -1
  141. package/dist/components/popover.cjs +2 -2
  142. package/dist/components/popover.cjs.map +1 -1
  143. package/dist/components/power-history-chart.cjs +3 -3
  144. package/dist/components/power-history-chart.cjs.map +1 -1
  145. package/dist/components/power-history-chart.js +1 -1
  146. package/dist/components/power-history-chart.js.map +1 -1
  147. package/dist/components/power-network.cjs +9 -9
  148. package/dist/components/power-network.cjs.map +1 -1
  149. package/dist/components/progress.cjs +3 -3
  150. package/dist/components/progress.cjs.map +1 -1
  151. package/dist/components/progress.js +1 -1
  152. package/dist/components/progress.js.map +1 -1
  153. package/dist/components/radio-card-group.cjs +3 -3
  154. package/dist/components/radio-card-group.cjs.map +1 -1
  155. package/dist/components/radio.cjs +3 -3
  156. package/dist/components/radio.cjs.map +1 -1
  157. package/dist/components/radio.js +1 -1
  158. package/dist/components/sankey-chart.cjs +4 -4
  159. package/dist/components/sankey-chart.cjs.map +1 -1
  160. package/dist/components/sankey-chart.js +2 -2
  161. package/dist/components/sankey-chart.js.map +1 -1
  162. package/dist/components/schedule-editor.cjs +9 -9
  163. package/dist/components/schedule-editor.cjs.map +1 -1
  164. package/dist/components/schedule-list.cjs +10 -10
  165. package/dist/components/schedule-list.cjs.map +1 -1
  166. package/dist/components/scroll-area.cjs +3 -3
  167. package/dist/components/scroll-area.cjs.map +1 -1
  168. package/dist/components/segmented-control.cjs +8 -8
  169. package/dist/components/segmented-control.cjs.map +1 -1
  170. package/dist/components/segmented-control.d.cts +2 -16
  171. package/dist/components/segmented-control.d.ts +2 -16
  172. package/dist/components/segmented-control.js +5 -5
  173. package/dist/components/segmented-control.js.map +1 -1
  174. package/dist/components/select.cjs +12 -12
  175. package/dist/components/select.cjs.map +1 -1
  176. package/dist/components/select.js +1 -1
  177. package/dist/components/separator.cjs +3 -3
  178. package/dist/components/separator.cjs.map +1 -1
  179. package/dist/components/series-legend.cjs +4 -4
  180. package/dist/components/series-legend.cjs.map +1 -1
  181. package/dist/components/sheet.cjs +8 -8
  182. package/dist/components/sheet.cjs.map +1 -1
  183. package/dist/components/skeleton.cjs +3 -3
  184. package/dist/components/skeleton.cjs.map +1 -1
  185. package/dist/components/slider.cjs +11 -11
  186. package/dist/components/slider.cjs.map +1 -1
  187. package/dist/components/slider.js.map +1 -1
  188. package/dist/components/solar-forecast-chart.cjs +2 -2
  189. package/dist/components/solar-forecast-chart.cjs.map +1 -1
  190. package/dist/components/sortable-list.cjs +3 -3
  191. package/dist/components/sortable-list.cjs.map +1 -1
  192. package/dist/components/spinner.cjs +2 -2
  193. package/dist/components/spinner.cjs.map +1 -1
  194. package/dist/components/stat-card.cjs +8 -8
  195. package/dist/components/stat-card.cjs.map +1 -1
  196. package/dist/components/stepper.cjs +2 -2
  197. package/dist/components/stepper.cjs.map +1 -1
  198. package/dist/components/switch.cjs +3 -3
  199. package/dist/components/switch.cjs.map +1 -1
  200. package/dist/components/switch.js +2 -2
  201. package/dist/components/switch.js.map +1 -1
  202. package/dist/components/table.cjs +8 -8
  203. package/dist/components/table.cjs.map +1 -1
  204. package/dist/components/tabs.cjs +9 -9
  205. package/dist/components/tabs.cjs.map +1 -1
  206. package/dist/components/tabs.d.cts +1 -8
  207. package/dist/components/tabs.d.ts +1 -8
  208. package/dist/components/tabs.js +2 -2
  209. package/dist/components/tabs.js.map +1 -1
  210. package/dist/components/textarea.cjs +3 -3
  211. package/dist/components/textarea.cjs.map +1 -1
  212. package/dist/components/textarea.js +1 -1
  213. package/dist/components/theme.cjs +2 -2
  214. package/dist/components/theme.cjs.map +1 -1
  215. package/dist/components/theme.js +1 -1
  216. package/dist/components/thumbnail.cjs +3 -3
  217. package/dist/components/thumbnail.cjs.map +1 -1
  218. package/dist/components/time-picker.cjs +3 -3
  219. package/dist/components/time-picker.cjs.map +1 -1
  220. package/dist/components/toast.cjs +39 -14
  221. package/dist/components/toast.cjs.map +1 -1
  222. package/dist/components/toast.d.cts +15 -2
  223. package/dist/components/toast.d.ts +15 -2
  224. package/dist/components/toast.js +32 -7
  225. package/dist/components/toast.js.map +1 -1
  226. package/dist/components/toggle-group.cjs +40 -0
  227. package/dist/components/toggle-group.cjs.map +1 -0
  228. package/dist/components/toggle-group.d.cts +28 -0
  229. package/dist/components/toggle-group.d.ts +28 -0
  230. package/dist/components/toggle-group.js +37 -0
  231. package/dist/components/toggle-group.js.map +1 -0
  232. package/dist/components/toggle.cjs +69 -0
  233. package/dist/components/toggle.cjs.map +1 -0
  234. package/dist/components/toggle.d.cts +23 -0
  235. package/dist/components/toggle.d.ts +23 -0
  236. package/dist/components/toggle.js +66 -0
  237. package/dist/components/toggle.js.map +1 -0
  238. package/dist/components/tooltip.cjs +3 -3
  239. package/dist/components/tooltip.cjs.map +1 -1
  240. package/dist/components/tooltip.js +1 -1
  241. package/dist/components/tooltip.js.map +1 -1
  242. package/dist/components/typography.cjs +6 -6
  243. package/dist/components/typography.cjs.map +1 -1
  244. package/dist/components/wizard-layout.cjs +8 -8
  245. package/dist/components/wizard-layout.cjs.map +1 -1
  246. package/dist/lib/generate-radix-colors.cjs +1 -1
  247. package/dist/lib/generate-radix-colors.cjs.map +1 -1
  248. package/dist/lib/generate-radix-colors.js +1 -1
  249. package/dist/lib/generate-radix-colors.js.map +1 -1
  250. package/dist/lib/input-box-variants.cjs +9 -9
  251. package/dist/lib/input-box-variants.cjs.map +1 -1
  252. package/dist/lib/toggle-group-context.cjs +12 -0
  253. package/dist/lib/toggle-group-context.cjs.map +1 -0
  254. package/dist/lib/toggle-group-context.d.cts +17 -0
  255. package/dist/lib/toggle-group-context.d.ts +17 -0
  256. package/dist/lib/toggle-group-context.js +9 -0
  257. package/dist/lib/toggle-group-context.js.map +1 -0
  258. package/dist/styles/spark-default.css +11 -0
  259. package/dist/styles/theme.css +15 -4
  260. package/dist/utils/cn.cjs +2 -2
  261. package/dist/utils/cn.d.cts +1 -1
  262. package/dist/utils/cn.d.ts +1 -1
  263. package/dist/utils/cn.js +1 -1
  264. package/dist/utils/format.cjs +1 -0
  265. package/dist/utils/format.cjs.map +1 -1
  266. package/dist/utils/format.d.cts +2 -1
  267. package/dist/utils/format.d.ts +2 -1
  268. package/dist/utils/format.js +1 -1
  269. package/dist/utils/format.js.map +1 -1
  270. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"radio.cjs","names":["RadioGroupPrimitive","accentByColor","RadioPrimitive"],"sources":["../../src/components/radio.tsx"],"sourcesContent":["import { Radio as RadioPrimitive } from '@base-ui/react/radio'\nimport { RadioGroup as RadioGroupPrimitive } from '@base-ui/react/radio-group'\nimport * as React from 'react'\nimport { accentByColor } from '../lib/accent-colors'\nimport type { SparkStyle } from '../lib/theme-types'\nimport { cn } from '../utils/cn'\n\nexport type SparkRadioColor = 'accent' | 'neutral' | 'danger'\n\ntype RadioGroupProps = Omit<\n React.ComponentProps<typeof RadioGroupPrimitive>,\n 'style'\n> & {\n styleVariant?: SparkStyle\n color?: SparkRadioColor\n /** How many `--spark-layout-gap` units apart each radio sits. */\n gap?: number\n // Base UI's own `style` also accepts a state-callback form; the gap-steps var below\n // needs a plain object to merge into, so narrow it to that here.\n style?: React.CSSProperties\n}\n\nfunction RadioGroup({\n className,\n styleVariant,\n color,\n gap = 3,\n style,\n ...props\n}: RadioGroupProps) {\n const hasLook = styleVariant !== undefined || color !== undefined\n const dataStyle = hasLook ? (styleVariant ?? 'solid') : undefined\n const dataAccentColor = color ? accentByColor[color] : undefined\n\n return (\n <RadioGroupPrimitive\n data-slot=\"radio-group\"\n data-style={dataStyle}\n data-accent-color={dataAccentColor}\n className={cn(\n 'grid gap-[calc(var(--spark-layout-gap)*var(--radio-group-gap-steps,3))]',\n className,\n )}\n style={\n { '--radio-group-gap-steps': gap, ...style } as React.CSSProperties\n }\n {...props}\n />\n )\n}\n\ntype RadioProps = React.ComponentProps<typeof RadioPrimitive.Root> & {\n styleVariant?: SparkStyle\n color?: SparkRadioColor\n}\n\nfunction Radio({\n className,\n styleVariant,\n color,\n render,\n nativeButton,\n ...props\n}: RadioProps) {\n const hasLook = styleVariant !== undefined || color !== undefined\n const dataStyle = hasLook ? (styleVariant ?? 'solid') : undefined\n const dataAccentColor = color ? accentByColor[color] : undefined\n\n return (\n <RadioPrimitive.Root\n data-slot=\"radio\"\n data-style={dataStyle}\n data-accent-color={dataAccentColor}\n // a native button owns the caller's `id`; on Base UI's default <span> the\n // `id` lands on the hidden input and the control gets a generated one\n nativeButton={nativeButton ?? render === undefined}\n render={render ?? <button />}\n className={cn(\n // p-0 defends the 24px box against the UA button padding when the\n // consumer's CSS has no Tailwind preflight\n 'peer touch-target relative my-2 inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-full border-2 p-0 transition-colors any-pointer-coarse:my-[calc((2.75rem-var(--spacing)*6)/2)]',\n // both overlays are reserved as layout, so neither can bleed into a scroller;\n // the coarse margin tracks --spacing so the 44px reserve holds at any [data-scaling]\n \"before:absolute before:top-1/2 before:left-1/2 before:size-10 before:-translate-x-1/2 before:-translate-y-1/2 before:content-['']\",\n 'focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',\n 'data-disabled:cursor-not-allowed data-disabled:opacity-50',\n 'border-(--spark-style-idle-border,var(--color-accent-ui)) bg-base-accent-soft data-unchecked:border-(length:--spark-style-border-width,2px)',\n 'data-checked:border-(--spark-radio-ring,var(--spark-9))',\n className,\n )}\n {...props}\n >\n <RadioPrimitive.Indicator\n data-slot=\"radio-indicator\"\n className=\"flex items-center justify-center\"\n >\n <span className=\"size-4 rounded-full bg-(--spark-radio-dot,var(--spark-9)) motion-safe:animate-dot-pop\" />\n </RadioPrimitive.Indicator>\n </RadioPrimitive.Root>\n )\n}\n\nexport { Radio, RadioGroup }\nexport type { RadioGroupProps, RadioProps }\n"],"mappings":";;;;;;;;;;;AAsBA,SAAS,WAAW,EAClB,WACA,cACA,OACA,MAAM,GACN,OACA,GAAG,SACe;CAKlB,OACE,iBAAA,GAAA,kBAAA,KAACA,2BAAAA,YAAD;EACE,aAAU;EACV,cAPY,iBAAiB,KAAA,KAAa,UAAU,KAAA,IAC3B,gBAAgB,UAAW,KAAA;EAOpD,qBANoB,QAAQC,0BAAAA,cAAc,SAAS,KAAA;EAOnD,YAAA,GAAA,OAAA,IACE,2EACA,SACF;EACA,OACE;GAAE,2BAA2B;GAAK,GAAG;EAAM;EAE7C,GAAI;CACL,CAAA;AAEL;AAOA,SAAS,MAAM,EACb,WACA,cACA,OACA,QACA,cACA,GAAG,SACU;CAEb,MAAM,YADU,iBAAiB,KAAA,KAAa,UAAU,KAAA,IAC3B,gBAAgB,UAAW,KAAA;CACxD,MAAM,kBAAkB,QAAQA,0BAAAA,cAAc,SAAS,KAAA;CAEvD,OACE,iBAAA,GAAA,kBAAA,KAACC,qBAAAA,MAAe,MAAhB;EACE,aAAU;EACV,cAAY;EACZ,qBAAmB;EAGnB,cAAc,gBAAgB,WAAW,KAAA;EACzC,QAAQ,UAAU,iBAAA,GAAA,kBAAA,KAAC,UAAD,CAAS,CAAA;EAC3B,YAAA,GAAA,OAAA,IAGE,iNAGA,qIACA,iFACA,6DACA,+IACA,2DACA,SACF;EACA,GAAI;YAEJ,iBAAA,GAAA,kBAAA,KAACA,qBAAAA,MAAe,WAAhB;GACE,aAAU;GACV,WAAU;aAEV,iBAAA,GAAA,kBAAA,KAAC,QAAD,EAAM,WAAU,wFAAyF,CAAA;EACjF,CAAA;CACP,CAAA;AAEzB"}
1
+ {"version":3,"file":"radio.cjs","names":["RadioGroupPrimitive","accentByColor","RadioPrimitive"],"sources":["../../src/components/radio.tsx"],"sourcesContent":["import { Radio as RadioPrimitive } from '@base-ui/react/radio'\nimport { RadioGroup as RadioGroupPrimitive } from '@base-ui/react/radio-group'\nimport * as React from 'react'\nimport { accentByColor } from '../lib/accent-colors'\nimport type { SparkStyle } from '../lib/theme-types'\nimport { cn } from '../utils/cn'\n\nexport type SparkRadioColor = 'accent' | 'neutral' | 'danger'\n\ntype RadioGroupProps = Omit<\n React.ComponentProps<typeof RadioGroupPrimitive>,\n 'style'\n> & {\n styleVariant?: SparkStyle\n color?: SparkRadioColor\n /** How many `--spark-layout-gap` units apart each radio sits. */\n gap?: number\n // Base UI's own `style` also accepts a state-callback form; the gap-steps var below\n // needs a plain object to merge into, so narrow it to that here.\n style?: React.CSSProperties\n}\n\nfunction RadioGroup({\n className,\n styleVariant,\n color,\n gap = 3,\n style,\n ...props\n}: RadioGroupProps) {\n const hasLook = styleVariant !== undefined || color !== undefined\n const dataStyle = hasLook ? (styleVariant ?? 'solid') : undefined\n const dataAccentColor = color ? accentByColor[color] : undefined\n\n return (\n <RadioGroupPrimitive\n data-slot=\"radio-group\"\n data-style={dataStyle}\n data-accent-color={dataAccentColor}\n className={cn(\n 'grid gap-[calc(var(--spark-layout-gap)*var(--radio-group-gap-steps,3))]',\n className,\n )}\n style={\n { '--radio-group-gap-steps': gap, ...style } as React.CSSProperties\n }\n {...props}\n />\n )\n}\n\ntype RadioProps = React.ComponentProps<typeof RadioPrimitive.Root> & {\n styleVariant?: SparkStyle\n color?: SparkRadioColor\n}\n\nfunction Radio({\n className,\n styleVariant,\n color,\n render,\n nativeButton,\n ...props\n}: RadioProps) {\n const hasLook = styleVariant !== undefined || color !== undefined\n const dataStyle = hasLook ? (styleVariant ?? 'solid') : undefined\n const dataAccentColor = color ? accentByColor[color] : undefined\n\n return (\n <RadioPrimitive.Root\n data-slot=\"radio\"\n data-style={dataStyle}\n data-accent-color={dataAccentColor}\n // a native button owns the caller's `id`; on Base UI's default <span> the\n // `id` lands on the hidden input and the control gets a generated one\n nativeButton={nativeButton ?? render === undefined}\n render={render ?? <button />}\n className={cn(\n // p-0 defends the 24px box against the UA button padding when the\n // consumer's CSS has no Tailwind preflight\n 'peer touch-target relative my-2 inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-full border-2 p-0 transition-colors any-pointer-coarse:my-[calc((2.75rem-var(--spacing)*6)/2)]',\n // both overlays are reserved as layout, so neither can bleed into a scroller;\n // the coarse margin tracks --spacing so the 44px reserve holds at any [data-scaling]\n \"before:absolute before:top-1/2 before:left-1/2 before:size-10 before:-translate-x-1/2 before:-translate-y-1/2 before:content-['']\",\n 'focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',\n 'data-disabled:cursor-not-allowed data-disabled:opacity-50',\n 'border-(--spark-style-idle-border,var(--color-accent-ui)) bg-base-accent-soft data-unchecked:border-(length:--spark-style-border-width,2px)',\n 'data-checked:border-(--spark-radio-ring,var(--spark-9))',\n className,\n )}\n {...props}\n >\n <RadioPrimitive.Indicator\n data-slot=\"radio-indicator\"\n className=\"flex items-center justify-center\"\n >\n <span className=\"size-4 rounded-full bg-(--spark-radio-dot,var(--spark-9)) motion-safe:animate-dot-pop\" />\n </RadioPrimitive.Indicator>\n </RadioPrimitive.Root>\n )\n}\n\nexport { Radio, RadioGroup }\nexport type { RadioGroupProps, RadioProps }\n"],"mappings":";;;;;;;;;;;AAsBA,SAAS,WAAW,EAClB,WACA,cACA,OACA,MAAM,GACN,OACA,GAAG,SACe;CAKlB,OACE,iBAAA,GAAA,kBAAA,KAACA,2BAAAA,YAAD;EACE,aAAU;EACV,cAPY,iBAAiB,KAAA,KAAa,UAAU,KAAA,IAC3B,gBAAgB,UAAW,KAAA;EAOpD,qBANoB,QAAQC,0BAAAA,cAAc,SAAS,KAAA;EAOnD,YAAA,GAAA,GAAA,IACE,2EACA,SACF;EACA,OACE;GAAE,2BAA2B;GAAK,GAAG;EAAM;EAE7C,GAAI;CACL,CAAA;AAEL;AAOA,SAAS,MAAM,EACb,WACA,cACA,OACA,QACA,cACA,GAAG,SACU;CAEb,MAAM,YADU,iBAAiB,KAAA,KAAa,UAAU,KAAA,IAC3B,gBAAgB,UAAW,KAAA;CACxD,MAAM,kBAAkB,QAAQA,0BAAAA,cAAc,SAAS,KAAA;CAEvD,OACE,iBAAA,GAAA,kBAAA,KAACC,qBAAAA,MAAe,MAAhB;EACE,aAAU;EACV,cAAY;EACZ,qBAAmB;EAGnB,cAAc,gBAAgB,WAAW,KAAA;EACzC,QAAQ,UAAU,iBAAA,GAAA,kBAAA,KAAC,UAAD,CAAS,CAAA;EAC3B,YAAA,GAAA,GAAA,IAGE,iNAGA,qIACA,iFACA,6DACA,+IACA,2DACA,SACF;EACA,GAAI;YAEJ,iBAAA,GAAA,kBAAA,KAACA,qBAAAA,MAAe,WAAhB;GACE,aAAU;GACV,WAAU;aAEV,iBAAA,GAAA,kBAAA,KAAC,QAAD,EAAM,WAAU,wFAAyF,CAAA;EACjF,CAAA;CACP,CAAA;AAEzB"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { cn } from "../utils/cn.js";
3
2
  import { accentByColor } from "../lib/accent-colors.js";
3
+ import { cn } from "../utils/cn.js";
4
4
  import "react";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  import { Radio as Radio$1 } from "@base-ui/react/radio";
@@ -6,7 +6,7 @@ let react = require("react");
6
6
  let react_jsx_runtime = require("react/jsx-runtime");
7
7
  let _visx_group = require("@visx/group");
8
8
  let _visx_sankey = require("@visx/sankey");
9
- let cnfast = require("cnfast");
9
+ let cn = require("cn");
10
10
  //#region src/components/sankey-chart.tsx
11
11
  const SANKEY_CATEGORY_COLORS = {
12
12
  solar: "var(--orange-a9)",
@@ -83,7 +83,7 @@ function SankeyChart({ nodes, links, categoryColors = SANKEY_CATEGORY_COLORS, de
83
83
  const halfLabelStack = LABEL_STACK_HEIGHT / 2;
84
84
  const labelWidth = Math.max(40, labelPadding - LABEL_GAP - 4);
85
85
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
86
- className: (0, cnfast.cn)("flex w-full flex-col gap-2 py-2", className),
86
+ className: (0, cn.cn)("flex w-full flex-col gap-2 py-2", className),
87
87
  children: [title && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_typography.SectionTitle, { children: title }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
88
88
  ref: containerRef,
89
89
  className: "relative w-full",
@@ -119,7 +119,7 @@ function SankeyChart({ nodes, links, categoryColors = SANKEY_CATEGORY_COLORS, de
119
119
  })
120
120
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
121
121
  className: "visx-sankey-nodes",
122
- children: laidOut.nodes.map((node, index) => {
122
+ children: laidOut.nodes.map((node) => {
123
123
  if (node.x0 === void 0 || node.x1 === void 0 || node.y0 === void 0 || node.y1 === void 0) return null;
124
124
  const w = node.x1 - node.x0;
125
125
  const h = node.y1 - node.y0;
@@ -131,7 +131,7 @@ function SankeyChart({ nodes, links, categoryColors = SANKEY_CATEGORY_COLORS, de
131
131
  height: Math.max(1, h),
132
132
  fill,
133
133
  rx: 2
134
- }, `sankey-node-${index}`);
134
+ }, node.id);
135
135
  })
136
136
  })]
137
137
  })
@@ -1 +1 @@
1
- {"version":3,"file":"sankey-chart.cjs","names":["SectionTitle","Sankey","Group","NumberFlow"],"sources":["../../src/components/sankey-chart.tsx"],"sourcesContent":["import { Group } from '@visx/group'\nimport {\n Sankey,\n sankeyJustify,\n type SankeyLink,\n type SankeyNode,\n} from '@visx/sankey'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { cn } from '../utils/cn'\nimport NumberFlow, { type Format } from './number-flow'\nimport { SectionTitle } from './typography'\n\nconst SANKEY_CATEGORY_COLORS: Record<string, string> = {\n solar: 'var(--orange-a9)',\n battery: 'var(--green-a9)',\n grid: 'var(--blue-9)',\n gridFeedIn: 'var(--blue-7)',\n home: 'var(--spark-9)',\n floor: 'var(--neutral-a9)',\n device: 'var(--neutral-a8)',\n}\n\nexport interface SankeyChartNode {\n id: string\n label: string\n /** Optional category — used to colour the node and any outgoing links. */\n category?: string\n /** Override the colour resolved from `category`. */\n color?: string\n}\n\nexport interface SankeyChartLink {\n source: string\n target: string\n value: number\n /** Override the colour of the link. Defaults to the source node colour. */\n color?: string\n}\n\nexport interface SankeyChartProps {\n nodes: SankeyChartNode[]\n links: SankeyChartLink[]\n /** Resolves a category to a colour. */\n categoryColors?: Record<string, string>\n /** Fallback colour for nodes/links without a category. */\n defaultColor?: string\n /** Suffix appended to each animated value label (e.g. \" W\"). */\n valueSuffix?: string\n /** NumberFlow `format` for value labels. */\n valueFormat?: Format\n height?: number\n nodeWidth?: number\n nodePadding?: number\n /** Reserved horizontal space on the right for labels. */\n labelPadding?: number\n /**\n * Node ids kept at their natural (computed) column instead of being pushed to\n * the last column. By default `sankeyJustify` sends every node with no\n * outgoing link to the right edge; use this to hold a terminal node (e.g. grid\n * feed-in) in a middle column alongside its siblings.\n */\n keepAtDepthIds?: readonly string[]\n title?: string\n className?: string\n}\n\ntype SankeyDatumNode = SankeyChartNode & {\n /** Computed by d3-sankey; present after layout. */\n}\n\ntype SankeyDatumLink = SankeyChartLink\n\nconst DEFAULT_HEIGHT = 260\nconst DEFAULT_NODE_WIDTH = 12\nconst DEFAULT_NODE_PADDING = 10\nconst DEFAULT_LABEL_PADDING = 96\nconst LEFT_INSET = 4\nconst TOP_INSET = 8\nconst LABEL_GAP = 8\nconst LABEL_STACK_HEIGHT = 26\nconst DEFAULT_COLOR = 'var(--neutral-a9)'\n\nfunction resolveNodeColor(\n node: SankeyChartNode,\n categoryColors: Record<string, string> | undefined,\n defaultColor: string,\n) {\n if (node.color) return node.color\n if (node.category && categoryColors?.[node.category]) {\n return categoryColors[node.category] as string\n }\n return defaultColor\n}\n\nfunction SankeyChart({\n nodes,\n links,\n categoryColors = SANKEY_CATEGORY_COLORS,\n defaultColor = DEFAULT_COLOR,\n valueSuffix,\n valueFormat,\n height = DEFAULT_HEIGHT,\n nodeWidth = DEFAULT_NODE_WIDTH,\n nodePadding = DEFAULT_NODE_PADDING,\n labelPadding = DEFAULT_LABEL_PADDING,\n keepAtDepthIds,\n title,\n className,\n}: SankeyChartProps): React.ReactElement {\n const containerRef = useRef<HTMLDivElement>(null)\n const [width, setWidth] = useState(0)\n\n useEffect(() => {\n const element = containerRef.current\n if (!element) return\n\n const resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (!entry) return\n setWidth(entry.contentRect.width)\n })\n\n resizeObserver.observe(element)\n return () => resizeObserver.disconnect()\n }, [])\n\n const nodeIds = useMemo(() => new Set(nodes.map((node) => node.id)), [nodes])\n\n // Drop zero-value links and any whose endpoints aren't in the current node\n // set (a stale link referencing a removed node makes d3-sankey throw\n // `missing: <id>`).\n const visibleLinks = useMemo(\n () =>\n links.filter(\n (link) =>\n link.value > 0 &&\n nodeIds.has(link.source) &&\n nodeIds.has(link.target),\n ),\n [links, nodeIds],\n )\n\n const visibleNodes = useMemo(() => {\n const referencedIds = new Set<string>()\n for (const link of visibleLinks) {\n referencedIds.add(link.source)\n referencedIds.add(link.target)\n }\n return nodes.filter((node) => referencedIds.has(node.id))\n }, [nodes, visibleLinks])\n\n const colorById = useMemo(() => {\n const map = new Map<string, string>()\n for (const node of nodes) {\n map.set(node.id, resolveNodeColor(node, categoryColors, defaultColor))\n }\n return map\n }, [categoryColors, defaultColor, nodes])\n\n const orderById = useMemo(() => {\n const map = new Map<string, number>()\n visibleNodes.forEach((node, index) => map.set(node.id, index))\n return map\n }, [visibleNodes])\n\n const nodeSort = useMemo(\n () =>\n (\n a: SankeyNode<SankeyDatumNode, SankeyDatumLink>,\n b: SankeyNode<SankeyDatumNode, SankeyDatumLink>,\n ) =>\n (orderById.get(a.id) ?? 0) - (orderById.get(b.id) ?? 0),\n [orderById],\n )\n\n const graph = useMemo(\n () => ({\n nodes: visibleNodes.map((node) => ({ ...node })),\n links: visibleLinks.map((link) => ({ ...link })),\n }),\n [visibleNodes, visibleLinks],\n )\n\n const nodeAlign = useMemo(() => {\n const keep = new Set(keepAtDepthIds)\n return (node: SankeyNode<SankeyDatumNode, SankeyDatumLink>, n: number) =>\n keep.has(node.id) ? (node.depth ?? 0) : sankeyJustify(node, n)\n }, [keepAtDepthIds])\n\n const innerWidth = Math.max(0, width - labelPadding - LEFT_INSET)\n const innerHeight = Math.max(0, height - TOP_INSET * 2)\n const halfLabelStack = LABEL_STACK_HEIGHT / 2\n const labelWidth = Math.max(40, labelPadding - LABEL_GAP - 4)\n\n return (\n <div className={cn('flex w-full flex-col gap-2 py-2', className)}>\n {title && <SectionTitle>{title}</SectionTitle>}\n\n <div ref={containerRef} className=\"relative w-full\" style={{ height }}>\n {width > 0 && innerWidth > 0 && (\n <Sankey<SankeyDatumNode, SankeyDatumLink>\n root={graph}\n size={[innerWidth, innerHeight]}\n nodeWidth={nodeWidth}\n nodePadding={nodePadding}\n nodeAlign={nodeAlign}\n nodeId={(node) => node.id}\n nodeSort={nodeSort}\n >\n {({ graph: laidOut, createPath }) => (\n <>\n <svg\n aria-hidden=\"true\"\n className=\"block\"\n height={height}\n width={width}\n >\n <Group left={LEFT_INSET} top={TOP_INSET}>\n <Group className=\"visx-sankey-links\">\n {laidOut.links.map((link, index) => {\n const sourceId =\n typeof link.source === 'object'\n ? (\n link.source as SankeyNode<\n SankeyDatumNode,\n SankeyDatumLink\n >\n ).id\n : String(link.source)\n const stroke =\n link.color ?? colorById.get(sourceId) ?? defaultColor\n\n return (\n <path\n key={`sankey-link-${index}`}\n d={createPath(link) ?? ''}\n fill=\"none\"\n stroke={stroke}\n strokeOpacity={0.32}\n strokeWidth={Math.max(1, link.width ?? 0)}\n />\n )\n })}\n </Group>\n\n <Group className=\"visx-sankey-nodes\">\n {laidOut.nodes.map((node, index) => {\n if (\n node.x0 === undefined ||\n node.x1 === undefined ||\n node.y0 === undefined ||\n node.y1 === undefined\n ) {\n return null\n }\n\n const w = node.x1 - node.x0\n const h = node.y1 - node.y0\n const fill = colorById.get(node.id) ?? defaultColor\n\n return (\n <rect\n key={`sankey-node-${index}`}\n x={node.x0}\n y={node.y0}\n width={w}\n height={Math.max(1, h)}\n fill={fill}\n rx={2}\n />\n )\n })}\n </Group>\n </Group>\n </svg>\n\n <div className=\"pointer-events-none absolute inset-0 [-webkit-text-size-adjust:100%] [text-size-adjust:100%]\">\n {laidOut.nodes.map((node, index) => {\n if (\n node.x0 === undefined ||\n node.x1 === undefined ||\n node.y0 === undefined ||\n node.y1 === undefined\n ) {\n return null\n }\n\n const h = node.y1 - node.y0\n const nodeCenterY = TOP_INSET + node.y0 + h / 2\n const labelCenterY = Math.min(\n Math.max(nodeCenterY, halfLabelStack),\n height - halfLabelStack,\n )\n\n return (\n <div\n key={`sankey-label-${node.id ?? index}`}\n className=\"absolute flex -translate-y-1/2 flex-col items-start gap-1\"\n style={{\n left: LEFT_INSET + node.x1 + LABEL_GAP,\n top: labelCenterY,\n width: labelWidth,\n }}\n >\n <span className=\"text-[11px] leading-none font-semibold whitespace-nowrap text-gray\">\n {node.label}\n </span>\n <NumberFlow\n value={node.value ?? 0}\n {...(valueSuffix !== undefined && {\n suffix: valueSuffix,\n })}\n {...(valueFormat !== undefined && {\n format: valueFormat,\n })}\n className=\"block min-h-[10px] text-[10px] leading-none text-gray-light tabular-nums\"\n />\n </div>\n )\n })}\n </div>\n </>\n )}\n </Sankey>\n )}\n </div>\n </div>\n )\n}\n\nexport type { SankeyLink, SankeyNode }\nexport { SankeyChart, SANKEY_CATEGORY_COLORS }\n"],"mappings":"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"}
1
+ {"version":3,"file":"sankey-chart.cjs","names":["SectionTitle","Sankey","Group","NumberFlow"],"sources":["../../src/components/sankey-chart.tsx"],"sourcesContent":["import { Group } from '@visx/group'\nimport {\n Sankey,\n sankeyJustify,\n type SankeyLink,\n type SankeyNode,\n} from '@visx/sankey'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { cn } from '../utils/cn'\nimport NumberFlow, { type Format } from './number-flow'\nimport { SectionTitle } from './typography'\n\nconst SANKEY_CATEGORY_COLORS: Record<string, string> = {\n solar: 'var(--orange-a9)',\n battery: 'var(--green-a9)',\n grid: 'var(--blue-9)',\n gridFeedIn: 'var(--blue-7)',\n home: 'var(--spark-9)',\n floor: 'var(--neutral-a9)',\n device: 'var(--neutral-a8)',\n}\n\nexport interface SankeyChartNode {\n id: string\n label: string\n /** Optional category — used to colour the node and any outgoing links. */\n category?: string\n /** Override the colour resolved from `category`. */\n color?: string\n}\n\nexport interface SankeyChartLink {\n source: string\n target: string\n value: number\n /** Override the colour of the link. Defaults to the source node colour. */\n color?: string\n}\n\nexport interface SankeyChartProps {\n nodes: SankeyChartNode[]\n links: SankeyChartLink[]\n /** Resolves a category to a colour. */\n categoryColors?: Record<string, string>\n /** Fallback colour for nodes/links without a category. */\n defaultColor?: string\n /** Suffix appended to each animated value label (e.g. \" W\"). */\n valueSuffix?: string\n /** NumberFlow `format` for value labels. */\n valueFormat?: Format\n height?: number\n nodeWidth?: number\n nodePadding?: number\n /** Reserved horizontal space on the right for labels. */\n labelPadding?: number\n /**\n * Node ids kept at their natural (computed) column instead of being pushed to\n * the last column. By default `sankeyJustify` sends every node with no\n * outgoing link to the right edge; use this to hold a terminal node (e.g. grid\n * feed-in) in a middle column alongside its siblings.\n */\n keepAtDepthIds?: readonly string[]\n title?: string\n className?: string\n}\n\ntype SankeyDatumNode = SankeyChartNode & {\n /** Computed by d3-sankey; present after layout. */\n}\n\ntype SankeyDatumLink = SankeyChartLink\n\nconst DEFAULT_HEIGHT = 260\nconst DEFAULT_NODE_WIDTH = 12\nconst DEFAULT_NODE_PADDING = 10\nconst DEFAULT_LABEL_PADDING = 96\nconst LEFT_INSET = 4\nconst TOP_INSET = 8\nconst LABEL_GAP = 8\nconst LABEL_STACK_HEIGHT = 26\nconst DEFAULT_COLOR = 'var(--neutral-a9)'\n\nfunction resolveNodeColor(\n node: SankeyChartNode,\n categoryColors: Record<string, string> | undefined,\n defaultColor: string,\n) {\n if (node.color) return node.color\n if (node.category && categoryColors?.[node.category]) {\n return categoryColors[node.category] as string\n }\n return defaultColor\n}\n\nfunction SankeyChart({\n nodes,\n links,\n categoryColors = SANKEY_CATEGORY_COLORS,\n defaultColor = DEFAULT_COLOR,\n valueSuffix,\n valueFormat,\n height = DEFAULT_HEIGHT,\n nodeWidth = DEFAULT_NODE_WIDTH,\n nodePadding = DEFAULT_NODE_PADDING,\n labelPadding = DEFAULT_LABEL_PADDING,\n keepAtDepthIds,\n title,\n className,\n}: SankeyChartProps): React.ReactElement {\n const containerRef = useRef<HTMLDivElement>(null)\n const [width, setWidth] = useState(0)\n\n useEffect(() => {\n const element = containerRef.current\n if (!element) return\n\n const resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (!entry) return\n setWidth(entry.contentRect.width)\n })\n\n resizeObserver.observe(element)\n return () => resizeObserver.disconnect()\n }, [])\n\n const nodeIds = useMemo(() => new Set(nodes.map((node) => node.id)), [nodes])\n\n // Drop zero-value links and any whose endpoints aren't in the current node\n // set (a stale link referencing a removed node makes d3-sankey throw\n // `missing: <id>`).\n const visibleLinks = useMemo(\n () =>\n links.filter(\n (link) =>\n link.value > 0 &&\n nodeIds.has(link.source) &&\n nodeIds.has(link.target),\n ),\n [links, nodeIds],\n )\n\n const visibleNodes = useMemo(() => {\n const referencedIds = new Set<string>()\n for (const link of visibleLinks) {\n referencedIds.add(link.source)\n referencedIds.add(link.target)\n }\n return nodes.filter((node) => referencedIds.has(node.id))\n }, [nodes, visibleLinks])\n\n const colorById = useMemo(() => {\n const map = new Map<string, string>()\n for (const node of nodes) {\n map.set(node.id, resolveNodeColor(node, categoryColors, defaultColor))\n }\n return map\n }, [categoryColors, defaultColor, nodes])\n\n const orderById = useMemo(() => {\n const map = new Map<string, number>()\n visibleNodes.forEach((node, index) => map.set(node.id, index))\n return map\n }, [visibleNodes])\n\n const nodeSort = useMemo(\n () =>\n (\n a: SankeyNode<SankeyDatumNode, SankeyDatumLink>,\n b: SankeyNode<SankeyDatumNode, SankeyDatumLink>,\n ) =>\n (orderById.get(a.id) ?? 0) - (orderById.get(b.id) ?? 0),\n [orderById],\n )\n\n const graph = useMemo(\n () => ({\n nodes: visibleNodes.map((node) => ({ ...node })),\n links: visibleLinks.map((link) => ({ ...link })),\n }),\n [visibleNodes, visibleLinks],\n )\n\n const nodeAlign = useMemo(() => {\n const keep = new Set(keepAtDepthIds)\n return (node: SankeyNode<SankeyDatumNode, SankeyDatumLink>, n: number) =>\n keep.has(node.id) ? (node.depth ?? 0) : sankeyJustify(node, n)\n }, [keepAtDepthIds])\n\n const innerWidth = Math.max(0, width - labelPadding - LEFT_INSET)\n const innerHeight = Math.max(0, height - TOP_INSET * 2)\n const halfLabelStack = LABEL_STACK_HEIGHT / 2\n const labelWidth = Math.max(40, labelPadding - LABEL_GAP - 4)\n\n return (\n <div className={cn('flex w-full flex-col gap-2 py-2', className)}>\n {title && <SectionTitle>{title}</SectionTitle>}\n\n <div ref={containerRef} className=\"relative w-full\" style={{ height }}>\n {width > 0 && innerWidth > 0 && (\n <Sankey<SankeyDatumNode, SankeyDatumLink>\n root={graph}\n size={[innerWidth, innerHeight]}\n nodeWidth={nodeWidth}\n nodePadding={nodePadding}\n nodeAlign={nodeAlign}\n nodeId={(node) => node.id}\n nodeSort={nodeSort}\n >\n {({ graph: laidOut, createPath }) => (\n <>\n <svg\n aria-hidden=\"true\"\n className=\"block\"\n height={height}\n width={width}\n >\n <Group left={LEFT_INSET} top={TOP_INSET}>\n <Group className=\"visx-sankey-links\">\n {laidOut.links.map((link, index) => {\n const sourceId =\n typeof link.source === 'object'\n ? (\n link.source as SankeyNode<\n SankeyDatumNode,\n SankeyDatumLink\n >\n ).id\n : String(link.source)\n const stroke =\n link.color ?? colorById.get(sourceId) ?? defaultColor\n\n return (\n <path\n // oxlint-disable-next-line react/no-array-index-key -- stateless SVG paths; source/target pairs may repeat\n key={`sankey-link-${index}`}\n d={createPath(link) ?? ''}\n fill=\"none\"\n stroke={stroke}\n strokeOpacity={0.32}\n strokeWidth={Math.max(1, link.width ?? 0)}\n />\n )\n })}\n </Group>\n\n <Group className=\"visx-sankey-nodes\">\n {laidOut.nodes.map((node) => {\n if (\n node.x0 === undefined ||\n node.x1 === undefined ||\n node.y0 === undefined ||\n node.y1 === undefined\n ) {\n return null\n }\n\n const w = node.x1 - node.x0\n const h = node.y1 - node.y0\n const fill = colorById.get(node.id) ?? defaultColor\n\n return (\n <rect\n key={node.id}\n x={node.x0}\n y={node.y0}\n width={w}\n height={Math.max(1, h)}\n fill={fill}\n rx={2}\n />\n )\n })}\n </Group>\n </Group>\n </svg>\n\n <div className=\"pointer-events-none absolute inset-0 [-webkit-text-size-adjust:100%] [text-size-adjust:100%]\">\n {laidOut.nodes.map((node, index) => {\n if (\n node.x0 === undefined ||\n node.x1 === undefined ||\n node.y0 === undefined ||\n node.y1 === undefined\n ) {\n return null\n }\n\n const h = node.y1 - node.y0\n const nodeCenterY = TOP_INSET + node.y0 + h / 2\n const labelCenterY = Math.min(\n Math.max(nodeCenterY, halfLabelStack),\n height - halfLabelStack,\n )\n\n return (\n <div\n key={`sankey-label-${node.id ?? index}`}\n className=\"absolute flex -translate-y-1/2 flex-col items-start gap-1\"\n style={{\n left: LEFT_INSET + node.x1 + LABEL_GAP,\n top: labelCenterY,\n width: labelWidth,\n }}\n >\n <span className=\"text-[11px] leading-none font-semibold whitespace-nowrap text-gray\">\n {node.label}\n </span>\n <NumberFlow\n value={node.value ?? 0}\n {...(valueSuffix !== undefined && {\n suffix: valueSuffix,\n })}\n {...(valueFormat !== undefined && {\n format: valueFormat,\n })}\n className=\"block min-h-[10px] text-[10px] leading-none text-gray-light tabular-nums\"\n />\n </div>\n )\n })}\n </div>\n </>\n )}\n </Sankey>\n )}\n </div>\n </div>\n )\n}\n\nexport type { SankeyLink, SankeyNode }\nexport { SankeyChart, SANKEY_CATEGORY_COLORS }\n"],"mappings":"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"}
@@ -118,7 +118,7 @@ function SankeyChart({ nodes, links, categoryColors = SANKEY_CATEGORY_COLORS, de
118
118
  })
119
119
  }), /* @__PURE__ */ jsx(Group, {
120
120
  className: "visx-sankey-nodes",
121
- children: laidOut.nodes.map((node, index) => {
121
+ children: laidOut.nodes.map((node) => {
122
122
  if (node.x0 === void 0 || node.x1 === void 0 || node.y0 === void 0 || node.y1 === void 0) return null;
123
123
  const w = node.x1 - node.x0;
124
124
  const h = node.y1 - node.y0;
@@ -130,7 +130,7 @@ function SankeyChart({ nodes, links, categoryColors = SANKEY_CATEGORY_COLORS, de
130
130
  height: Math.max(1, h),
131
131
  fill,
132
132
  rx: 2
133
- }, `sankey-node-${index}`);
133
+ }, node.id);
134
134
  })
135
135
  })]
136
136
  })
@@ -1 +1 @@
1
- {"version":3,"file":"sankey-chart.js","names":[],"sources":["../../src/components/sankey-chart.tsx"],"sourcesContent":["import { Group } from '@visx/group'\nimport {\n Sankey,\n sankeyJustify,\n type SankeyLink,\n type SankeyNode,\n} from '@visx/sankey'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { cn } from '../utils/cn'\nimport NumberFlow, { type Format } from './number-flow'\nimport { SectionTitle } from './typography'\n\nconst SANKEY_CATEGORY_COLORS: Record<string, string> = {\n solar: 'var(--orange-a9)',\n battery: 'var(--green-a9)',\n grid: 'var(--blue-9)',\n gridFeedIn: 'var(--blue-7)',\n home: 'var(--spark-9)',\n floor: 'var(--neutral-a9)',\n device: 'var(--neutral-a8)',\n}\n\nexport interface SankeyChartNode {\n id: string\n label: string\n /** Optional category — used to colour the node and any outgoing links. */\n category?: string\n /** Override the colour resolved from `category`. */\n color?: string\n}\n\nexport interface SankeyChartLink {\n source: string\n target: string\n value: number\n /** Override the colour of the link. Defaults to the source node colour. */\n color?: string\n}\n\nexport interface SankeyChartProps {\n nodes: SankeyChartNode[]\n links: SankeyChartLink[]\n /** Resolves a category to a colour. */\n categoryColors?: Record<string, string>\n /** Fallback colour for nodes/links without a category. */\n defaultColor?: string\n /** Suffix appended to each animated value label (e.g. \" W\"). */\n valueSuffix?: string\n /** NumberFlow `format` for value labels. */\n valueFormat?: Format\n height?: number\n nodeWidth?: number\n nodePadding?: number\n /** Reserved horizontal space on the right for labels. */\n labelPadding?: number\n /**\n * Node ids kept at their natural (computed) column instead of being pushed to\n * the last column. By default `sankeyJustify` sends every node with no\n * outgoing link to the right edge; use this to hold a terminal node (e.g. grid\n * feed-in) in a middle column alongside its siblings.\n */\n keepAtDepthIds?: readonly string[]\n title?: string\n className?: string\n}\n\ntype SankeyDatumNode = SankeyChartNode & {\n /** Computed by d3-sankey; present after layout. */\n}\n\ntype SankeyDatumLink = SankeyChartLink\n\nconst DEFAULT_HEIGHT = 260\nconst DEFAULT_NODE_WIDTH = 12\nconst DEFAULT_NODE_PADDING = 10\nconst DEFAULT_LABEL_PADDING = 96\nconst LEFT_INSET = 4\nconst TOP_INSET = 8\nconst LABEL_GAP = 8\nconst LABEL_STACK_HEIGHT = 26\nconst DEFAULT_COLOR = 'var(--neutral-a9)'\n\nfunction resolveNodeColor(\n node: SankeyChartNode,\n categoryColors: Record<string, string> | undefined,\n defaultColor: string,\n) {\n if (node.color) return node.color\n if (node.category && categoryColors?.[node.category]) {\n return categoryColors[node.category] as string\n }\n return defaultColor\n}\n\nfunction SankeyChart({\n nodes,\n links,\n categoryColors = SANKEY_CATEGORY_COLORS,\n defaultColor = DEFAULT_COLOR,\n valueSuffix,\n valueFormat,\n height = DEFAULT_HEIGHT,\n nodeWidth = DEFAULT_NODE_WIDTH,\n nodePadding = DEFAULT_NODE_PADDING,\n labelPadding = DEFAULT_LABEL_PADDING,\n keepAtDepthIds,\n title,\n className,\n}: SankeyChartProps): React.ReactElement {\n const containerRef = useRef<HTMLDivElement>(null)\n const [width, setWidth] = useState(0)\n\n useEffect(() => {\n const element = containerRef.current\n if (!element) return\n\n const resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (!entry) return\n setWidth(entry.contentRect.width)\n })\n\n resizeObserver.observe(element)\n return () => resizeObserver.disconnect()\n }, [])\n\n const nodeIds = useMemo(() => new Set(nodes.map((node) => node.id)), [nodes])\n\n // Drop zero-value links and any whose endpoints aren't in the current node\n // set (a stale link referencing a removed node makes d3-sankey throw\n // `missing: <id>`).\n const visibleLinks = useMemo(\n () =>\n links.filter(\n (link) =>\n link.value > 0 &&\n nodeIds.has(link.source) &&\n nodeIds.has(link.target),\n ),\n [links, nodeIds],\n )\n\n const visibleNodes = useMemo(() => {\n const referencedIds = new Set<string>()\n for (const link of visibleLinks) {\n referencedIds.add(link.source)\n referencedIds.add(link.target)\n }\n return nodes.filter((node) => referencedIds.has(node.id))\n }, [nodes, visibleLinks])\n\n const colorById = useMemo(() => {\n const map = new Map<string, string>()\n for (const node of nodes) {\n map.set(node.id, resolveNodeColor(node, categoryColors, defaultColor))\n }\n return map\n }, [categoryColors, defaultColor, nodes])\n\n const orderById = useMemo(() => {\n const map = new Map<string, number>()\n visibleNodes.forEach((node, index) => map.set(node.id, index))\n return map\n }, [visibleNodes])\n\n const nodeSort = useMemo(\n () =>\n (\n a: SankeyNode<SankeyDatumNode, SankeyDatumLink>,\n b: SankeyNode<SankeyDatumNode, SankeyDatumLink>,\n ) =>\n (orderById.get(a.id) ?? 0) - (orderById.get(b.id) ?? 0),\n [orderById],\n )\n\n const graph = useMemo(\n () => ({\n nodes: visibleNodes.map((node) => ({ ...node })),\n links: visibleLinks.map((link) => ({ ...link })),\n }),\n [visibleNodes, visibleLinks],\n )\n\n const nodeAlign = useMemo(() => {\n const keep = new Set(keepAtDepthIds)\n return (node: SankeyNode<SankeyDatumNode, SankeyDatumLink>, n: number) =>\n keep.has(node.id) ? (node.depth ?? 0) : sankeyJustify(node, n)\n }, [keepAtDepthIds])\n\n const innerWidth = Math.max(0, width - labelPadding - LEFT_INSET)\n const innerHeight = Math.max(0, height - TOP_INSET * 2)\n const halfLabelStack = LABEL_STACK_HEIGHT / 2\n const labelWidth = Math.max(40, labelPadding - LABEL_GAP - 4)\n\n return (\n <div className={cn('flex w-full flex-col gap-2 py-2', className)}>\n {title && <SectionTitle>{title}</SectionTitle>}\n\n <div ref={containerRef} className=\"relative w-full\" style={{ height }}>\n {width > 0 && innerWidth > 0 && (\n <Sankey<SankeyDatumNode, SankeyDatumLink>\n root={graph}\n size={[innerWidth, innerHeight]}\n nodeWidth={nodeWidth}\n nodePadding={nodePadding}\n nodeAlign={nodeAlign}\n nodeId={(node) => node.id}\n nodeSort={nodeSort}\n >\n {({ graph: laidOut, createPath }) => (\n <>\n <svg\n aria-hidden=\"true\"\n className=\"block\"\n height={height}\n width={width}\n >\n <Group left={LEFT_INSET} top={TOP_INSET}>\n <Group className=\"visx-sankey-links\">\n {laidOut.links.map((link, index) => {\n const sourceId =\n typeof link.source === 'object'\n ? (\n link.source as SankeyNode<\n SankeyDatumNode,\n SankeyDatumLink\n >\n ).id\n : String(link.source)\n const stroke =\n link.color ?? colorById.get(sourceId) ?? defaultColor\n\n return (\n <path\n key={`sankey-link-${index}`}\n d={createPath(link) ?? ''}\n fill=\"none\"\n stroke={stroke}\n strokeOpacity={0.32}\n strokeWidth={Math.max(1, link.width ?? 0)}\n />\n )\n })}\n </Group>\n\n <Group className=\"visx-sankey-nodes\">\n {laidOut.nodes.map((node, index) => {\n if (\n node.x0 === undefined ||\n node.x1 === undefined ||\n node.y0 === undefined ||\n node.y1 === undefined\n ) {\n return null\n }\n\n const w = node.x1 - node.x0\n const h = node.y1 - node.y0\n const fill = colorById.get(node.id) ?? defaultColor\n\n return (\n <rect\n key={`sankey-node-${index}`}\n x={node.x0}\n y={node.y0}\n width={w}\n height={Math.max(1, h)}\n fill={fill}\n rx={2}\n />\n )\n })}\n </Group>\n </Group>\n </svg>\n\n <div className=\"pointer-events-none absolute inset-0 [-webkit-text-size-adjust:100%] [text-size-adjust:100%]\">\n {laidOut.nodes.map((node, index) => {\n if (\n node.x0 === undefined ||\n node.x1 === undefined ||\n node.y0 === undefined ||\n node.y1 === undefined\n ) {\n return null\n }\n\n const h = node.y1 - node.y0\n const nodeCenterY = TOP_INSET + node.y0 + h / 2\n const labelCenterY = Math.min(\n Math.max(nodeCenterY, halfLabelStack),\n height - halfLabelStack,\n )\n\n return (\n <div\n key={`sankey-label-${node.id ?? index}`}\n className=\"absolute flex -translate-y-1/2 flex-col items-start gap-1\"\n style={{\n left: LEFT_INSET + node.x1 + LABEL_GAP,\n top: labelCenterY,\n width: labelWidth,\n }}\n >\n <span className=\"text-[11px] leading-none font-semibold whitespace-nowrap text-gray\">\n {node.label}\n </span>\n <NumberFlow\n value={node.value ?? 0}\n {...(valueSuffix !== undefined && {\n suffix: valueSuffix,\n })}\n {...(valueFormat !== undefined && {\n format: valueFormat,\n })}\n className=\"block min-h-[10px] text-[10px] leading-none text-gray-light tabular-nums\"\n />\n </div>\n )\n })}\n </div>\n </>\n )}\n </Sankey>\n )}\n </div>\n </div>\n )\n}\n\nexport type { SankeyLink, SankeyNode }\nexport { SankeyChart, SANKEY_CATEGORY_COLORS }\n"],"mappings":"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"}
1
+ {"version":3,"file":"sankey-chart.js","names":[],"sources":["../../src/components/sankey-chart.tsx"],"sourcesContent":["import { Group } from '@visx/group'\nimport {\n Sankey,\n sankeyJustify,\n type SankeyLink,\n type SankeyNode,\n} from '@visx/sankey'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { cn } from '../utils/cn'\nimport NumberFlow, { type Format } from './number-flow'\nimport { SectionTitle } from './typography'\n\nconst SANKEY_CATEGORY_COLORS: Record<string, string> = {\n solar: 'var(--orange-a9)',\n battery: 'var(--green-a9)',\n grid: 'var(--blue-9)',\n gridFeedIn: 'var(--blue-7)',\n home: 'var(--spark-9)',\n floor: 'var(--neutral-a9)',\n device: 'var(--neutral-a8)',\n}\n\nexport interface SankeyChartNode {\n id: string\n label: string\n /** Optional category — used to colour the node and any outgoing links. */\n category?: string\n /** Override the colour resolved from `category`. */\n color?: string\n}\n\nexport interface SankeyChartLink {\n source: string\n target: string\n value: number\n /** Override the colour of the link. Defaults to the source node colour. */\n color?: string\n}\n\nexport interface SankeyChartProps {\n nodes: SankeyChartNode[]\n links: SankeyChartLink[]\n /** Resolves a category to a colour. */\n categoryColors?: Record<string, string>\n /** Fallback colour for nodes/links without a category. */\n defaultColor?: string\n /** Suffix appended to each animated value label (e.g. \" W\"). */\n valueSuffix?: string\n /** NumberFlow `format` for value labels. */\n valueFormat?: Format\n height?: number\n nodeWidth?: number\n nodePadding?: number\n /** Reserved horizontal space on the right for labels. */\n labelPadding?: number\n /**\n * Node ids kept at their natural (computed) column instead of being pushed to\n * the last column. By default `sankeyJustify` sends every node with no\n * outgoing link to the right edge; use this to hold a terminal node (e.g. grid\n * feed-in) in a middle column alongside its siblings.\n */\n keepAtDepthIds?: readonly string[]\n title?: string\n className?: string\n}\n\ntype SankeyDatumNode = SankeyChartNode & {\n /** Computed by d3-sankey; present after layout. */\n}\n\ntype SankeyDatumLink = SankeyChartLink\n\nconst DEFAULT_HEIGHT = 260\nconst DEFAULT_NODE_WIDTH = 12\nconst DEFAULT_NODE_PADDING = 10\nconst DEFAULT_LABEL_PADDING = 96\nconst LEFT_INSET = 4\nconst TOP_INSET = 8\nconst LABEL_GAP = 8\nconst LABEL_STACK_HEIGHT = 26\nconst DEFAULT_COLOR = 'var(--neutral-a9)'\n\nfunction resolveNodeColor(\n node: SankeyChartNode,\n categoryColors: Record<string, string> | undefined,\n defaultColor: string,\n) {\n if (node.color) return node.color\n if (node.category && categoryColors?.[node.category]) {\n return categoryColors[node.category] as string\n }\n return defaultColor\n}\n\nfunction SankeyChart({\n nodes,\n links,\n categoryColors = SANKEY_CATEGORY_COLORS,\n defaultColor = DEFAULT_COLOR,\n valueSuffix,\n valueFormat,\n height = DEFAULT_HEIGHT,\n nodeWidth = DEFAULT_NODE_WIDTH,\n nodePadding = DEFAULT_NODE_PADDING,\n labelPadding = DEFAULT_LABEL_PADDING,\n keepAtDepthIds,\n title,\n className,\n}: SankeyChartProps): React.ReactElement {\n const containerRef = useRef<HTMLDivElement>(null)\n const [width, setWidth] = useState(0)\n\n useEffect(() => {\n const element = containerRef.current\n if (!element) return\n\n const resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (!entry) return\n setWidth(entry.contentRect.width)\n })\n\n resizeObserver.observe(element)\n return () => resizeObserver.disconnect()\n }, [])\n\n const nodeIds = useMemo(() => new Set(nodes.map((node) => node.id)), [nodes])\n\n // Drop zero-value links and any whose endpoints aren't in the current node\n // set (a stale link referencing a removed node makes d3-sankey throw\n // `missing: <id>`).\n const visibleLinks = useMemo(\n () =>\n links.filter(\n (link) =>\n link.value > 0 &&\n nodeIds.has(link.source) &&\n nodeIds.has(link.target),\n ),\n [links, nodeIds],\n )\n\n const visibleNodes = useMemo(() => {\n const referencedIds = new Set<string>()\n for (const link of visibleLinks) {\n referencedIds.add(link.source)\n referencedIds.add(link.target)\n }\n return nodes.filter((node) => referencedIds.has(node.id))\n }, [nodes, visibleLinks])\n\n const colorById = useMemo(() => {\n const map = new Map<string, string>()\n for (const node of nodes) {\n map.set(node.id, resolveNodeColor(node, categoryColors, defaultColor))\n }\n return map\n }, [categoryColors, defaultColor, nodes])\n\n const orderById = useMemo(() => {\n const map = new Map<string, number>()\n visibleNodes.forEach((node, index) => map.set(node.id, index))\n return map\n }, [visibleNodes])\n\n const nodeSort = useMemo(\n () =>\n (\n a: SankeyNode<SankeyDatumNode, SankeyDatumLink>,\n b: SankeyNode<SankeyDatumNode, SankeyDatumLink>,\n ) =>\n (orderById.get(a.id) ?? 0) - (orderById.get(b.id) ?? 0),\n [orderById],\n )\n\n const graph = useMemo(\n () => ({\n nodes: visibleNodes.map((node) => ({ ...node })),\n links: visibleLinks.map((link) => ({ ...link })),\n }),\n [visibleNodes, visibleLinks],\n )\n\n const nodeAlign = useMemo(() => {\n const keep = new Set(keepAtDepthIds)\n return (node: SankeyNode<SankeyDatumNode, SankeyDatumLink>, n: number) =>\n keep.has(node.id) ? (node.depth ?? 0) : sankeyJustify(node, n)\n }, [keepAtDepthIds])\n\n const innerWidth = Math.max(0, width - labelPadding - LEFT_INSET)\n const innerHeight = Math.max(0, height - TOP_INSET * 2)\n const halfLabelStack = LABEL_STACK_HEIGHT / 2\n const labelWidth = Math.max(40, labelPadding - LABEL_GAP - 4)\n\n return (\n <div className={cn('flex w-full flex-col gap-2 py-2', className)}>\n {title && <SectionTitle>{title}</SectionTitle>}\n\n <div ref={containerRef} className=\"relative w-full\" style={{ height }}>\n {width > 0 && innerWidth > 0 && (\n <Sankey<SankeyDatumNode, SankeyDatumLink>\n root={graph}\n size={[innerWidth, innerHeight]}\n nodeWidth={nodeWidth}\n nodePadding={nodePadding}\n nodeAlign={nodeAlign}\n nodeId={(node) => node.id}\n nodeSort={nodeSort}\n >\n {({ graph: laidOut, createPath }) => (\n <>\n <svg\n aria-hidden=\"true\"\n className=\"block\"\n height={height}\n width={width}\n >\n <Group left={LEFT_INSET} top={TOP_INSET}>\n <Group className=\"visx-sankey-links\">\n {laidOut.links.map((link, index) => {\n const sourceId =\n typeof link.source === 'object'\n ? (\n link.source as SankeyNode<\n SankeyDatumNode,\n SankeyDatumLink\n >\n ).id\n : String(link.source)\n const stroke =\n link.color ?? colorById.get(sourceId) ?? defaultColor\n\n return (\n <path\n // oxlint-disable-next-line react/no-array-index-key -- stateless SVG paths; source/target pairs may repeat\n key={`sankey-link-${index}`}\n d={createPath(link) ?? ''}\n fill=\"none\"\n stroke={stroke}\n strokeOpacity={0.32}\n strokeWidth={Math.max(1, link.width ?? 0)}\n />\n )\n })}\n </Group>\n\n <Group className=\"visx-sankey-nodes\">\n {laidOut.nodes.map((node) => {\n if (\n node.x0 === undefined ||\n node.x1 === undefined ||\n node.y0 === undefined ||\n node.y1 === undefined\n ) {\n return null\n }\n\n const w = node.x1 - node.x0\n const h = node.y1 - node.y0\n const fill = colorById.get(node.id) ?? defaultColor\n\n return (\n <rect\n key={node.id}\n x={node.x0}\n y={node.y0}\n width={w}\n height={Math.max(1, h)}\n fill={fill}\n rx={2}\n />\n )\n })}\n </Group>\n </Group>\n </svg>\n\n <div className=\"pointer-events-none absolute inset-0 [-webkit-text-size-adjust:100%] [text-size-adjust:100%]\">\n {laidOut.nodes.map((node, index) => {\n if (\n node.x0 === undefined ||\n node.x1 === undefined ||\n node.y0 === undefined ||\n node.y1 === undefined\n ) {\n return null\n }\n\n const h = node.y1 - node.y0\n const nodeCenterY = TOP_INSET + node.y0 + h / 2\n const labelCenterY = Math.min(\n Math.max(nodeCenterY, halfLabelStack),\n height - halfLabelStack,\n )\n\n return (\n <div\n key={`sankey-label-${node.id ?? index}`}\n className=\"absolute flex -translate-y-1/2 flex-col items-start gap-1\"\n style={{\n left: LEFT_INSET + node.x1 + LABEL_GAP,\n top: labelCenterY,\n width: labelWidth,\n }}\n >\n <span className=\"text-[11px] leading-none font-semibold whitespace-nowrap text-gray\">\n {node.label}\n </span>\n <NumberFlow\n value={node.value ?? 0}\n {...(valueSuffix !== undefined && {\n suffix: valueSuffix,\n })}\n {...(valueFormat !== undefined && {\n format: valueFormat,\n })}\n className=\"block min-h-[10px] text-[10px] leading-none text-gray-light tabular-nums\"\n />\n </div>\n )\n })}\n </div>\n </>\n )}\n </Sankey>\n )}\n </div>\n </div>\n )\n}\n\nexport type { SankeyLink, SankeyNode }\nexport { SankeyChart, SANKEY_CATEGORY_COLORS }\n"],"mappings":"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"}
@@ -4,35 +4,35 @@ const require_chunk = require("../chunk-DY84GLCh.cjs");
4
4
  let react = require("react");
5
5
  react = require_chunk.__toESM(react);
6
6
  let react_jsx_runtime = require("react/jsx-runtime");
7
- let cnfast = require("cnfast");
7
+ let cn = require("cn");
8
8
  //#region src/components/schedule-editor.tsx
9
9
  const ScheduleEditor = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
10
10
  ref,
11
- className: (0, cnfast.cn)("flex flex-col gap-4 px-2", className),
11
+ className: (0, cn.cn)("flex flex-col gap-4 px-2", className),
12
12
  ...props
13
13
  }));
14
14
  ScheduleEditor.displayName = "ScheduleEditor";
15
15
  const ScheduleEditorHeader = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", {
16
16
  ref,
17
- className: (0, cnfast.cn)("flex flex-col gap-1", className),
17
+ className: (0, cn.cn)("flex flex-col gap-1", className),
18
18
  ...props
19
19
  }));
20
20
  ScheduleEditorHeader.displayName = "ScheduleEditorHeader";
21
21
  const ScheduleEditorTitle = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
22
22
  ref,
23
- className: (0, cnfast.cn)("text-base font-bold text-gray", className),
23
+ className: (0, cn.cn)("text-base font-bold text-gray", className),
24
24
  ...props
25
25
  }));
26
26
  ScheduleEditorTitle.displayName = "ScheduleEditorTitle";
27
27
  const ScheduleEditorDescription = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
28
28
  ref,
29
- className: (0, cnfast.cn)("text-sm leading-5 text-gray-light", className),
29
+ className: (0, cn.cn)("text-sm leading-5 text-gray-light", className),
30
30
  ...props
31
31
  }));
32
32
  ScheduleEditorDescription.displayName = "ScheduleEditorDescription";
33
33
  const ScheduleEditorBody = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
34
34
  ref,
35
- className: (0, cnfast.cn)("flex flex-col gap-[calc(var(--spark-layout-gap)*4)]", className),
35
+ className: (0, cn.cn)("flex flex-col gap-[calc(var(--spark-layout-gap)*4)]", className),
36
36
  ...props
37
37
  }));
38
38
  ScheduleEditorBody.displayName = "ScheduleEditorBody";
@@ -41,20 +41,20 @@ ScheduleEditorBody.displayName = "ScheduleEditorBody";
41
41
  * pattern. Override with `className` if you need a different arrangement. */
42
42
  const ScheduleEditorFooter = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("footer", {
43
43
  ref,
44
- className: (0, cnfast.cn)("flex items-center justify-between gap-2 pt-2", className),
44
+ className: (0, cn.cn)("flex items-center justify-between gap-2 pt-2", className),
45
45
  ...props
46
46
  }));
47
47
  ScheduleEditorFooter.displayName = "ScheduleEditorFooter";
48
48
  /** Right-aligned cluster of footer actions (e.g. Cancel + Save). */
49
49
  const ScheduleEditorActions = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
50
50
  ref,
51
- className: (0, cnfast.cn)("ml-auto flex items-center gap-2", className),
51
+ className: (0, cn.cn)("ml-auto flex items-center gap-2", className),
52
52
  ...props
53
53
  }));
54
54
  ScheduleEditorActions.displayName = "ScheduleEditorActions";
55
55
  const ScheduleEditorField = react.forwardRef(({ children, className, hint, label, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
56
56
  ref,
57
- className: (0, cnfast.cn)("flex flex-col gap-1.5", className),
57
+ className: (0, cn.cn)("flex flex-col gap-1.5", className),
58
58
  ...props,
59
59
  children: [
60
60
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"schedule-editor.cjs","names":["React"],"sources":["../../src/components/schedule-editor.tsx"],"sourcesContent":["import * as React from 'react'\nimport { cn } from '../utils/cn'\n\nconst ScheduleEditor = React.forwardRef<\n HTMLElement,\n React.HTMLAttributes<HTMLElement>\n>(({ className, ...props }, ref) => (\n <section\n ref={ref}\n className={cn('flex flex-col gap-4 px-2', className)}\n {...props}\n />\n))\n\nScheduleEditor.displayName = 'ScheduleEditor'\n\nconst ScheduleEditorHeader = React.forwardRef<\n HTMLElement,\n React.HTMLAttributes<HTMLElement>\n>(({ className, ...props }, ref) => (\n <header\n ref={ref}\n className={cn('flex flex-col gap-1', className)}\n {...props}\n />\n))\n\nScheduleEditorHeader.displayName = 'ScheduleEditorHeader'\n\nconst ScheduleEditorTitle = React.forwardRef<\n HTMLHeadingElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h3\n ref={ref}\n className={cn('text-base font-bold text-gray', className)}\n {...props}\n />\n))\n\nScheduleEditorTitle.displayName = 'ScheduleEditorTitle'\n\nconst ScheduleEditorDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('text-sm leading-5 text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleEditorDescription.displayName = 'ScheduleEditorDescription'\n\nconst ScheduleEditorBody = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n))\n\nScheduleEditorBody.displayName = 'ScheduleEditorBody'\n\n/** Footer slot. Default layout splits children into a `justify-between` row,\n * which matches the common \"destructive on the left, primary on the right\"\n * pattern. Override with `className` if you need a different arrangement. */\nconst ScheduleEditorFooter = React.forwardRef<\n HTMLElement,\n React.HTMLAttributes<HTMLElement>\n>(({ className, ...props }, ref) => (\n <footer\n ref={ref}\n className={cn('flex items-center justify-between gap-2 pt-2', className)}\n {...props}\n />\n))\n\nScheduleEditorFooter.displayName = 'ScheduleEditorFooter'\n\n/** Right-aligned cluster of footer actions (e.g. Cancel + Save). */\nconst ScheduleEditorActions = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('ml-auto flex items-center gap-2', className)}\n {...props}\n />\n))\n\nScheduleEditorActions.displayName = 'ScheduleEditorActions'\n\ninterface ScheduleEditorFieldProps extends Omit<\n React.LabelHTMLAttributes<HTMLLabelElement>,\n 'children'\n> {\n label: React.ReactNode\n hint?: React.ReactNode\n children: React.ReactNode\n}\n\nconst ScheduleEditorField = React.forwardRef<\n HTMLLabelElement,\n ScheduleEditorFieldProps\n>(({ children, className, hint, label, ...props }, ref) => (\n <label\n ref={ref}\n className={cn('flex flex-col gap-1.5', className)}\n {...props}\n >\n <span className=\"text-sm font-medium text-gray\">{label}</span>\n {children}\n {hint && <span className=\"text-xs text-gray-light\">{hint}</span>}\n </label>\n))\n\nScheduleEditorField.displayName = 'ScheduleEditorField'\n\nexport {\n ScheduleEditor,\n ScheduleEditorActions,\n ScheduleEditorBody,\n ScheduleEditorDescription,\n ScheduleEditorField,\n ScheduleEditorFooter,\n ScheduleEditorHeader,\n ScheduleEditorTitle,\n}\n"],"mappings":";;;;;;;;AAGA,MAAM,iBAAiBA,MAAM,YAG1B,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,WAAD;CACO;CACL,YAAA,GAAA,OAAA,IAAc,4BAA4B,SAAS;CACnD,GAAI;AACL,CAAA,CACF;AAED,eAAe,cAAc;AAE7B,MAAM,uBAAuBA,MAAM,YAGhC,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,UAAD;CACO;CACL,YAAA,GAAA,OAAA,IAAc,uBAAuB,SAAS;CAC9C,GAAI;AACL,CAAA,CACF;AAED,qBAAqB,cAAc;AAEnC,MAAM,sBAAsBA,MAAM,YAG/B,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,MAAD;CACO;CACL,YAAA,GAAA,OAAA,IAAc,iCAAiC,SAAS;CACxD,GAAI;AACL,CAAA,CACF;AAED,oBAAoB,cAAc;AAElC,MAAM,4BAA4BA,MAAM,YAGrC,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,KAAD;CACO;CACL,YAAA,GAAA,OAAA,IAAc,qCAAqC,SAAS;CAC5D,GAAI;AACL,CAAA,CACF;AAED,0BAA0B,cAAc;AAExC,MAAM,qBAAqBA,MAAM,YAG9B,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,OAAD;CACO;CACL,YAAA,GAAA,OAAA,IACE,uDACA,SACF;CACA,GAAI;AACL,CAAA,CACF;AAED,mBAAmB,cAAc;;;;AAKjC,MAAM,uBAAuBA,MAAM,YAGhC,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,UAAD;CACO;CACL,YAAA,GAAA,OAAA,IAAc,gDAAgD,SAAS;CACvE,GAAI;AACL,CAAA,CACF;AAED,qBAAqB,cAAc;;AAGnC,MAAM,wBAAwBA,MAAM,YAGjC,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,OAAD;CACO;CACL,YAAA,GAAA,OAAA,IAAc,mCAAmC,SAAS;CAC1D,GAAI;AACL,CAAA,CACF;AAED,sBAAsB,cAAc;AAWpC,MAAM,sBAAsBA,MAAM,YAG/B,EAAE,UAAU,WAAW,MAAM,OAAO,GAAG,SAAS,QACjD,iBAAA,GAAA,kBAAA,MAAC,SAAD;CACO;CACL,YAAA,GAAA,OAAA,IAAc,yBAAyB,SAAS;CAChD,GAAI;WAHN;EAKE,iBAAA,GAAA,kBAAA,KAAC,QAAD;GAAM,WAAU;aAAiC;EAAY,CAAA;EAC5D;EACA,QAAQ,iBAAA,GAAA,kBAAA,KAAC,QAAD;GAAM,WAAU;aAA2B;EAAW,CAAA;CAC1D;EACR;AAED,oBAAoB,cAAc"}
1
+ {"version":3,"file":"schedule-editor.cjs","names":["React"],"sources":["../../src/components/schedule-editor.tsx"],"sourcesContent":["import * as React from 'react'\nimport { cn } from '../utils/cn'\n\nconst ScheduleEditor = React.forwardRef<\n HTMLElement,\n React.HTMLAttributes<HTMLElement>\n>(({ className, ...props }, ref) => (\n <section\n ref={ref}\n className={cn('flex flex-col gap-4 px-2', className)}\n {...props}\n />\n))\n\nScheduleEditor.displayName = 'ScheduleEditor'\n\nconst ScheduleEditorHeader = React.forwardRef<\n HTMLElement,\n React.HTMLAttributes<HTMLElement>\n>(({ className, ...props }, ref) => (\n <header\n ref={ref}\n className={cn('flex flex-col gap-1', className)}\n {...props}\n />\n))\n\nScheduleEditorHeader.displayName = 'ScheduleEditorHeader'\n\nconst ScheduleEditorTitle = React.forwardRef<\n HTMLHeadingElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h3\n ref={ref}\n className={cn('text-base font-bold text-gray', className)}\n {...props}\n />\n))\n\nScheduleEditorTitle.displayName = 'ScheduleEditorTitle'\n\nconst ScheduleEditorDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('text-sm leading-5 text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleEditorDescription.displayName = 'ScheduleEditorDescription'\n\nconst ScheduleEditorBody = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*4)]',\n className,\n )}\n {...props}\n />\n))\n\nScheduleEditorBody.displayName = 'ScheduleEditorBody'\n\n/** Footer slot. Default layout splits children into a `justify-between` row,\n * which matches the common \"destructive on the left, primary on the right\"\n * pattern. Override with `className` if you need a different arrangement. */\nconst ScheduleEditorFooter = React.forwardRef<\n HTMLElement,\n React.HTMLAttributes<HTMLElement>\n>(({ className, ...props }, ref) => (\n <footer\n ref={ref}\n className={cn('flex items-center justify-between gap-2 pt-2', className)}\n {...props}\n />\n))\n\nScheduleEditorFooter.displayName = 'ScheduleEditorFooter'\n\n/** Right-aligned cluster of footer actions (e.g. Cancel + Save). */\nconst ScheduleEditorActions = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('ml-auto flex items-center gap-2', className)}\n {...props}\n />\n))\n\nScheduleEditorActions.displayName = 'ScheduleEditorActions'\n\ninterface ScheduleEditorFieldProps extends Omit<\n React.LabelHTMLAttributes<HTMLLabelElement>,\n 'children'\n> {\n label: React.ReactNode\n hint?: React.ReactNode\n children: React.ReactNode\n}\n\nconst ScheduleEditorField = React.forwardRef<\n HTMLLabelElement,\n ScheduleEditorFieldProps\n>(({ children, className, hint, label, ...props }, ref) => (\n <label\n ref={ref}\n className={cn('flex flex-col gap-1.5', className)}\n {...props}\n >\n <span className=\"text-sm font-medium text-gray\">{label}</span>\n {children}\n {hint && <span className=\"text-xs text-gray-light\">{hint}</span>}\n </label>\n))\n\nScheduleEditorField.displayName = 'ScheduleEditorField'\n\nexport {\n ScheduleEditor,\n ScheduleEditorActions,\n ScheduleEditorBody,\n ScheduleEditorDescription,\n ScheduleEditorField,\n ScheduleEditorFooter,\n ScheduleEditorHeader,\n ScheduleEditorTitle,\n}\n"],"mappings":";;;;;;;;AAGA,MAAM,iBAAiBA,MAAM,YAG1B,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,WAAD;CACO;CACL,YAAA,GAAA,GAAA,IAAc,4BAA4B,SAAS;CACnD,GAAI;AACL,CAAA,CACF;AAED,eAAe,cAAc;AAE7B,MAAM,uBAAuBA,MAAM,YAGhC,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,UAAD;CACO;CACL,YAAA,GAAA,GAAA,IAAc,uBAAuB,SAAS;CAC9C,GAAI;AACL,CAAA,CACF;AAED,qBAAqB,cAAc;AAEnC,MAAM,sBAAsBA,MAAM,YAG/B,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,MAAD;CACO;CACL,YAAA,GAAA,GAAA,IAAc,iCAAiC,SAAS;CACxD,GAAI;AACL,CAAA,CACF;AAED,oBAAoB,cAAc;AAElC,MAAM,4BAA4BA,MAAM,YAGrC,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,KAAD;CACO;CACL,YAAA,GAAA,GAAA,IAAc,qCAAqC,SAAS;CAC5D,GAAI;AACL,CAAA,CACF;AAED,0BAA0B,cAAc;AAExC,MAAM,qBAAqBA,MAAM,YAG9B,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,OAAD;CACO;CACL,YAAA,GAAA,GAAA,IACE,uDACA,SACF;CACA,GAAI;AACL,CAAA,CACF;AAED,mBAAmB,cAAc;;;;AAKjC,MAAM,uBAAuBA,MAAM,YAGhC,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,UAAD;CACO;CACL,YAAA,GAAA,GAAA,IAAc,gDAAgD,SAAS;CACvE,GAAI;AACL,CAAA,CACF;AAED,qBAAqB,cAAc;;AAGnC,MAAM,wBAAwBA,MAAM,YAGjC,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,OAAD;CACO;CACL,YAAA,GAAA,GAAA,IAAc,mCAAmC,SAAS;CAC1D,GAAI;AACL,CAAA,CACF;AAED,sBAAsB,cAAc;AAWpC,MAAM,sBAAsBA,MAAM,YAG/B,EAAE,UAAU,WAAW,MAAM,OAAO,GAAG,SAAS,QACjD,iBAAA,GAAA,kBAAA,MAAC,SAAD;CACO;CACL,YAAA,GAAA,GAAA,IAAc,yBAAyB,SAAS;CAChD,GAAI;WAHN;EAKE,iBAAA,GAAA,kBAAA,KAAC,QAAD;GAAM,WAAU;aAAiC;EAAY,CAAA;EAC5D;EACA,QAAQ,iBAAA,GAAA,kBAAA,KAAC,QAAD;GAAM,WAAU;aAA2B;EAAW,CAAA;CAC1D;EACR;AAED,oBAAoB,cAAc"}
@@ -5,24 +5,24 @@ let react = require("react");
5
5
  react = require_chunk.__toESM(react);
6
6
  let _epilot_spark_icons = require("@epilot/spark-icons");
7
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
- let cnfast = require("cnfast");
8
+ let cn = require("cn");
9
9
  //#region src/components/schedule-list.tsx
10
10
  const ScheduleList = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11
11
  ref,
12
- className: (0, cnfast.cn)("flex flex-col gap-[calc(var(--spark-layout-gap)*2)]", className),
12
+ className: (0, cn.cn)("flex flex-col gap-[calc(var(--spark-layout-gap)*2)]", className),
13
13
  ...props
14
14
  }));
15
15
  ScheduleList.displayName = "ScheduleList";
16
16
  const ScheduleListEmpty = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
17
17
  ref,
18
- className: (0, cnfast.cn)("px-3 py-2 text-sm text-gray-light", className),
18
+ className: (0, cn.cn)("px-3 py-2 text-sm text-gray-light", className),
19
19
  ...props
20
20
  }));
21
21
  ScheduleListEmpty.displayName = "ScheduleListEmpty";
22
22
  const ScheduleListAdd = react.forwardRef(({ children, className, icon, type = "button", ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
23
23
  ref,
24
24
  type,
25
- className: (0, cnfast.cn)("inline-flex h-11 w-full items-center justify-center gap-1.5 rounded-lg border border-dashed border-gray text-sm font-medium text-gray-light transition-colors hover:border-spark-a8 hover:bg-base-accent-soft hover:text-accent focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className),
25
+ className: (0, cn.cn)("inline-flex h-11 w-full items-center justify-center gap-1.5 rounded-lg border border-dashed border-gray text-sm font-medium text-gray-light transition-colors hover:border-spark-a8 hover:bg-base-accent-soft hover:text-accent focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className),
26
26
  ...props,
27
27
  children: [icon ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_epilot_spark_icons.Add, { className: "[--spark-icon-size:14px]" }), children]
28
28
  }));
@@ -43,7 +43,7 @@ const ScheduleEntry = react.forwardRef(({ children, className, disabled, onClick
43
43
  }
44
44
  } : void 0,
45
45
  "aria-disabled": disabled || void 0,
46
- className: (0, cnfast.cn)("flex items-center gap-3 rounded-lg bg-base-gray-soft px-3 py-2.5 transition-colors motion-reduce:transition-none", interactive && "cursor-pointer touch-target-row hover:bg-gray-a3 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden", disabled && "cursor-not-allowed opacity-50", className),
46
+ className: (0, cn.cn)("flex items-center gap-3 rounded-lg bg-base-gray-soft px-3 py-2.5 transition-colors motion-reduce:transition-none", interactive && "cursor-pointer touch-target-row hover:bg-gray-a3 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden", disabled && "cursor-not-allowed opacity-50", className),
47
47
  ...props,
48
48
  children
49
49
  });
@@ -51,19 +51,19 @@ const ScheduleEntry = react.forwardRef(({ children, className, disabled, onClick
51
51
  ScheduleEntry.displayName = "ScheduleEntry";
52
52
  const ScheduleEntryContent = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
53
53
  ref,
54
- className: (0, cnfast.cn)("flex min-w-0 flex-1 flex-col gap-0.5", className),
54
+ className: (0, cn.cn)("flex min-w-0 flex-1 flex-col gap-0.5", className),
55
55
  ...props
56
56
  }));
57
57
  ScheduleEntryContent.displayName = "ScheduleEntryContent";
58
58
  const ScheduleEntryTitle = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
59
59
  ref,
60
- className: (0, cnfast.cn)("flex min-w-0 items-center gap-2 truncate text-sm font-medium text-gray", className),
60
+ className: (0, cn.cn)("flex min-w-0 items-center gap-2 truncate text-sm font-medium text-gray", className),
61
61
  ...props
62
62
  }));
63
63
  ScheduleEntryTitle.displayName = "ScheduleEntryTitle";
64
64
  const ScheduleEntrySubtitle = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
65
65
  ref,
66
- className: (0, cnfast.cn)("truncate text-xs text-gray-light", className),
66
+ className: (0, cn.cn)("truncate text-xs text-gray-light", className),
67
67
  ...props
68
68
  }));
69
69
  ScheduleEntrySubtitle.displayName = "ScheduleEntrySubtitle";
@@ -76,7 +76,7 @@ const ScheduleEntryActions = react.forwardRef(({ className, onClick, ...props },
76
76
  event.stopPropagation();
77
77
  onClick?.(event);
78
78
  },
79
- className: (0, cnfast.cn)("flex shrink-0 items-center gap-1.5", className),
79
+ className: (0, cn.cn)("flex shrink-0 items-center gap-1.5", className),
80
80
  ...props
81
81
  }));
82
82
  ScheduleEntryActions.displayName = "ScheduleEntryActions";
@@ -88,7 +88,7 @@ const ScheduleEntryDelete = react.forwardRef(({ "aria-label": ariaLabel = "Delet
88
88
  event.stopPropagation();
89
89
  onClick?.(event);
90
90
  },
91
- className: (0, cnfast.cn)("inline-flex size-8 shrink-0 items-center justify-center rounded-full text-gray-light transition-colors hover:bg-base-error-soft hover:text-error focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className),
91
+ className: (0, cn.cn)("inline-flex size-8 shrink-0 items-center justify-center rounded-full text-gray-light transition-colors hover:bg-base-error-soft hover:text-error focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50", className),
92
92
  ...props,
93
93
  children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_epilot_spark_icons.Delete, { className: "[--spark-icon-size:14px]" })
94
94
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"schedule-list.cjs","names":["React","Add","Delete"],"sources":["../../src/components/schedule-list.tsx"],"sourcesContent":["import { Add, Delete } from '@epilot/spark-icons'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\n\nconst ScheduleList = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*2)]',\n className,\n )}\n {...props}\n />\n))\n\nScheduleList.displayName = 'ScheduleList'\n\nconst ScheduleListEmpty = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('px-3 py-2 text-sm text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleListEmpty.displayName = 'ScheduleListEmpty'\n\ninterface ScheduleListAddProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Optional icon override; defaults to a `+`. */\n icon?: React.ReactNode\n}\n\nconst ScheduleListAdd = React.forwardRef<\n HTMLButtonElement,\n ScheduleListAddProps\n>(({ children, className, icon, type = 'button', ...props }, ref) => (\n <button\n ref={ref}\n type={type}\n className={cn(\n 'inline-flex h-11 w-full items-center justify-center gap-1.5 rounded-lg border border-dashed border-gray text-sm font-medium text-gray-light transition-colors hover:border-spark-a8 hover:bg-base-accent-soft hover:text-accent focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {icon ?? <Add className=\"[--spark-icon-size:14px]\" />}\n {children}\n </button>\n))\n\nScheduleListAdd.displayName = 'ScheduleListAdd'\n\ninterface ScheduleEntryProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Make the row interactive — enables hover, role=button, keyboard activation. */\n onClick?: () => void\n disabled?: boolean\n}\n\nconst ScheduleEntry = React.forwardRef<HTMLDivElement, ScheduleEntryProps>(\n ({ children, className, disabled, onClick, ...props }, ref) => {\n const interactive = onClick !== undefined && !disabled\n // role, tab stop and key handler travel together -- the row is never\n // clickable without Enter/Space, and never focusable without a role\n const interaction = interactive\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onClick,\n onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onClick()\n }\n },\n }\n : undefined\n return (\n <div\n ref={ref}\n {...interaction}\n aria-disabled={disabled || undefined}\n className={cn(\n 'flex items-center gap-3 rounded-lg bg-base-gray-soft px-3 py-2.5 transition-colors motion-reduce:transition-none',\n interactive &&\n 'cursor-pointer touch-target-row hover:bg-gray-a3 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',\n disabled && 'cursor-not-allowed opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n },\n)\n\nScheduleEntry.displayName = 'ScheduleEntry'\n\nconst ScheduleEntryContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex min-w-0 flex-1 flex-col gap-0.5', className)}\n {...props}\n />\n))\n\nScheduleEntryContent.displayName = 'ScheduleEntryContent'\n\nconst ScheduleEntryTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex min-w-0 items-center gap-2 truncate text-sm font-medium text-gray',\n className,\n )}\n {...props}\n />\n))\n\nScheduleEntryTitle.displayName = 'ScheduleEntryTitle'\n\nconst ScheduleEntrySubtitle = React.forwardRef<\n HTMLSpanElement,\n React.HTMLAttributes<HTMLSpanElement>\n>(({ className, ...props }, ref) => (\n <span\n ref={ref}\n className={cn('truncate text-xs text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleEntrySubtitle.displayName = 'ScheduleEntrySubtitle'\n\n/** Right-aligned action area. Stops click propagation so inner controls\n * don't fire the parent `ScheduleEntry`'s `onClick`. */\nconst ScheduleEntryActions = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, onClick, ...props }, ref) => (\n <div\n ref={ref}\n // a layout wrapper, not a control: the handler only shields the inner\n // buttons' clicks (keyboard activation included) from the parent row\n role=\"presentation\"\n onClick={(event) => {\n event.stopPropagation()\n onClick?.(event)\n }}\n className={cn('flex shrink-0 items-center gap-1.5', className)}\n {...props}\n />\n))\n\nScheduleEntryActions.displayName = 'ScheduleEntryActions'\n\ninterface ScheduleEntryDeleteProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}\n\nconst ScheduleEntryDelete = React.forwardRef<\n HTMLButtonElement,\n ScheduleEntryDeleteProps\n>(\n (\n {\n 'aria-label': ariaLabel = 'Delete schedule entry',\n children,\n className,\n onClick,\n type = 'button',\n ...props\n },\n ref,\n ) => (\n <button\n ref={ref}\n type={type}\n aria-label={ariaLabel}\n onClick={(event) => {\n event.stopPropagation()\n onClick?.(event)\n }}\n className={cn(\n 'inline-flex size-8 shrink-0 items-center justify-center rounded-full text-gray-light transition-colors hover:bg-base-error-soft hover:text-error focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {children ?? <Delete className=\"[--spark-icon-size:14px]\" />}\n </button>\n ),\n)\n\nScheduleEntryDelete.displayName = 'ScheduleEntryDelete'\n\nexport {\n ScheduleEntry,\n ScheduleEntryActions,\n ScheduleEntryContent,\n ScheduleEntryDelete,\n ScheduleEntrySubtitle,\n ScheduleEntryTitle,\n ScheduleList,\n ScheduleListAdd,\n ScheduleListEmpty,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"schedule-list.cjs","names":["React","Add","Delete"],"sources":["../../src/components/schedule-list.tsx"],"sourcesContent":["import { Add, Delete } from '@epilot/spark-icons'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\n\nconst ScheduleList = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-[calc(var(--spark-layout-gap)*2)]',\n className,\n )}\n {...props}\n />\n))\n\nScheduleList.displayName = 'ScheduleList'\n\nconst ScheduleListEmpty = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <p\n ref={ref}\n className={cn('px-3 py-2 text-sm text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleListEmpty.displayName = 'ScheduleListEmpty'\n\ninterface ScheduleListAddProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Optional icon override; defaults to a `+`. */\n icon?: React.ReactNode\n}\n\nconst ScheduleListAdd = React.forwardRef<\n HTMLButtonElement,\n ScheduleListAddProps\n>(({ children, className, icon, type = 'button', ...props }, ref) => (\n <button\n ref={ref}\n type={type}\n className={cn(\n 'inline-flex h-11 w-full items-center justify-center gap-1.5 rounded-lg border border-dashed border-gray text-sm font-medium text-gray-light transition-colors hover:border-spark-a8 hover:bg-base-accent-soft hover:text-accent focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {icon ?? <Add className=\"[--spark-icon-size:14px]\" />}\n {children}\n </button>\n))\n\nScheduleListAdd.displayName = 'ScheduleListAdd'\n\ninterface ScheduleEntryProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Make the row interactive — enables hover, role=button, keyboard activation. */\n onClick?: () => void\n disabled?: boolean\n}\n\nconst ScheduleEntry = React.forwardRef<HTMLDivElement, ScheduleEntryProps>(\n ({ children, className, disabled, onClick, ...props }, ref) => {\n const interactive = onClick !== undefined && !disabled\n // role, tab stop and key handler travel together -- the row is never\n // clickable without Enter/Space, and never focusable without a role\n const interaction = interactive\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onClick,\n onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onClick()\n }\n },\n }\n : undefined\n return (\n <div\n ref={ref}\n {...interaction}\n aria-disabled={disabled || undefined}\n className={cn(\n 'flex items-center gap-3 rounded-lg bg-base-gray-soft px-3 py-2.5 transition-colors motion-reduce:transition-none',\n interactive &&\n 'cursor-pointer touch-target-row hover:bg-gray-a3 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden',\n disabled && 'cursor-not-allowed opacity-50',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n )\n },\n)\n\nScheduleEntry.displayName = 'ScheduleEntry'\n\nconst ScheduleEntryContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn('flex min-w-0 flex-1 flex-col gap-0.5', className)}\n {...props}\n />\n))\n\nScheduleEntryContent.displayName = 'ScheduleEntryContent'\n\nconst ScheduleEntryTitle = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex min-w-0 items-center gap-2 truncate text-sm font-medium text-gray',\n className,\n )}\n {...props}\n />\n))\n\nScheduleEntryTitle.displayName = 'ScheduleEntryTitle'\n\nconst ScheduleEntrySubtitle = React.forwardRef<\n HTMLSpanElement,\n React.HTMLAttributes<HTMLSpanElement>\n>(({ className, ...props }, ref) => (\n <span\n ref={ref}\n className={cn('truncate text-xs text-gray-light', className)}\n {...props}\n />\n))\n\nScheduleEntrySubtitle.displayName = 'ScheduleEntrySubtitle'\n\n/** Right-aligned action area. Stops click propagation so inner controls\n * don't fire the parent `ScheduleEntry`'s `onClick`. */\nconst ScheduleEntryActions = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, onClick, ...props }, ref) => (\n <div\n ref={ref}\n // a layout wrapper, not a control: the handler only shields the inner\n // buttons' clicks (keyboard activation included) from the parent row\n role=\"presentation\"\n onClick={(event) => {\n event.stopPropagation()\n onClick?.(event)\n }}\n className={cn('flex shrink-0 items-center gap-1.5', className)}\n {...props}\n />\n))\n\nScheduleEntryActions.displayName = 'ScheduleEntryActions'\n\ninterface ScheduleEntryDeleteProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}\n\nconst ScheduleEntryDelete = React.forwardRef<\n HTMLButtonElement,\n ScheduleEntryDeleteProps\n>(\n (\n {\n 'aria-label': ariaLabel = 'Delete schedule entry',\n children,\n className,\n onClick,\n type = 'button',\n ...props\n },\n ref,\n ) => (\n <button\n ref={ref}\n type={type}\n aria-label={ariaLabel}\n onClick={(event) => {\n event.stopPropagation()\n onClick?.(event)\n }}\n className={cn(\n 'inline-flex size-8 shrink-0 items-center justify-center rounded-full text-gray-light transition-colors hover:bg-base-error-soft hover:text-error focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {children ?? <Delete className=\"[--spark-icon-size:14px]\" />}\n </button>\n ),\n)\n\nScheduleEntryDelete.displayName = 'ScheduleEntryDelete'\n\nexport {\n ScheduleEntry,\n ScheduleEntryActions,\n ScheduleEntryContent,\n ScheduleEntryDelete,\n ScheduleEntrySubtitle,\n ScheduleEntryTitle,\n ScheduleList,\n ScheduleListAdd,\n ScheduleListEmpty,\n}\n"],"mappings":";;;;;;;;;AAIA,MAAM,eAAeA,MAAM,YAGxB,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,OAAD;CACO;CACL,YAAA,GAAA,GAAA,IACE,uDACA,SACF;CACA,GAAI;AACL,CAAA,CACF;AAED,aAAa,cAAc;AAE3B,MAAM,oBAAoBA,MAAM,YAG7B,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,KAAD;CACO;CACL,YAAA,GAAA,GAAA,IAAc,qCAAqC,SAAS;CAC5D,GAAI;AACL,CAAA,CACF;AAED,kBAAkB,cAAc;AAOhC,MAAM,kBAAkBA,MAAM,YAG3B,EAAE,UAAU,WAAW,MAAM,OAAO,UAAU,GAAG,SAAS,QAC3D,iBAAA,GAAA,kBAAA,MAAC,UAAD;CACO;CACC;CACN,YAAA,GAAA,GAAA,IACE,iWACA,SACF;CACA,GAAI;WAPN,CASG,QAAQ,iBAAA,GAAA,kBAAA,KAACC,oBAAAA,KAAD,EAAK,WAAU,2BAA4B,CAAA,GACnD,QACK;EACT;AAED,gBAAgB,cAAc;AAQ9B,MAAM,gBAAgBD,MAAM,YACzB,EAAE,UAAU,WAAW,UAAU,SAAS,GAAG,SAAS,QAAQ;CAC7D,MAAM,cAAc,YAAY,KAAA,KAAa,CAAC;CAgB9C,OACE,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACO;EACL,GAhBgB,cAChB;GACE,MAAM;GACN,UAAU;GACV;GACA,YAAY,UAA+C;IACzD,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;KAC9C,MAAM,eAAe;KACrB,QAAQ;IACV;GACF;EACF,IACA,KAAA;EAKA,iBAAe,YAAY,KAAA;EAC3B,YAAA,GAAA,GAAA,IACE,oHACA,eACE,kIACF,YAAY,iCACZ,SACF;EACA,GAAI;EAEH;CACE,CAAA;AAET,CACF;AAEA,cAAc,cAAc;AAE5B,MAAM,uBAAuBA,MAAM,YAGhC,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,OAAD;CACO;CACL,YAAA,GAAA,GAAA,IAAc,wCAAwC,SAAS;CAC/D,GAAI;AACL,CAAA,CACF;AAED,qBAAqB,cAAc;AAEnC,MAAM,qBAAqBA,MAAM,YAG9B,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,OAAD;CACO;CACL,YAAA,GAAA,GAAA,IACE,0EACA,SACF;CACA,GAAI;AACL,CAAA,CACF;AAED,mBAAmB,cAAc;AAEjC,MAAM,wBAAwBA,MAAM,YAGjC,EAAE,WAAW,GAAG,SAAS,QAC1B,iBAAA,GAAA,kBAAA,KAAC,QAAD;CACO;CACL,YAAA,GAAA,GAAA,IAAc,oCAAoC,SAAS;CAC3D,GAAI;AACL,CAAA,CACF;AAED,sBAAsB,cAAc;;;AAIpC,MAAM,uBAAuBA,MAAM,YAGhC,EAAE,WAAW,SAAS,GAAG,SAAS,QACnC,iBAAA,GAAA,kBAAA,KAAC,OAAD;CACO;CAGL,MAAK;CACL,UAAU,UAAU;EAClB,MAAM,gBAAgB;EACtB,UAAU,KAAK;CACjB;CACA,YAAA,GAAA,GAAA,IAAc,sCAAsC,SAAS;CAC7D,GAAI;AACL,CAAA,CACF;AAED,qBAAqB,cAAc;AAInC,MAAM,sBAAsBA,MAAM,YAK9B,EACE,cAAc,YAAY,yBAC1B,UACA,WACA,SACA,OAAO,UACP,GAAG,SAEL,QAEA,iBAAA,GAAA,kBAAA,KAAC,UAAD;CACO;CACC;CACN,cAAY;CACZ,UAAU,UAAU;EAClB,MAAM,gBAAgB;EACtB,UAAU,KAAK;CACjB;CACA,YAAA,GAAA,GAAA,IACE,kRACA,SACF;CACA,GAAI;WAEH,YAAY,iBAAA,GAAA,kBAAA,KAACE,oBAAAA,QAAD,EAAQ,WAAU,2BAA4B,CAAA;AACrD,CAAA,CAEZ;AAEA,oBAAoB,cAAc"}
@@ -5,12 +5,12 @@ let react = require("react");
5
5
  react = require_chunk.__toESM(react);
6
6
  let react_jsx_runtime = require("react/jsx-runtime");
7
7
  let _base_ui_react_scroll_area = require("@base-ui/react/scroll-area");
8
- let cnfast = require("cnfast");
8
+ let cn = require("cn");
9
9
  //#region src/components/scroll-area.tsx
10
10
  function ScrollArea({ className, children, ...props }) {
11
11
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_base_ui_react_scroll_area.ScrollArea.Root, {
12
12
  "data-slot": "scroll-area",
13
- className: (0, cnfast.cn)("relative", className),
13
+ className: (0, cn.cn)("relative", className),
14
14
  ...props,
15
15
  children: [
16
16
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_scroll_area.ScrollArea.Viewport, {
@@ -28,7 +28,7 @@ function ScrollBar({ className, orientation = "vertical", ...props }) {
28
28
  "data-slot": "scroll-area-scrollbar",
29
29
  "data-orientation": orientation,
30
30
  orientation,
31
- className: (0, cnfast.cn)("flex touch-none p-px transition-colors select-none data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:border-t data-[orientation=horizontal]:border-t-transparent data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2.5 data-[orientation=vertical]:border-l data-[orientation=vertical]:border-l-transparent", "opacity-0 transition-[color,background-color,opacity] delay-[600ms] duration-150 data-hovering:opacity-100 data-hovering:delay-0 data-scrolling:opacity-100 data-scrolling:delay-0 motion-reduce:transition-none", className),
31
+ className: (0, cn.cn)("flex touch-none p-px transition-colors select-none data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:border-t data-[orientation=horizontal]:border-t-transparent data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2.5 data-[orientation=vertical]:border-l data-[orientation=vertical]:border-l-transparent", "opacity-0 transition-[color,background-color,opacity] delay-[600ms] duration-150 data-hovering:opacity-100 data-hovering:delay-0 data-scrolling:opacity-100 data-scrolling:delay-0 motion-reduce:transition-none", className),
32
32
  ...props,
33
33
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_scroll_area.ScrollArea.Thumb, {
34
34
  "data-slot": "scroll-area-thumb",
@@ -1 +1 @@
1
- {"version":3,"file":"scroll-area.cjs","names":["ScrollAreaPrimitive"],"sources":["../../src/components/scroll-area.tsx"],"sourcesContent":["import { ScrollArea as ScrollAreaPrimitive } from '@base-ui/react/scroll-area'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\n\nfunction ScrollArea({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {\n return (\n <ScrollAreaPrimitive.Root\n data-slot=\"scroll-area\"\n className={cn('relative', className)}\n {...props}\n >\n <ScrollAreaPrimitive.Viewport\n data-slot=\"scroll-area-viewport\"\n className=\"size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden motion-reduce:transition-none\"\n >\n {children}\n </ScrollAreaPrimitive.Viewport>\n <ScrollBar />\n <ScrollAreaPrimitive.Corner />\n </ScrollAreaPrimitive.Root>\n )\n}\n\nfunction ScrollBar({\n className,\n orientation = 'vertical',\n ...props\n}: React.ComponentProps<typeof ScrollAreaPrimitive.Scrollbar>) {\n return (\n <ScrollAreaPrimitive.Scrollbar\n data-slot=\"scroll-area-scrollbar\"\n data-orientation={orientation}\n orientation={orientation}\n className={cn(\n 'flex touch-none p-px transition-colors select-none data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:border-t data-[orientation=horizontal]:border-t-transparent data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2.5 data-[orientation=vertical]:border-l data-[orientation=vertical]:border-l-transparent',\n // radix type=\"hover\" behavior: fade in on hover/scroll, fade out 600ms later\n 'opacity-0 transition-[color,background-color,opacity] delay-[600ms] duration-150 data-hovering:opacity-100 data-hovering:delay-0 data-scrolling:opacity-100 data-scrolling:delay-0 motion-reduce:transition-none',\n className,\n )}\n {...props}\n >\n <ScrollAreaPrimitive.Thumb\n data-slot=\"scroll-area-thumb\"\n className=\"relative flex-1 rounded-full bg-gray-a8 [[data-high-contrast]_&]:bg-gray-a11\"\n />\n </ScrollAreaPrimitive.Scrollbar>\n )\n}\n\n// Radix primitives for consumers that need a custom composition (e.g. an\n// aria-labelled focusable viewport or a horizontal-only scroll area)\nconst ScrollAreaRoot = ScrollAreaPrimitive.Root\nconst ScrollAreaViewport = ScrollAreaPrimitive.Viewport\nconst ScrollAreaScrollbar = ScrollAreaPrimitive.Scrollbar\nconst ScrollAreaThumb = ScrollAreaPrimitive.Thumb\nconst ScrollAreaCorner = ScrollAreaPrimitive.Corner\n\nexport {\n ScrollArea,\n ScrollAreaCorner,\n ScrollAreaRoot,\n ScrollAreaScrollbar,\n ScrollAreaThumb,\n ScrollAreaViewport,\n ScrollBar,\n}\n"],"mappings":";;;;;;;;;AAIA,SAAS,WAAW,EAClB,WACA,UACA,GAAG,SACqD;CACxD,OACE,iBAAA,GAAA,kBAAA,MAACA,2BAAAA,WAAoB,MAArB;EACE,aAAU;EACV,YAAA,GAAA,OAAA,IAAc,YAAY,SAAS;EACnC,GAAI;YAHN;GAKE,iBAAA,GAAA,kBAAA,KAACA,2BAAAA,WAAoB,UAArB;IACE,aAAU;IACV,WAAU;IAET;GAC2B,CAAA;GAC9B,iBAAA,GAAA,kBAAA,KAAC,WAAD,CAAY,CAAA;GACZ,iBAAA,GAAA,kBAAA,KAACA,2BAAAA,WAAoB,QAArB,CAA6B,CAAA;EACL;;AAE9B;AAEA,SAAS,UAAU,EACjB,WACA,cAAc,YACd,GAAG,SAC0D;CAC7D,OACE,iBAAA,GAAA,kBAAA,KAACA,2BAAAA,WAAoB,WAArB;EACE,aAAU;EACV,oBAAkB;EACL;EACb,YAAA,GAAA,OAAA,IACE,sXAEA,oNACA,SACF;EACA,GAAI;YAEJ,iBAAA,GAAA,kBAAA,KAACA,2BAAAA,WAAoB,OAArB;GACE,aAAU;GACV,WAAU;EACX,CAAA;CAC4B,CAAA;AAEnC;AAIA,MAAM,iBAAiBA,2BAAAA,WAAoB;AAC3C,MAAM,qBAAqBA,2BAAAA,WAAoB;AAC/C,MAAM,sBAAsBA,2BAAAA,WAAoB;AAChD,MAAM,kBAAkBA,2BAAAA,WAAoB;AAC5C,MAAM,mBAAmBA,2BAAAA,WAAoB"}
1
+ {"version":3,"file":"scroll-area.cjs","names":["ScrollAreaPrimitive"],"sources":["../../src/components/scroll-area.tsx"],"sourcesContent":["import { ScrollArea as ScrollAreaPrimitive } from '@base-ui/react/scroll-area'\nimport * as React from 'react'\nimport { cn } from '../utils/cn'\n\nfunction ScrollArea({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {\n return (\n <ScrollAreaPrimitive.Root\n data-slot=\"scroll-area\"\n className={cn('relative', className)}\n {...props}\n >\n <ScrollAreaPrimitive.Viewport\n data-slot=\"scroll-area-viewport\"\n className=\"size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden motion-reduce:transition-none\"\n >\n {children}\n </ScrollAreaPrimitive.Viewport>\n <ScrollBar />\n <ScrollAreaPrimitive.Corner />\n </ScrollAreaPrimitive.Root>\n )\n}\n\nfunction ScrollBar({\n className,\n orientation = 'vertical',\n ...props\n}: React.ComponentProps<typeof ScrollAreaPrimitive.Scrollbar>) {\n return (\n <ScrollAreaPrimitive.Scrollbar\n data-slot=\"scroll-area-scrollbar\"\n data-orientation={orientation}\n orientation={orientation}\n className={cn(\n 'flex touch-none p-px transition-colors select-none data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:border-t data-[orientation=horizontal]:border-t-transparent data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2.5 data-[orientation=vertical]:border-l data-[orientation=vertical]:border-l-transparent',\n // radix type=\"hover\" behavior: fade in on hover/scroll, fade out 600ms later\n 'opacity-0 transition-[color,background-color,opacity] delay-[600ms] duration-150 data-hovering:opacity-100 data-hovering:delay-0 data-scrolling:opacity-100 data-scrolling:delay-0 motion-reduce:transition-none',\n className,\n )}\n {...props}\n >\n <ScrollAreaPrimitive.Thumb\n data-slot=\"scroll-area-thumb\"\n className=\"relative flex-1 rounded-full bg-gray-a8 [[data-high-contrast]_&]:bg-gray-a11\"\n />\n </ScrollAreaPrimitive.Scrollbar>\n )\n}\n\n// Radix primitives for consumers that need a custom composition (e.g. an\n// aria-labelled focusable viewport or a horizontal-only scroll area)\nconst ScrollAreaRoot = ScrollAreaPrimitive.Root\nconst ScrollAreaViewport = ScrollAreaPrimitive.Viewport\nconst ScrollAreaScrollbar = ScrollAreaPrimitive.Scrollbar\nconst ScrollAreaThumb = ScrollAreaPrimitive.Thumb\nconst ScrollAreaCorner = ScrollAreaPrimitive.Corner\n\nexport {\n ScrollArea,\n ScrollAreaCorner,\n ScrollAreaRoot,\n ScrollAreaScrollbar,\n ScrollAreaThumb,\n ScrollAreaViewport,\n ScrollBar,\n}\n"],"mappings":";;;;;;;;;AAIA,SAAS,WAAW,EAClB,WACA,UACA,GAAG,SACqD;CACxD,OACE,iBAAA,GAAA,kBAAA,MAACA,2BAAAA,WAAoB,MAArB;EACE,aAAU;EACV,YAAA,GAAA,GAAA,IAAc,YAAY,SAAS;EACnC,GAAI;YAHN;GAKE,iBAAA,GAAA,kBAAA,KAACA,2BAAAA,WAAoB,UAArB;IACE,aAAU;IACV,WAAU;IAET;GAC2B,CAAA;GAC9B,iBAAA,GAAA,kBAAA,KAAC,WAAD,CAAY,CAAA;GACZ,iBAAA,GAAA,kBAAA,KAACA,2BAAAA,WAAoB,QAArB,CAA6B,CAAA;EACL;;AAE9B;AAEA,SAAS,UAAU,EACjB,WACA,cAAc,YACd,GAAG,SAC0D;CAC7D,OACE,iBAAA,GAAA,kBAAA,KAACA,2BAAAA,WAAoB,WAArB;EACE,aAAU;EACV,oBAAkB;EACL;EACb,YAAA,GAAA,GAAA,IACE,sXAEA,oNACA,SACF;EACA,GAAI;YAEJ,iBAAA,GAAA,kBAAA,KAACA,2BAAAA,WAAoB,OAArB;GACE,aAAU;GACV,WAAU;EACX,CAAA;CAC4B,CAAA;AAEnC;AAIA,MAAM,iBAAiBA,2BAAAA,WAAoB;AAC3C,MAAM,qBAAqBA,2BAAAA,WAAoB;AAC/C,MAAM,sBAAsBA,2BAAAA,WAAoB;AAChD,MAAM,kBAAkBA,2BAAAA,WAAoB;AAC5C,MAAM,mBAAmBA,2BAAAA,WAAoB"}
@@ -6,9 +6,9 @@ let react = require("react");
6
6
  react = require_chunk.__toESM(react);
7
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
8
  let _base_ui_react_tabs = require("@base-ui/react/tabs");
9
- let cnfast = require("cnfast");
9
+ let cn = require("cn");
10
10
  //#region src/components/segmented-control.tsx
11
- function SegmentedControl({ className, styleVariant = "solid", size = "default", children, ref, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...props }) {
11
+ const SegmentedControl = react.forwardRef(function SegmentedControl({ className, styleVariant = "solid", size = "default", children, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...props }, ref) {
12
12
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_tabs.Tabs.Root, {
13
13
  "data-slot": "segmented-control",
14
14
  ref,
@@ -19,24 +19,24 @@ function SegmentedControl({ className, styleVariant = "solid", size = "default",
19
19
  "data-size": size,
20
20
  "data-slot": "segmented-control-track",
21
21
  "data-style": styleVariant,
22
- className: (0, cnfast.cn)("group/segmented relative isolate flex w-full items-stretch p-1", "rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))]", "data-[style=soft]:bg-gray-a3 data-[style=solid]:bg-gray-a3", "data-[style=surface]:bg-gray-a2 data-[style=surface]:inset-ring data-[style=surface]:inset-ring-(--spark-style-border)", "data-[style=outline]:inset-ring data-[style=outline]:inset-ring-(--spark-style-border)", size === "small" && "h-9 text-sm", size === "default" && "h-10 text-base", size === "medium" && "h-11 text-base", className),
22
+ className: (0, cn.cn)("group/segmented relative isolate flex w-full items-stretch p-1", "rounded-[max(var(--spark-rounded-md),var(--spark-rounded-full))]", "data-[style=soft]:bg-gray-a3 data-[style=solid]:bg-gray-a3", "data-[style=surface]:bg-gray-a2 data-[style=surface]:inset-ring data-[style=surface]:inset-ring-(--spark-style-border)", "data-[style=outline]:inset-ring data-[style=outline]:inset-ring-(--spark-style-border)", size === "small" && "h-9 text-sm", size === "default" && "h-10 text-base", size === "medium" && "h-11 text-base", className),
23
23
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_tabs.Tabs.Indicator, {
24
24
  "data-slot": "segmented-control-indicator",
25
25
  renderBeforeHydration: true,
26
- className: (0, cnfast.cn)("pointer-events-none absolute top-(--active-tab-top) left-(--active-tab-left) z-0 h-(--active-tab-height) w-(--active-tab-width)", "rounded-[max(var(--spark-rounded-sm),var(--spark-rounded-full))]", "bg-gray-1 dark:bg-gray-a4", "group-data-[style=solid]/segmented:bg-(--spark-style-bg,var(--color-primary))", "shadow-[0_1px_2px_0_rgb(0_0_0/0.06),inset_0_0_0_var(--spark-style-border-width,1px)_var(--spark-style-border,transparent)]", "transition-[left,top,width,height] duration-200 ease-out motion-reduce:transition-none", "data-starting-style:transition-none")
26
+ className: (0, cn.cn)("pointer-events-none absolute top-(--active-tab-top) left-(--active-tab-left) z-0 h-(--active-tab-height) w-(--active-tab-width)", "rounded-[max(var(--spark-rounded-sm),var(--spark-rounded-full))]", "bg-gray-1 dark:bg-gray-a4", "group-data-[style=solid]/segmented:bg-(--spark-style-bg,var(--color-primary))", "shadow-[0_1px_2px_0_rgb(0_0_0/0.06),inset_0_0_0_var(--spark-style-border-width,1px)_var(--spark-style-border,transparent)]", "transition-[left,top,width,height] duration-200 ease-out motion-reduce:transition-none", "data-starting-style:transition-none")
27
27
  }), children]
28
28
  })
29
29
  });
30
- }
31
- function SegmentedControlItem({ className, children, ref, ...props }) {
30
+ });
31
+ const SegmentedControlItem = react.forwardRef(function SegmentedControlItem({ className, children, ...props }, ref) {
32
32
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_tabs.Tabs.Tab, {
33
33
  "data-slot": "segmented-control-item",
34
34
  ref,
35
- className: (0, cnfast.cn)("relative z-10 inline-flex h-full flex-1 basis-0 cursor-pointer items-center justify-center gap-1.5 font-medium whitespace-nowrap select-none", "touch-target", "rounded-[max(var(--spark-rounded-sm),var(--spark-rounded-full))]", "text-gray-a11 transition-colors motion-reduce:transition-none", "not-data-active:hover:text-gray-12", "data-active:text-(--spark-style-fg,var(--color-primary-foreground))", "focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:outline-hidden", "data-disabled:pointer-events-none data-disabled:text-gray-a8", "[&_svg]:pointer-events-none [&_svg]:shrink-0", "group-data-[size=small]/segmented:px-3 group-data-[size=small]/segmented:[--spark-icon-size:1rem] group-data-[size=small]/segmented:[&_svg:not([class*=size-])]:size-4", "group-data-[size=default]/segmented:px-3 group-data-[size=default]/segmented:[--spark-icon-size:1.25rem] group-data-[size=default]/segmented:[&_svg:not([class*=size-])]:size-5", "group-data-[size=medium]/segmented:px-4 group-data-[size=medium]/segmented:[--spark-icon-size:1.5rem] group-data-[size=medium]/segmented:[&_svg:not([class*=size-])]:size-6", className),
35
+ className: (0, cn.cn)("relative z-10 inline-flex h-full flex-1 basis-0 cursor-pointer items-center justify-center gap-1.5 font-medium whitespace-nowrap select-none", "touch-target", "rounded-[max(var(--spark-rounded-sm),var(--spark-rounded-full))]", "text-gray-a11 transition-colors motion-reduce:transition-none", "not-data-active:hover:text-gray-12", "data-active:text-(--spark-style-fg,var(--color-primary-foreground))", "focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:outline-hidden", "data-disabled:pointer-events-none data-disabled:text-gray-a8", "[&_svg]:pointer-events-none [&_svg]:shrink-0", "group-data-[size=small]/segmented:px-3 group-data-[size=small]/segmented:[--spark-icon-size:1rem] group-data-[size=small]/segmented:[&_svg:not([class*=size-])]:size-4", "group-data-[size=default]/segmented:px-3 group-data-[size=default]/segmented:[--spark-icon-size:1.25rem] group-data-[size=default]/segmented:[&_svg:not([class*=size-])]:size-5", "group-data-[size=medium]/segmented:px-4 group-data-[size=medium]/segmented:[--spark-icon-size:1.5rem] group-data-[size=medium]/segmented:[&_svg:not([class*=size-])]:size-6", className),
36
36
  ...props,
37
37
  children
38
38
  });
39
- }
39
+ });
40
40
  //#endregion
41
41
  exports.SegmentedControl = SegmentedControl;
42
42
  exports.SegmentedControlItem = SegmentedControlItem;