@blips/ui 1.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/index.cjs +3612 -2515
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +329 -484
  4. package/dist/index.d.ts +329 -484
  5. package/dist/index.js +3602 -2513
  6. package/dist/index.js.map +1 -1
  7. package/package.json +14 -12
  8. package/src/components/accordion.tsx +56 -46
  9. package/src/components/alert-dialog.tsx +166 -109
  10. package/src/components/alert.tsx +45 -38
  11. package/src/components/aspect-ratio.tsx +7 -1
  12. package/src/components/avatar.tsx +104 -45
  13. package/src/components/badge.tsx +25 -13
  14. package/src/components/breadcrumb.tsx +76 -82
  15. package/src/components/button-group.tsx +2 -2
  16. package/src/components/button.tsx +36 -28
  17. package/src/components/calendar.tsx +35 -28
  18. package/src/components/card.tsx +83 -70
  19. package/src/components/carousel.tsx +118 -137
  20. package/src/components/chart.tsx +197 -208
  21. package/src/components/checkbox.tsx +25 -21
  22. package/src/components/collapsible.tsx +25 -3
  23. package/src/components/command.tsx +138 -105
  24. package/src/components/context-menu.tsx +215 -161
  25. package/src/components/dialog.tsx +127 -91
  26. package/src/components/drawer.tsx +102 -83
  27. package/src/components/dropdown-menu.tsx +227 -170
  28. package/src/components/form.tsx +41 -52
  29. package/src/components/hover-card.tsx +36 -19
  30. package/src/components/input-group.tsx +4 -4
  31. package/src/components/input-otp.tsx +51 -43
  32. package/src/components/input.tsx +16 -17
  33. package/src/components/kbd.tsx +1 -1
  34. package/src/components/label.tsx +16 -18
  35. package/src/components/menubar.tsx +214 -192
  36. package/src/components/navigation-menu.tsx +140 -98
  37. package/src/components/pagination.tsx +97 -87
  38. package/src/components/popover.tsx +83 -23
  39. package/src/components/progress.tsx +23 -20
  40. package/src/components/radio-group.tsx +23 -20
  41. package/src/components/resizable.tsx +39 -31
  42. package/src/components/scroll-area.tsx +51 -39
  43. package/src/components/select.tsx +161 -131
  44. package/src/components/separator.tsx +13 -14
  45. package/src/components/sheet.tsx +112 -109
  46. package/src/components/sidebar.tsx +422 -470
  47. package/src/components/skeleton.tsx +4 -6
  48. package/src/components/slider.tsx +57 -20
  49. package/src/components/sonner.tsx +19 -24
  50. package/src/components/spinner.tsx +3 -3
  51. package/src/components/switch.tsx +28 -20
  52. package/src/components/table.tsx +94 -95
  53. package/src/components/tabs.tsx +88 -50
  54. package/src/components/textarea.tsx +5 -9
  55. package/src/components/toggle-group.tsx +52 -30
  56. package/src/components/toggle.tsx +24 -20
  57. package/src/components/tooltip.tsx +46 -19
  58. package/src/globals.css +213 -96
  59. package/src/index.ts +27 -6
@@ -1,7 +1,9 @@
1
+ "use client"
2
+
1
3
  import * as React from "react"
2
4
  import * as RechartsPrimitive from "recharts"
3
5
 
4
- import { cn } from "@/lib/utils"
6
+ import { cn } from "../lib/utils"
5
7
 
6
8
  // Format: { THEME_NAME: CSS_SELECTOR }
7
9
  const THEMES = { light: "", dark: ".dark" } as const
@@ -32,25 +34,28 @@ function useChart() {
32
34
  return context
33
35
  }
34
36
 
35
- const ChartContainer = React.forwardRef<
36
- HTMLDivElement,
37
- React.ComponentProps<"div"> & {
38
- config: ChartConfig
39
- children: React.ComponentProps<
40
- typeof RechartsPrimitive.ResponsiveContainer
41
- >["children"]
42
- }
43
- >(({ id, className, children, config, ...props }, ref) => {
37
+ function ChartContainer({
38
+ id,
39
+ className,
40
+ children,
41
+ config,
42
+ ...props
43
+ }: React.ComponentProps<"div"> & {
44
+ config: ChartConfig
45
+ children: React.ComponentProps<
46
+ typeof RechartsPrimitive.ResponsiveContainer
47
+ >["children"]
48
+ }) {
44
49
  const uniqueId = React.useId()
45
50
  const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
46
51
 
47
52
  return (
48
53
  <ChartContext.Provider value={{ config }}>
49
54
  <div
55
+ data-slot="chart"
50
56
  data-chart={chartId}
51
- ref={ref}
52
57
  className={cn(
53
- "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-none [&_.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[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
58
+ "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",
54
59
  className
55
60
  )}
56
61
  {...props}
@@ -62,8 +67,7 @@ const ChartContainer = React.forwardRef<
62
67
  </div>
63
68
  </ChartContext.Provider>
64
69
  )
65
- })
66
- ChartContainer.displayName = "Chart"
70
+ }
67
71
 
68
72
  const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
69
73
  const colorConfig = Object.entries(config).filter(
@@ -76,7 +80,6 @@ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
76
80
 
77
81
  return (
78
82
  <style
79
- // biome-ignore lint/security/noDangerouslySetInnerHtml: Required for dynamic CSS variables injection in charts
80
83
  dangerouslySetInnerHTML={{
81
84
  __html: Object.entries(THEMES)
82
85
  .map(
@@ -101,223 +104,209 @@ ${colorConfig
101
104
 
102
105
  const ChartTooltip = RechartsPrimitive.Tooltip
103
106
 
104
- const ChartTooltipContent = React.forwardRef<
105
- HTMLDivElement,
106
- React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
107
- React.ComponentProps<"div"> & {
108
- hideLabel?: boolean
109
- hideIndicator?: boolean
110
- indicator?: "line" | "dot" | "dashed"
111
- nameKey?: string
112
- labelKey?: string
113
- }
114
- >(
115
- (
116
- {
117
- active,
118
- payload,
119
- className,
120
- indicator = "dot",
121
- hideLabel = false,
122
- hideIndicator = false,
123
- label,
124
- labelFormatter,
125
- labelClassName,
126
- formatter,
127
- color,
128
- nameKey,
129
- labelKey,
130
- },
131
- ref
132
- ) => {
133
- const { config } = useChart()
134
-
135
- const tooltipLabel = React.useMemo(() => {
136
- if (hideLabel || !payload?.length) {
137
- return null
138
- }
139
-
140
- const [item] = payload
141
- const key = `${labelKey || item?.dataKey || item?.name || "value"}`
142
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
143
- const value =
144
- !labelKey && typeof label === "string"
145
- ? config[label as keyof typeof config]?.label || label
146
- : itemConfig?.label
147
-
148
- if (labelFormatter) {
149
- return (
150
- <div className={cn("font-medium", labelClassName)}>
151
- {labelFormatter(value, payload)}
152
- </div>
153
- )
154
- }
155
-
156
- if (!value) {
157
- return null
158
- }
159
-
160
- return <div className={cn("font-medium", labelClassName)}>{value}</div>
161
- }, [
162
- label,
163
- labelFormatter,
164
- payload,
165
- hideLabel,
166
- labelClassName,
167
- config,
168
- labelKey,
169
- ])
170
-
171
- if (!active || !payload?.length) {
107
+ function ChartTooltipContent({
108
+ active,
109
+ payload,
110
+ className,
111
+ indicator = "dot",
112
+ hideLabel = false,
113
+ hideIndicator = false,
114
+ label,
115
+ labelFormatter,
116
+ labelClassName,
117
+ formatter,
118
+ color,
119
+ nameKey,
120
+ labelKey,
121
+ }: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
122
+ React.ComponentProps<"div"> & {
123
+ hideLabel?: boolean
124
+ hideIndicator?: boolean
125
+ indicator?: "line" | "dot" | "dashed"
126
+ nameKey?: string
127
+ labelKey?: string
128
+ }) {
129
+ const { config } = useChart()
130
+
131
+ const tooltipLabel = React.useMemo(() => {
132
+ if (hideLabel || !payload?.length) {
172
133
  return null
173
134
  }
174
135
 
175
- const nestLabel = payload.length === 1 && indicator !== "dot"
176
-
177
- return (
178
- <div
179
- ref={ref}
180
- className={cn(
181
- "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
182
- className
183
- )}
184
- >
185
- {!nestLabel ? tooltipLabel : null}
186
- <div className="grid gap-1.5">
187
- {payload
188
- .filter((item) => item.type !== "none")
189
- .map((item, index) => {
190
- const key = `${nameKey || item.name || item.dataKey || "value"}`
191
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
192
- const indicatorColor = color || item.payload.fill || item.color
193
-
194
- return (
195
- <div
196
- key={item.dataKey}
197
- className={cn(
198
- "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
199
- indicator === "dot" && "items-center"
200
- )}
201
- >
202
- {formatter && item?.value !== undefined && item.name ? (
203
- formatter(item.value, item.name, item, index, item.payload)
204
- ) : (
205
- <>
206
- {itemConfig?.icon ? (
207
- <itemConfig.icon />
208
- ) : (
209
- !hideIndicator && (
210
- <div
211
- className={cn(
212
- "shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
213
- {
214
- "h-2.5 w-2.5": indicator === "dot",
215
- "w-1": indicator === "line",
216
- "w-0 border-[1.5px] border-dashed bg-transparent":
217
- indicator === "dashed",
218
- "my-0.5": nestLabel && indicator === "dashed",
219
- }
220
- )}
221
- style={
222
- {
223
- "--color-bg": indicatorColor,
224
- "--color-border": indicatorColor,
225
- } as React.CSSProperties
226
- }
227
- />
228
- )
229
- )}
230
- <div
231
- className={cn(
232
- "flex flex-1 justify-between leading-none",
233
- nestLabel ? "items-end" : "items-center"
234
- )}
235
- >
236
- <div className="grid gap-1.5">
237
- {nestLabel ? tooltipLabel : null}
238
- <span className="text-muted-foreground">
239
- {itemConfig?.label || item.name}
240
- </span>
241
- </div>
242
- {item.value && (
243
- <span className="font-mono font-medium tabular-nums text-foreground">
244
- {item.value.toLocaleString()}
245
- </span>
246
- )}
247
- </div>
248
- </>
249
- )}
250
- </div>
251
- )
252
- })}
136
+ const [item] = payload
137
+ const key = `${labelKey || item?.dataKey || item?.name || "value"}`
138
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
139
+ const value =
140
+ !labelKey && typeof label === "string"
141
+ ? config[label as keyof typeof config]?.label || label
142
+ : itemConfig?.label
143
+
144
+ if (labelFormatter) {
145
+ return (
146
+ <div className={cn("font-medium", labelClassName)}>
147
+ {labelFormatter(value, payload)}
253
148
  </div>
254
- </div>
255
- )
256
- }
257
- )
258
- ChartTooltipContent.displayName = "ChartTooltip"
259
-
260
- const ChartLegend = RechartsPrimitive.Legend
261
-
262
- const ChartLegendContent = React.forwardRef<
263
- HTMLDivElement,
264
- React.ComponentProps<"div"> &
265
- Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
266
- hideIcon?: boolean
267
- nameKey?: string
149
+ )
268
150
  }
269
- >(
270
- (
271
- { className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
272
- ref
273
- ) => {
274
- const { config } = useChart()
275
-
276
- if (!payload?.length) {
151
+
152
+ if (!value) {
277
153
  return null
278
154
  }
279
155
 
280
- return (
281
- <div
282
- ref={ref}
283
- className={cn(
284
- "flex items-center justify-center gap-4",
285
- verticalAlign === "top" ? "pb-3" : "pt-3",
286
- className
287
- )}
288
- >
156
+ return <div className={cn("font-medium", labelClassName)}>{value}</div>
157
+ }, [
158
+ label,
159
+ labelFormatter,
160
+ payload,
161
+ hideLabel,
162
+ labelClassName,
163
+ config,
164
+ labelKey,
165
+ ])
166
+
167
+ if (!active || !payload?.length) {
168
+ return null
169
+ }
170
+
171
+ const nestLabel = payload.length === 1 && indicator !== "dot"
172
+
173
+ return (
174
+ <div
175
+ className={cn(
176
+ "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
177
+ className
178
+ )}
179
+ >
180
+ {!nestLabel ? tooltipLabel : null}
181
+ <div className="grid gap-1.5">
289
182
  {payload
290
183
  .filter((item) => item.type !== "none")
291
- .map((item) => {
292
- const key = `${nameKey || item.dataKey || "value"}`
184
+ .map((item, index) => {
185
+ const key = `${nameKey || item.name || item.dataKey || "value"}`
293
186
  const itemConfig = getPayloadConfigFromPayload(config, item, key)
187
+ const indicatorColor = color || item.payload.fill || item.color
294
188
 
295
189
  return (
296
190
  <div
297
- key={item.value}
191
+ key={item.dataKey}
298
192
  className={cn(
299
- "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
193
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
194
+ indicator === "dot" && "items-center"
300
195
  )}
301
196
  >
302
- {itemConfig?.icon && !hideIcon ? (
303
- <itemConfig.icon />
197
+ {formatter && item?.value !== undefined && item.name ? (
198
+ formatter(item.value, item.name, item, index, item.payload)
304
199
  ) : (
305
- <div
306
- className="h-2 w-2 shrink-0 rounded-[2px]"
307
- style={{
308
- backgroundColor: item.color,
309
- }}
310
- />
200
+ <>
201
+ {itemConfig?.icon ? (
202
+ <itemConfig.icon />
203
+ ) : (
204
+ !hideIndicator && (
205
+ <div
206
+ className={cn(
207
+ "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
208
+ {
209
+ "h-2.5 w-2.5": indicator === "dot",
210
+ "w-1": indicator === "line",
211
+ "w-0 border-[1.5px] border-dashed bg-transparent":
212
+ indicator === "dashed",
213
+ "my-0.5": nestLabel && indicator === "dashed",
214
+ }
215
+ )}
216
+ style={
217
+ {
218
+ "--color-bg": indicatorColor,
219
+ "--color-border": indicatorColor,
220
+ } as React.CSSProperties
221
+ }
222
+ />
223
+ )
224
+ )}
225
+ <div
226
+ className={cn(
227
+ "flex flex-1 justify-between leading-none",
228
+ nestLabel ? "items-end" : "items-center"
229
+ )}
230
+ >
231
+ <div className="grid gap-1.5">
232
+ {nestLabel ? tooltipLabel : null}
233
+ <span className="text-muted-foreground">
234
+ {itemConfig?.label || item.name}
235
+ </span>
236
+ </div>
237
+ {item.value && (
238
+ <span className="font-mono font-medium text-foreground tabular-nums">
239
+ {item.value.toLocaleString()}
240
+ </span>
241
+ )}
242
+ </div>
243
+ </>
311
244
  )}
312
- {itemConfig?.label}
313
245
  </div>
314
246
  )
315
247
  })}
316
248
  </div>
317
- )
249
+ </div>
250
+ )
251
+ }
252
+
253
+ const ChartLegend = RechartsPrimitive.Legend
254
+
255
+ function ChartLegendContent({
256
+ className,
257
+ hideIcon = false,
258
+ payload,
259
+ verticalAlign = "bottom",
260
+ nameKey,
261
+ }: React.ComponentProps<"div"> &
262
+ Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
263
+ hideIcon?: boolean
264
+ nameKey?: string
265
+ }) {
266
+ const { config } = useChart()
267
+
268
+ if (!payload?.length) {
269
+ return null
318
270
  }
319
- )
320
- ChartLegendContent.displayName = "ChartLegend"
271
+
272
+ return (
273
+ <div
274
+ className={cn(
275
+ "flex items-center justify-center gap-4",
276
+ verticalAlign === "top" ? "pb-3" : "pt-3",
277
+ className
278
+ )}
279
+ >
280
+ {payload
281
+ .filter((item) => item.type !== "none")
282
+ .map((item) => {
283
+ const key = `${nameKey || item.dataKey || "value"}`
284
+ const itemConfig = getPayloadConfigFromPayload(config, item, key)
285
+
286
+ return (
287
+ <div
288
+ key={item.value}
289
+ className={cn(
290
+ "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
291
+ )}
292
+ >
293
+ {itemConfig?.icon && !hideIcon ? (
294
+ <itemConfig.icon />
295
+ ) : (
296
+ <div
297
+ className="h-2 w-2 shrink-0 rounded-[2px]"
298
+ style={{
299
+ backgroundColor: item.color,
300
+ }}
301
+ />
302
+ )}
303
+ {itemConfig?.label}
304
+ </div>
305
+ )
306
+ })}
307
+ </div>
308
+ )
309
+ }
321
310
 
322
311
  // Helper to extract item config from a payload.
323
312
  function getPayloadConfigFromPayload(
@@ -1,28 +1,32 @@
1
+ "use client"
2
+
1
3
  import * as React from "react"
4
+ import { Check } from "@phosphor-icons/react"
2
5
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
3
- import { Check } from "lucide-react"
4
6
 
5
- import { cn } from "@/lib/utils"
7
+ import { cn } from "../lib/utils"
6
8
 
7
- const Checkbox = React.forwardRef<
8
- React.ElementRef<typeof CheckboxPrimitive.Root>,
9
- React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
10
- >(({ className, ...props }, ref) => (
11
- <CheckboxPrimitive.Root
12
- ref={ref}
13
- className={cn(
14
- "grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
15
- className
16
- )}
17
- {...props}
18
- >
19
- <CheckboxPrimitive.Indicator
20
- className={cn("grid place-content-center text-current")}
9
+ function Checkbox({
10
+ className,
11
+ ...props
12
+ }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
13
+ return (
14
+ <CheckboxPrimitive.Root
15
+ data-slot="checkbox"
16
+ className={cn(
17
+ "peer size-4 shrink-0 rounded-[4px] border border-input shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:data-[state=checked]:bg-primary",
18
+ className
19
+ )}
20
+ {...props}
21
21
  >
22
- <Check className="h-4 w-4" />
23
- </CheckboxPrimitive.Indicator>
24
- </CheckboxPrimitive.Root>
25
- ))
26
- Checkbox.displayName = CheckboxPrimitive.Root.displayName
22
+ <CheckboxPrimitive.Indicator
23
+ data-slot="checkbox-indicator"
24
+ className="grid place-content-center text-current transition-none"
25
+ >
26
+ <Check className="size-3.5" />
27
+ </CheckboxPrimitive.Indicator>
28
+ </CheckboxPrimitive.Root>
29
+ )
30
+ }
27
31
 
28
32
  export { Checkbox }
@@ -2,10 +2,32 @@
2
2
 
3
3
  import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
4
4
 
5
- const Collapsible = CollapsiblePrimitive.Root
5
+ function Collapsible({
6
+ ...props
7
+ }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
8
+ return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />
9
+ }
6
10
 
7
- const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
11
+ function CollapsibleTrigger({
12
+ ...props
13
+ }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
14
+ return (
15
+ <CollapsiblePrimitive.CollapsibleTrigger
16
+ data-slot="collapsible-trigger"
17
+ {...props}
18
+ />
19
+ )
20
+ }
8
21
 
9
- const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
22
+ function CollapsibleContent({
23
+ ...props
24
+ }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
25
+ return (
26
+ <CollapsiblePrimitive.CollapsibleContent
27
+ data-slot="collapsible-content"
28
+ {...props}
29
+ />
30
+ )
31
+ }
10
32
 
11
33
  export { Collapsible, CollapsibleTrigger, CollapsibleContent }