sparkdesign 0.4.6 → 0.4.8

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 (276) hide show
  1. package/AI_README.md +60 -0
  2. package/README.md +1 -1
  3. package/cli/dist/commands/add.js +1 -1
  4. package/cli/dist/commands/init.js +1 -1
  5. package/cli/registry/AGENTS.md +9 -2
  6. package/cli/registry/agent-manifest.json +794 -0
  7. package/cli/registry/basic/alert-dialog.tsx +3 -6
  8. package/cli/registry/basic/alert.tsx +76 -0
  9. package/cli/registry/basic/aspect-ratio.tsx +8 -0
  10. package/cli/registry/basic/breadcrumb.tsx +117 -0
  11. package/cli/registry/basic/button-group.tsx +79 -0
  12. package/cli/registry/basic/button.tsx +19 -6
  13. package/cli/registry/basic/calendar.tsx +221 -0
  14. package/cli/registry/basic/card.tsx +115 -0
  15. package/cli/registry/basic/carousel.tsx +241 -0
  16. package/cli/registry/basic/chart.tsx +372 -0
  17. package/cli/registry/basic/checkbox.tsx +42 -0
  18. package/cli/registry/basic/collapsible-card.tsx +4 -6
  19. package/cli/registry/basic/combobox.tsx +133 -0
  20. package/cli/registry/basic/command.tsx +184 -0
  21. package/cli/registry/basic/context-menu.tsx +238 -0
  22. package/cli/registry/basic/data-table.tsx +73 -0
  23. package/cli/registry/basic/date-picker.tsx +84 -0
  24. package/cli/registry/basic/dialog.tsx +164 -0
  25. package/cli/registry/basic/direction.tsx +25 -0
  26. package/cli/registry/basic/drawer.tsx +162 -0
  27. package/cli/registry/basic/dropdown-menu.tsx +2 -7
  28. package/cli/registry/basic/empty.tsx +104 -0
  29. package/cli/registry/basic/field.tsx +248 -0
  30. package/cli/registry/basic/hover-card.tsx +57 -0
  31. package/cli/registry/basic/icon-button.tsx +18 -11
  32. package/cli/registry/basic/input-group.tsx +168 -0
  33. package/cli/registry/basic/input-otp.tsx +75 -0
  34. package/cli/registry/basic/input.tsx +43 -0
  35. package/cli/registry/basic/item.tsx +204 -0
  36. package/cli/registry/basic/label.tsx +24 -0
  37. package/cli/registry/basic/menubar.tsx +274 -0
  38. package/cli/registry/basic/native-select.tsx +62 -0
  39. package/cli/registry/basic/navigation-menu.tsx +168 -0
  40. package/cli/registry/basic/popover.tsx +58 -0
  41. package/cli/registry/basic/scroll-area.tsx +58 -0
  42. package/cli/registry/basic/select.tsx +24 -3
  43. package/cli/registry/basic/separator.tsx +26 -0
  44. package/cli/registry/basic/sheet.tsx +18 -0
  45. package/cli/registry/basic/spinner.tsx +20 -5
  46. package/cli/registry/basic/textarea.tsx +43 -0
  47. package/cli/registry/basic/toggle.tsx +1 -1
  48. package/cli/registry/basic/tooltip.tsx +2 -1
  49. package/cli/registry/basic/typography.tsx +1 -1
  50. package/cli/registry/chat/chat-input/chat-input-textarea.tsx +1 -1
  51. package/cli/registry/chat/chat-input/compound.tsx +4 -3
  52. package/cli/registry/chat/chat-input/context.tsx +4 -1
  53. package/cli/registry/chat/code-block-part.tsx +1 -1
  54. package/cli/registry/chat/conversation-anchor-nav.tsx +349 -0
  55. package/cli/registry/chat/file-attachment.tsx +2 -1
  56. package/cli/registry/chat/file-review-part.tsx +21 -21
  57. package/cli/registry/chat/markdown.tsx +2 -2
  58. package/cli/registry/chat/queue-indicator.tsx +1 -0
  59. package/cli/registry/chat/streaming-markdown-block.tsx +12 -8
  60. package/cli/registry/chat/tool-invocation-card.tsx +4 -1
  61. package/cli/registry/lib/file-icon-maps.ts +22 -22
  62. package/cli/registry/meta.json +600 -15
  63. package/cli/registry/tokens/ontology.json +404 -0
  64. package/cli/registry/tokens/scale/presets/compact.css +16 -5
  65. package/cli/registry/tokens/scale/presets/dense.css +13 -2
  66. package/cli/registry/tokens/scale/presets/sharp.css +18 -6
  67. package/cli/registry/tokens/scale/presets/soft.css +23 -1
  68. package/dist/registry/basic/alert-dialog.d.ts +1 -1
  69. package/dist/registry/basic/alert.d.ts +24 -0
  70. package/dist/registry/basic/aspect-ratio.d.ts +16 -0
  71. package/dist/registry/basic/avatar.d.ts +1 -1
  72. package/dist/registry/basic/breadcrumb.d.ts +24 -0
  73. package/dist/registry/basic/button-group.d.ts +26 -0
  74. package/dist/registry/basic/button.d.ts +3 -1
  75. package/dist/registry/basic/calendar.d.ts +22 -0
  76. package/dist/registry/basic/card.d.ts +32 -0
  77. package/dist/registry/basic/carousel.d.ts +19 -0
  78. package/dist/registry/basic/chart.d.ts +55 -0
  79. package/dist/registry/basic/checkbox.d.ts +21 -0
  80. package/dist/registry/basic/combobox.d.ts +37 -0
  81. package/dist/registry/basic/command.d.ts +18 -0
  82. package/dist/registry/basic/context-menu.d.ts +44 -0
  83. package/dist/registry/basic/data-table.d.ts +26 -0
  84. package/dist/registry/basic/date-picker.d.ts +27 -0
  85. package/dist/registry/basic/dialog.d.ts +39 -0
  86. package/dist/registry/basic/direction.d.ts +19 -0
  87. package/dist/registry/basic/drawer.d.ts +37 -0
  88. package/dist/registry/basic/empty.d.ts +22 -0
  89. package/dist/registry/basic/field.d.ts +24 -0
  90. package/dist/registry/basic/hover-card.d.ts +22 -0
  91. package/dist/registry/basic/icon-button.d.ts +2 -1
  92. package/dist/registry/basic/input-group.d.ts +29 -0
  93. package/dist/registry/basic/input-otp.d.ts +22 -0
  94. package/dist/registry/basic/input.d.ts +20 -0
  95. package/dist/registry/basic/item.d.ts +34 -0
  96. package/dist/registry/basic/label.d.ts +16 -0
  97. package/dist/registry/basic/menubar.d.ts +37 -0
  98. package/dist/registry/basic/native-select.d.ts +18 -0
  99. package/dist/registry/basic/navigation-menu.d.ts +25 -0
  100. package/dist/registry/basic/popover.d.ts +23 -0
  101. package/dist/registry/basic/resizable.d.ts +48 -48
  102. package/dist/registry/basic/scroll-area.d.ts +5 -0
  103. package/dist/registry/basic/select.d.ts +7 -2
  104. package/dist/registry/basic/separator.d.ts +16 -0
  105. package/dist/registry/basic/sheet.d.ts +13 -0
  106. package/dist/registry/basic/spinner.d.ts +6 -2
  107. package/dist/registry/basic/tag.d.ts +1 -1
  108. package/dist/registry/basic/textarea.d.ts +21 -0
  109. package/dist/registry/chat/chat-input/context.d.ts +3 -1
  110. package/dist/registry/chat/conversation-anchor-nav.d.ts +72 -0
  111. package/dist/registry/chat/tool-invocation-card.d.ts +2 -0
  112. package/dist/scale/computed.css +11 -0
  113. package/dist/scale/config.css +11 -0
  114. package/dist/scale/presets/compact.css +23 -5
  115. package/dist/scale/presets/dense.css +20 -2
  116. package/dist/scale/presets/sharp.css +25 -6
  117. package/dist/scale/presets/soft.css +30 -1
  118. package/dist/spark-design.cjs.js +37 -33
  119. package/dist/spark-design.es.js +10324 -8950
  120. package/dist/sparkdesign.css +1 -1
  121. package/dist/src/components/basic/Alert/index.d.ts +13 -0
  122. package/dist/src/components/basic/AspectRatio/index.d.ts +13 -0
  123. package/dist/src/components/basic/Breadcrumb/index.d.ts +12 -0
  124. package/dist/src/components/basic/ButtonGroup/index.d.ts +13 -0
  125. package/dist/src/components/basic/Calendar/index.d.ts +13 -0
  126. package/dist/src/components/basic/Card/index.d.ts +13 -0
  127. package/dist/src/components/basic/Carousel/index.d.ts +12 -0
  128. package/dist/src/components/basic/Chart/index.d.ts +13 -0
  129. package/dist/src/components/basic/Checkbox/index.d.ts +13 -0
  130. package/dist/src/components/basic/Combobox/index.d.ts +13 -0
  131. package/dist/src/components/basic/Command/index.d.ts +12 -0
  132. package/dist/src/components/basic/ContextMenu/index.d.ts +19 -0
  133. package/dist/src/components/basic/DataTable/index.d.ts +13 -0
  134. package/dist/src/components/basic/DatePicker/index.d.ts +13 -0
  135. package/dist/src/components/basic/Dialog/index.d.ts +16 -0
  136. package/dist/src/components/basic/Direction/index.d.ts +13 -0
  137. package/dist/src/components/basic/Drawer/index.d.ts +16 -0
  138. package/dist/src/components/basic/Empty/index.d.ts +12 -0
  139. package/dist/src/components/basic/Field/index.d.ts +12 -0
  140. package/dist/src/components/basic/HoverCard/index.d.ts +16 -0
  141. package/dist/src/components/basic/Input/index.d.ts +13 -0
  142. package/dist/src/components/basic/InputGroup/index.d.ts +12 -0
  143. package/dist/src/components/basic/InputOTP/index.d.ts +12 -0
  144. package/dist/src/components/basic/Item/index.d.ts +12 -0
  145. package/dist/src/components/basic/Label/index.d.ts +13 -0
  146. package/dist/src/components/basic/Menubar/index.d.ts +12 -0
  147. package/dist/src/components/basic/NativeSelect/index.d.ts +12 -0
  148. package/dist/src/components/basic/NavigationMenu/index.d.ts +12 -0
  149. package/dist/src/components/basic/Popover/index.d.ts +16 -0
  150. package/dist/src/components/basic/ScrollArea/index.d.ts +12 -0
  151. package/dist/src/components/basic/Separator/index.d.ts +13 -0
  152. package/dist/src/components/basic/Sheet/index.d.ts +13 -0
  153. package/dist/src/components/basic/Textarea/index.d.ts +13 -0
  154. package/dist/src/components/chat/ConversationAnchorNav/index.d.ts +13 -0
  155. package/dist/src/components/chat/StreamingMarkdownBlock/index.d.ts +13 -0
  156. package/dist/src/components/index.d.ts +58 -1
  157. package/dist/src/lib/index.d.ts +1 -1
  158. package/dist/src/lib/motion.d.ts +79 -0
  159. package/dist/theme-base.css +22 -0
  160. package/dist/themes/dark-mint.css +6 -0
  161. package/dist/themes/dark-parchment.css +6 -0
  162. package/dist/themes/light-parchment.css +6 -0
  163. package/dist/tokens/AGENTS.md +1 -0
  164. package/dist/tokens/scale/computed.css +11 -0
  165. package/dist/tokens/scale/config.css +11 -0
  166. package/dist/tokens/scale/presets/compact.css +23 -5
  167. package/dist/tokens/scale/presets/dense.css +20 -2
  168. package/dist/tokens/scale/presets/sharp.css +25 -6
  169. package/dist/tokens/scale/presets/soft.css +30 -1
  170. package/dist/tokens/theme-base.css +22 -0
  171. package/dist/tokens/themes/dark-mint.css +6 -0
  172. package/dist/tokens/themes/dark-parchment.css +6 -0
  173. package/dist/tokens/themes/light-parchment.css +6 -0
  174. package/docs/agent/component-selection.md +60 -0
  175. package/docs/agent/token-ontology.md +37 -0
  176. package/package.json +31 -5
  177. package/registry/agent-manifest.json +794 -0
  178. package/registry/tokens/ontology.json +404 -0
  179. package/dist/_basePickBy-DnQN8w3y.js +0 -151
  180. package/dist/_basePickBy-a-kPMlkg.cjs +0 -1
  181. package/dist/_baseUniq-B-N2NQ50.js +0 -614
  182. package/dist/_baseUniq-Cc_zbSif.cjs +0 -1
  183. package/dist/arc-BQBhijZ6.js +0 -83
  184. package/dist/arc-mWQt0Yph.cjs +0 -1
  185. package/dist/architectureDiagram-VXUJARFQ-BMZEucno.cjs +0 -36
  186. package/dist/architectureDiagram-VXUJARFQ-DTdjD3Bp.js +0 -4661
  187. package/dist/blockDiagram-VD42YOAC-CzHn0yob.js +0 -2256
  188. package/dist/blockDiagram-VD42YOAC-DDxdHAlz.cjs +0 -122
  189. package/dist/c4Diagram-YG6GDRKO-4Gz0I4gj.cjs +0 -10
  190. package/dist/c4Diagram-YG6GDRKO-BIy--yVN.js +0 -1580
  191. package/dist/channel-BQn0o8bs.js +0 -5
  192. package/dist/channel-DaN7XniJ.cjs +0 -1
  193. package/dist/chunk-4BX2VUAB-BlQFTQqz.cjs +0 -1
  194. package/dist/chunk-4BX2VUAB-Czitj3Kc.js +0 -8
  195. package/dist/chunk-55IACEB6-DXacNZbO.js +0 -8
  196. package/dist/chunk-55IACEB6-DnDxpye9.cjs +0 -1
  197. package/dist/chunk-B4BG7PRW-CBdN0q_V.js +0 -1375
  198. package/dist/chunk-B4BG7PRW-DbGvUkGO.cjs +0 -165
  199. package/dist/chunk-DI55MBZ5-D1YJMs6x.cjs +0 -220
  200. package/dist/chunk-DI55MBZ5-NCQTvayw.js +0 -1370
  201. package/dist/chunk-FMBD7UC4-CsGMbrtr.js +0 -19
  202. package/dist/chunk-FMBD7UC4-Di7cUUh5.cjs +0 -15
  203. package/dist/chunk-QN33PNHL-0j5LC8Lm.cjs +0 -1
  204. package/dist/chunk-QN33PNHL-3GERZBRm.js +0 -19
  205. package/dist/chunk-QZHKN3VN-AVEY9ImQ.js +0 -15
  206. package/dist/chunk-QZHKN3VN-s8Z0a8mc.cjs +0 -1
  207. package/dist/chunk-TZMSLE5B-CAf87HPt.cjs +0 -1
  208. package/dist/chunk-TZMSLE5B-sbiflal0.js +0 -64
  209. package/dist/classDiagram-2ON5EDUG-Ct9JLIN2.cjs +0 -1
  210. package/dist/classDiagram-2ON5EDUG-Dzfrft3a.js +0 -16
  211. package/dist/classDiagram-v2-WZHVMYZB-Ct9JLIN2.cjs +0 -1
  212. package/dist/classDiagram-v2-WZHVMYZB-Dzfrft3a.js +0 -16
  213. package/dist/clone-Cde_NQ8V.js +0 -8
  214. package/dist/clone-DCNjWuM2.cjs +0 -1
  215. package/dist/cose-bilkent-S5V4N54A-0uLijMro.cjs +0 -1
  216. package/dist/cose-bilkent-S5V4N54A-Bb08N431.js +0 -2608
  217. package/dist/cytoscape.esm-CNUX3VTg.cjs +0 -321
  218. package/dist/cytoscape.esm-Cvf3sx9F.js +0 -18704
  219. package/dist/dagre-6UL2VRFP-CY_Wz5Zd.js +0 -444
  220. package/dist/dagre-6UL2VRFP-Dxe7_qZc.cjs +0 -4
  221. package/dist/defaultLocale-BgPVtth8.js +0 -171
  222. package/dist/defaultLocale-C4wbwF1n.cjs +0 -1
  223. package/dist/diagram-PSM6KHXK-D2bdb7MT.js +0 -531
  224. package/dist/diagram-PSM6KHXK-YF69SUjY.cjs +0 -24
  225. package/dist/diagram-QEK2KX5R-BpUSoh0-.js +0 -217
  226. package/dist/diagram-QEK2KX5R-DZPGteon.cjs +0 -43
  227. package/dist/diagram-S2PKOQOG-ht-zdvFG.cjs +0 -24
  228. package/dist/diagram-S2PKOQOG-zFeLJ50Z.js +0 -142
  229. package/dist/erDiagram-Q2GNP2WA-B38iJ6ts.js +0 -841
  230. package/dist/erDiagram-Q2GNP2WA-RgS80DDU.cjs +0 -60
  231. package/dist/flowDiagram-NV44I4VS-BHilOs2p.cjs +0 -162
  232. package/dist/flowDiagram-NV44I4VS-BrBJcoce.js +0 -1620
  233. package/dist/ganttDiagram-JELNMOA3-pZiJeFio.cjs +0 -267
  234. package/dist/ganttDiagram-JELNMOA3-tw6FhkWJ.js +0 -2670
  235. package/dist/gitGraphDiagram-V2S2FVAM-BWn5uIK5.js +0 -699
  236. package/dist/gitGraphDiagram-V2S2FVAM-DKKeG-9R.cjs +0 -65
  237. package/dist/graph-DIbblrZP.cjs +0 -1
  238. package/dist/graph-DPcK91G3.js +0 -247
  239. package/dist/infoDiagram-HS3SLOUP-B8gwwhct.cjs +0 -2
  240. package/dist/infoDiagram-HS3SLOUP-D47PNcP_.js +0 -24
  241. package/dist/init-CHZsXQcr.cjs +0 -1
  242. package/dist/init-DjUOC4st.js +0 -16
  243. package/dist/journeyDiagram-XKPGCS4Q-BG3cfhyU.js +0 -834
  244. package/dist/journeyDiagram-XKPGCS4Q-D8DVLJof.cjs +0 -139
  245. package/dist/kanban-definition-3W4ZIXB7-4OCnEouP.cjs +0 -89
  246. package/dist/kanban-definition-3W4ZIXB7-CWi_ssF9.js +0 -719
  247. package/dist/layout-Byuh8f-J.cjs +0 -1
  248. package/dist/layout-CdLdvj1j.js +0 -1335
  249. package/dist/linear-C2Q_PI9B.js +0 -259
  250. package/dist/linear-C69aPBW1.cjs +0 -1
  251. package/dist/mermaid.core-DBwAx_jp.cjs +0 -249
  252. package/dist/mermaid.core-gFR0XUlD.js +0 -15300
  253. package/dist/mindmap-definition-VGOIOE7T-8P7obVV4.cjs +0 -68
  254. package/dist/mindmap-definition-VGOIOE7T-DnOa7WJ9.js +0 -784
  255. package/dist/ordinal-B6-f3MAq.js +0 -61
  256. package/dist/ordinal-CagbB1m8.cjs +0 -1
  257. package/dist/pieDiagram-ADFJNKIX-5NAlvhMo.js +0 -161
  258. package/dist/pieDiagram-ADFJNKIX-CQBG4yR9.cjs +0 -30
  259. package/dist/quadrantDiagram-AYHSOK5B-Oe4y7RZ0.cjs +0 -7
  260. package/dist/quadrantDiagram-AYHSOK5B-rh2DPEP1.js +0 -1022
  261. package/dist/requirementDiagram-UZGBJVZJ-DcWaCuXr.js +0 -850
  262. package/dist/requirementDiagram-UZGBJVZJ-gfdlrFiq.cjs +0 -64
  263. package/dist/sankeyDiagram-TZEHDZUN-CQIKFwD0.js +0 -810
  264. package/dist/sankeyDiagram-TZEHDZUN-DvPtzQvC.cjs +0 -10
  265. package/dist/sequenceDiagram-WL72ISMW-BNrsMagL.cjs +0 -145
  266. package/dist/sequenceDiagram-WL72ISMW-iCX3ckKx.js +0 -2511
  267. package/dist/stateDiagram-FKZM4ZOC-DBvJ_eeL.cjs +0 -1
  268. package/dist/stateDiagram-FKZM4ZOC-ZVsJlaHJ.js +0 -263
  269. package/dist/stateDiagram-v2-4FDKWEC3-CB_nTHcE.js +0 -16
  270. package/dist/stateDiagram-v2-4FDKWEC3-Xkx17v6T.cjs +0 -1
  271. package/dist/timeline-definition-IT6M3QCI-BmGkYQiz.cjs +0 -61
  272. package/dist/timeline-definition-IT6M3QCI-Ck8zTt6w.js +0 -795
  273. package/dist/treemap-GDKQZRPO-B9sfERx8.js +0 -17922
  274. package/dist/treemap-GDKQZRPO-BVfJRs0Z.cjs +0 -160
  275. package/dist/xychartDiagram-PRI3JC2R-By_S8NzN.js +0 -1340
  276. package/dist/xychartDiagram-PRI3JC2R-CNfDrGxM.cjs +0 -7
@@ -0,0 +1,372 @@
1
+ import * as React from "react"
2
+ import * as RechartsPrimitive from "recharts"
3
+ import type { TooltipValueType } from "recharts"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ // Format: { THEME_NAME: CSS_SELECTOR }
8
+ const THEMES = { light: "", dark: ".dark" } as const
9
+
10
+ const INITIAL_DIMENSION = { width: 320, height: 200 } as const
11
+ type TooltipNameType = number | string
12
+
13
+ export type ChartConfig = Record<
14
+ string,
15
+ {
16
+ label?: React.ReactNode
17
+ icon?: React.ComponentType
18
+ } & (
19
+ | { color?: string; theme?: never }
20
+ | { color?: never; theme: Record<keyof typeof THEMES, string> }
21
+ )
22
+ >
23
+
24
+ type ChartContextProps = {
25
+ config: ChartConfig
26
+ }
27
+
28
+ const ChartContext = React.createContext<ChartContextProps | null>(null)
29
+
30
+ function useChart() {
31
+ const context = React.useContext(ChartContext)
32
+
33
+ if (!context) {
34
+ throw new Error("useChart must be used within a <ChartContainer />")
35
+ }
36
+
37
+ return context
38
+ }
39
+
40
+ function ChartContainer({
41
+ id,
42
+ className,
43
+ children,
44
+ config,
45
+ initialDimension = INITIAL_DIMENSION,
46
+ ...props
47
+ }: React.ComponentProps<"div"> & {
48
+ config: ChartConfig
49
+ children: React.ComponentProps<
50
+ typeof RechartsPrimitive.ResponsiveContainer
51
+ >["children"]
52
+ initialDimension?: {
53
+ width: number
54
+ height: number
55
+ }
56
+ }) {
57
+ const uniqueId = React.useId()
58
+ const chartId = `chart-${id ?? uniqueId.replace(/:/g, "")}`
59
+
60
+ return (
61
+ <ChartContext.Provider value={{ config }}>
62
+ <div
63
+ data-slot="chart"
64
+ data-chart={chartId}
65
+ className={cn(
66
+ "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-text-tertiary [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-layer]:outline-none [&_.recharts-radial-bar-background-sector]:fill-fill-tertiary [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-fill-tertiary [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
67
+ className
68
+ )}
69
+ {...props}
70
+ >
71
+ <ChartStyle id={chartId} config={config} />
72
+ <RechartsPrimitive.ResponsiveContainer
73
+ initialDimension={initialDimension}
74
+ >
75
+ {children}
76
+ </RechartsPrimitive.ResponsiveContainer>
77
+ </div>
78
+ </ChartContext.Provider>
79
+ )
80
+ }
81
+
82
+ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
83
+ const colorConfig = Object.entries(config).filter(
84
+ ([, config]) => config.theme ?? config.color
85
+ )
86
+
87
+ if (!colorConfig.length) {
88
+ return null
89
+ }
90
+
91
+ return (
92
+ <style
93
+ dangerouslySetInnerHTML={{
94
+ __html: Object.entries(THEMES)
95
+ .map(
96
+ ([theme, prefix]) => `
97
+ ${prefix} [data-chart=${id}] {
98
+ ${colorConfig
99
+ .map(([key, itemConfig]) => {
100
+ const color =
101
+ itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ??
102
+ itemConfig.color
103
+ return color ? ` --color-${key}: ${color};` : null
104
+ })
105
+ .join("\n")}
106
+ }
107
+ `
108
+ )
109
+ .join("\n"),
110
+ }}
111
+ />
112
+ )
113
+ }
114
+
115
+ const ChartTooltip = RechartsPrimitive.Tooltip
116
+
117
+ function ChartTooltipContent({
118
+ active,
119
+ payload,
120
+ className,
121
+ indicator = "dot",
122
+ hideLabel = false,
123
+ hideIndicator = false,
124
+ label,
125
+ labelFormatter,
126
+ labelClassName,
127
+ formatter,
128
+ color,
129
+ nameKey,
130
+ labelKey,
131
+ }: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
132
+ React.ComponentProps<"div"> & {
133
+ hideLabel?: boolean
134
+ hideIndicator?: boolean
135
+ indicator?: "line" | "dot" | "dashed"
136
+ nameKey?: string
137
+ labelKey?: string
138
+ } & Omit<
139
+ RechartsPrimitive.DefaultTooltipContentProps<
140
+ TooltipValueType,
141
+ TooltipNameType
142
+ >,
143
+ "accessibilityLayer"
144
+ >) {
145
+ const { config } = useChart()
146
+
147
+ const tooltipLabel = React.useMemo(() => {
148
+ if (hideLabel || !payload?.length) {
149
+ return null
150
+ }
151
+
152
+ const [item] = payload
153
+ const key = `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}`
154
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
155
+ const value =
156
+ !labelKey && typeof label === "string"
157
+ ? (config[label]?.label ?? label)
158
+ : itemConfig?.label
159
+
160
+ if (labelFormatter) {
161
+ return (
162
+ <div className={cn("font-medium", labelClassName)}>
163
+ {labelFormatter(value, payload)}
164
+ </div>
165
+ )
166
+ }
167
+
168
+ if (!value) {
169
+ return null
170
+ }
171
+
172
+ return <div className={cn("font-medium", labelClassName)}>{value}</div>
173
+ }, [
174
+ label,
175
+ labelFormatter,
176
+ payload,
177
+ hideLabel,
178
+ labelClassName,
179
+ config,
180
+ labelKey,
181
+ ])
182
+
183
+ if (!active || !payload?.length) {
184
+ return null
185
+ }
186
+
187
+ const nestLabel = payload.length === 1 && indicator !== "dot"
188
+
189
+ return (
190
+ <div
191
+ className={cn(
192
+ "grid min-w-32 items-start gap-1.5 rounded-lg border border-border/50 bg-bg-base px-2.5 py-1.5 text-xs shadow-xl",
193
+ className
194
+ )}
195
+ >
196
+ {!nestLabel ? tooltipLabel : null}
197
+ <div className="grid gap-1.5">
198
+ {payload
199
+ .filter((item) => item.type !== "none")
200
+ .map((item, index) => {
201
+ const key = `${nameKey ?? item.name ?? item.dataKey ?? "value"}`
202
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
203
+ const indicatorColor = color ?? item.payload?.fill ?? item.color
204
+
205
+ return (
206
+ <div
207
+ key={index}
208
+ className={cn(
209
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-text-tertiary",
210
+ indicator === "dot" && "items-center"
211
+ )}
212
+ >
213
+ {formatter && item?.value !== undefined && item.name ? (
214
+ formatter(item.value, item.name, item, index, item.payload)
215
+ ) : (
216
+ <>
217
+ {itemConfig?.icon ? (
218
+ <itemConfig.icon />
219
+ ) : (
220
+ !hideIndicator && (
221
+ <div
222
+ className={cn(
223
+ "shrink-0 rounded-sm border-(--color-border) bg-(--color-bg)",
224
+ {
225
+ "h-2.5 w-2.5": indicator === "dot",
226
+ "w-1": indicator === "line",
227
+ "w-0 border-[1.5px] border-dashed bg-transparent":
228
+ indicator === "dashed",
229
+ "my-0.5": nestLabel && indicator === "dashed",
230
+ }
231
+ )}
232
+ style={
233
+ {
234
+ "--color-bg": indicatorColor,
235
+ "--color-border": indicatorColor,
236
+ } as React.CSSProperties
237
+ }
238
+ />
239
+ )
240
+ )}
241
+ <div
242
+ className={cn(
243
+ "flex flex-1 justify-between leading-none",
244
+ nestLabel ? "items-end" : "items-center"
245
+ )}
246
+ >
247
+ <div className="grid gap-1.5">
248
+ {nestLabel ? tooltipLabel : null}
249
+ <span className="text-text-tertiary">
250
+ {itemConfig?.label ?? item.name}
251
+ </span>
252
+ </div>
253
+ {item.value != null && (
254
+ <span className="font-mono font-medium text-text tabular-nums">
255
+ {typeof item.value === "number"
256
+ ? item.value.toLocaleString()
257
+ : String(item.value)}
258
+ </span>
259
+ )}
260
+ </div>
261
+ </>
262
+ )}
263
+ </div>
264
+ )
265
+ })}
266
+ </div>
267
+ </div>
268
+ )
269
+ }
270
+
271
+ const ChartLegend = RechartsPrimitive.Legend
272
+
273
+ function ChartLegendContent({
274
+ className,
275
+ hideIcon = false,
276
+ payload,
277
+ verticalAlign = "bottom",
278
+ nameKey,
279
+ }: React.ComponentProps<"div"> & {
280
+ hideIcon?: boolean
281
+ nameKey?: string
282
+ } & RechartsPrimitive.DefaultLegendContentProps) {
283
+ const { config } = useChart()
284
+
285
+ if (!payload?.length) {
286
+ return null
287
+ }
288
+
289
+ return (
290
+ <div
291
+ className={cn(
292
+ "flex items-center justify-center gap-4",
293
+ verticalAlign === "top" ? "pb-3" : "pt-3",
294
+ className
295
+ )}
296
+ >
297
+ {payload
298
+ .filter((item) => item.type !== "none")
299
+ .map((item, index) => {
300
+ const key = `${nameKey ?? item.dataKey ?? "value"}`
301
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
302
+
303
+ return (
304
+ <div
305
+ key={index}
306
+ className={cn(
307
+ "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-text-tertiary"
308
+ )}
309
+ >
310
+ {itemConfig?.icon && !hideIcon ? (
311
+ <itemConfig.icon />
312
+ ) : (
313
+ <div
314
+ className="h-2 w-2 shrink-0 rounded-sm"
315
+ style={{
316
+ backgroundColor: item.color,
317
+ }}
318
+ />
319
+ )}
320
+ {itemConfig?.label}
321
+ </div>
322
+ )
323
+ })}
324
+ </div>
325
+ )
326
+ }
327
+
328
+ // Helper to extract item config from a payload.
329
+ function getPayloadConfigFromPayload(
330
+ config: ChartConfig,
331
+ payload: unknown,
332
+ key: string
333
+ ) {
334
+ if (typeof payload !== "object" || payload === null) {
335
+ return undefined
336
+ }
337
+
338
+ const payloadPayload =
339
+ "payload" in payload &&
340
+ typeof payload.payload === "object" &&
341
+ payload.payload !== null
342
+ ? payload.payload
343
+ : undefined
344
+
345
+ let configLabelKey: string = key
346
+
347
+ if (
348
+ key in payload &&
349
+ typeof payload[key as keyof typeof payload] === "string"
350
+ ) {
351
+ configLabelKey = payload[key as keyof typeof payload] as string
352
+ } else if (
353
+ payloadPayload &&
354
+ key in payloadPayload &&
355
+ typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
356
+ ) {
357
+ configLabelKey = payloadPayload[
358
+ key as keyof typeof payloadPayload
359
+ ] as string
360
+ }
361
+
362
+ return configLabelKey in config ? config[configLabelKey] : config[key]
363
+ }
364
+
365
+ export {
366
+ ChartContainer,
367
+ ChartTooltip,
368
+ ChartTooltipContent,
369
+ ChartLegend,
370
+ ChartLegendContent,
371
+ ChartStyle,
372
+ }
@@ -0,0 +1,42 @@
1
+ import * as React from 'react'
2
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
3
+ import { cva, type VariantProps } from 'class-variance-authority'
4
+ import { cn } from '@/lib/utils'
5
+ import { CheckLine } from './icons-inline'
6
+
7
+ const checkboxVariants = cva(
8
+ 'group peer shrink-0 rounded-sm border border-border-tertiary bg-bg-container outline-offset-2 transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-border disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-text-on-primary data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-text-on-primary',
9
+ {
10
+ variants: {
11
+ size: {
12
+ sm: 'size-3.5',
13
+ md: 'size-4',
14
+ lg: 'size-5',
15
+ },
16
+ },
17
+ defaultVariants: { size: 'md' },
18
+ },
19
+ )
20
+
21
+ export interface CheckboxProps
22
+ extends React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,
23
+ VariantProps<typeof checkboxVariants> {}
24
+
25
+ const Checkbox = React.forwardRef<
26
+ React.ElementRef<typeof CheckboxPrimitive.Root>,
27
+ CheckboxProps
28
+ >(({ className, size = 'md', ...props }, ref) => (
29
+ <CheckboxPrimitive.Root
30
+ ref={ref}
31
+ className={cn(checkboxVariants({ size }), className)}
32
+ {...props}
33
+ >
34
+ <CheckboxPrimitive.Indicator className="flex items-center justify-center text-current">
35
+ <CheckLine className="size-[0.875em] group-data-[state=indeterminate]:hidden" />
36
+ <span className="hidden h-[0.125em] w-[0.625em] rounded-sm bg-current group-data-[state=indeterminate]:block" />
37
+ </CheckboxPrimitive.Indicator>
38
+ </CheckboxPrimitive.Root>
39
+ ))
40
+ Checkbox.displayName = CheckboxPrimitive.Root.displayName
41
+
42
+ export { Checkbox, checkboxVariants }
@@ -1,6 +1,7 @@
1
1
  import { useState, useRef, useLayoutEffect, type ReactNode } from 'react'
2
2
  import { motion, AnimatePresence } from 'framer-motion'
3
3
  import { cn } from '@/lib/utils'
4
+ import { MOTION_EXPAND } from '@/lib/motion'
4
5
  import { ArrowDownSLine } from './icons-inline'
5
6
 
6
7
  export interface CollapsibleCardProps {
@@ -31,7 +32,7 @@ export function CollapsibleCard({
31
32
  headerRight,
32
33
  children,
33
34
  defaultExpanded = true,
34
- contentPadding = 'var(--spacing-1\.5) var(--spacing-2)',
35
+ contentPadding = 'var(--spacing-1.5) var(--spacing-2)',
35
36
  onToggle,
36
37
  collapsible = true,
37
38
  footer,
@@ -150,10 +151,7 @@ export function CollapsibleCard({
150
151
  <AnimatePresence initial={false}>
151
152
  {isExpanded && (
152
153
  <motion.div
153
- initial={{ height: 0, opacity: 0 }}
154
- animate={{ height: 'auto', opacity: 1 }}
155
- exit={{ height: 0, opacity: 0 }}
156
- transition={{ duration: 0.2, ease: [0.2, 0.8, 0.2, 1] }}
154
+ {...MOTION_EXPAND}
157
155
  className={cn('overflow-hidden', isAnimating && 'select-none')}
158
156
  >
159
157
  {/* 隐藏测量用,用于获取内容实际高度 */}
@@ -187,7 +185,7 @@ export function CollapsibleCard({
187
185
  {useExpandAllLogic && shouldShowBar && contentHeight > maxHeight && (
188
186
  <div
189
187
  className={cn(
190
- 'absolute bottom-0 left-0 right-0 pointer-events-none h-[25px] bg-gradient-to-b from-transparent to-[var(--color-bg-base)] transition-opacity duration-300',
188
+ 'absolute bottom-0 left-0 right-0 pointer-events-none h-6 bg-gradient-to-b from-transparent to-[var(--color-bg-base)] transition-opacity duration-300',
191
189
  expandAll ? 'opacity-0' : 'opacity-100'
192
190
  )}
193
191
  />
@@ -0,0 +1,133 @@
1
+ import * as React from 'react'
2
+ import { CheckIcon, ChevronsUpDownIcon } from 'lucide-react'
3
+
4
+ import { cn } from '@/lib/utils'
5
+ import { Button } from './button'
6
+ import {
7
+ Command,
8
+ CommandEmpty,
9
+ CommandGroup,
10
+ CommandInput,
11
+ CommandItem,
12
+ CommandList,
13
+ } from './command'
14
+ import { Popover, PopoverContent, PopoverTrigger } from './popover'
15
+
16
+ export interface ComboboxOption {
17
+ value: string
18
+ label: string
19
+ disabled?: boolean
20
+ keywords?: string[]
21
+ }
22
+
23
+ export interface ComboboxProps {
24
+ options: ComboboxOption[]
25
+ value?: string
26
+ defaultValue?: string
27
+ onValueChange?: (value: string) => void
28
+ placeholder?: React.ReactNode
29
+ searchPlaceholder?: string
30
+ emptyText?: React.ReactNode
31
+ disabled?: boolean
32
+ className?: string
33
+ contentClassName?: string
34
+ align?: 'start' | 'center' | 'end'
35
+ triggerClassName?: string
36
+ id?: string
37
+ name?: string
38
+ 'aria-label'?: string
39
+ }
40
+
41
+ function Combobox({
42
+ options,
43
+ value,
44
+ defaultValue,
45
+ onValueChange,
46
+ placeholder = 'Select an option…',
47
+ searchPlaceholder = 'Search…',
48
+ emptyText = 'No option found.',
49
+ disabled,
50
+ className,
51
+ contentClassName,
52
+ triggerClassName,
53
+ align = 'start',
54
+ id,
55
+ name,
56
+ 'aria-label': ariaLabel,
57
+ }: ComboboxProps) {
58
+ const isControlled = value !== undefined
59
+ const [internal, setInternal] = React.useState<string | undefined>(defaultValue)
60
+ const [open, setOpen] = React.useState(false)
61
+ const current = isControlled ? value : internal
62
+ const selected = options.find((option) => option.value === current)
63
+
64
+ const handleSelect = React.useCallback(
65
+ (next: string) => {
66
+ const resolved = next === current ? '' : next
67
+ if (!isControlled) setInternal(resolved)
68
+ onValueChange?.(resolved)
69
+ setOpen(false)
70
+ },
71
+ [current, isControlled, onValueChange],
72
+ )
73
+
74
+ return (
75
+ <div className={cn('w-60', className)}>
76
+ <Popover open={open} onOpenChange={setOpen}>
77
+ <PopoverTrigger asChild>
78
+ <Button
79
+ id={id}
80
+ variant="outline"
81
+ role="combobox"
82
+ aria-expanded={open}
83
+ aria-label={ariaLabel}
84
+ disabled={disabled}
85
+ className={cn(
86
+ 'w-full justify-between font-normal',
87
+ !selected && 'text-text-tertiary',
88
+ triggerClassName,
89
+ )}
90
+ suffixIcon={<ChevronsUpDownIcon className="size-4 shrink-0 opacity-60" />}
91
+ >
92
+ <span className="truncate text-left">
93
+ {selected ? selected.label : placeholder}
94
+ </span>
95
+ </Button>
96
+ </PopoverTrigger>
97
+ <PopoverContent
98
+ align={align}
99
+ className={cn('w-[var(--radix-popover-trigger-width)] min-w-56 p-0', contentClassName)}
100
+ >
101
+ <Command>
102
+ <CommandInput placeholder={searchPlaceholder} />
103
+ <CommandList>
104
+ <CommandEmpty>{emptyText}</CommandEmpty>
105
+ <CommandGroup>
106
+ {options.map((option) => (
107
+ <CommandItem
108
+ key={option.value}
109
+ value={option.value}
110
+ keywords={[option.label, ...(option.keywords ?? [])]}
111
+ disabled={option.disabled}
112
+ onSelect={handleSelect}
113
+ >
114
+ <CheckIcon
115
+ className={cn(
116
+ 'mr-2 size-4',
117
+ option.value === current ? 'opacity-100' : 'opacity-0',
118
+ )}
119
+ />
120
+ <span className="truncate">{option.label}</span>
121
+ </CommandItem>
122
+ ))}
123
+ </CommandGroup>
124
+ </CommandList>
125
+ </Command>
126
+ </PopoverContent>
127
+ </Popover>
128
+ {name ? <input type="hidden" name={name} value={current ?? ''} /> : null}
129
+ </div>
130
+ )
131
+ }
132
+
133
+ export { Combobox }