@srcroot/ui 0.0.44 → 0.0.46

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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @srcroot/ui - Slate Theme (Tailwind 4)
3
- * Cool gray with strong blue undertones (shadcn default)
3
+ * Cool gray with strong blue undertones (default)
4
4
  */
5
5
 
6
6
  @import "tailwindcss";
@@ -126,54 +126,52 @@
126
126
  }
127
127
  }
128
128
 
129
- @media (prefers-color-scheme: dark) {
130
- :root {
131
- --background: hsl(222.2 84% 4.9%);
132
- --foreground: hsl(210 40% 98%);
129
+ .dark {
130
+ --background: hsl(222.2 84% 4.9%);
131
+ --foreground: hsl(210 40% 98%);
133
132
 
134
- --card: hsl(222.2 84% 4.9%);
135
- --card-foreground: hsl(210 40% 98%);
133
+ --card: hsl(222.2 84% 4.9%);
134
+ --card-foreground: hsl(210 40% 98%);
136
135
 
137
- --popover: hsl(222.2 84% 4.9%);
138
- --popover-foreground: hsl(210 40% 98%);
136
+ --popover: hsl(222.2 84% 4.9%);
137
+ --popover-foreground: hsl(210 40% 98%);
139
138
 
140
- --primary: hsl(210 40% 98%);
141
- --primary-foreground: hsl(222.2 47.4% 11.2%);
139
+ --primary: hsl(210 40% 98%);
140
+ --primary-foreground: hsl(222.2 47.4% 11.2%);
142
141
 
143
- --secondary: hsl(217.2 32.6% 17.5%);
144
- --secondary-foreground: hsl(210 40% 98%);
142
+ --secondary: hsl(217.2 32.6% 17.5%);
143
+ --secondary-foreground: hsl(210 40% 98%);
145
144
 
146
- --muted: hsl(217.2 32.6% 17.5%);
147
- --muted-foreground: hsl(215 20.2% 65.1%);
145
+ --muted: hsl(217.2 32.6% 17.5%);
146
+ --muted-foreground: hsl(215 20.2% 65.1%);
148
147
 
149
- --accent: hsl(217.2 32.6% 17.5%);
150
- --accent-foreground: hsl(210 40% 98%);
148
+ --accent: hsl(217.2 32.6% 17.5%);
149
+ --accent-foreground: hsl(210 40% 98%);
151
150
 
152
- --destructive: hsl(0 62.8% 30.6%);
153
- --destructive-foreground: hsl(210 40% 98%);
154
-
155
- --success: hsl(142.1 70.6% 45.3%);
156
- --success-foreground: hsl(222.2 47.4% 11.2%);
157
-
158
- --warning: hsl(48 96.5% 53.1%);
159
- --warning-foreground: hsl(222.2 47.4% 11.2%);
151
+ --destructive: hsl(0 62.8% 30.6%);
152
+ --destructive-foreground: hsl(210 40% 98%);
160
153
 
161
- --info: hsl(199.4 95.5% 53.8%);
162
- --info-foreground: hsl(222.2 47.4% 11.2%);
154
+ --success: hsl(142.1 70.6% 45.3%);
155
+ --success-foreground: hsl(222.2 47.4% 11.2%);
163
156
 
164
- --border: hsl(217.2 32.6% 17.5%);
165
- --input: hsl(217.2 32.6% 17.5%);
166
- --ring: hsl(212.7 26.8% 83.9%);
157
+ --warning: hsl(48 96.5% 53.1%);
158
+ --warning-foreground: hsl(222.2 47.4% 11.2%);
167
159
 
168
- --sidebar-background: hsl(222.2 84% 10%);
169
- --sidebar-foreground: hsl(210 40% 98%);
170
- --sidebar-primary: hsl(210 40% 98%);
171
- --sidebar-primary-foreground: hsl(222.2 47.4% 11.2%);
172
- --sidebar-accent: hsl(217.2 32.6% 17.5%);
173
- --sidebar-accent-foreground: hsl(210 40% 98%);
174
- --sidebar-border: hsl(217.2 32.6% 17.5%);
175
- --sidebar-ring: hsl(212.7 26.8% 83.9%);
176
- }
160
+ --info: hsl(199.4 95.5% 53.8%);
161
+ --info-foreground: hsl(222.2 47.4% 11.2%);
162
+
163
+ --border: hsl(217.2 32.6% 17.5%);
164
+ --input: hsl(217.2 32.6% 17.5%);
165
+ --ring: hsl(212.7 26.8% 83.9%);
166
+
167
+ --sidebar-background: hsl(222.2 84% 10%);
168
+ --sidebar-foreground: hsl(210 40% 98%);
169
+ --sidebar-primary: hsl(210 40% 98%);
170
+ --sidebar-primary-foreground: hsl(222.2 47.4% 11.2%);
171
+ --sidebar-accent: hsl(217.2 32.6% 17.5%);
172
+ --sidebar-accent-foreground: hsl(210 40% 98%);
173
+ --sidebar-border: hsl(217.2 32.6% 17.5%);
174
+ --sidebar-ring: hsl(212.7 26.8% 83.9%);
177
175
  }
178
176
 
179
177
  body {
@@ -126,54 +126,52 @@
126
126
  }
127
127
  }
128
128
 
129
- @media (prefers-color-scheme: dark) {
130
- :root {
131
- --background: hsl(24 9.8% 10%);
132
- --foreground: hsl(60 9.1% 97.8%);
129
+ .dark {
130
+ --background: hsl(24 9.8% 10%);
131
+ --foreground: hsl(60 9.1% 97.8%);
133
132
 
134
- --card: hsl(24 9.8% 10%);
135
- --card-foreground: hsl(60 9.1% 97.8%);
133
+ --card: hsl(24 9.8% 10%);
134
+ --card-foreground: hsl(60 9.1% 97.8%);
136
135
 
137
- --popover: hsl(24 9.8% 10%);
138
- --popover-foreground: hsl(60 9.1% 97.8%);
136
+ --popover: hsl(24 9.8% 10%);
137
+ --popover-foreground: hsl(60 9.1% 97.8%);
139
138
 
140
- --primary: hsl(60 9.1% 97.8%);
141
- --primary-foreground: hsl(24 9.8% 10%);
139
+ --primary: hsl(60 9.1% 97.8%);
140
+ --primary-foreground: hsl(24 9.8% 10%);
142
141
 
143
- --secondary: hsl(12 6.5% 15.1%);
144
- --secondary-foreground: hsl(60 9.1% 97.8%);
142
+ --secondary: hsl(12 6.5% 15.1%);
143
+ --secondary-foreground: hsl(60 9.1% 97.8%);
145
144
 
146
- --muted: hsl(12 6.5% 15.1%);
147
- --muted-foreground: hsl(24 5.4% 63.9%);
145
+ --muted: hsl(12 6.5% 15.1%);
146
+ --muted-foreground: hsl(24 5.4% 63.9%);
148
147
 
149
- --accent: hsl(12 6.5% 15.1%);
150
- --accent-foreground: hsl(60 9.1% 97.8%);
148
+ --accent: hsl(12 6.5% 15.1%);
149
+ --accent-foreground: hsl(60 9.1% 97.8%);
151
150
 
152
- --destructive: hsl(0 62.8% 30.6%);
153
- --destructive-foreground: hsl(60 9.1% 97.8%);
154
-
155
- --success: hsl(142.1 70.6% 45.3%);
156
- --success-foreground: hsl(24 9.8% 10%);
157
-
158
- --warning: hsl(48 96.5% 53.1%);
159
- --warning-foreground: hsl(24 9.8% 10%);
151
+ --destructive: hsl(0 62.8% 30.6%);
152
+ --destructive-foreground: hsl(60 9.1% 97.8%);
160
153
 
161
- --info: hsl(199.4 95.5% 53.8%);
162
- --info-foreground: hsl(24 9.8% 10%);
154
+ --success: hsl(142.1 70.6% 45.3%);
155
+ --success-foreground: hsl(24 9.8% 10%);
163
156
 
164
- --border: hsl(12 6.5% 15.1%);
165
- --input: hsl(12 6.5% 15.1%);
166
- --ring: hsl(24 5.7% 82.9%);
157
+ --warning: hsl(48 96.5% 53.1%);
158
+ --warning-foreground: hsl(24 9.8% 10%);
167
159
 
168
- --sidebar-background: hsl(24 9.8% 14%);
169
- --sidebar-foreground: hsl(60 9.1% 97.8%);
170
- --sidebar-primary: hsl(60 9.1% 97.8%);
171
- --sidebar-primary-foreground: hsl(24 9.8% 10%);
172
- --sidebar-accent: hsl(12 6.5% 15.1%);
173
- --sidebar-accent-foreground: hsl(60 9.1% 97.8%);
174
- --sidebar-border: hsl(12 6.5% 15.1%);
175
- --sidebar-ring: hsl(24 5.7% 82.9%);
176
- }
160
+ --info: hsl(199.4 95.5% 53.8%);
161
+ --info-foreground: hsl(24 9.8% 10%);
162
+
163
+ --border: hsl(12 6.5% 15.1%);
164
+ --input: hsl(12 6.5% 15.1%);
165
+ --ring: hsl(24 5.7% 82.9%);
166
+
167
+ --sidebar-background: hsl(24 9.8% 14%);
168
+ --sidebar-foreground: hsl(60 9.1% 97.8%);
169
+ --sidebar-primary: hsl(60 9.1% 97.8%);
170
+ --sidebar-primary-foreground: hsl(24 9.8% 10%);
171
+ --sidebar-accent: hsl(12 6.5% 15.1%);
172
+ --sidebar-accent-foreground: hsl(60 9.1% 97.8%);
173
+ --sidebar-border: hsl(12 6.5% 15.1%);
174
+ --sidebar-ring: hsl(24 5.7% 82.9%);
177
175
  }
178
176
 
179
177
  body {
@@ -126,54 +126,52 @@
126
126
  }
127
127
  }
128
128
 
129
- @media (prefers-color-scheme: dark) {
130
- :root {
131
- --background: hsl(246 20% 6%);
132
- --foreground: hsl(0 0% 98%);
129
+ .dark {
130
+ --background: hsl(246 20% 6%);
131
+ --foreground: hsl(0 0% 98%);
133
132
 
134
- --card: hsl(246 20% 8%);
135
- --card-foreground: hsl(0 0% 98%);
133
+ --card: hsl(246 20% 8%);
134
+ --card-foreground: hsl(0 0% 98%);
136
135
 
137
- --popover: hsl(246 20% 8%);
138
- --popover-foreground: hsl(0 0% 98%);
136
+ --popover: hsl(246 20% 8%);
137
+ --popover-foreground: hsl(0 0% 98%);
139
138
 
140
- --primary: hsl(246 80% 65%);
141
- --primary-foreground: hsl(246 20% 6%);
139
+ --primary: hsl(246 80% 65%);
140
+ --primary-foreground: hsl(246 20% 6%);
142
141
 
143
- --secondary: hsl(320 85% 60%);
144
- --secondary-foreground: hsl(0 0% 100%);
145
-
146
- --muted: hsl(246 20% 15%);
147
- --muted-foreground: hsl(246 10% 60%);
148
-
149
- --accent: hsl(320 85% 60%);
150
- --accent-foreground: hsl(0 0% 100%);
142
+ --secondary: hsl(320 85% 60%);
143
+ --secondary-foreground: hsl(0 0% 100%);
151
144
 
152
- --destructive: hsl(0 62.8% 30.6%);
153
- --destructive-foreground: hsl(0 0% 98%);
145
+ --muted: hsl(246 20% 15%);
146
+ --muted-foreground: hsl(246 10% 60%);
154
147
 
155
- --success: hsl(142.1 70.6% 45.3%);
156
- --success-foreground: hsl(246 80% 60%);
148
+ --accent: hsl(320 85% 60%);
149
+ --accent-foreground: hsl(0 0% 100%);
157
150
 
158
- --warning: hsl(48 96.5% 53.1%);
159
- --warning-foreground: hsl(246 80% 60%);
151
+ --destructive: hsl(0 62.8% 30.6%);
152
+ --destructive-foreground: hsl(0 0% 98%);
160
153
 
161
- --info: hsl(199.4 95.5% 53.8%);
162
- --info-foreground: hsl(246 80% 60%);
154
+ --success: hsl(142.1 70.6% 45.3%);
155
+ --success-foreground: hsl(246 80% 60%);
163
156
 
164
- --border: hsl(246 20% 18%);
165
- --input: hsl(246 20% 18%);
166
- --ring: hsl(246 80% 65%);
157
+ --warning: hsl(48 96.5% 53.1%);
158
+ --warning-foreground: hsl(246 80% 60%);
167
159
 
168
- --sidebar-background: hsl(246 20% 10%);
169
- --sidebar-foreground: hsl(0 0% 98%);
170
- --sidebar-primary: hsl(246 80% 65%);
171
- --sidebar-primary-foreground: hsl(246 20% 6%);
172
- --sidebar-accent: hsl(320 85% 60%);
173
- --sidebar-accent-foreground: hsl(0 0% 100%);
174
- --sidebar-border: hsl(246 20% 18%);
175
- --sidebar-ring: hsl(246 80% 65%);
176
- }
160
+ --info: hsl(199.4 95.5% 53.8%);
161
+ --info-foreground: hsl(246 80% 60%);
162
+
163
+ --border: hsl(246 20% 18%);
164
+ --input: hsl(246 20% 18%);
165
+ --ring: hsl(246 80% 65%);
166
+
167
+ --sidebar-background: hsl(246 20% 10%);
168
+ --sidebar-foreground: hsl(0 0% 98%);
169
+ --sidebar-primary: hsl(246 80% 65%);
170
+ --sidebar-primary-foreground: hsl(246 20% 6%);
171
+ --sidebar-accent: hsl(320 85% 60%);
172
+ --sidebar-accent-foreground: hsl(0 0% 100%);
173
+ --sidebar-border: hsl(246 20% 18%);
174
+ --sidebar-ring: hsl(246 80% 65%);
177
175
  }
178
176
 
179
177
  body {
@@ -126,54 +126,52 @@
126
126
  }
127
127
  }
128
128
 
129
- @media (prefers-color-scheme: dark) {
130
- :root {
131
- --background: hsl(240 10% 3.9%);
132
- --foreground: hsl(0 0% 98%);
129
+ .dark {
130
+ --background: hsl(240 10% 3.9%);
131
+ --foreground: hsl(0 0% 98%);
133
132
 
134
- --card: hsl(240 10% 3.9%);
135
- --card-foreground: hsl(0 0% 98%);
133
+ --card: hsl(240 10% 3.9%);
134
+ --card-foreground: hsl(0 0% 98%);
136
135
 
137
- --popover: hsl(240 10% 3.9%);
138
- --popover-foreground: hsl(0 0% 98%);
136
+ --popover: hsl(240 10% 3.9%);
137
+ --popover-foreground: hsl(0 0% 98%);
139
138
 
140
- --primary: hsl(0 0% 98%);
141
- --primary-foreground: hsl(240 5.9% 10%);
139
+ --primary: hsl(0 0% 98%);
140
+ --primary-foreground: hsl(240 5.9% 10%);
142
141
 
143
- --secondary: hsl(240 3.7% 15.9%);
144
- --secondary-foreground: hsl(0 0% 98%);
142
+ --secondary: hsl(240 3.7% 15.9%);
143
+ --secondary-foreground: hsl(0 0% 98%);
145
144
 
146
- --muted: hsl(240 3.7% 15.9%);
147
- --muted-foreground: hsl(240 5% 64.9%);
145
+ --muted: hsl(240 3.7% 15.9%);
146
+ --muted-foreground: hsl(240 5% 64.9%);
148
147
 
149
- --accent: hsl(240 3.7% 15.9%);
150
- --accent-foreground: hsl(0 0% 98%);
148
+ --accent: hsl(240 3.7% 15.9%);
149
+ --accent-foreground: hsl(0 0% 98%);
151
150
 
152
- --destructive: hsl(0 62.8% 30.6%);
153
- --destructive-foreground: hsl(0 0% 98%);
151
+ --destructive: hsl(0 62.8% 30.6%);
152
+ --destructive-foreground: hsl(0 0% 98%);
154
153
 
155
- --success: hsl(142.1 70.6% 45.3%);
156
- --success-foreground: hsl(240 5.9% 10%);
154
+ --success: hsl(142.1 70.6% 45.3%);
155
+ --success-foreground: hsl(240 5.9% 10%);
157
156
 
158
- --warning: hsl(48 96.5% 53.1%);
159
- --warning-foreground: hsl(240 5.9% 10%);
157
+ --warning: hsl(48 96.5% 53.1%);
158
+ --warning-foreground: hsl(240 5.9% 10%);
160
159
 
161
- --info: hsl(199.4 95.5% 53.8%);
162
- --info-foreground: hsl(240 5.9% 10%);
160
+ --info: hsl(199.4 95.5% 53.8%);
161
+ --info-foreground: hsl(240 5.9% 10%);
163
162
 
164
- --border: hsl(240 3.7% 15.9%);
165
- --input: hsl(240 3.7% 15.9%);
166
- --ring: hsl(240 4.9% 83.9%);
163
+ --border: hsl(240 3.7% 15.9%);
164
+ --input: hsl(240 3.7% 15.9%);
165
+ --ring: hsl(240 4.9% 83.9%);
167
166
 
168
- --sidebar-background: hsl(240 5.9% 10%);
169
- --sidebar-foreground: hsl(240 4.8% 95.9%);
170
- --sidebar-primary: hsl(224.3 76.3% 48%);
171
- --sidebar-primary-foreground: hsl(0 0% 100%);
172
- --sidebar-accent: hsl(240 3.7% 15.9%);
173
- --sidebar-accent-foreground: hsl(240 4.8% 95.9%);
174
- --sidebar-border: hsl(240 3.7% 15.9%);
175
- --sidebar-ring: hsl(217.2 91.2% 59.8%);
176
- }
167
+ --sidebar-background: hsl(240 5.9% 10%);
168
+ --sidebar-foreground: hsl(240 4.8% 95.9%);
169
+ --sidebar-primary: hsl(224.3 76.3% 48%);
170
+ --sidebar-primary-foreground: hsl(0 0% 100%);
171
+ --sidebar-accent: hsl(240 3.7% 15.9%);
172
+ --sidebar-accent-foreground: hsl(240 4.8% 95.9%);
173
+ --sidebar-border: hsl(240 3.7% 15.9%);
174
+ --sidebar-ring: hsl(217.2 91.2% 59.8%);
177
175
  }
178
176
 
179
177
  body {
@@ -72,7 +72,8 @@ function getDaysInMonth(year: number, month: number): Date[] {
72
72
  return days
73
73
  }
74
74
 
75
- function isSameDay(d1: Date, d2: Date): boolean {
75
+ function isSameDay(d1: Date | undefined | null, d2: Date | undefined | null): boolean {
76
+ if (!d1 || !d2) return false
76
77
  return d1.getDate() === d2.getDate() &&
77
78
  d1.getMonth() === d2.getMonth() &&
78
79
  d1.getFullYear() === d2.getFullYear()
@@ -509,4 +510,3 @@ const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>(
509
510
  Calendar.displayName = "Calendar"
510
511
 
511
512
  export { Calendar }
512
-
@@ -1,7 +1,11 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from "react"
4
- import { ResponsiveContainer } from "recharts"
4
+ import {
5
+ Legend as ChartLegendPrimitive,
6
+ ResponsiveContainer,
7
+ Tooltip as ChartTooltipPrimitive,
8
+ } from "recharts"
5
9
 
6
10
  import { cn } from "@/lib/utils"
7
11
 
@@ -102,13 +106,19 @@ const ChartTooltip = ChartTooltipPrimitive
102
106
 
103
107
  const ChartTooltipContent = React.forwardRef<
104
108
  HTMLDivElement,
105
- React.ComponentProps<typeof ChartTooltipPrimitive> &
109
+ Omit<React.ComponentProps<typeof ChartTooltipPrimitive>, "payload"> &
106
110
  React.ComponentProps<"div"> & {
107
111
  hideLabel?: boolean
108
112
  hideIndicator?: boolean
109
113
  indicator?: "line" | "dot" | "dashed"
110
114
  nameKey?: string
111
115
  labelKey?: string
116
+ payload?: any[]
117
+ label?: any
118
+ labelFormatter?: any
119
+ labelClassName?: string
120
+ formatter?: any
121
+ color?: string
112
122
  }
113
123
  >(
114
124
  (
@@ -181,7 +191,7 @@ const ChartTooltipContent = React.forwardRef<
181
191
  >
182
192
  {!nestLabel ? tooltipLabel : null}
183
193
  <div className="grid gap-1.5">
184
- {payload.map((item, index) => {
194
+ {payload.map((item: any, index: number) => {
185
195
  const key = `${nameKey || item.name || item.dataKey || "value"}`
186
196
  const itemConfig = getPayloadConfigFromPayload(config, item, key)
187
197
  const indicatorColor = color || item.payload.fill || item.color
@@ -257,7 +267,9 @@ const ChartLegend = ChartLegendPrimitive
257
267
  const ChartLegendContent = React.forwardRef<
258
268
  HTMLDivElement,
259
269
  React.ComponentProps<"div"> &
260
- Pick<React.ComponentProps<typeof ChartLegendPrimitive>, "payload" | "verticalAlign"> & {
270
+ {
271
+ payload?: any[]
272
+ verticalAlign?: "top" | "middle" | "bottom"
261
273
  hideIcon?: boolean
262
274
  nameKey?: string
263
275
  }
@@ -281,7 +293,7 @@ const ChartLegendContent = React.forwardRef<
281
293
  className
282
294
  )}
283
295
  >
284
- {payload.map((item) => {
296
+ {(payload as any[]).map((item) => {
285
297
  const key = `${nameKey || item.dataKey || "value"}`
286
298
  const itemConfig = getPayloadConfigFromPayload(config, item, key)
287
299
 
@@ -351,16 +363,6 @@ function getPayloadConfigFromPayload(
351
363
  : config[key as keyof typeof config]
352
364
  }
353
365
 
354
- // Recharts Primitive Imports - We import specific components to avoid large bundle reference but for now let's just use * and assume tree shaking or specific imports in consuming app.
355
- // However, the above code uses RechartsPrimitive.Tooltip and Legend.
356
- // Ideally we should import them from recharts.
357
-
358
- import {
359
- Legend as ChartLegendPrimitive,
360
- Tooltip as ChartTooltipPrimitive,
361
- ResponsiveContainer,
362
- } from "recharts"
363
-
364
366
  export {
365
367
  ChartContainer,
366
368
  ChartTooltip,
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from "react"
4
+ import { addDays, startOfMonth, endOfMonth } from "date-fns"
4
5
  import { Calendar } from "./calendar"
5
6
  import { Popover, PopoverContent, PopoverTrigger } from "./popover"
6
7
  import { Button } from "./button"
@@ -125,6 +126,31 @@ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
125
126
  : mode === "multiple" ? "Pick dates"
126
127
  : "Pick a date range"
127
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
+
128
154
  // Handle selection
129
155
  const handleSelect = (value: any) => {
130
156
  if (mode === "single") {
@@ -135,10 +161,18 @@ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
135
161
  } else {
136
162
  const dates = value || []
137
163
  ; (onSelect as ((dates: Date[]) => void))?.(dates)
138
- // Close when range is complete (2 dates)
139
- if (dates.length === 2) {
140
- setOpen(false)
141
- }
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)
142
176
  }
143
177
  }
144
178
 
@@ -150,9 +184,8 @@ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
150
184
  variant="outline"
151
185
  disabled={disabled}
152
186
  className={cn(
153
- "w-[280px] justify-start text-left font-normal",
187
+ "w-[260px] justify-start text-left font-normal",
154
188
  !displayText && "text-muted-foreground",
155
- numberOfMonths === 2 && "w-[320px]",
156
189
  className
157
190
  )}
158
191
  >
@@ -160,15 +193,31 @@ const DatePicker = React.forwardRef<HTMLButtonElement, DatePickerProps>(
160
193
  {displayText || <span>{placeholder || defaultPlaceholder}</span>}
161
194
  </Button>
162
195
  </PopoverTrigger>
163
- <PopoverContent className="w-auto p-0">
164
- <Calendar
165
- mode={mode}
166
- numberOfMonths={numberOfMonths}
167
- size={size}
168
- selected={selected}
169
- onSelect={handleSelect}
170
- className="rounded-md border-0 shadow-none"
171
- />
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>
172
221
  </PopoverContent>
173
222
  </Popover>
174
223
  )