@inferencesh/ui 0.0.0-stage → 0.1.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 (165) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +68 -2
  3. package/components.json +22 -0
  4. package/package.json +231 -4
  5. package/src/components/audio-player.tsx +549 -0
  6. package/src/components/button.tsx +13 -0
  7. package/src/components/chart.tsx +403 -0
  8. package/src/components/circuit.tsx +276 -0
  9. package/src/components/code-block/code-block.tsx +260 -0
  10. package/src/components/code-block/index.ts +18 -0
  11. package/src/components/code-block/languages.ts +311 -0
  12. package/src/components/code-block/styles.ts +39 -0
  13. package/src/components/code-block/tokenizer.ts +290 -0
  14. package/src/components/code-block/types.ts +38 -0
  15. package/src/components/code-block/utils.ts +39 -0
  16. package/src/components/code.tsx +48 -0
  17. package/src/components/cookie-consent.tsx +137 -0
  18. package/src/components/copy-button.tsx +44 -0
  19. package/src/components/country-dropdown.tsx +188 -0
  20. package/src/components/glow-loader-fast.tsx +32 -0
  21. package/src/components/glow-loader-mono.tsx +33 -0
  22. package/src/components/glow-loader-sm-fast.tsx +32 -0
  23. package/src/components/glow-loader-sm-mono.tsx +34 -0
  24. package/src/components/glow-loader-sm.tsx +32 -0
  25. package/src/components/glow-loader.tsx +32 -0
  26. package/src/components/glow-logo.tsx +32 -0
  27. package/src/components/gradient.tsx +80 -0
  28. package/src/components/index.ts +45 -0
  29. package/src/components/inline-sidebar.tsx +351 -0
  30. package/src/components/input-color.tsx +349 -0
  31. package/src/components/logo-base.tsx +213 -0
  32. package/src/components/logo-color.tsx +23 -0
  33. package/src/components/logo-full.tsx +71 -0
  34. package/src/components/logo-svg.tsx +23 -0
  35. package/src/components/menu-navigation.tsx +359 -0
  36. package/src/components/multi-select.tsx +721 -0
  37. package/src/components/pastel-gradient.tsx +25 -0
  38. package/src/components/pixel-symmetry.tsx +151 -0
  39. package/src/components/progress.tsx +28 -0
  40. package/src/components/scroll-more.tsx +131 -0
  41. package/src/components/select.tsx +85 -0
  42. package/src/components/shimmering-text.tsx +108 -0
  43. package/src/components/sidebar-light.tsx +102 -0
  44. package/src/components/sonner.tsx +38 -0
  45. package/src/components/theme-switcher-sidebar.tsx +56 -0
  46. package/src/components/theme-switcher-simple.tsx +110 -0
  47. package/src/components/theme-switcher.tsx +47 -0
  48. package/src/components/toggle-group.tsx +55 -0
  49. package/src/components/tooltip-button.tsx +91 -0
  50. package/src/components/tooltip.tsx +71 -0
  51. package/src/components/tree-view.tsx +499 -0
  52. package/src/components/unglow-loader.tsx +33 -0
  53. package/src/components/waveform.tsx +1632 -0
  54. package/src/components/zoomable-image.tsx +76 -0
  55. package/src/docs/api-docs.tsx +763 -0
  56. package/src/docs/callout.tsx +160 -0
  57. package/src/docs/code-group.tsx +215 -0
  58. package/src/docs/copy-menu.tsx +143 -0
  59. package/src/docs/doc-tabs.tsx +84 -0
  60. package/src/docs/index.ts +16 -0
  61. package/src/docs/steps.tsx +105 -0
  62. package/src/docs/table-of-contents.tsx +174 -0
  63. package/src/examples/guide-markdown.ts +129 -0
  64. package/src/examples/index.ts +1153 -0
  65. package/src/global.d.ts +1 -0
  66. package/src/hooks/use-copy-to-clipboard.ts +36 -0
  67. package/src/hooks/use-mobile.ts +19 -0
  68. package/src/lib/display-name.ts +15 -0
  69. package/src/lib/example-input.ts +130 -0
  70. package/src/lib/plans.ts +44 -0
  71. package/src/lib/safe-content.ts +137 -0
  72. package/src/lib/schema.ts +320 -0
  73. package/src/lib/storage.ts +108 -0
  74. package/src/markdown/docs-markdown-renderer.tsx +518 -0
  75. package/src/markdown/helpers.ts +95 -0
  76. package/src/markdown/index.ts +24 -0
  77. package/src/markdown/markdown-renderer.tsx +232 -0
  78. package/src/markdown/youtube-embed.tsx +43 -0
  79. package/src/og/image.ts +312 -0
  80. package/src/og/index.tsx +430 -0
  81. package/src/og/query.ts +26 -0
  82. package/src/shadcn/accordion.tsx +71 -0
  83. package/src/shadcn/alert-dialog.tsx +187 -0
  84. package/src/shadcn/alert.tsx +75 -0
  85. package/src/shadcn/aspect-ratio.tsx +22 -0
  86. package/src/shadcn/attachment.tsx +207 -0
  87. package/src/shadcn/avatar.tsx +106 -0
  88. package/src/shadcn/badge.tsx +51 -0
  89. package/src/shadcn/breadcrumb.tsx +124 -0
  90. package/src/shadcn/bubble.tsx +127 -0
  91. package/src/shadcn/button-group.tsx +87 -0
  92. package/src/shadcn/button.tsx +57 -0
  93. package/src/shadcn/calendar.tsx +219 -0
  94. package/src/shadcn/card.tsx +102 -0
  95. package/src/shadcn/carousel.tsx +242 -0
  96. package/src/shadcn/chart.tsx +372 -0
  97. package/src/shadcn/checkbox.tsx +28 -0
  98. package/src/shadcn/collapsible.tsx +19 -0
  99. package/src/shadcn/combobox.tsx +297 -0
  100. package/src/shadcn/command.tsx +194 -0
  101. package/src/shadcn/context-menu.tsx +270 -0
  102. package/src/shadcn/dialog.tsx +158 -0
  103. package/src/shadcn/direction.tsx +4 -0
  104. package/src/shadcn/drawer.tsx +227 -0
  105. package/src/shadcn/dropdown-menu.tsx +265 -0
  106. package/src/shadcn/empty.tsx +103 -0
  107. package/src/shadcn/field.tsx +238 -0
  108. package/src/shadcn/form.tsx +173 -0
  109. package/src/shadcn/hover-card.tsx +50 -0
  110. package/src/shadcn/index.ts +53 -0
  111. package/src/shadcn/input-group.tsx +156 -0
  112. package/src/shadcn/input-otp.tsx +84 -0
  113. package/src/shadcn/input.tsx +19 -0
  114. package/src/shadcn/item.tsx +201 -0
  115. package/src/shadcn/kbd.tsx +26 -0
  116. package/src/shadcn/label.tsx +19 -0
  117. package/src/shadcn/marker.tsx +70 -0
  118. package/src/shadcn/menubar.tsx +278 -0
  119. package/src/shadcn/message-scroller.tsx +131 -0
  120. package/src/shadcn/message.tsx +91 -0
  121. package/src/shadcn/native-select.tsx +60 -0
  122. package/src/shadcn/navigation-menu.tsx +167 -0
  123. package/src/shadcn/pagination.tsx +130 -0
  124. package/src/shadcn/popover.tsx +87 -0
  125. package/src/shadcn/progress.tsx +82 -0
  126. package/src/shadcn/radio-group.tsx +35 -0
  127. package/src/shadcn/resizable.tsx +49 -0
  128. package/src/shadcn/scroll-area.tsx +52 -0
  129. package/src/shadcn/select.tsx +200 -0
  130. package/src/shadcn/separator.tsx +22 -0
  131. package/src/shadcn/sheet.tsx +136 -0
  132. package/src/shadcn/sidebar.tsx +721 -0
  133. package/src/shadcn/skeleton.tsx +13 -0
  134. package/src/shadcn/slider.tsx +51 -0
  135. package/src/shadcn/sonner.tsx +49 -0
  136. package/src/shadcn/spinner.tsx +10 -0
  137. package/src/shadcn/switch.tsx +29 -0
  138. package/src/shadcn/table.tsx +115 -0
  139. package/src/shadcn/tabs.tsx +79 -0
  140. package/src/shadcn/textarea.tsx +17 -0
  141. package/src/shadcn/toggle-group.tsx +89 -0
  142. package/src/shadcn/toggle.tsx +44 -0
  143. package/src/shadcn/tooltip.tsx +63 -0
  144. package/src/theme/config.ts +48 -0
  145. package/src/theme/css/base.css +92 -0
  146. package/src/theme/css/bitboy.css +75 -0
  147. package/src/theme/css/dark.css +47 -0
  148. package/src/theme/css/designer.css +122 -0
  149. package/src/theme/css/fonts.css +33 -0
  150. package/src/theme/css/globals.css +14 -0
  151. package/src/theme/css/hackintosh.css +57 -0
  152. package/src/theme/css/llama.css +103 -0
  153. package/src/theme/css/safelist.css +39 -0
  154. package/src/theme/css/shadcn.css +77 -0
  155. package/src/theme/css/theme.css +216 -0
  156. package/src/theme/embed-theme.ts +146 -0
  157. package/src/theme/fonts/FiraCode-VF.woff2 +0 -0
  158. package/src/theme/fonts/Hack-Regular.woff2 +0 -0
  159. package/src/theme/fonts/LICENSE-FiraCode.txt +93 -0
  160. package/src/theme/fonts/LICENSE-Hack.txt +45 -0
  161. package/src/theme/fonts/LICENSE-MonaSans.txt +93 -0
  162. package/src/theme/fonts/Mona-Sans.woff2 +0 -0
  163. package/src/theme/index.ts +15 -0
  164. package/src/utils/cn.ts +3 -0
  165. package/src/utils/index.ts +2 -0
@@ -0,0 +1,102 @@
1
+ import * as React from "react"
2
+ import { cn } from "cn"
3
+
4
+ function Card({
5
+ className,
6
+ size = "default",
7
+ ...props
8
+ }: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
9
+ return (
10
+ <div
11
+ data-slot="card"
12
+ data-size={size}
13
+ className={cn(
14
+ "group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
15
+ className
16
+ )}
17
+ {...props}
18
+ />
19
+ )
20
+ }
21
+
22
+ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
23
+ return (
24
+ <div
25
+ data-slot="card-header"
26
+ className={cn(
27
+ "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",
28
+ className
29
+ )}
30
+ {...props}
31
+ />
32
+ )
33
+ }
34
+
35
+ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
36
+ return (
37
+ <div
38
+ data-slot="card-title"
39
+ className={cn(
40
+ "text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
41
+ className
42
+ )}
43
+ {...props}
44
+ />
45
+ )
46
+ }
47
+
48
+ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
49
+ return (
50
+ <div
51
+ data-slot="card-description"
52
+ className={cn("text-sm text-muted-foreground", className)}
53
+ {...props}
54
+ />
55
+ )
56
+ }
57
+
58
+ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
59
+ return (
60
+ <div
61
+ data-slot="card-action"
62
+ className={cn(
63
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
64
+ className
65
+ )}
66
+ {...props}
67
+ />
68
+ )
69
+ }
70
+
71
+ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
72
+ return (
73
+ <div
74
+ data-slot="card-content"
75
+ className={cn("px-(--card-spacing)", className)}
76
+ {...props}
77
+ />
78
+ )
79
+ }
80
+
81
+ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
82
+ return (
83
+ <div
84
+ data-slot="card-footer"
85
+ className={cn(
86
+ "flex items-center rounded-b-xl border-t bg-muted/50 p-(--card-spacing)",
87
+ className
88
+ )}
89
+ {...props}
90
+ />
91
+ )
92
+ }
93
+
94
+ export {
95
+ Card,
96
+ CardHeader,
97
+ CardFooter,
98
+ CardTitle,
99
+ CardAction,
100
+ CardDescription,
101
+ CardContent,
102
+ }
@@ -0,0 +1,242 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "cn"
5
+ import useEmblaCarousel, {
6
+ type UseEmblaCarouselType,
7
+ } from "embla-carousel-react"
8
+
9
+ import { Button } from "@inferencesh/ui/shadcn/button"
10
+ import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"
11
+
12
+ type CarouselApi = UseEmblaCarouselType[1]
13
+ type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
14
+ type CarouselOptions = UseCarouselParameters[0]
15
+ type CarouselPlugin = UseCarouselParameters[1]
16
+
17
+ type CarouselProps = {
18
+ opts?: CarouselOptions
19
+ plugins?: CarouselPlugin
20
+ orientation?: "horizontal" | "vertical"
21
+ setApi?: (api: CarouselApi) => void
22
+ }
23
+
24
+ type CarouselContextProps = {
25
+ carouselRef: ReturnType<typeof useEmblaCarousel>[0]
26
+ api: ReturnType<typeof useEmblaCarousel>[1]
27
+ scrollPrev: () => void
28
+ scrollNext: () => void
29
+ canScrollPrev: boolean
30
+ canScrollNext: boolean
31
+ } & CarouselProps
32
+
33
+ const CarouselContext = React.createContext<CarouselContextProps | null>(null)
34
+
35
+ function useCarousel() {
36
+ const context = React.useContext(CarouselContext)
37
+
38
+ if (!context) {
39
+ throw new Error("useCarousel must be used within a <Carousel />")
40
+ }
41
+
42
+ return context
43
+ }
44
+
45
+ function Carousel({
46
+ orientation = "horizontal",
47
+ opts,
48
+ setApi,
49
+ plugins,
50
+ className,
51
+ children,
52
+ ...props
53
+ }: React.ComponentProps<"div"> & CarouselProps) {
54
+ const [carouselRef, api] = useEmblaCarousel(
55
+ {
56
+ ...opts,
57
+ axis: orientation === "horizontal" ? "x" : "y",
58
+ },
59
+ plugins
60
+ )
61
+ const [canScrollPrev, setCanScrollPrev] = React.useState(false)
62
+ const [canScrollNext, setCanScrollNext] = React.useState(false)
63
+
64
+ const onSelect = React.useCallback((api: CarouselApi) => {
65
+ if (!api) return
66
+ setCanScrollPrev(api.canScrollPrev())
67
+ setCanScrollNext(api.canScrollNext())
68
+ }, [])
69
+
70
+ const scrollPrev = React.useCallback(() => {
71
+ api?.scrollPrev()
72
+ }, [api])
73
+
74
+ const scrollNext = React.useCallback(() => {
75
+ api?.scrollNext()
76
+ }, [api])
77
+
78
+ const handleKeyDown = React.useCallback(
79
+ (event: React.KeyboardEvent<HTMLDivElement>) => {
80
+ if (event.key === "ArrowLeft") {
81
+ event.preventDefault()
82
+ scrollPrev()
83
+ } else if (event.key === "ArrowRight") {
84
+ event.preventDefault()
85
+ scrollNext()
86
+ }
87
+ },
88
+ [scrollPrev, scrollNext]
89
+ )
90
+
91
+ React.useEffect(() => {
92
+ if (!api || !setApi) return
93
+ setApi(api)
94
+ }, [api, setApi])
95
+
96
+ React.useEffect(() => {
97
+ if (!api) return
98
+ onSelect(api)
99
+ api.on("reInit", onSelect)
100
+ api.on("select", onSelect)
101
+
102
+ return () => {
103
+ api?.off("select", onSelect)
104
+ }
105
+ }, [api, onSelect])
106
+
107
+ return (
108
+ <CarouselContext.Provider
109
+ value={{
110
+ carouselRef,
111
+ api: api,
112
+ opts,
113
+ orientation:
114
+ orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
115
+ scrollPrev,
116
+ scrollNext,
117
+ canScrollPrev,
118
+ canScrollNext,
119
+ }}
120
+ >
121
+ <div
122
+ onKeyDownCapture={handleKeyDown}
123
+ className={cn("relative", className)}
124
+ role="region"
125
+ aria-roledescription="carousel"
126
+ data-slot="carousel"
127
+ {...props}
128
+ >
129
+ {children}
130
+ </div>
131
+ </CarouselContext.Provider>
132
+ )
133
+ }
134
+
135
+ function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
136
+ const { carouselRef, orientation } = useCarousel()
137
+
138
+ return (
139
+ <div
140
+ ref={carouselRef}
141
+ className="overflow-hidden"
142
+ data-slot="carousel-content"
143
+ >
144
+ <div
145
+ className={cn(
146
+ "flex",
147
+ orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
148
+ className
149
+ )}
150
+ {...props}
151
+ />
152
+ </div>
153
+ )
154
+ }
155
+
156
+ function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
157
+ const { orientation } = useCarousel()
158
+
159
+ return (
160
+ <div
161
+ role="group"
162
+ aria-roledescription="slide"
163
+ data-slot="carousel-item"
164
+ className={cn(
165
+ "min-w-0 shrink-0 grow-0 basis-full",
166
+ orientation === "horizontal" ? "pl-4" : "pt-4",
167
+ className
168
+ )}
169
+ {...props}
170
+ />
171
+ )
172
+ }
173
+
174
+ function CarouselPrevious({
175
+ className,
176
+ variant = "outline",
177
+ size = "icon-sm",
178
+ ...props
179
+ }: React.ComponentProps<typeof Button>) {
180
+ const { orientation, scrollPrev, canScrollPrev } = useCarousel()
181
+
182
+ return (
183
+ <Button
184
+ data-slot="carousel-previous"
185
+ variant={variant}
186
+ size={size}
187
+ className={cn(
188
+ "absolute touch-manipulation rounded-full",
189
+ orientation === "horizontal"
190
+ ? "inset-y-0 -left-12 my-auto"
191
+ : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
192
+ className
193
+ )}
194
+ disabled={!canScrollPrev}
195
+ onClick={scrollPrev}
196
+ {...props}
197
+ >
198
+ <ChevronLeftIcon />
199
+ <span className="sr-only">Previous slide</span>
200
+ </Button>
201
+ )
202
+ }
203
+
204
+ function CarouselNext({
205
+ className,
206
+ variant = "outline",
207
+ size = "icon-sm",
208
+ ...props
209
+ }: React.ComponentProps<typeof Button>) {
210
+ const { orientation, scrollNext, canScrollNext } = useCarousel()
211
+
212
+ return (
213
+ <Button
214
+ data-slot="carousel-next"
215
+ variant={variant}
216
+ size={size}
217
+ className={cn(
218
+ "absolute touch-manipulation rounded-full",
219
+ orientation === "horizontal"
220
+ ? "inset-y-0 -right-12 my-auto"
221
+ : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
222
+ className
223
+ )}
224
+ disabled={!canScrollNext}
225
+ onClick={scrollNext}
226
+ {...props}
227
+ >
228
+ <ChevronRightIcon />
229
+ <span className="sr-only">Next slide</span>
230
+ </Button>
231
+ )
232
+ }
233
+
234
+ export {
235
+ type CarouselApi,
236
+ Carousel,
237
+ CarouselContent,
238
+ CarouselItem,
239
+ CarouselPrevious,
240
+ CarouselNext,
241
+ useCarousel,
242
+ }
@@ -0,0 +1,372 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "cn"
5
+ import * as RechartsPrimitive from "recharts"
6
+ import type { TooltipValueType } from "recharts"
7
+
8
+ // Format: { THEME_NAME: CSS_SELECTOR }
9
+ const THEMES = { light: "", dark: ".dark" } as const
10
+
11
+ const INITIAL_DIMENSION = { width: 320, height: 200 } as const
12
+ type TooltipNameType = number | string
13
+
14
+ export type ChartConfig = Record<
15
+ string,
16
+ {
17
+ label?: React.ReactNode
18
+ icon?: React.ComponentType
19
+ } & (
20
+ | { color?: string; theme?: never }
21
+ | { color?: never; theme: Record<keyof typeof THEMES, string> }
22
+ )
23
+ >
24
+
25
+ type ChartContextProps = {
26
+ config: ChartConfig
27
+ }
28
+
29
+ const ChartContext = React.createContext<ChartContextProps | null>(null)
30
+
31
+ function useChart() {
32
+ const context = React.useContext(ChartContext)
33
+
34
+ if (!context) {
35
+ throw new Error("useChart must be used within a <ChartContainer />")
36
+ }
37
+
38
+ return context
39
+ }
40
+
41
+ function ChartContainer({
42
+ id,
43
+ className,
44
+ children,
45
+ config,
46
+ initialDimension = INITIAL_DIMENSION,
47
+ ...props
48
+ }: React.ComponentProps<"div"> & {
49
+ config: ChartConfig
50
+ children: React.ComponentProps<
51
+ typeof RechartsPrimitive.ResponsiveContainer
52
+ >["children"]
53
+ initialDimension?: {
54
+ width: number
55
+ height: number
56
+ }
57
+ }) {
58
+ const uniqueId = React.useId()
59
+ const chartId = `chart-${id ?? uniqueId.replace(/:/g, "")}`
60
+
61
+ return (
62
+ <ChartContext.Provider value={{ config }}>
63
+ <div
64
+ data-slot="chart"
65
+ data-chart={chartId}
66
+ className={cn(
67
+ "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",
68
+ className
69
+ )}
70
+ {...props}
71
+ >
72
+ <ChartStyle id={chartId} config={config} />
73
+ <RechartsPrimitive.ResponsiveContainer
74
+ initialDimension={initialDimension}
75
+ >
76
+ {children}
77
+ </RechartsPrimitive.ResponsiveContainer>
78
+ </div>
79
+ </ChartContext.Provider>
80
+ )
81
+ }
82
+
83
+ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
84
+ const colorConfig = Object.entries(config).filter(
85
+ ([, config]) => config.theme ?? config.color
86
+ )
87
+
88
+ if (!colorConfig.length) {
89
+ return null
90
+ }
91
+
92
+ return (
93
+ <style
94
+ dangerouslySetInnerHTML={{
95
+ __html: Object.entries(THEMES)
96
+ .map(
97
+ ([theme, prefix]) => `
98
+ ${prefix} [data-chart=${id}] {
99
+ ${colorConfig
100
+ .map(([key, itemConfig]) => {
101
+ const color =
102
+ itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ??
103
+ itemConfig.color
104
+ return color ? ` --color-${key}: ${color};` : null
105
+ })
106
+ .join("\n")}
107
+ }
108
+ `
109
+ )
110
+ .join("\n"),
111
+ }}
112
+ />
113
+ )
114
+ }
115
+
116
+ const ChartTooltip = RechartsPrimitive.Tooltip
117
+
118
+ function ChartTooltipContent({
119
+ active,
120
+ payload,
121
+ className,
122
+ indicator = "dot",
123
+ hideLabel = false,
124
+ hideIndicator = false,
125
+ label,
126
+ labelFormatter,
127
+ labelClassName,
128
+ formatter,
129
+ color,
130
+ nameKey,
131
+ labelKey,
132
+ }: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
133
+ React.ComponentProps<"div"> & {
134
+ hideLabel?: boolean
135
+ hideIndicator?: boolean
136
+ indicator?: "line" | "dot" | "dashed"
137
+ nameKey?: string
138
+ labelKey?: string
139
+ } & Omit<
140
+ RechartsPrimitive.DefaultTooltipContentProps<
141
+ TooltipValueType,
142
+ TooltipNameType
143
+ >,
144
+ "accessibilityLayer"
145
+ >) {
146
+ const { config } = useChart()
147
+
148
+ const tooltipLabel = React.useMemo(() => {
149
+ if (hideLabel || !payload?.length) {
150
+ return null
151
+ }
152
+
153
+ const [item] = payload
154
+ const key = `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}`
155
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
156
+ const value =
157
+ !labelKey && typeof label === "string"
158
+ ? (config[label]?.label ?? label)
159
+ : itemConfig?.label
160
+
161
+ if (labelFormatter) {
162
+ return (
163
+ <div className={cn("font-medium", labelClassName)}>
164
+ {labelFormatter(value, payload)}
165
+ </div>
166
+ )
167
+ }
168
+
169
+ if (!value) {
170
+ return null
171
+ }
172
+
173
+ return <div className={cn("font-medium", labelClassName)}>{value}</div>
174
+ }, [
175
+ label,
176
+ labelFormatter,
177
+ payload,
178
+ hideLabel,
179
+ labelClassName,
180
+ config,
181
+ labelKey,
182
+ ])
183
+
184
+ if (!active || !payload?.length) {
185
+ return null
186
+ }
187
+
188
+ const nestLabel = payload.length === 1 && indicator !== "dot"
189
+
190
+ return (
191
+ <div
192
+ className={cn(
193
+ "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",
194
+ className
195
+ )}
196
+ >
197
+ {!nestLabel ? tooltipLabel : null}
198
+ <div className="grid gap-1.5">
199
+ {payload
200
+ .filter((item) => item.type !== "none")
201
+ .map((item, index) => {
202
+ const key = `${nameKey ?? item.name ?? item.dataKey ?? "value"}`
203
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
204
+ const indicatorColor = color ?? item.payload?.fill ?? item.color
205
+
206
+ return (
207
+ <div
208
+ key={index}
209
+ className={cn(
210
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
211
+ indicator === "dot" && "items-center"
212
+ )}
213
+ >
214
+ {formatter && item?.value !== undefined && item.name ? (
215
+ formatter(item.value, item.name, item, index, item.payload)
216
+ ) : (
217
+ <>
218
+ {itemConfig?.icon ? (
219
+ <itemConfig.icon />
220
+ ) : (
221
+ !hideIndicator && (
222
+ <div
223
+ className={cn(
224
+ "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
225
+ {
226
+ "h-2.5 w-2.5": indicator === "dot",
227
+ "w-1": indicator === "line",
228
+ "w-0 border-[1.5px] border-dashed bg-transparent":
229
+ indicator === "dashed",
230
+ "my-0.5": nestLabel && indicator === "dashed",
231
+ }
232
+ )}
233
+ style={
234
+ {
235
+ "--color-bg": indicatorColor,
236
+ "--color-border": indicatorColor,
237
+ } as React.CSSProperties
238
+ }
239
+ />
240
+ )
241
+ )}
242
+ <div
243
+ className={cn(
244
+ "flex flex-1 justify-between leading-none",
245
+ nestLabel ? "items-end" : "items-center"
246
+ )}
247
+ >
248
+ <div className="grid gap-1.5">
249
+ {nestLabel ? tooltipLabel : null}
250
+ <span className="text-muted-foreground">
251
+ {itemConfig?.label ?? item.name}
252
+ </span>
253
+ </div>
254
+ {item.value != null && (
255
+ <span className="font-mono font-medium text-foreground tabular-nums">
256
+ {typeof item.value === "number"
257
+ ? item.value.toLocaleString()
258
+ : String(item.value)}
259
+ </span>
260
+ )}
261
+ </div>
262
+ </>
263
+ )}
264
+ </div>
265
+ )
266
+ })}
267
+ </div>
268
+ </div>
269
+ )
270
+ }
271
+
272
+ const ChartLegend = RechartsPrimitive.Legend
273
+
274
+ function ChartLegendContent({
275
+ className,
276
+ hideIcon = false,
277
+ payload,
278
+ verticalAlign = "bottom",
279
+ nameKey,
280
+ }: React.ComponentProps<"div"> & {
281
+ hideIcon?: boolean
282
+ nameKey?: string
283
+ } & RechartsPrimitive.DefaultLegendContentProps) {
284
+ const { config } = useChart()
285
+
286
+ if (!payload?.length) {
287
+ return null
288
+ }
289
+
290
+ return (
291
+ <div
292
+ className={cn(
293
+ "flex items-center justify-center gap-4",
294
+ verticalAlign === "top" ? "pb-3" : "pt-3",
295
+ className
296
+ )}
297
+ >
298
+ {payload
299
+ .filter((item) => item.type !== "none")
300
+ .map((item, index) => {
301
+ const key = `${nameKey ?? item.dataKey ?? "value"}`
302
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
303
+
304
+ return (
305
+ <div
306
+ key={index}
307
+ className={cn(
308
+ "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
309
+ )}
310
+ >
311
+ {itemConfig?.icon && !hideIcon ? (
312
+ <itemConfig.icon />
313
+ ) : (
314
+ <div
315
+ className="h-2 w-2 shrink-0 rounded-[2px]"
316
+ style={{
317
+ backgroundColor: item.color,
318
+ }}
319
+ />
320
+ )}
321
+ {itemConfig?.label}
322
+ </div>
323
+ )
324
+ })}
325
+ </div>
326
+ )
327
+ }
328
+
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
+ }