@srcroot/ui 0.0.54 → 0.0.56

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 (107) hide show
  1. package/README.md +151 -151
  2. package/dist/index.d.ts +0 -0
  3. package/dist/index.js +55 -1
  4. package/package.json +7 -2
  5. package/src/registry/analytics/google-analytics.tsx +36 -39
  6. package/src/registry/analytics/google-tag-manager.tsx +62 -65
  7. package/src/registry/analytics/meta-pixel.tsx +44 -47
  8. package/src/registry/analytics/microsoft-clarity.tsx +31 -34
  9. package/src/registry/analytics/tiktok-pixel.tsx +34 -37
  10. package/src/registry/lib/utils.ts +0 -0
  11. package/src/registry/themes/v3/blue.css +157 -157
  12. package/src/registry/themes/v3/glass.css +153 -153
  13. package/src/registry/themes/v3/gray.css +157 -157
  14. package/src/registry/themes/v3/green.css +157 -157
  15. package/src/registry/themes/v3/neutral.css +157 -157
  16. package/src/registry/themes/v3/orange.css +157 -157
  17. package/src/registry/themes/v3/rose.css +157 -157
  18. package/src/registry/themes/v3/slate.css +157 -157
  19. package/src/registry/themes/v3/stone.css +157 -157
  20. package/src/registry/themes/v3/violet.css +186 -186
  21. package/src/registry/themes/v3/zinc.css +157 -157
  22. package/src/registry/themes/v4/blue.css +184 -184
  23. package/src/registry/themes/v4/glass.css +180 -180
  24. package/src/registry/themes/v4/gray.css +184 -184
  25. package/src/registry/themes/v4/green.css +184 -184
  26. package/src/registry/themes/v4/neutral.css +184 -184
  27. package/src/registry/themes/v4/orange.css +184 -184
  28. package/src/registry/themes/v4/rose.css +184 -184
  29. package/src/registry/themes/v4/slate.css +184 -184
  30. package/src/registry/themes/v4/stone.css +184 -184
  31. package/src/registry/themes/v4/violet.css +184 -184
  32. package/src/registry/themes/v4/zinc.css +184 -184
  33. package/src/registry/ui/accordion.tsx +164 -165
  34. package/src/registry/ui/alert-dialog.tsx +213 -214
  35. package/src/registry/ui/alert.tsx +73 -76
  36. package/src/registry/ui/aspect-ratio.tsx +44 -47
  37. package/src/registry/ui/avatar.tsx +96 -97
  38. package/src/registry/ui/badge.tsx +52 -55
  39. package/src/registry/ui/breadcrumb.tsx +147 -150
  40. package/src/registry/ui/button-group.tsx +64 -67
  41. package/src/registry/ui/button.tsx +71 -72
  42. package/src/registry/ui/calendar.tsx +514 -515
  43. package/src/registry/ui/card.tsx +88 -91
  44. package/src/registry/ui/carousel.tsx +214 -214
  45. package/src/registry/ui/chart.tsx +373 -373
  46. package/src/registry/ui/chatbot.tsx +86 -13
  47. package/src/registry/ui/checkbox.tsx +93 -94
  48. package/src/registry/ui/collapsible.tsx +107 -108
  49. package/src/registry/ui/combobox.tsx +171 -171
  50. package/src/registry/ui/command.tsx +300 -300
  51. package/src/registry/ui/container.tsx +44 -47
  52. package/src/registry/ui/context-menu.tsx +221 -221
  53. package/src/registry/ui/date-picker.tsx +228 -228
  54. package/src/registry/ui/dialog.tsx +269 -270
  55. package/src/registry/ui/drawer.tsx +10 -4
  56. package/src/registry/ui/dropdown-menu.tsx +529 -530
  57. package/src/registry/ui/empty-state.tsx +0 -2
  58. package/src/registry/ui/file-upload.tsx +0 -0
  59. package/src/registry/ui/floating-dock.tsx +0 -0
  60. package/src/registry/ui/form-field.tsx +91 -94
  61. package/src/registry/ui/google-analytics.tsx +38 -0
  62. package/src/registry/ui/google-tag-manager.tsx +64 -0
  63. package/src/registry/ui/hover-card.tsx +223 -223
  64. package/src/registry/ui/image.tsx +144 -147
  65. package/src/registry/ui/input-group.tsx +82 -85
  66. package/src/registry/ui/input.tsx +125 -125
  67. package/src/registry/ui/kbd.tsx +60 -63
  68. package/src/registry/ui/label.tsx +36 -37
  69. package/src/registry/ui/loading-spinner.tsx +108 -111
  70. package/src/registry/ui/map.tsx +0 -0
  71. package/src/registry/ui/marquee.tsx +2 -0
  72. package/src/registry/ui/menubar.tsx +246 -246
  73. package/src/registry/ui/meta-pixel.tsx +46 -0
  74. package/src/registry/ui/microsoft-clarity.tsx +33 -0
  75. package/src/registry/ui/native-select.tsx +49 -52
  76. package/src/registry/ui/otp-input.tsx +152 -155
  77. package/src/registry/ui/pagination.tsx +149 -152
  78. package/src/registry/ui/patterns.tsx +28 -0
  79. package/src/registry/ui/popover.tsx +226 -227
  80. package/src/registry/ui/progress.tsx +51 -52
  81. package/src/registry/ui/radio.tsx +99 -102
  82. package/src/registry/ui/resizable.tsx +314 -314
  83. package/src/registry/ui/scroll-animation.tsx +45 -0
  84. package/src/registry/ui/scroll-area.tsx +121 -122
  85. package/src/registry/ui/scroll-to-top.tsx +0 -0
  86. package/src/registry/ui/search.tsx +147 -150
  87. package/src/registry/ui/select.tsx +292 -293
  88. package/src/registry/ui/separator.tsx +46 -47
  89. package/src/registry/ui/sheet.tsx +6 -3
  90. package/src/registry/ui/sidebar.tsx +628 -628
  91. package/src/registry/ui/skeleton.tsx +26 -29
  92. package/src/registry/ui/slider.tsx +196 -197
  93. package/src/registry/ui/slot.tsx +69 -72
  94. package/src/registry/ui/star-rating.tsx +131 -134
  95. package/src/registry/ui/switch.tsx +72 -73
  96. package/src/registry/ui/table-of-contents.tsx +96 -96
  97. package/src/registry/ui/table.tsx +138 -139
  98. package/src/registry/ui/tabs.tsx +124 -125
  99. package/src/registry/ui/text.tsx +61 -64
  100. package/src/registry/ui/textarea.tsx +41 -42
  101. package/src/registry/ui/theme-switcher.tsx +66 -66
  102. package/src/registry/ui/tiktok-pixel.tsx +36 -0
  103. package/src/registry/ui/toast.tsx +97 -98
  104. package/src/registry/ui/toggle-group.tsx +129 -129
  105. package/src/registry/ui/toggle.tsx +72 -72
  106. package/src/registry/ui/tooltip.tsx +143 -144
  107. package/src/registry/ui/whatsapp.tsx +0 -0
@@ -1,228 +1,228 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import { addDays, startOfMonth, endOfMonth } from "date-fns"
5
- import { Calendar } from "./calendar"
6
- import { Popover, PopoverContent, PopoverTrigger } from "./popover"
7
- import { Button } from "./button"
8
- import { cn } from "@/lib/utils"
9
-
10
- // Calendar icon
11
- const CalendarIcon = () => (
12
- <svg
13
- xmlns="http://www.w3.org/2000/svg"
14
- width="16"
15
- height="16"
16
- viewBox="0 0 24 24"
17
- fill="none"
18
- stroke="currentColor"
19
- strokeWidth="2"
20
- strokeLinecap="round"
21
- strokeLinejoin="round"
22
- className="mr-2 h-4 w-4 opacity-50"
23
- >
24
- <rect width="18" height="18" x="3" y="4" rx="2" ry="2" />
25
- <line x1="16" x2="16" y1="2" y2="6" />
26
- <line x1="8" x2="8" y1="2" y2="6" />
27
- <line x1="3" x2="21" y1="10" y2="10" />
28
- </svg>
29
- )
30
-
31
- // Format helpers
32
- const formatDate = (date: Date) => {
33
- return date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })
34
- }
35
-
36
- const formatRange = (dates: Date[]) => {
37
- if (dates.length === 0) return null
38
- if (dates.length === 1) return formatDate(dates[0])
39
- return `${formatDate(dates[0])} → ${formatDate(dates[1])}`
40
- }
41
-
42
- const formatMultiple = (dates: Date[]) => {
43
- if (dates.length === 0) return null
44
- return `${dates.length} date${dates.length > 1 ? 's' : ''} selected`
45
- }
46
-
47
- // DatePicker Props
48
- interface DatePickerBaseProps {
49
- /** Placeholder text when no date selected */
50
- placeholder?: string
51
- /** Whether the picker is disabled */
52
- disabled?: boolean
53
- /** Custom class name for the trigger button */
54
- className?: string
55
- /** Number of months to display */
56
- numberOfMonths?: 1 | 2
57
- /** Calendar size */
58
- size?: "xs" | "sm" | "default" | "md" | "lg"
59
- }
60
-
61
- interface DatePickerSingleProps extends DatePickerBaseProps {
62
- mode?: "single"
63
- selected?: Date
64
- onSelect?: (date: Date | undefined) => void
65
- }
66
-
67
- interface DatePickerMultipleProps extends DatePickerBaseProps {
68
- mode: "multiple"
69
- selected?: Date[]
70
- onSelect?: (dates: Date[]) => void
71
- }
72
-
73
- interface DatePickerRangeProps extends DatePickerBaseProps {
74
- mode: "range"
75
- selected?: Date[]
76
- onSelect?: (dates: Date[]) => void
77
- }
78
-
79
- type DatePickerProps = DatePickerSingleProps | DatePickerMultipleProps | DatePickerRangeProps
80
-
81
- /**
82
- * DatePicker - A complete date picker component
83
- *
84
- * Combines Calendar + Popover for a ready-to-use date selection experience.
85
- * Supports single, multiple, and range selection modes.
86
- *
87
- * @example
88
- * // Single date
89
- * <DatePicker selected={date} onSelect={setDate} />
90
- *
91
- * // Multiple dates
92
- * <DatePicker mode="multiple" selected={dates} onSelect={setDates} />
93
- *
94
- * // Date range with dual months
95
- * <DatePicker mode="range" numberOfMonths={2} selected={range} onSelect={setRange} />
96
- */
97
- const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
98
- ({
99
- mode = "single",
100
- selected,
101
- onSelect,
102
- placeholder,
103
- disabled = false,
104
- className,
105
- numberOfMonths = 1,
106
- size = "default",
107
- ...props
108
- }, ref) => {
109
- const [open, setOpen] = React.useState(false)
110
-
111
- // Determine display text
112
- const getDisplayText = () => {
113
- if (mode === "single") {
114
- return selected ? formatDate(selected as Date) : null
115
- } else if (mode === "multiple") {
116
- const dates = (selected as Date[]) || []
117
- return dates.length > 0 ? formatMultiple(dates) : null
118
- } else {
119
- const dates = (selected as Date[]) || []
120
- return dates.length > 0 ? formatRange(dates) : null
121
- }
122
- }
123
-
124
- const displayText = getDisplayText()
125
- const defaultPlaceholder = mode === "single" ? "Pick a date"
126
- : mode === "multiple" ? "Pick dates"
127
- : "Pick a date range"
128
-
129
- // Presets for Range Mode
130
- const presets = [
131
- {
132
- label: "Last 7 Days",
133
- getValue: () => {
134
- const today = new Date()
135
- return [addDays(today, -7), today]
136
- },
137
- },
138
- {
139
- label: "Last 30 Days",
140
- getValue: () => {
141
- const today = new Date()
142
- return [addDays(today, -30), today]
143
- },
144
- },
145
- {
146
- label: "This Month",
147
- getValue: () => {
148
- const today = new Date()
149
- return [startOfMonth(today), endOfMonth(today)]
150
- },
151
- },
152
- ]
153
-
154
- // Handle selection
155
- const handleSelect = (value: any) => {
156
- if (mode === "single") {
157
- (onSelect as ((date: Date | undefined) => void))?.(value)
158
- setOpen(false) // Close on single selection
159
- } else if (mode === "multiple") {
160
- (onSelect as ((dates: Date[]) => void))?.(value || [])
161
- } else {
162
- const dates = value || []
163
- ; (onSelect as ((dates: Date[]) => void))?.(dates)
164
- // Do not close automatically for range to allow adjustment
165
- }
166
- }
167
-
168
- const handlePresetSelect = (preset: { getValue: () => Date[] }) => {
169
- if (mode === "range") {
170
- const dates = preset.getValue()
171
- ; (onSelect as ((dates: Date[]) => void))?.(dates)
172
- // Update internal state if uncontrolled (not covered here fully but ensures trigger updates if parent consumes correctly)
173
- // For this component to be fully controlled, parent must pass `selected`.
174
- // If we want it to close on preset select:
175
- setOpen(false)
176
- }
177
- }
178
-
179
- return (
180
- <Popover open={open} onOpenChange={setOpen}>
181
- <PopoverTrigger asChild>
182
- <Button
183
- ref={ref}
184
- variant="outline"
185
- disabled={disabled}
186
- className={cn(
187
- "w-[260px] justify-start text-left font-normal",
188
- !displayText && "text-muted-foreground",
189
- className
190
- )}
191
- >
192
- <CalendarIcon />
193
- {displayText || <span>{placeholder || defaultPlaceholder}</span>}
194
- </Button>
195
- </PopoverTrigger>
196
- <PopoverContent className="w-auto p-0" align="end">
197
- <div className="flex">
198
- {mode === "range" && (
199
- <div className="border-r p-2 space-y-1 w-[140px]">
200
- {presets.map((preset) => (
201
- <Button
202
- key={preset.label}
203
- variant="ghost"
204
- className="w-full justify-start font-normal"
205
- onClick={() => handlePresetSelect(preset)}
206
- >
207
- {preset.label}
208
- </Button>
209
- ))}
210
- </div>
211
- )}
212
- <Calendar
213
- mode={mode}
214
- numberOfMonths={numberOfMonths}
215
- size={size}
216
- selected={selected}
217
- onSelect={handleSelect}
218
- className="rounded-md border-0 shadow-none"
219
- />
220
- </div>
221
- </PopoverContent>
222
- </Popover>
223
- )
224
- }
225
- )
226
- DatePicker.displayName = "DatePicker"
227
-
228
- export { DatePicker, type DatePickerProps }
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { addDays, startOfMonth, endOfMonth } from "date-fns"
5
+ import { Calendar } from "./calendar"
6
+ import { Popover, PopoverContent, PopoverTrigger } from "./popover"
7
+ import { Button } from "./button"
8
+ import { cn } from "@/lib/utils"
9
+
10
+ // Calendar icon
11
+ const CalendarIcon = () => (
12
+ <svg
13
+ xmlns="http://www.w3.org/2000/svg"
14
+ width="16"
15
+ height="16"
16
+ viewBox="0 0 24 24"
17
+ fill="none"
18
+ stroke="currentColor"
19
+ strokeWidth="2"
20
+ strokeLinecap="round"
21
+ strokeLinejoin="round"
22
+ className="mr-2 h-4 w-4 opacity-50"
23
+ >
24
+ <rect width="18" height="18" x="3" y="4" rx="2" ry="2" />
25
+ <line x1="16" x2="16" y1="2" y2="6" />
26
+ <line x1="8" x2="8" y1="2" y2="6" />
27
+ <line x1="3" x2="21" y1="10" y2="10" />
28
+ </svg>
29
+ )
30
+
31
+ // Format helpers
32
+ const formatDate = (date: Date) => {
33
+ return date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })
34
+ }
35
+
36
+ const formatRange = (dates: Date[]) => {
37
+ if (dates.length === 0) return null
38
+ if (dates.length === 1) return formatDate(dates[0])
39
+ return `${formatDate(dates[0])} → ${formatDate(dates[1])}`
40
+ }
41
+
42
+ const formatMultiple = (dates: Date[]) => {
43
+ if (dates.length === 0) return null
44
+ return `${dates.length} date${dates.length > 1 ? 's' : ''} selected`
45
+ }
46
+
47
+ // DatePicker Props
48
+ interface DatePickerBaseProps {
49
+ /** Placeholder text when no date selected */
50
+ placeholder?: string
51
+ /** Whether the picker is disabled */
52
+ disabled?: boolean
53
+ /** Custom class name for the trigger button */
54
+ className?: string
55
+ /** Number of months to display */
56
+ numberOfMonths?: 1 | 2
57
+ /** Calendar size */
58
+ size?: "xs" | "sm" | "default" | "md" | "lg"
59
+ }
60
+
61
+ interface DatePickerSingleProps extends DatePickerBaseProps {
62
+ mode?: "single"
63
+ selected?: Date
64
+ onSelect?: (date: Date | undefined) => void
65
+ }
66
+
67
+ interface DatePickerMultipleProps extends DatePickerBaseProps {
68
+ mode: "multiple"
69
+ selected?: Date[]
70
+ onSelect?: (dates: Date[]) => void
71
+ }
72
+
73
+ interface DatePickerRangeProps extends DatePickerBaseProps {
74
+ mode: "range"
75
+ selected?: Date[]
76
+ onSelect?: (dates: Date[]) => void
77
+ }
78
+
79
+ type DatePickerProps = DatePickerSingleProps | DatePickerMultipleProps | DatePickerRangeProps
80
+
81
+ /**
82
+ * DatePicker - A complete date picker component
83
+ *
84
+ * Combines Calendar + Popover for a ready-to-use date selection experience.
85
+ * Supports single, multiple, and range selection modes.
86
+ *
87
+ * @example
88
+ * // Single date
89
+ * <DatePicker selected={date} onSelect={setDate} />
90
+ *
91
+ * // Multiple dates
92
+ * <DatePicker mode="multiple" selected={dates} onSelect={setDates} />
93
+ *
94
+ * // Date range with dual months
95
+ * <DatePicker mode="range" numberOfMonths={2} selected={range} onSelect={setRange} />
96
+ */
97
+ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
98
+ ({
99
+ mode = "single",
100
+ selected,
101
+ onSelect,
102
+ placeholder,
103
+ disabled = false,
104
+ className,
105
+ numberOfMonths = 1,
106
+ size = "default",
107
+ ...props
108
+ }, ref) => {
109
+ const [open, setOpen] = React.useState(false)
110
+
111
+ // Determine display text
112
+ const getDisplayText = () => {
113
+ if (mode === "single") {
114
+ return selected ? formatDate(selected as Date) : null
115
+ } else if (mode === "multiple") {
116
+ const dates = (selected as Date[]) || []
117
+ return dates.length > 0 ? formatMultiple(dates) : null
118
+ } else {
119
+ const dates = (selected as Date[]) || []
120
+ return dates.length > 0 ? formatRange(dates) : null
121
+ }
122
+ }
123
+
124
+ const displayText = getDisplayText()
125
+ const defaultPlaceholder = mode === "single" ? "Pick a date"
126
+ : mode === "multiple" ? "Pick dates"
127
+ : "Pick a date range"
128
+
129
+ // Presets for Range Mode
130
+ const presets = [
131
+ {
132
+ label: "Last 7 Days",
133
+ getValue: () => {
134
+ const today = new Date()
135
+ return [addDays(today, -7), today]
136
+ },
137
+ },
138
+ {
139
+ label: "Last 30 Days",
140
+ getValue: () => {
141
+ const today = new Date()
142
+ return [addDays(today, -30), today]
143
+ },
144
+ },
145
+ {
146
+ label: "This Month",
147
+ getValue: () => {
148
+ const today = new Date()
149
+ return [startOfMonth(today), endOfMonth(today)]
150
+ },
151
+ },
152
+ ]
153
+
154
+ // Handle selection
155
+ const handleSelect = (value: any) => {
156
+ if (mode === "single") {
157
+ (onSelect as ((date: Date | undefined) => void))?.(value)
158
+ setOpen(false) // Close on single selection
159
+ } else if (mode === "multiple") {
160
+ (onSelect as ((dates: Date[]) => void))?.(value || [])
161
+ } else {
162
+ const dates = value || []
163
+ ; (onSelect as ((dates: Date[]) => void))?.(dates)
164
+ // Do not close automatically for range to allow adjustment
165
+ }
166
+ }
167
+
168
+ const handlePresetSelect = (preset: { getValue: () => Date[] }) => {
169
+ if (mode === "range") {
170
+ const dates = preset.getValue()
171
+ ; (onSelect as ((dates: Date[]) => void))?.(dates)
172
+ // Update internal state if uncontrolled (not covered here fully but ensures trigger updates if parent consumes correctly)
173
+ // For this component to be fully controlled, parent must pass `selected`.
174
+ // If we want it to close on preset select:
175
+ setOpen(false)
176
+ }
177
+ }
178
+
179
+ return (
180
+ <Popover open={open} onOpenChange={setOpen}>
181
+ <PopoverTrigger asChild>
182
+ <Button
183
+ ref={ref}
184
+ variant="outline"
185
+ disabled={disabled}
186
+ className={cn(
187
+ "w-[260px] justify-start text-left font-normal",
188
+ !displayText && "text-muted-foreground",
189
+ className
190
+ )}
191
+ >
192
+ <CalendarIcon />
193
+ {displayText || <span>{placeholder || defaultPlaceholder}</span>}
194
+ </Button>
195
+ </PopoverTrigger>
196
+ <PopoverContent className="w-auto p-0" align="end">
197
+ <div className="flex">
198
+ {mode === "range" && (
199
+ <div className="border-r p-2 space-y-1 w-[140px]">
200
+ {presets.map((preset) => (
201
+ <Button
202
+ key={preset.label}
203
+ variant="ghost"
204
+ className="w-full justify-start font-normal"
205
+ onClick={() => handlePresetSelect(preset)}
206
+ >
207
+ {preset.label}
208
+ </Button>
209
+ ))}
210
+ </div>
211
+ )}
212
+ <Calendar
213
+ mode={mode}
214
+ numberOfMonths={numberOfMonths}
215
+ size={size}
216
+ selected={selected}
217
+ onSelect={handleSelect}
218
+ className="rounded-md border-0 shadow-none"
219
+ />
220
+ </div>
221
+ </PopoverContent>
222
+ </Popover>
223
+ )
224
+ }
225
+ )
226
+ DatePicker.displayName = "DatePicker"
227
+
228
+ export { DatePicker, type DatePickerProps }