@srcroot/ui 0.0.45 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@srcroot/ui",
3
- "version": "0.0.45",
3
+ "version": "0.0.46",
4
4
  "description": "A UI library with polymorphic, accessible React components",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @srcroot/ui - Slate Theme (Tailwind 3)
3
- * Cool gray with strong blue undertones (shadcn default)
3
+ * Cool gray with strong blue undertones (default)
4
4
  */
5
5
 
6
6
  @tailwind base;
@@ -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";
@@ -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,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
  )
@@ -83,8 +83,8 @@ PopoverTrigger.displayName = "PopoverTrigger"
83
83
 
84
84
  const PopoverContent = React.forwardRef<
85
85
  HTMLDivElement,
86
- React.HTMLAttributes<HTMLDivElement>
87
- >(({ className, children, ...props }, ref) => {
86
+ React.HTMLAttributes<HTMLDivElement> & { align?: "start" | "center" | "end" }
87
+ >(({ className, children, align = "center", ...props }, ref) => {
88
88
  const context = React.useContext(PopoverContext)
89
89
  if (!context) throw new Error("PopoverContent must be used within Popover")
90
90
 
@@ -121,6 +121,7 @@ const PopoverContent = React.forwardRef<
121
121
  ref={ref}
122
122
  className={cn(
123
123
  "absolute z-50 mt-2 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none",
124
+ align === "end" ? "right-0" : align === "start" ? "left-0" : "left-1/2 -translate-x-1/2",
124
125
  className
125
126
  )}
126
127
  onClick={(e) => e.stopPropagation()}