snack-datepicker 0.0.1

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/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # 📅 Snack Datepicker
2
+
3
+ A modern **React Date Picker & Date Range Picker** built for flexibility, performance, and developer experience.
4
+
5
+ **Snack Datepicker** provides a clean, customizable, and lightweight component for selecting **single dates** or **date ranges**, with powerful configuration options such as presets, disabled dates, multi-month view, and custom day rendering.
6
+
7
+ Ideal for **analytics dashboards, booking systems, reporting tools, admin panels, data filters, and forms**.
8
+
9
+ 👉 [Try it](https://snack-calendar.vercel.app/)
10
+
11
+ <p align="center">
12
+ <img src="https://github.com/hemanth-user13/Snack-DatePicker/blob/master/src/assests/Screenshot%202026-03-15%20183307.png" width="900"/>
13
+ </p>
14
+
15
+ <p align="center">
16
+ <img src="https://github.com/hemanth-user13/Snack-DatePicker/blob/master/src/assests/Screenshot%202026-03-15%20183352.png" width="900"/>
17
+ </p>
18
+
19
+ ## Features
20
+
21
+ - 📅 **Single Date Picker** — clean, minimal single date selection
22
+ - 📆 **Date Range Picker** — intuitive start and end date selection
23
+ - 🎯 **Preset date ranges** — quickly jump to common ranges like Last 7 Days or Last 30 Days
24
+ - 📊 **Multi-month view** — display multiple months simultaneously
25
+ - 🔒 **Min / Max date restrictions** — constrain selectable dates to a valid range
26
+ - 🚫 **Disabled dates support** — block out specific unavailable dates
27
+ - 🎨 **Custom day renderer** — full control over how each day cell looks
28
+ - ⚡ **Lightweight & fast** — minimal bundle impact, tree-shakable
29
+ - 🧩 **Highly customizable** — adapt to any design system
30
+ - ⚛️ **Built for modern React** — hooks-first, no legacy patterns
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ npm install snack-datepicker
36
+ # or
37
+ yarn add snack-datepicker
38
+ ```
39
+
40
+ ### Peer Dependencies
41
+
42
+ Ensure your project has these installed:
43
+
44
+ ```bash
45
+ npm install react react-dom
46
+ ```
47
+
48
+ ## Usage
49
+
50
+ > [!IMPORTANT]
51
+ > You must import the stylesheet for the datepicker to display correctly:
52
+ >
53
+ > ```tsx
54
+ > import "snack-datepicker/dist/style.css";
55
+ > ```
56
+
57
+ ### Basic
58
+
59
+ ```tsx
60
+ import { DatePicker } from "snack-datepicker";
61
+ import "snack-datepicker/dist/style.css";
62
+
63
+ function App() {
64
+ return <DatePicker mode="single" onChange={(date) => console.log(date)} />;
65
+ }
66
+
67
+ export default App;
68
+ ```
69
+
70
+ ### Date Range Example
71
+
72
+ ```tsx
73
+ import { DatePicker } from "snack-datepicker";
74
+ import { useState } from "react";
75
+
76
+ function App() {
77
+ const [range, setRange] = useState({
78
+ start: null,
79
+ end: null,
80
+ });
81
+
82
+ return (
83
+ <DatePicker
84
+ mode="range"
85
+ value={range}
86
+ onChange={(value) => setRange(value)}
87
+ numberOfMonths={2}
88
+ />
89
+ );
90
+ }
91
+ ```
92
+
93
+ ### Preset Range Example
94
+
95
+ ```tsx
96
+ import { DatePicker } from "snack-datepicker";
97
+
98
+ const presets = [
99
+ {
100
+ label: "Last 7 Days",
101
+ getValue: () => {
102
+ const end = new Date();
103
+ const start = new Date();
104
+ start.setDate(end.getDate() - 7);
105
+ return { start, end };
106
+ },
107
+ },
108
+ {
109
+ label: "Last 30 Days",
110
+ getValue: () => {
111
+ const end = new Date();
112
+ const start = new Date();
113
+ start.setDate(end.getDate() - 30);
114
+ return { start, end };
115
+ },
116
+ },
117
+ ];
118
+
119
+ function App() {
120
+ return <DatePicker mode="range" presets={presets} />;
121
+ }
122
+ ```
123
+
124
+ ### Props API
125
+
126
+ | Prop | Type | Description |
127
+ | ---------------- | --------------------------- | --------------------------------------- |
128
+ | `mode` | `"single" \| "range"` | Date picker mode |
129
+ | `value` | `Date \| DateRange` | Current selected value |
130
+ | `onChange` | `(value) => void` | Triggered when date changes |
131
+ | `onApply` | `(value) => void` | Triggered when apply button is clicked |
132
+ | `onReset` | `() => void` | Reset the current selection |
133
+ | `minDate` | `Date` | Minimum selectable date |
134
+ | `maxDate` | `Date` | Maximum selectable date |
135
+ | `disabledDates` | `Date[]` | Disable specific dates |
136
+ | `weekStart` | `0 \| 1` | Week start day (0 = Sunday, 1 = Monday) |
137
+ | `numberOfMonths` | `number` | Number of months displayed at once |
138
+ | `showFooter` | `boolean` | Show apply / reset footer |
139
+ | `className` | `string` | Custom CSS class for styling |
140
+ | `renderDay` | `(date: Date) => ReactNode` | Custom day cell renderer |
141
+ | `presets` | `PresetRange[]` | Preset date range options |
142
+
143
+ ### Types
144
+
145
+ ```ts
146
+ export type DatePickerMode = "single" | "range";
147
+
148
+ export interface DateRange {
149
+ start: Date | null;
150
+ end: Date | null;
151
+ }
152
+
153
+ export interface PresetRange {
154
+ label: string;
155
+ getValue: () => DateRange;
156
+ }
157
+
158
+ export interface DatePickerProps {
159
+ mode?: DatePickerMode;
160
+ value?: Date | DateRange;
161
+ onChange?: (value: Date | DateRange) => void;
162
+ onApply?: (value: Date | DateRange | undefined) => void;
163
+ onReset?: () => void;
164
+ minDate?: Date;
165
+ maxDate?: Date;
166
+ disabledDates?: Date[];
167
+ weekStart?: 0 | 1;
168
+ numberOfMonths?: number;
169
+ showFooter?: boolean;
170
+ className?: string;
171
+ renderDay?: (date: Date) => ReactNode;
172
+ presets?: PresetRange[];
173
+ }
174
+ ```
175
+
176
+ ## Built With
177
+
178
+ [React](https://react.dev) · [Radix UI](https://www.radix-ui.com) · [date-fns](https://date-fns.org) · [TailwindCSS](https://tailwindcss.com) · [Framer Motion](https://www.framer.com/motion) · [Lucide Icons](https://lucide.dev)
179
+
180
+ ## License
181
+
182
+ MIT
183
+
184
+ ## Author
185
+
186
+ **Hemanth Dev**
@@ -0,0 +1,31 @@
1
+ import React, { ReactNode } from 'react';
2
+
3
+ type DatePickerMode = "single" | "range";
4
+ interface DateRange {
5
+ start: Date | null;
6
+ end: Date | null;
7
+ }
8
+ interface PresetRange {
9
+ label: string;
10
+ getValue: () => DateRange;
11
+ }
12
+ interface DatePickerProps {
13
+ mode?: DatePickerMode;
14
+ value?: Date | DateRange;
15
+ onChange?: (value: Date | DateRange) => void;
16
+ onApply?: (value: Date | DateRange | undefined) => void;
17
+ onReset?: () => void;
18
+ minDate?: Date;
19
+ maxDate?: Date;
20
+ disabledDates?: Date[];
21
+ weekStart?: 0 | 1;
22
+ numberOfMonths?: number;
23
+ showFooter?: boolean;
24
+ className?: string;
25
+ renderDay?: (date: Date) => ReactNode;
26
+ presets?: PresetRange[];
27
+ }
28
+
29
+ declare const DatePicker: React.ForwardRefExoticComponent<DatePickerProps & React.RefAttributes<HTMLDivElement>>;
30
+
31
+ export { DatePicker, type DatePickerProps };
@@ -0,0 +1,31 @@
1
+ import React, { ReactNode } from 'react';
2
+
3
+ type DatePickerMode = "single" | "range";
4
+ interface DateRange {
5
+ start: Date | null;
6
+ end: Date | null;
7
+ }
8
+ interface PresetRange {
9
+ label: string;
10
+ getValue: () => DateRange;
11
+ }
12
+ interface DatePickerProps {
13
+ mode?: DatePickerMode;
14
+ value?: Date | DateRange;
15
+ onChange?: (value: Date | DateRange) => void;
16
+ onApply?: (value: Date | DateRange | undefined) => void;
17
+ onReset?: () => void;
18
+ minDate?: Date;
19
+ maxDate?: Date;
20
+ disabledDates?: Date[];
21
+ weekStart?: 0 | 1;
22
+ numberOfMonths?: number;
23
+ showFooter?: boolean;
24
+ className?: string;
25
+ renderDay?: (date: Date) => ReactNode;
26
+ presets?: PresetRange[];
27
+ }
28
+
29
+ declare const DatePicker: React.ForwardRefExoticComponent<DatePickerProps & React.RefAttributes<HTMLDivElement>>;
30
+
31
+ export { DatePicker, type DatePickerProps };
package/dist/index.js ADDED
@@ -0,0 +1,411 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var dateFns = require('date-fns');
5
+ var lucideReact = require('lucide-react');
6
+ var framerMotion = require('framer-motion');
7
+ var clsx = require('clsx');
8
+ var tailwindMerge = require('tailwind-merge');
9
+ var jsxRuntime = require('react/jsx-runtime');
10
+
11
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
+
13
+ var React__default = /*#__PURE__*/_interopDefault(React);
14
+
15
+ // src/components/date-picker/DatePicker.tsx
16
+ function cn(...inputs) {
17
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
18
+ }
19
+ var WEEK_DAYS_SUN = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
20
+ var WEEK_DAYS_MON = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
21
+ var MonthGrid = ({
22
+ month,
23
+ mode,
24
+ selectedDate,
25
+ selectedRange,
26
+ hoverDate,
27
+ onDateClick,
28
+ onDateHover,
29
+ minDate,
30
+ maxDate,
31
+ disabledDates = [],
32
+ weekStart = 0,
33
+ renderDay,
34
+ showLabel = true
35
+ }) => {
36
+ const days = React.useMemo(() => {
37
+ return dateFns.eachDayOfInterval({
38
+ start: dateFns.startOfMonth(month),
39
+ end: dateFns.endOfMonth(month)
40
+ });
41
+ }, [month]);
42
+ const weekDays = weekStart === 1 ? WEEK_DAYS_MON : WEEK_DAYS_SUN;
43
+ const startPad = React.useMemo(() => {
44
+ const dayOfWeek = days[0].getDay();
45
+ return weekStart === 1 ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek;
46
+ }, [days, weekStart]);
47
+ const isDisabled = (date) => {
48
+ if (minDate && dateFns.isBefore(date, minDate)) return true;
49
+ if (maxDate && dateFns.isAfter(date, maxDate)) return true;
50
+ return disabledDates.some((d) => dateFns.isSameDay(d, date));
51
+ };
52
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-[252px]", children: [
53
+ showLabel && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center mb-3", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-dp-text", children: dateFns.format(month, "MMMM yyyy") }) }),
54
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 mb-1.5", children: weekDays.map((d) => /* @__PURE__ */ jsxRuntime.jsx(
55
+ "span",
56
+ {
57
+ className: "text-[11px] font-semibold text-dp-text-muted text-center uppercase tracking-wider py-1",
58
+ children: d
59
+ },
60
+ d
61
+ )) }),
62
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-7", children: [
63
+ [...Array(startPad)].map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-9 w-9" }, `pad-${i}`)),
64
+ days.map((day) => {
65
+ const disabled = isDisabled(day);
66
+ const isSelected = mode === "single" ? selectedDate && dateFns.isSameDay(day, selectedDate) : selectedRange && (selectedRange.start && dateFns.isSameDay(day, selectedRange.start) || selectedRange.end && dateFns.isSameDay(day, selectedRange.end));
67
+ const isStart = mode === "range" && (selectedRange == null ? void 0 : selectedRange.start) && dateFns.isSameDay(day, selectedRange.start);
68
+ const isEnd = mode === "range" && (selectedRange == null ? void 0 : selectedRange.end) && dateFns.isSameDay(day, selectedRange.end);
69
+ let inRange = false;
70
+ if (mode === "range" && (selectedRange == null ? void 0 : selectedRange.start)) {
71
+ if (selectedRange.end) {
72
+ inRange = dateFns.isWithinInterval(day, {
73
+ start: selectedRange.start,
74
+ end: selectedRange.end
75
+ });
76
+ } else if (hoverDate) {
77
+ const rangeStart = dateFns.isBefore(hoverDate, selectedRange.start) ? hoverDate : selectedRange.start;
78
+ const rangeEnd = dateFns.isBefore(hoverDate, selectedRange.start) ? selectedRange.start : hoverDate;
79
+ inRange = dateFns.isWithinInterval(day, {
80
+ start: rangeStart,
81
+ end: rangeEnd
82
+ });
83
+ }
84
+ }
85
+ return /* @__PURE__ */ jsxRuntime.jsx(
86
+ "button",
87
+ {
88
+ type: "button",
89
+ disabled,
90
+ onClick: () => !disabled && onDateClick(day),
91
+ onMouseEnter: () => !disabled && onDateHover(day),
92
+ onMouseLeave: () => onDateHover(null),
93
+ "aria-label": dateFns.format(day, "PPPP"),
94
+ "aria-selected": !!isSelected,
95
+ className: cn(
96
+ "relative h-9 w-9 text-sm flex items-center justify-center transition-all tabular-nums",
97
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
98
+ "active:scale-[0.96]",
99
+ // Default
100
+ !isSelected && !inRange && "text-dp-text hover:bg-dp-surface-hover rounded-lg",
101
+ // Selected (start/end/single)
102
+ isSelected && "bg-dp-surface-active text-dp-text-selected z-10 shadow-sm font-semibold",
103
+ // Single mode selected
104
+ mode === "single" && isSelected && "rounded-lg",
105
+ // Range endpoints
106
+ isStart && !isEnd && "rounded-l-lg rounded-r-none",
107
+ isEnd && !isStart && "rounded-r-lg rounded-l-none",
108
+ isStart && isEnd && "rounded-lg",
109
+ // In range but not selected
110
+ inRange && !isSelected && "bg-[hsl(var(--dp-range-tint)/0.08)] text-primary rounded-none",
111
+ // Disabled
112
+ disabled && "text-dp-text-muted/40 cursor-not-allowed hover:bg-transparent"
113
+ ),
114
+ children: renderDay ? renderDay(day) : dateFns.format(day, "d")
115
+ },
116
+ day.toISOString()
117
+ );
118
+ })
119
+ ] })
120
+ ] });
121
+ };
122
+ var MonthGrid_default = React__default.default.memo(MonthGrid);
123
+ var MonthSelector = ({
124
+ currentMonth,
125
+ onSelect
126
+ }) => {
127
+ const current = dateFns.getMonth(currentMonth);
128
+ return /* @__PURE__ */ jsxRuntime.jsx(
129
+ framerMotion.motion.div,
130
+ {
131
+ initial: { opacity: 0, y: 4 },
132
+ animate: { opacity: 1, y: 0 },
133
+ exit: { opacity: 0, y: -4 },
134
+ transition: { duration: 0.15, ease: [0.25, 0.1, 0.25, 1] },
135
+ className: "grid grid-cols-3 gap-2 w-full max-w-[320px] mx-auto",
136
+ children: Array.from({ length: 12 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
137
+ "button",
138
+ {
139
+ type: "button",
140
+ onClick: () => onSelect(i),
141
+ className: cn(
142
+ "py-3 text-sm font-medium rounded-lg transition-all active:scale-[0.97]",
143
+ current === i ? "bg-dp-surface-active text-dp-text-selected shadow-sm" : "hover:bg-dp-surface-hover text-dp-text"
144
+ ),
145
+ children: dateFns.format(new Date(2024, i, 1), "MMM")
146
+ },
147
+ i
148
+ ))
149
+ },
150
+ "month-selector"
151
+ );
152
+ };
153
+ var MonthSelector_default = MonthSelector;
154
+ var YearSelector = ({
155
+ currentYear,
156
+ onSelect,
157
+ minDate,
158
+ maxDate
159
+ }) => {
160
+ const years = Array.from({ length: 12 }, (_, i) => currentYear - 5 + i);
161
+ return /* @__PURE__ */ jsxRuntime.jsx(
162
+ framerMotion.motion.div,
163
+ {
164
+ initial: { opacity: 0, y: 4 },
165
+ animate: { opacity: 1, y: 0 },
166
+ exit: { opacity: 0, y: -4 },
167
+ transition: { duration: 0.15, ease: [0.25, 0.1, 0.25, 1] },
168
+ className: "grid grid-cols-3 gap-2 w-full max-w-[320px] mx-auto",
169
+ children: years.map((y) => {
170
+ const disabled = minDate && y < minDate.getFullYear() || maxDate && y > maxDate.getFullYear();
171
+ return /* @__PURE__ */ jsxRuntime.jsx(
172
+ "button",
173
+ {
174
+ type: "button",
175
+ disabled: !!disabled,
176
+ onClick: () => !disabled && onSelect(y),
177
+ className: cn(
178
+ "py-3 text-sm font-medium rounded-lg transition-all active:scale-[0.97]",
179
+ currentYear === y ? "bg-dp-surface-active text-dp-text-selected shadow-sm" : "hover:bg-dp-surface-hover text-dp-text",
180
+ disabled && "opacity-30 cursor-not-allowed"
181
+ ),
182
+ children: y
183
+ },
184
+ y
185
+ );
186
+ })
187
+ },
188
+ "year-selector"
189
+ );
190
+ };
191
+ var YearSelector_default = YearSelector;
192
+ var DatePicker = React__default.default.forwardRef(
193
+ ({
194
+ mode = "single",
195
+ value,
196
+ onChange,
197
+ onApply,
198
+ onReset,
199
+ minDate,
200
+ maxDate,
201
+ disabledDates,
202
+ weekStart = 0,
203
+ numberOfMonths = 2,
204
+ showFooter = true,
205
+ className,
206
+ renderDay,
207
+ presets
208
+ }, ref) => {
209
+ const [viewDate, setViewDate] = React.useState(() => {
210
+ if (mode === "single" && value instanceof Date) return value;
211
+ if (mode === "range" && value && "start" in value && value.start)
212
+ return value.start;
213
+ return /* @__PURE__ */ new Date();
214
+ });
215
+ const [viewMode, setViewMode] = React.useState("calendar");
216
+ const [hoverDate, setHoverDate] = React.useState(null);
217
+ const selectedRange = mode === "range" ? value != null ? value : null : null;
218
+ const selectedDate = mode === "single" ? value != null ? value : null : null;
219
+ const handleDateClick = React.useCallback(
220
+ (date) => {
221
+ if (mode === "single") {
222
+ onChange == null ? void 0 : onChange(date);
223
+ } else {
224
+ const range = selectedRange || { start: null, end: null };
225
+ if (!range.start || range.start && range.end) {
226
+ onChange == null ? void 0 : onChange({ start: date, end: null });
227
+ } else {
228
+ if (dateFns.isBefore(date, range.start)) {
229
+ onChange == null ? void 0 : onChange({ start: date, end: range.start });
230
+ } else if (dateFns.isSameDay(date, range.start)) {
231
+ onChange == null ? void 0 : onChange({ start: date, end: date });
232
+ } else {
233
+ onChange == null ? void 0 : onChange({ start: range.start, end: date });
234
+ }
235
+ }
236
+ }
237
+ },
238
+ [mode, selectedRange, onChange]
239
+ );
240
+ const handleKeyDown = React.useCallback((e) => {
241
+ if (e.key === "Escape") {
242
+ setViewMode("calendar");
243
+ }
244
+ }, []);
245
+ const handlePresetClick = React.useCallback(
246
+ (preset) => {
247
+ const range = preset.getValue();
248
+ onChange == null ? void 0 : onChange(range);
249
+ },
250
+ [onChange]
251
+ );
252
+ return /* @__PURE__ */ jsxRuntime.jsxs(
253
+ "div",
254
+ {
255
+ ref,
256
+ className: cn(
257
+ "inline-flex flex-col rounded-xl border border-dp-border bg-dp-surface select-none antialiased",
258
+ "shadow-[var(--dp-shadow)]",
259
+ className
260
+ ),
261
+ onKeyDown: handleKeyDown,
262
+ role: "application",
263
+ "aria-label": "Date picker",
264
+ children: [
265
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-dp-border", children: [
266
+ /* @__PURE__ */ jsxRuntime.jsx(
267
+ "button",
268
+ {
269
+ type: "button",
270
+ onClick: () => setViewDate(dateFns.subMonths(viewDate, 1)),
271
+ className: "p-1.5 rounded-md hover:bg-dp-surface-hover text-dp-text-muted hover:text-dp-text transition-colors",
272
+ "aria-label": "Previous month",
273
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { size: 16 })
274
+ }
275
+ ),
276
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
277
+ /* @__PURE__ */ jsxRuntime.jsx(
278
+ "button",
279
+ {
280
+ type: "button",
281
+ onClick: () => setViewMode(viewMode === "month" ? "calendar" : "month"),
282
+ className: cn(
283
+ "text-sm font-semibold px-2 py-1 rounded-md transition-colors",
284
+ viewMode === "month" ? "bg-dp-surface-hover text-dp-text" : "hover:bg-dp-surface-hover text-dp-text"
285
+ ),
286
+ children: dateFns.format(viewDate, "MMMM")
287
+ }
288
+ ),
289
+ /* @__PURE__ */ jsxRuntime.jsx(
290
+ "button",
291
+ {
292
+ type: "button",
293
+ onClick: () => setViewMode(viewMode === "year" ? "calendar" : "year"),
294
+ className: cn(
295
+ "text-sm font-semibold px-2 py-1 rounded-md transition-colors",
296
+ viewMode === "year" ? "bg-dp-surface-hover text-dp-text" : "hover:bg-dp-surface-hover text-dp-text"
297
+ ),
298
+ children: dateFns.format(viewDate, "yyyy")
299
+ }
300
+ )
301
+ ] }),
302
+ /* @__PURE__ */ jsxRuntime.jsx(
303
+ "button",
304
+ {
305
+ type: "button",
306
+ onClick: () => setViewDate(dateFns.addMonths(viewDate, 1)),
307
+ className: "p-1.5 rounded-md hover:bg-dp-surface-hover text-dp-text-muted hover:text-dp-text transition-colors",
308
+ "aria-label": "Next month",
309
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { size: 16 })
310
+ }
311
+ )
312
+ ] }),
313
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
314
+ presets && presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-r border-dp-border p-3 min-w-[140px] flex flex-col gap-0.5", children: presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
315
+ "button",
316
+ {
317
+ type: "button",
318
+ onClick: () => handlePresetClick(preset),
319
+ className: "text-left text-xs font-medium px-2.5 py-1.5 rounded-md text-dp-text-muted hover:text-dp-text hover:bg-dp-surface-hover transition-colors",
320
+ children: preset.label
321
+ },
322
+ preset.label
323
+ )) }),
324
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(framerMotion.AnimatePresence, { mode: "wait", children: [
325
+ viewMode === "calendar" && /* @__PURE__ */ jsxRuntime.jsx(
326
+ framerMotion.motion.div,
327
+ {
328
+ initial: { opacity: 0, y: 4 },
329
+ animate: { opacity: 1, y: 0 },
330
+ exit: { opacity: 0, y: -4 },
331
+ transition: { duration: 0.15, ease: [0.25, 0.1, 0.25, 1] },
332
+ className: "flex flex-col md:flex-row gap-6",
333
+ children: [...Array(numberOfMonths)].map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
334
+ MonthGrid_default,
335
+ {
336
+ month: dateFns.addMonths(viewDate, i),
337
+ mode,
338
+ selectedDate,
339
+ selectedRange,
340
+ hoverDate,
341
+ onDateClick: handleDateClick,
342
+ onDateHover: setHoverDate,
343
+ minDate,
344
+ maxDate,
345
+ disabledDates,
346
+ weekStart,
347
+ renderDay,
348
+ showLabel: numberOfMonths > 1
349
+ },
350
+ i
351
+ ))
352
+ },
353
+ "calendar"
354
+ ),
355
+ viewMode === "month" && /* @__PURE__ */ jsxRuntime.jsx(
356
+ MonthSelector_default,
357
+ {
358
+ currentMonth: viewDate,
359
+ onSelect: (m) => {
360
+ setViewDate(dateFns.setMonth(viewDate, m));
361
+ setViewMode("calendar");
362
+ }
363
+ }
364
+ ),
365
+ viewMode === "year" && /* @__PURE__ */ jsxRuntime.jsx(
366
+ YearSelector_default,
367
+ {
368
+ currentYear: dateFns.getYear(viewDate),
369
+ onSelect: (y) => {
370
+ setViewDate(dateFns.setYear(viewDate, y));
371
+ setViewMode("calendar");
372
+ },
373
+ minDate,
374
+ maxDate
375
+ }
376
+ )
377
+ ] }) })
378
+ ] }),
379
+ showFooter && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 bg-dp-footer border-t border-dp-border rounded-b-xl", children: [
380
+ /* @__PURE__ */ jsxRuntime.jsxs(
381
+ "button",
382
+ {
383
+ type: "button",
384
+ onClick: onReset,
385
+ className: "flex items-center gap-1.5 text-xs font-medium text-dp-text-muted hover:text-dp-text transition-colors",
386
+ children: [
387
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { size: 13 }),
388
+ "Reset"
389
+ ]
390
+ }
391
+ ),
392
+ /* @__PURE__ */ jsxRuntime.jsx(
393
+ "button",
394
+ {
395
+ type: "button",
396
+ onClick: () => onApply == null ? void 0 : onApply(value),
397
+ className: "px-5 py-1.5 bg-primary text-primary-foreground text-xs font-semibold rounded hover:opacity-90 shadow-sm transition-all active:scale-[0.98]",
398
+ children: "Apply"
399
+ }
400
+ )
401
+ ] })
402
+ ]
403
+ }
404
+ );
405
+ }
406
+ );
407
+ DatePicker.displayName = "DatePicker";
408
+
409
+ exports.DatePicker = DatePicker;
410
+ //# sourceMappingURL=index.js.map
411
+ //# sourceMappingURL=index.js.map