@codefast/ui 0.3.16-canary.2 → 0.4.0-canary.4

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 (289) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +28 -17
  3. package/dist/components/accordion.d.mts +7 -22
  4. package/dist/components/accordion.mjs +26 -29
  5. package/dist/components/alert-dialog.d.mts +27 -26
  6. package/dist/components/alert-dialog.mjs +53 -45
  7. package/dist/components/alert.d.mts +14 -14
  8. package/dist/components/alert.mjs +17 -28
  9. package/dist/components/aspect-ratio.d.mts +2 -2
  10. package/dist/components/aspect-ratio.mjs +2 -3
  11. package/dist/components/avatar.d.mts +41 -5
  12. package/dist/components/avatar.mjs +40 -10
  13. package/dist/components/badge.d.mts +3 -15
  14. package/dist/components/badge.mjs +6 -48
  15. package/dist/components/breadcrumb.d.mts +1 -0
  16. package/dist/components/breadcrumb.mjs +11 -10
  17. package/dist/components/button-group.d.mts +3 -13
  18. package/dist/components/button-group.mjs +9 -31
  19. package/dist/components/button.d.mts +3 -26
  20. package/dist/components/button.mjs +9 -79
  21. package/dist/components/calendar.d.mts +6 -2
  22. package/dist/components/calendar.mjs +41 -44
  23. package/dist/components/card.d.mts +4 -2
  24. package/dist/components/card.mjs +9 -9
  25. package/dist/components/carousel.d.mts +16 -5
  26. package/dist/components/carousel.mjs +24 -11
  27. package/dist/components/chart.d.mts +9 -6
  28. package/dist/components/chart.mjs +21 -15
  29. package/dist/components/checkbox-cards.mjs +4 -4
  30. package/dist/components/checkbox-group.mjs +3 -4
  31. package/dist/components/checkbox.d.mts +2 -2
  32. package/dist/components/checkbox.mjs +6 -7
  33. package/dist/components/collapsible.d.mts +4 -4
  34. package/dist/components/collapsible.mjs +4 -5
  35. package/dist/components/command.d.mts +11 -1
  36. package/dist/components/command.mjs +35 -32
  37. package/dist/components/context-menu.d.mts +22 -15
  38. package/dist/components/context-menu.mjs +44 -39
  39. package/dist/components/dialog.d.mts +19 -23
  40. package/dist/components/dialog.mjs +48 -47
  41. package/dist/components/direction.d.mts +24 -0
  42. package/dist/components/direction.mjs +18 -0
  43. package/dist/components/drawer.d.mts +3 -21
  44. package/dist/components/drawer.mjs +19 -27
  45. package/dist/components/dropdown-menu.d.mts +22 -15
  46. package/dist/components/dropdown-menu.mjs +41 -37
  47. package/dist/components/empty.d.mts +3 -13
  48. package/dist/components/empty.mjs +8 -23
  49. package/dist/components/field.d.mts +3 -14
  50. package/dist/components/field.mjs +14 -44
  51. package/dist/components/form.d.mts +7 -10
  52. package/dist/components/form.mjs +6 -7
  53. package/dist/components/hover-card.d.mts +5 -5
  54. package/dist/components/hover-card.mjs +14 -12
  55. package/dist/components/input-group.d.mts +4 -31
  56. package/dist/components/input-group.mjs +14 -96
  57. package/dist/components/input-number.d.mts +3 -1
  58. package/dist/components/input-number.mjs +50 -28
  59. package/dist/components/input-otp.mjs +9 -7
  60. package/dist/components/input-password.mjs +1 -4
  61. package/dist/components/input-search.mjs +3 -5
  62. package/dist/components/input.mjs +1 -2
  63. package/dist/components/item.d.mts +4 -29
  64. package/dist/components/item.mjs +12 -65
  65. package/dist/components/kbd.mjs +1 -1
  66. package/dist/components/label.d.mts +2 -2
  67. package/dist/components/label.mjs +3 -4
  68. package/dist/components/menubar.d.mts +22 -16
  69. package/dist/components/menubar.mjs +54 -47
  70. package/dist/components/native-select.d.mts +5 -1
  71. package/dist/components/native-select.mjs +9 -6
  72. package/dist/components/navigation-menu.d.mts +30 -13
  73. package/dist/components/navigation-menu.mjs +35 -32
  74. package/dist/components/pagination.d.mts +7 -1
  75. package/dist/components/pagination.mjs +27 -12
  76. package/dist/components/popover.d.mts +40 -7
  77. package/dist/components/popover.mjs +46 -14
  78. package/dist/components/progress-circle.d.mts +3 -47
  79. package/dist/components/progress-circle.mjs +2 -48
  80. package/dist/components/progress.d.mts +2 -2
  81. package/dist/components/progress.mjs +5 -6
  82. package/dist/components/radio-cards.d.mts +3 -3
  83. package/dist/components/radio-cards.mjs +11 -11
  84. package/dist/components/radio-group.d.mts +3 -3
  85. package/dist/components/radio-group.mjs +9 -9
  86. package/dist/components/radio.mjs +2 -3
  87. package/dist/components/resizable.mjs +3 -8
  88. package/dist/components/scroll-area.d.mts +8 -24
  89. package/dist/components/scroll-area.mjs +16 -70
  90. package/dist/components/select.d.mts +14 -14
  91. package/dist/components/select.mjs +47 -47
  92. package/dist/components/separator.d.mts +4 -19
  93. package/dist/components/separator.mjs +6 -27
  94. package/dist/components/sheet.d.mts +18 -31
  95. package/dist/components/sheet.mjs +46 -87
  96. package/dist/components/sidebar.d.mts +3 -19
  97. package/dist/components/sidebar.mjs +48 -84
  98. package/dist/components/skeleton.mjs +1 -1
  99. package/dist/components/slider.d.mts +2 -2
  100. package/dist/components/slider.mjs +9 -11
  101. package/dist/components/sonner.mjs +11 -3
  102. package/dist/components/spinner.mjs +6 -7
  103. package/dist/components/switch.d.mts +5 -2
  104. package/dist/components/switch.mjs +7 -7
  105. package/dist/components/table.mjs +10 -10
  106. package/dist/components/tabs.d.mts +8 -5
  107. package/dist/components/tabs.mjs +18 -12
  108. package/dist/components/textarea.mjs +1 -1
  109. package/dist/components/toggle-group.d.mts +11 -7
  110. package/dist/components/toggle-group.mjs +20 -21
  111. package/dist/components/toggle.d.mts +4 -24
  112. package/dist/components/toggle.mjs +6 -45
  113. package/dist/components/tooltip.d.mts +7 -6
  114. package/dist/components/tooltip.mjs +19 -17
  115. package/dist/hooks/use-animated-value.mjs +0 -1
  116. package/dist/hooks/use-copy-to-clipboard.mjs +0 -1
  117. package/dist/hooks/use-is-mobile.mjs +0 -1
  118. package/dist/hooks/use-media-query.mjs +0 -1
  119. package/dist/hooks/use-mutation-observer.mjs +0 -1
  120. package/dist/hooks/use-pagination.mjs +0 -1
  121. package/dist/index.d.mts +38 -21
  122. package/dist/index.mjs +40 -23
  123. package/dist/lib/utils.d.mts +1 -12
  124. package/dist/lib/utils.mjs +1 -9
  125. package/dist/primitives/checkbox-group.d.mts +9 -11
  126. package/dist/primitives/checkbox-group.mjs +14 -19
  127. package/dist/primitives/input-number.d.mts +3 -4
  128. package/dist/primitives/input-number.mjs +3 -5
  129. package/dist/primitives/input.d.mts +4 -5
  130. package/dist/primitives/input.mjs +2 -3
  131. package/dist/primitives/progress-circle.d.mts +3 -4
  132. package/dist/primitives/progress-circle.mjs +2 -3
  133. package/dist/variants/alert.d.mts +18 -0
  134. package/dist/variants/alert.mjs +15 -0
  135. package/dist/variants/badge.d.mts +22 -0
  136. package/dist/variants/badge.mjs +19 -0
  137. package/dist/variants/button-group.d.mts +18 -0
  138. package/dist/variants/button-group.mjs +15 -0
  139. package/dist/variants/button.d.mts +32 -0
  140. package/dist/variants/button.mjs +34 -0
  141. package/dist/variants/empty.d.mts +18 -0
  142. package/dist/variants/empty.mjs +15 -0
  143. package/dist/variants/field.d.mts +19 -0
  144. package/dist/variants/field.mjs +16 -0
  145. package/dist/variants/input-group.d.mts +43 -0
  146. package/dist/variants/input-group.mjs +34 -0
  147. package/dist/variants/input-number.d.mts +45 -0
  148. package/dist/variants/input-number.mjs +40 -0
  149. package/dist/variants/item.d.mts +38 -0
  150. package/dist/variants/item.mjs +38 -0
  151. package/dist/variants/navigation-menu.d.mts +13 -0
  152. package/dist/variants/navigation-menu.mjs +8 -0
  153. package/dist/variants/progress-circle.d.mts +52 -0
  154. package/dist/variants/progress-circle.mjs +45 -0
  155. package/dist/variants/scroll-area.d.mts +24 -0
  156. package/dist/variants/scroll-area.mjs +58 -0
  157. package/dist/variants/separator.d.mts +23 -0
  158. package/dist/variants/separator.mjs +25 -0
  159. package/dist/variants/sheet.d.mts +20 -0
  160. package/dist/variants/sheet.mjs +17 -0
  161. package/dist/variants/sidebar.d.mts +23 -0
  162. package/dist/variants/sidebar.mjs +25 -0
  163. package/dist/variants/tabs.d.mts +18 -0
  164. package/dist/variants/tabs.mjs +15 -0
  165. package/dist/variants/toggle.d.mts +23 -0
  166. package/dist/variants/toggle.mjs +25 -0
  167. package/package.json +186 -55
  168. package/src/components/accordion.tsx +114 -0
  169. package/src/components/alert-dialog.tsx +298 -0
  170. package/src/components/alert.tsx +94 -0
  171. package/src/components/aspect-ratio.tsx +25 -0
  172. package/src/components/avatar.tsx +171 -0
  173. package/src/components/badge.tsx +35 -0
  174. package/src/components/breadcrumb.tsx +191 -0
  175. package/src/components/button-group.tsx +97 -0
  176. package/src/components/button.tsx +55 -0
  177. package/src/components/calendar.tsx +222 -0
  178. package/src/components/card.tsx +169 -0
  179. package/src/components/carousel.tsx +349 -0
  180. package/src/components/chart.tsx +536 -0
  181. package/src/components/checkbox-cards.tsx +72 -0
  182. package/src/components/checkbox-group.tsx +60 -0
  183. package/src/components/checkbox.tsx +44 -0
  184. package/src/components/collapsible.tsx +57 -0
  185. package/src/components/command.tsx +298 -0
  186. package/src/components/context-menu.tsx +410 -0
  187. package/src/components/dialog.tsx +243 -0
  188. package/src/components/direction.tsx +32 -0
  189. package/src/components/drawer.tsx +209 -0
  190. package/src/components/dropdown-menu.tsx +419 -0
  191. package/src/components/empty.tsx +155 -0
  192. package/src/components/field.tsx +329 -0
  193. package/src/components/form.tsx +258 -0
  194. package/src/components/hover-card.tsx +93 -0
  195. package/src/components/input-group.tsx +185 -0
  196. package/src/components/input-number.tsx +141 -0
  197. package/src/components/input-otp.tsx +132 -0
  198. package/src/components/input-password.tsx +50 -0
  199. package/src/components/input-search.tsx +81 -0
  200. package/src/components/input.tsx +36 -0
  201. package/src/components/item.tsx +266 -0
  202. package/src/components/kbd.tsx +47 -0
  203. package/src/components/label.tsx +36 -0
  204. package/src/components/menubar.tsx +440 -0
  205. package/src/components/native-select.tsx +87 -0
  206. package/src/components/navigation-menu.tsx +235 -0
  207. package/src/components/pagination.tsx +198 -0
  208. package/src/components/popover.tsx +170 -0
  209. package/src/components/progress-circle.tsx +185 -0
  210. package/src/components/progress.tsx +41 -0
  211. package/src/components/radio-cards.tsx +66 -0
  212. package/src/components/radio-group.tsx +59 -0
  213. package/src/components/radio.tsx +40 -0
  214. package/src/components/resizable.tsx +78 -0
  215. package/src/components/scroll-area.tsx +95 -0
  216. package/src/components/select.tsx +296 -0
  217. package/src/components/separator.tsx +60 -0
  218. package/src/components/sheet.tsx +241 -0
  219. package/src/components/sidebar.tsx +926 -0
  220. package/src/components/skeleton.tsx +35 -0
  221. package/src/components/slider.tsx +66 -0
  222. package/src/components/sonner.tsx +57 -0
  223. package/src/components/spinner.tsx +66 -0
  224. package/src/components/switch.tsx +44 -0
  225. package/src/components/table.tsx +183 -0
  226. package/src/components/tabs.tsx +110 -0
  227. package/src/components/textarea.tsx +35 -0
  228. package/src/components/toggle-group.tsx +137 -0
  229. package/src/components/toggle.tsx +30 -0
  230. package/src/components/tooltip.tsx +115 -0
  231. package/src/css/foundation/base.css +50 -0
  232. package/src/css/foundation/motion.css +36 -0
  233. package/src/css/foundation/source.css +3 -0
  234. package/src/css/foundation/tokens.css +71 -0
  235. package/src/css/foundation/variants.css +113 -0
  236. package/src/css/preset.css +5 -195
  237. package/src/css/style.css +1 -1
  238. package/src/css/{amber.css → themes/amber.css} +59 -22
  239. package/src/css/{blue.css → themes/blue.css} +59 -22
  240. package/src/css/{cyan.css → themes/cyan.css} +59 -22
  241. package/src/css/{emerald.css → themes/emerald.css} +59 -22
  242. package/src/css/{fuchsia.css → themes/fuchsia.css} +59 -22
  243. package/src/css/{gray.css → themes/gray.css} +59 -22
  244. package/src/css/{green.css → themes/green.css} +59 -22
  245. package/src/css/{indigo.css → themes/indigo.css} +59 -22
  246. package/src/css/{lime.css → themes/lime.css} +59 -22
  247. package/src/css/{neutral.css → themes/neutral.css} +59 -22
  248. package/src/css/{orange.css → themes/orange.css} +59 -22
  249. package/src/css/{pink.css → themes/pink.css} +59 -22
  250. package/src/css/{purple.css → themes/purple.css} +59 -22
  251. package/src/css/{red.css → themes/red.css} +59 -22
  252. package/src/css/{rose.css → themes/rose.css} +59 -22
  253. package/src/css/{sky.css → themes/sky.css} +59 -22
  254. package/src/css/{slate.css → themes/slate.css} +59 -22
  255. package/src/css/{stone.css → themes/stone.css} +59 -22
  256. package/src/css/{teal.css → themes/teal.css} +59 -22
  257. package/src/css/{violet.css → themes/violet.css} +59 -22
  258. package/src/css/{yellow.css → themes/yellow.css} +59 -22
  259. package/src/css/{zinc.css → themes/zinc.css} +59 -22
  260. package/src/hooks/use-animated-value.ts +91 -0
  261. package/src/hooks/use-copy-to-clipboard.ts +58 -0
  262. package/src/hooks/use-is-mobile.ts +25 -0
  263. package/src/hooks/use-media-query.ts +69 -0
  264. package/src/hooks/use-mutation-observer.ts +51 -0
  265. package/src/hooks/use-pagination.ts +164 -0
  266. package/src/index.ts +679 -0
  267. package/src/lib/utils.ts +5 -0
  268. package/src/primitives/checkbox-group.tsx +346 -0
  269. package/src/primitives/input-number.tsx +967 -0
  270. package/src/primitives/input.tsx +227 -0
  271. package/src/primitives/progress-circle.tsx +507 -0
  272. package/src/variants/alert.ts +34 -0
  273. package/src/variants/badge.ts +39 -0
  274. package/src/variants/button-group.ts +36 -0
  275. package/src/variants/button.ts +56 -0
  276. package/src/variants/empty.ts +34 -0
  277. package/src/variants/field.ts +37 -0
  278. package/src/variants/input-group.ts +80 -0
  279. package/src/variants/input-number.ts +65 -0
  280. package/src/variants/item.ts +68 -0
  281. package/src/variants/navigation-menu.ts +25 -0
  282. package/src/variants/progress-circle.ts +46 -0
  283. package/src/variants/scroll-area.ts +73 -0
  284. package/src/variants/separator.ts +40 -0
  285. package/src/variants/sheet.ts +37 -0
  286. package/src/variants/sidebar.ts +41 -0
  287. package/src/variants/tabs.ts +34 -0
  288. package/src/variants/toggle.ts +40 -0
  289. package/dist/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/clsx.d.mts +0 -6
@@ -0,0 +1,536 @@
1
+ import { Context } from "radix-ui/internal";
2
+ import type { ComponentProps, ComponentType, CSSProperties, JSX, ReactNode } from "react";
3
+ import { useId, useMemo } from "react";
4
+ import type { TooltipContentProps, TooltipProps } from "recharts";
5
+ import * as RechartsPrimitive from "recharts";
6
+ import type { NameType, Payload, ValueType } from "recharts/types/component/DefaultTooltipContent";
7
+
8
+ import { cn } from "#/lib/utils";
9
+
10
+ /* -----------------------------------------------------------------------------
11
+ * Type Definitions and Utilities
12
+ * -------------------------------------------------------------------------- */
13
+
14
+ type ExtractProps<T> = T extends (props: infer P) => ReactNode ? P : never;
15
+
16
+ type MakeOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
17
+
18
+ /* -----------------------------------------------------------------------------
19
+ * Chart Configuration and Theme Constants
20
+ * --------------------------------------------------------------------------- */
21
+
22
+ const THEMES = { dark: ".dark", light: "" } as const;
23
+
24
+ const INITIAL_DIMENSION = { height: 200, width: 320 } as const;
25
+
26
+ /**
27
+ * @since 0.3.16-canary.0
28
+ */
29
+ type ChartConfig = Record<
30
+ string,
31
+ {
32
+ label?: ReactNode;
33
+ icon?: ComponentType;
34
+ } & ({ color?: never; theme: Record<keyof typeof THEMES, string> } | { color?: string; theme?: never })
35
+ >;
36
+
37
+ /* -----------------------------------------------------------------------------
38
+ * Context: ChartProvider
39
+ * --------------------------------------------------------------------------- */
40
+
41
+ const CHART_PROVIDER_NAME = "ChartProvider";
42
+
43
+ type ScopedProps<P> = P & { __scopeChart?: Context.Scope };
44
+
45
+ /**
46
+ * Value provided by Chart Context
47
+ */
48
+ interface ChartContextValue {
49
+ /**
50
+ * Display configuration for the chart
51
+ */
52
+ config: ChartConfig;
53
+ }
54
+
55
+ const [createChartContext, createChartScope] = Context.createContextScope(CHART_PROVIDER_NAME);
56
+
57
+ const [ChartContextProvider, useChartContext] = createChartContext<ChartContextValue>(CHART_PROVIDER_NAME);
58
+
59
+ /* -----------------------------------------------------------------------------
60
+ * Component: Chart
61
+ * -------------------------------------------------------------------------- */
62
+
63
+ /**
64
+ * @since 0.3.16-canary.0
65
+ */
66
+ interface ChartContainerProps extends ComponentProps<"div"> {
67
+ children: ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>["children"];
68
+ config: ChartConfig;
69
+ initialDimension?: {
70
+ height: number;
71
+ width: number;
72
+ };
73
+ }
74
+
75
+ /**
76
+ * @since 0.3.16-canary.0
77
+ */
78
+ function ChartContainer({
79
+ __scopeChart,
80
+ children,
81
+ className,
82
+ config,
83
+ id,
84
+ initialDimension = INITIAL_DIMENSION,
85
+ ...props
86
+ }: ScopedProps<ChartContainerProps>): JSX.Element {
87
+ const uniqueId = useId();
88
+ const chartId = `chart-${id ?? uniqueId.replace(/:/g, "")}`;
89
+
90
+ return (
91
+ <ChartContextProvider config={config} scope={__scopeChart}>
92
+ <div
93
+ className={cn(
94
+ "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
95
+ className,
96
+ )}
97
+ data-chart={chartId}
98
+ data-slot="chart"
99
+ {...props}
100
+ >
101
+ <ChartStyle config={config} id={chartId} />
102
+ <RechartsPrimitive.ResponsiveContainer initialDimension={initialDimension}>
103
+ {children}
104
+ </RechartsPrimitive.ResponsiveContainer>
105
+ </div>
106
+ </ChartContextProvider>
107
+ );
108
+ }
109
+
110
+ /* -----------------------------------------------------------------------------
111
+ * Component: ChartStyle
112
+ * -------------------------------------------------------------------------- */
113
+
114
+ /**
115
+ * @since 0.3.16-canary.0
116
+ */
117
+ interface ChartStyleProps {
118
+ config: ChartConfig;
119
+ id: string;
120
+ }
121
+
122
+ /**
123
+ * @since 0.3.16-canary.0
124
+ */
125
+ function ChartStyle({ config, id }: ChartStyleProps): ReactNode {
126
+ const colorConfig = Object.entries(config).filter(([, itemConfig]) => itemConfig.theme ?? itemConfig.color);
127
+
128
+ if (colorConfig.length === 0) {
129
+ return null;
130
+ }
131
+
132
+ return (
133
+ <style
134
+ dangerouslySetInnerHTML={{
135
+ __html: generateChartStyles(id, colorConfig),
136
+ }}
137
+ />
138
+ );
139
+ }
140
+
141
+ /* -----------------------------------------------------------------------------
142
+ * Component: ChartTooltip
143
+ * -------------------------------------------------------------------------- */
144
+
145
+ /**
146
+ * @since 0.3.16-canary.0
147
+ */
148
+ type ChartTooltipProps<TValue extends ValueType, TName extends NameType> = TooltipProps<TValue, TName>;
149
+
150
+ /**
151
+ * @since 0.3.16-canary.0
152
+ */
153
+ const ChartTooltip = RechartsPrimitive.Tooltip;
154
+
155
+ /* -----------------------------------------------------------------------------
156
+ * Component: ChartTooltipContent
157
+ * -------------------------------------------------------------------------- */
158
+
159
+ const CHART_TOOLTIP_CONTENT_NAME = "ChartTooltipContent";
160
+
161
+ /**
162
+ * @since 0.3.16-canary.0
163
+ */
164
+ type ChartTooltipContentProps<TValue extends ValueType, TName extends NameType> = Omit<
165
+ MakeOptional<
166
+ TooltipContentProps<TValue, TName>,
167
+ "accessibilityLayer" | "active" | "activeIndex" | "coordinate" | "payload"
168
+ >,
169
+ "payload"
170
+ > & {
171
+ hideIndicator?: boolean;
172
+ hideLabel?: boolean;
173
+ indicator?: "dashed" | "dot" | "line";
174
+ labelKey?: string;
175
+ nameKey?: string;
176
+ color?: string | undefined;
177
+ className?: string | undefined;
178
+ payload?: Array<Payload<TValue, TName>>;
179
+ };
180
+
181
+ /**
182
+ * @since 0.3.16-canary.0
183
+ */
184
+ function ChartTooltipContent<TValue extends ValueType, TName extends NameType>({
185
+ __scopeChart,
186
+ active,
187
+ className,
188
+ color,
189
+ formatter,
190
+ hideIndicator = false,
191
+ hideLabel = false,
192
+ indicator = "dot",
193
+ label,
194
+ labelClassName,
195
+ labelFormatter,
196
+ labelKey,
197
+ nameKey,
198
+ payload = [],
199
+ }: ScopedProps<ChartTooltipContentProps<TValue, TName>>): ReactNode {
200
+ const { config } = useChartContext(CHART_TOOLTIP_CONTENT_NAME, __scopeChart);
201
+
202
+ const tooltipLabel = useMemo((): ReactNode => {
203
+ if (hideLabel || payload.length === 0) {
204
+ return null;
205
+ }
206
+
207
+ const item = payload[0];
208
+ if (item === undefined) {
209
+ return null;
210
+ }
211
+ const key = safeToString(labelKey ?? item.dataKey ?? item.name ?? "value");
212
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
213
+ const configEntry = typeof label === "string" && label in config ? config[label] : undefined;
214
+ const value =
215
+ !labelKey && typeof label === "string"
216
+ ? configEntry !== undefined
217
+ ? (configEntry.label ?? label)
218
+ : label
219
+ : itemConfig?.label;
220
+
221
+ if (labelFormatter) {
222
+ return <div className={cn("font-medium", labelClassName)}>{labelFormatter(value, payload)}</div>;
223
+ }
224
+
225
+ if (!value) {
226
+ return null;
227
+ }
228
+
229
+ return <div className={cn("font-medium", labelClassName)}>{value}</div>;
230
+ }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey]);
231
+
232
+ if (!active || payload.length === 0) {
233
+ return null;
234
+ }
235
+
236
+ const nestLabel = payload.length === 1 && indicator !== "dot";
237
+
238
+ return (
239
+ <div
240
+ className={cn(
241
+ "grid min-w-32 items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
242
+ className,
243
+ )}
244
+ >
245
+ {nestLabel ? null : tooltipLabel}
246
+ <div className="grid gap-1.5">
247
+ {payload.map((item, index) => {
248
+ const key = safeToString(nameKey ?? item.name ?? item.dataKey ?? "value");
249
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
250
+ const indicatorColor =
251
+ color ??
252
+ (isRecord(item.payload) && "fill" in item.payload && typeof item.payload.fill === "string"
253
+ ? item.payload.fill
254
+ : undefined) ??
255
+ item.color;
256
+
257
+ return (
258
+ <div
259
+ key={key}
260
+ className={cn(
261
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
262
+ indicator === "dot" && "items-center",
263
+ )}
264
+ >
265
+ {formatter && item.value !== undefined && item.name ? (
266
+ formatter(item.value, item.name, item, index, [item])
267
+ ) : (
268
+ <>
269
+ {itemConfig?.icon ? (
270
+ <itemConfig.icon />
271
+ ) : (
272
+ !hideIndicator && (
273
+ <div
274
+ className={cn("shrink-0 rounded-xs border-(--color-border) bg-(--color-bg)", {
275
+ "h-2.5 w-2.5": indicator === "dot",
276
+ "my-0.5": nestLabel && indicator === "dashed",
277
+ "w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed",
278
+ "w-1": indicator === "line",
279
+ })}
280
+ style={
281
+ {
282
+ "--color-bg": indicatorColor,
283
+ "--color-border": indicatorColor,
284
+ } as CSSProperties
285
+ }
286
+ />
287
+ )
288
+ )}
289
+ <div
290
+ className={cn("flex flex-1 justify-between leading-none", nestLabel ? "items-end" : "items-center")}
291
+ >
292
+ <div className="grid gap-1.5">
293
+ {nestLabel ? tooltipLabel : null}
294
+ <span className="text-muted-foreground">{itemConfig?.label ?? item.name}</span>
295
+ </div>
296
+ {item.value != null && (
297
+ <span className="font-mono font-medium text-foreground tabular-nums">
298
+ {typeof item.value === "number" ? item.value.toLocaleString() : safeToString(item.value)}
299
+ </span>
300
+ )}
301
+ </div>
302
+ </>
303
+ )}
304
+ </div>
305
+ );
306
+ })}
307
+ </div>
308
+ </div>
309
+ );
310
+ }
311
+
312
+ /* -----------------------------------------------------------------------------
313
+ * Component: ChartLegend
314
+ * -------------------------------------------------------------------------- */
315
+
316
+ /**
317
+ * @since 0.3.16-canary.0
318
+ */
319
+ type ChartLegendProps = ComponentProps<typeof RechartsPrimitive.Legend>;
320
+
321
+ /**
322
+ * @since 0.3.16-canary.0
323
+ */
324
+ const ChartLegend: typeof RechartsPrimitive.Legend = RechartsPrimitive.Legend;
325
+
326
+ /* -----------------------------------------------------------------------------
327
+ * Component: ChartLegendContent
328
+ * -------------------------------------------------------------------------- */
329
+
330
+ const CHART_LEGEND_CONTENT_NAME = "ChartLegendContent";
331
+
332
+ /**
333
+ * @since 0.3.16-canary.0
334
+ */
335
+ type ChartLegendContentProps = ComponentProps<"div"> &
336
+ ExtractProps<RechartsPrimitive.LegendProps["content"]> & {
337
+ hideIcon?: boolean;
338
+ nameKey?: string;
339
+ };
340
+
341
+ /**
342
+ * @since 0.3.16-canary.0
343
+ */
344
+ function ChartLegendContent({
345
+ __scopeChart,
346
+ className,
347
+ hideIcon = false,
348
+ nameKey,
349
+ payload,
350
+ verticalAlign = "bottom",
351
+ }: ScopedProps<ChartLegendContentProps>): ReactNode {
352
+ const { config } = useChartContext(CHART_LEGEND_CONTENT_NAME, __scopeChart);
353
+
354
+ if (!payload?.length) {
355
+ return null;
356
+ }
357
+
358
+ return (
359
+ <div className={cn("flex items-center justify-center gap-4", verticalAlign === "top" ? "pb-3" : "pt-3", className)}>
360
+ {payload.map((item) => {
361
+ let key = "value";
362
+
363
+ if (nameKey) {
364
+ key = nameKey;
365
+ } else if (item.dataKey != null) {
366
+ key = safeToString(item.dataKey);
367
+ }
368
+
369
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
370
+
371
+ return (
372
+ <div
373
+ key={nameKey ? safeToString(itemConfig?.color ?? "") : safeToString(item.value ?? "")}
374
+ className="flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
375
+ >
376
+ {itemConfig?.icon && !hideIcon ? (
377
+ <itemConfig.icon />
378
+ ) : (
379
+ <div
380
+ className="h-2 w-2 shrink-0 rounded-xs"
381
+ style={{
382
+ backgroundColor: item.color,
383
+ }}
384
+ />
385
+ )}
386
+ {itemConfig?.label}
387
+ </div>
388
+ );
389
+ })}
390
+ </div>
391
+ );
392
+ }
393
+
394
+ /* -----------------------------------------------------------------------------
395
+ * Helpers
396
+ * -------------------------------------------------------------------------- */
397
+
398
+ /**
399
+ * Type guard to check if an unknown value is a record with string keys
400
+ */
401
+ function isRecord(value: unknown): value is Record<string, unknown> {
402
+ return typeof value === "object" && value !== null;
403
+ }
404
+
405
+ /**
406
+ * Safely gets a string value from a record by key
407
+ */
408
+ function getStringValue(record: Record<string, unknown>, key: string): string | undefined {
409
+ if (key in record) {
410
+ const value = record[key];
411
+
412
+ return typeof value === "string" ? value : undefined;
413
+ }
414
+
415
+ return undefined;
416
+ }
417
+
418
+ /**
419
+ * Safely converts a value to string without type coercion
420
+ */
421
+ function safeToString(value: unknown): string {
422
+ if (typeof value === "string") {
423
+ return value;
424
+ }
425
+
426
+ if (typeof value === "number") {
427
+ return value.toString();
428
+ }
429
+
430
+ if (value === null || value === undefined) {
431
+ return "";
432
+ }
433
+
434
+ if (typeof value === "boolean") {
435
+ return value.toString();
436
+ }
437
+
438
+ if (typeof value === "bigint") {
439
+ return value.toString();
440
+ }
441
+
442
+ if (typeof value === "symbol") {
443
+ return value.toString();
444
+ }
445
+
446
+ // For objects, arrays, functions, and other complex types, return empty string to avoid [object Object]
447
+ return "";
448
+ }
449
+
450
+ function getPayloadConfigFromPayload(
451
+ config: ChartConfig,
452
+ payload: unknown,
453
+ key: string,
454
+ ): ChartConfig[string] | undefined {
455
+ if (!isRecord(payload)) {
456
+ return undefined;
457
+ }
458
+
459
+ const payloadPayload = isRecord(payload.payload) ? payload.payload : undefined;
460
+ let configLabelKey: string = key;
461
+
462
+ // Try to get the config key from the payload first
463
+ const payloadValue = getStringValue(payload, key);
464
+
465
+ if (payloadValue) {
466
+ configLabelKey = payloadValue;
467
+ } else if (payloadPayload) {
468
+ // If not found in the payload, try the nested payload
469
+ const nestedValue = getStringValue(payloadPayload, key);
470
+
471
+ if (nestedValue) {
472
+ configLabelKey = nestedValue;
473
+ }
474
+ }
475
+
476
+ return configLabelKey in config ? config[configLabelKey] : config[key];
477
+ }
478
+
479
+ /**
480
+ * Generates CSS custom property for a specific theme and config item
481
+ */
482
+ function generateCssVariable(key: string, itemConfig: ChartConfig[string], theme: string): null | string {
483
+ const color = itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ?? itemConfig.color;
484
+
485
+ return color ? ` --color-${key}: ${color};` : null;
486
+ }
487
+
488
+ /**
489
+ * Generates CSS rules for a specific theme
490
+ */
491
+ function generateThemeStyles(
492
+ theme: string,
493
+ prefix: string,
494
+ id: string,
495
+ colorConfig: Array<[string, ChartConfig[string]]>,
496
+ ): string {
497
+ const cssVariables = colorConfig
498
+ .map(([key, itemConfig]) => generateCssVariable(key, itemConfig, theme))
499
+ .filter(Boolean)
500
+ .join("\n");
501
+
502
+ return `${prefix} [data-chart=${id}] {\n${cssVariables}\n}`;
503
+ }
504
+
505
+ /**
506
+ * Generates complete CSS styles for all themes
507
+ */
508
+ function generateChartStyles(id: string, colorConfig: Array<[string, ChartConfig[string]]>): string {
509
+ return Object.entries(THEMES)
510
+ .map(([theme, prefix]) => generateThemeStyles(theme, prefix, id, colorConfig))
511
+ .join("\n\n");
512
+ }
513
+
514
+ /* -----------------------------------------------------------------------------
515
+ * Exports
516
+ * -------------------------------------------------------------------------- */
517
+
518
+ export type {
519
+ ChartConfig,
520
+ ChartContainerProps,
521
+ ChartLegendContentProps,
522
+ ChartLegendProps,
523
+ ChartStyleProps,
524
+ ChartTooltipContentProps,
525
+ ChartTooltipProps,
526
+ };
527
+
528
+ export {
529
+ ChartContainer,
530
+ ChartLegend,
531
+ ChartLegendContent,
532
+ ChartStyle,
533
+ ChartTooltip,
534
+ ChartTooltipContent,
535
+ createChartScope,
536
+ };
@@ -0,0 +1,72 @@
1
+ import { CheckIcon } from "lucide-react";
2
+ import type { ComponentProps, JSX } from "react";
3
+
4
+ import { Label } from "#/components/label";
5
+ import { cn } from "#/lib/utils";
6
+ import * as CheckboxGroupPrimitive from "#/primitives/checkbox-group";
7
+
8
+ /* -----------------------------------------------------------------------------
9
+ * Component: CheckboxCards
10
+ * -------------------------------------------------------------------------- */
11
+
12
+ /**
13
+ * @since 0.3.16-canary.0
14
+ */
15
+ type CheckboxCardsProps = ComponentProps<typeof CheckboxGroupPrimitive.Root>;
16
+
17
+ /**
18
+ * @since 0.3.16-canary.0
19
+ */
20
+ function CheckboxCards(props: CheckboxCardsProps): JSX.Element {
21
+ return <CheckboxGroupPrimitive.Root data-slot="checkbox-cards" {...props} />;
22
+ }
23
+
24
+ /* -----------------------------------------------------------------------------
25
+ * Component: CheckboxCardsItem
26
+ * -------------------------------------------------------------------------- */
27
+
28
+ /**
29
+ * @since 0.3.16-canary.0
30
+ */
31
+ interface CheckboxCardsItemProps extends ComponentProps<typeof CheckboxGroupPrimitive.Item> {
32
+ checkboxClassName?: string;
33
+ }
34
+
35
+ /**
36
+ * @since 0.3.16-canary.0
37
+ */
38
+ function CheckboxCardsItem({ checkboxClassName, children, className, ...props }: CheckboxCardsItemProps): JSX.Element {
39
+ return (
40
+ <Label
41
+ className={cn(
42
+ "flex items-start gap-3 rounded-md border border-input p-3 transition has-focus-visible:border-ring has-disabled:opacity-50 has-data-checked:border-primary/30 has-data-checked:bg-primary/5",
43
+ className,
44
+ )}
45
+ data-slot="checkbox-card"
46
+ >
47
+ <CheckboxGroupPrimitive.Item
48
+ className={cn(
49
+ "peer relative flex size-4 shrink-0 items-center justify-center rounded-sm border border-input shadow-xs transition-shadow outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
50
+ checkboxClassName,
51
+ )}
52
+ data-slot="checkbox-card-item"
53
+ {...props}
54
+ >
55
+ <CheckboxGroupPrimitive.CheckboxGroupIndicator
56
+ className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
57
+ data-slot="checkbox-card-indicator"
58
+ >
59
+ <CheckIcon />
60
+ </CheckboxGroupPrimitive.CheckboxGroupIndicator>
61
+ </CheckboxGroupPrimitive.Item>
62
+ {children}
63
+ </Label>
64
+ );
65
+ }
66
+
67
+ /* -----------------------------------------------------------------------------
68
+ * Exports
69
+ * -------------------------------------------------------------------------- */
70
+
71
+ export { CheckboxCards, CheckboxCardsItem };
72
+ export type { CheckboxCardsItemProps, CheckboxCardsProps };
@@ -0,0 +1,60 @@
1
+ import { CheckIcon } from "lucide-react";
2
+ import type { ComponentProps, JSX } from "react";
3
+
4
+ import { cn } from "#/lib/utils";
5
+ import * as CheckboxGroupPrimitive from "#/primitives/checkbox-group";
6
+
7
+ /* -----------------------------------------------------------------------------
8
+ * Component: CheckboxGroup
9
+ * -------------------------------------------------------------------------- */
10
+
11
+ /**
12
+ * @since 0.3.16-canary.0
13
+ */
14
+ type CheckboxGroupProps = ComponentProps<typeof CheckboxGroupPrimitive.Root>;
15
+
16
+ /**
17
+ * @since 0.3.16-canary.0
18
+ */
19
+ function CheckboxGroup({ className, ...props }: CheckboxGroupProps): JSX.Element {
20
+ return <CheckboxGroupPrimitive.Root className={cn("grid gap-2", className)} data-slot="checkbox-group" {...props} />;
21
+ }
22
+
23
+ /* -----------------------------------------------------------------------------
24
+ * Component: CheckboxGroupItem
25
+ * -------------------------------------------------------------------------- */
26
+
27
+ /**
28
+ * @since 0.3.16-canary.0
29
+ */
30
+ type CheckboxGroupItemProps = ComponentProps<typeof CheckboxGroupPrimitive.Item>;
31
+
32
+ /**
33
+ * @since 0.3.16-canary.0
34
+ */
35
+ function CheckboxGroupItem({ className, ...props }: CheckboxGroupItemProps): JSX.Element {
36
+ return (
37
+ <CheckboxGroupPrimitive.Item
38
+ className={cn(
39
+ "peer relative flex size-4 shrink-0 items-center justify-center rounded-sm border border-input shadow-xs transition-shadow outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
40
+ className,
41
+ )}
42
+ data-slot="checkbox-group-item"
43
+ {...props}
44
+ >
45
+ <CheckboxGroupPrimitive.CheckboxGroupIndicator
46
+ className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
47
+ data-slot="checkbox-group-indicator"
48
+ >
49
+ <CheckIcon />
50
+ </CheckboxGroupPrimitive.CheckboxGroupIndicator>
51
+ </CheckboxGroupPrimitive.Item>
52
+ );
53
+ }
54
+
55
+ /* -----------------------------------------------------------------------------
56
+ * Exports
57
+ * -------------------------------------------------------------------------- */
58
+
59
+ export { CheckboxGroup, CheckboxGroupItem };
60
+ export type { CheckboxGroupItemProps, CheckboxGroupProps };