@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
|
@@ -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
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
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-[
|
|
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
|
-
<
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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()}
|