react-modular-datepicker 0.0.4 → 0.0.6

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 CHANGED
@@ -3,12 +3,12 @@
3
3
  A modular, lightweight, and type-safe React datepicker library. Whether you need a fully-featured calendar component or a headless hook to build your own UI, `react-modular-datepicker` has you covered.
4
4
 
5
5
  <p align="center">
6
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/hero-calendar.png" alt="react-modular-datepicker preview" width="320" />
6
+ <img src="./packages/docs/docs/images/hero-calendar.png" alt="react-modular-datepicker preview" width="320" />
7
7
  </p>
8
8
 
9
- ## Strengths
9
+ ## Features
10
10
 
11
- - 🏗️ **Headless & Modular**: Use the `useDates` hook for complete control over your UI, or the `Calendar` component for a beautiful, ready-to-use setup.
11
+ - 🏗️ **Headless & Modular**: Use the `useDates` hook for complete control over your UI, or the `Calendar` component for a ready-to-use setup.
12
12
  - 🪶 **Lightweight**: Small footprint with a pluggable adapter system (defaults to Day.js).
13
13
  - 🛡️ **Type-safe**: Written in TypeScript for a great developer experience.
14
14
  - 🎨 **Fully Customizable**: Style everything via Tailwind CSS or custom class names.
@@ -27,515 +27,101 @@ pnpm add react-modular-datepicker dayjs
27
27
  yarn add react-modular-datepicker dayjs
28
28
  ```
29
29
 
30
- > **Note on Peer Dependencies**: `dayjs` is configured as an optional peer dependency. By default, `react-modular-datepicker` uses the built-in `DayjsAdapter`, so `dayjs` must be installed in your project. However, if you bring your own date management library (such as `date-fns` or Luxon), you can implement a custom `DateAdapter` and pass it to the `adapter` prop without needing `dayjs`.
30
+ > **Note**: `dayjs` is an optional peer dependency used as the default date adapter. You can also implement a custom `DateAdapter` (e.g., using `date-fns` or Luxon).
31
31
 
32
32
  ---
33
33
 
34
- ## API Reference
35
-
36
- ### Imports
37
-
38
- ```tsx
39
- import {
40
- Calendar,
41
- useDates,
42
- Dates,
43
- Day,
44
- DayjsAdapter,
45
- defaultAdapter
46
- } from 'react-modular-datepicker';
47
- ```
34
+ ## Quick Start
48
35
 
49
36
  ### `Calendar` Component
50
37
 
51
- The primary component for a ready-to-use calendar.
52
-
53
- | Prop | Type | Default | Description |
54
- | :--- | :--- | :--- | :--- |
55
- | `date` | `Date` | `new Date()` | The initial date/month to display. |
56
- | `selected` | `Date \| Date[] \| Range` | `undefined` | The currently selected date(s). |
57
- | `selectionMode` | `'single' \| 'range' \| 'multiple'` | `'single'` | The selection behavior. |
58
- | `onChange` | `(selected: any) => void` | `undefined` | Callback triggered when the selection changes. |
59
- | `minDate` | `Date` | `undefined` | The earliest selectable date. |
60
- | `maxDate` | `Date` | `undefined` | The latest selectable date. |
61
- | `disabledDates` | `Date[]` | `undefined` | An array of dates that should be disabled. |
62
- | `monthsToDisplay` | `number` | `1` | Number of months to show simultaneously. |
63
- | `firstDayOfWeek` | `number` | `0` | The first day of the week (0=Sun, 1=Mon, ...). |
64
- | `showOutsideDays` | `boolean` | `false` | Whether to show days from the previous/next months. |
65
- | `classNames` | `CalendarClassNames` | `undefined` | Custom classes for styling various parts of the UI. |
66
- | `locale` | `string` | `undefined` | Locale for date formatting (e.g., 'fr', 'es'). |
67
- | `translations` | `Partial<Translations>` | `undefined` | Custom translation strings for "Back" and "Forward". |
68
- | `adapter` | `DateAdapter` | `defaultAdapter` | The date management adapter (e.g., DayjsAdapter). |
69
-
70
- ### `useDates` Hook
71
-
72
- The logic core of the library. It handles selection, navigation, and grid generation.
73
-
74
- ```typescript
75
- const {
76
- calendars,
77
- getDateProps,
78
- getBackProps,
79
- getForwardProps,
80
- setOffset
81
- } = useDates(props: UseDatesProps);
82
- ```
83
-
84
- **`UseDatesProps`** includes all props from `Calendar` (except `classNames`, `locale`, `translations`) plus:
85
- - `onDateSelected`: `(dateObj: DateObj, event: any) => void`
86
- - `onOffsetChanged`: `(newOffset: number) => void`
87
- - `modifiers`: `Record<string, (date: Date) => boolean>`
88
-
89
- ### Main Types
90
-
91
- #### `DateObj`
92
- Represents a single day in the calendar grid.
93
- - `date`: `Date`
94
- - `selected`: `boolean`
95
- - `selectable`: `boolean`
96
- - `today`: `boolean`
97
- - `prevMonth`/`nextMonth`: `boolean` (if outside current month)
98
- - `isRangeStart`/`isRangeEnd`/`isRangeBetween`/`isRangeHovering`: `boolean`
99
- - `modifiers`: `string[]`
100
-
101
- #### `Calendar`
102
- Represents a month grid.
103
- - `month`: `number` (0-11)
104
- - `year`: `number`
105
- - `weeks`: `(DateObj | null)[][]`
106
-
107
- #### `DateAdapter`
108
- Pluggable interface for date operations:
109
- ```typescript
110
- export interface DateAdapter<T = any> {
111
- date(value?: any): T;
112
- add(date: T, amount: number, unit: 'day' | 'month' | 'year'): T;
113
- subtract(date: T, amount: number, unit: 'day' | 'month' | 'year'): T;
114
- startOf(date: T, unit: 'day' | 'month' | 'year'): T;
115
- endOf(date: T, unit: 'day' | 'month' | 'year'): T;
116
- isBefore(date: T, comparison: T, unit?: 'day' | 'month' | 'year'): boolean;
117
- isAfter(date: T, comparison: T, unit?: 'day' | 'month' | 'year'): boolean;
118
- isSame(date: T, comparison: T, unit?: 'day' | 'month' | 'year'): boolean;
119
- set(date: T, unit: 'day' | 'month' | 'year', value: number): T;
120
- get(date: T, unit: 'day' | 'month' | 'year'): number;
121
- format(date: T, formatStr: string, locale?: string): string;
122
- getDaysInMonth(date: T): number;
123
- toDate(date: T): Date;
124
- diff(date: T, comparison: T, unit: 'month' | 'year'): number;
125
- getMonths(locale?: string): string[];
126
- getWeekdays(locale?: string): string[];
127
- }
128
- ```
129
-
130
- ---
131
-
132
- ## Recipes
133
-
134
- <details>
135
- <summary><b>Basic Selection</b></summary>
136
- A simple single-date selection calendar.
137
-
138
38
  ```tsx
139
39
  import { Calendar } from 'react-modular-datepicker';
140
40
  import 'react-modular-datepicker/dist/index.css';
141
41
 
142
- function BasicExample() {
42
+ export function App() {
143
43
  return <Calendar onChange={(date) => console.log(date)} />;
144
44
  }
145
45
  ```
146
46
 
147
- <br />
148
-
149
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/basic.png" alt="Basic Selection" width="500" />
150
-
151
- </details>
152
-
153
- <details>
154
- <summary><b>Range Selection</b></summary>
155
- Select a start and end date with a hover preview.
156
-
157
- ```tsx
158
- <Calendar
159
- selectionMode="range"
160
- monthsToDisplay={2}
161
- onChange={(range) => console.log(range)}
162
- />
163
- ```
164
-
165
- <br />
166
-
167
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/range.png" alt="Range Selection" width="500" />
168
-
169
- </details>
170
-
171
- <details>
172
- <summary><b>Multiple Selection</b></summary>
173
- Select as many dates as you want.
174
-
175
- ```tsx
176
- <Calendar
177
- selectionMode="multiple"
178
- onChange={(dates) => console.log(dates)}
179
- />
180
- ```
181
-
182
- <br />
183
-
184
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/multiple.png" alt="Multiple Selection" width="500" />
185
-
186
- </details>
187
-
188
- <details>
189
- <summary><b>Headless Usage</b></summary>
190
- Complete freedom over your UI using the `useDates` hook.
191
-
192
- ```tsx
193
- const { calendars, getDateProps } = useDates({ selectionMode: 'single' });
194
-
195
- return (
196
- <div className="grid grid-cols-7">
197
- {calendars[0].weeks.flat().map((dateObj, i) => (
198
- dateObj ? (
199
- <button key={i} {...getDateProps({ dateObj })}>
200
- {dateObj.date.getDate()}
201
- </button>
202
- ) : <div key={i} />
203
- ))}
204
- </div>
205
- );
206
- ```
207
-
208
- <br />
209
-
210
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/headless.png" alt="Headless Usage" width="500" />
211
-
212
- </details>
213
-
214
- <details>
215
- <summary><b>Custom Styling</b></summary>
216
- Easily customize the look and feel using the `classNames` prop.
217
-
218
- ```tsx
219
- <Calendar
220
- classNames={{
221
- root: 'bg-stone-50 p-6 rounded-2xl border border-stone-200 shadow-lg text-stone-800',
222
- monthYearLabel: 'font-serif text-stone-900 text-lg font-bold',
223
- day: {
224
- unselected: 'bg-white border border-stone-200 hover:bg-amber-100/50 text-stone-800',
225
- selected: 'bg-amber-800 text-amber-50 font-bold',
226
- }
227
- }}
228
- />
229
- ```
230
-
231
- <br />
232
-
233
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/custom-styling.png" alt="Custom Styling" width="500" />
234
-
235
- </details>
236
-
237
- <details>
238
- <summary><b>Localization & i18n</b></summary>
239
- Easily customize language, month/weekday labels, and the first day of week.
47
+ ### `useDates` Hook (Headless)
240
48
 
241
49
  ```tsx
242
- <Calendar
243
- firstDayOfWeek={1} // Start week on Monday
244
- translations={{
245
- months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
246
- weekdays: ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb'],
247
- }}
248
- />
249
- ```
250
-
251
- <br />
252
-
253
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/localization.png" alt="Localization & i18n" width="500" />
254
-
255
- </details>
256
-
257
- <details>
258
- <summary><b>Form Integration</b></summary>
259
- Integrate the calendar into a form or popup.
260
-
261
- ```tsx
262
- const [date, setDate] = useState<Date | null>(null);
263
-
264
- <div className="relative group">
265
- <input
266
- type="text"
267
- readOnly
268
- value={date ? date.toLocaleDateString() : ''}
269
- placeholder="Pick a date"
270
- />
271
- <div className="absolute top-full left-0 mt-2 z-50 invisible group-focus-within:visible">
272
- <Calendar
273
- selected={date}
274
- onChange={(d) => setDate(d as Date)}
275
- />
276
- </div>
277
- </div>
278
- ```
279
-
280
- <br />
281
-
282
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/form-integration.png" alt="Form Integration" width="500" />
283
-
284
- </details>
285
-
286
- <details>
287
- <summary><b>Custom Header & Footer</b></summary>
288
- Customize header, footer, and day tooltips.
289
-
290
- ```tsx
291
- <Calendar
292
- selected={selected}
293
- onChange={(val) => setSelected(val as Date)}
294
- monthsToDisplay={2}
295
- header={<div className="p-2 bg-blue-100 text-blue-800 font-bold text-center rounded-t-lg">My Header</div>}
296
- footer={<div className="p-2 bg-gray-100 text-gray-600 text-sm text-center rounded-b-lg border-t">My Custom Footer</div>}
297
- renderDayTooltip={(dateObj) => (
298
- dateObj.date.getDate() === 15 ? 'Middle of the month!' : null
299
- )}
300
- />
301
- ```
302
-
303
- <br />
304
-
305
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/custom-header-footer.png" alt="Custom Header & Footer" width="500" />
306
-
307
- </details>
308
-
309
- <details>
310
- <summary><b>Min, Max & Disabled Dates</b></summary>
311
- Restrict date selection with min/max bounds or specific disabled dates.
312
-
313
- ```tsx
314
- <Calendar
315
- selected={selected}
316
- onChange={(val) => setSelected(val as Date)}
317
- minDate={minDate}
318
- maxDate={maxDate}
319
- disabledDates={[disabledDate1, disabledDate2]}
320
- />
321
- ```
322
-
323
- <br />
324
-
325
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/min-max-disabled.png" alt="Min, Max & Disabled Dates" width="500" />
326
-
327
- </details>
328
-
329
- <details>
330
- <summary><b>Yearly View</b></summary>
331
- Display an entire year at once by customizing the grid and `monthsToDisplay`.
332
-
333
- ```tsx
334
- <Calendar
335
- selected={selected}
336
- onChange={(val) => setSelected(val as Date)}
337
- monthsToDisplay={12}
338
- classNames={{
339
- calendarsContainer: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"
340
- }}
341
- />
342
- ```
343
-
344
- <br />
345
-
346
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/yearly.png" alt="Yearly View" width="500" />
347
-
348
- </details>
349
-
350
- <details>
351
- <summary><b>Availability & Async Data</b></summary>
352
- Fetch and display availability dynamically when the month changes.
353
-
354
- ```tsx
355
- <Calendar
356
- selected={selected}
357
- onChange={(val) => setSelected(val as Date)}
358
- onMonthChange={(date) => fetchAvailabilities(date)}
359
- modifiers={{
360
- available: (date) => availabilities[date.toDateString()] === true,
361
- unavailable: (date) => availabilities[date.toDateString()] === false,
362
- }}
363
- disabledDates={
364
- Object.keys(availabilities)
365
- .filter(key => !availabilities[key])
366
- .map(key => new Date(key))
367
- }
368
- classNames={{
369
- day: {
370
- available: "bg-green-100 text-green-800 hover:bg-green-200",
371
- unavailable: "bg-red-50 text-red-300 line-through cursor-not-allowed",
372
- }
373
- }}
374
- />
375
- ```
376
-
377
- <br />
378
-
379
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/availability.png" alt="Availability Demo" width="500" />
380
-
381
- </details>
382
-
383
- <details>
384
- <summary><b>Full-Featured / Events Calendar (Google Calendar style)</b></summary>
385
- Build a full-page events calendar using the `useDates` hook.
386
-
387
- ```tsx
388
- const { calendars, getBackProps, getForwardProps, getDateProps } = useDates({
389
- showOutsideDays: true,
390
- selected: selectedDate,
391
- onChange: (d) => setSelectedDate(d as Date),
392
- });
393
-
394
- // Render custom full-grid layout with event badges...
50
+ import { useDates } from 'react-modular-datepicker';
51
+
52
+ export function CustomCalendar() {
53
+ const { calendars, getDateProps, getBackProps, getForwardProps } = useDates({
54
+ selectionMode: 'single',
55
+ });
56
+
57
+ const calendar = calendars[0];
58
+ if (!calendar) return null;
59
+
60
+ return (
61
+ <div>
62
+ <div className="flex justify-between">
63
+ <button {...getBackProps({ calendars })}>Prev</button>
64
+ <span>{calendar.year} - {calendar.month + 1}</span>
65
+ <button {...getForwardProps({ calendars })}>Next</button>
66
+ </div>
67
+ <div className="grid grid-cols-7">
68
+ {calendar.weeks.flat().map((dateObj, i) => (
69
+ dateObj ? (
70
+ <button key={i} {...getDateProps({ dateObj })}>
71
+ {dateObj.date.getDate()}
72
+ </button>
73
+ ) : <div key={i} />
74
+ ))}
75
+ </div>
76
+ </div>
77
+ );
78
+ }
395
79
  ```
396
80
 
397
- <br />
398
-
399
- <img src="https://6pcvnpdosyar2uqr.public.blob.vercel-storage.com/docs/images/events.png" alt="Events Calendar" width="500" />
400
-
401
- </details>
402
-
403
- <details>
404
- <summary><b>Custom Date Adapter (e.g. date-fns)</b></summary>
405
- Replace the default `DayjsAdapter` with a custom adapter using `date-fns` (or any date library).
81
+ ---
406
82
 
407
- ```tsx
408
- import { Calendar, DateAdapter } from 'react-modular-datepicker';
409
- import {
410
- addDays, addMonths, addYears,
411
- subDays, subMonths, subYears,
412
- startOfDay, startOfMonth, startOfYear,
413
- endOfDay, endOfMonth, endOfYear,
414
- isBefore, isAfter, isSameDay, isSameMonth, isSameYear,
415
- setDate, setMonth, setYear,
416
- getDate, getMonth, getYear,
417
- format, getDaysInMonth,
418
- differenceInCalendarMonths, differenceInCalendarYears
419
- } from 'date-fns';
420
-
421
- class DateFnsAdapter implements DateAdapter<Date> {
422
- date(value?: any): Date { return value ? new Date(value) : new Date(); }
423
- add(date: Date, amount: number, unit: 'day' | 'month' | 'year'): Date {
424
- if (unit === 'day') return addDays(date, amount);
425
- if (unit === 'month') return addMonths(date, amount);
426
- return addYears(date, amount);
427
- }
428
- subtract(date: Date, amount: number, unit: 'day' | 'month' | 'year'): Date {
429
- if (unit === 'day') return subDays(date, amount);
430
- if (unit === 'month') return subMonths(date, amount);
431
- return subYears(date, amount);
432
- }
433
- startOf(date: Date, unit: 'day' | 'month' | 'year'): Date {
434
- if (unit === 'day') return startOfDay(date);
435
- if (unit === 'month') return startOfMonth(date);
436
- return startOfYear(date);
437
- }
438
- endOf(date: Date, unit: 'day' | 'month' | 'year'): Date {
439
- if (unit === 'day') return endOfDay(date);
440
- if (unit === 'month') return endOfMonth(date);
441
- return endOfYear(date);
442
- }
443
- isBefore(date: Date, comparison: Date, unit?: 'day' | 'month' | 'year'): boolean {
444
- if (unit === 'day') return startOfDay(date) < startOfDay(comparison);
445
- if (unit === 'month') return startOfMonth(date) < startOfMonth(comparison);
446
- if (unit === 'year') return startOfYear(date) < startOfYear(comparison);
447
- return date < comparison;
448
- }
449
- isAfter(date: Date, comparison: Date, unit?: 'day' | 'month' | 'year'): boolean {
450
- if (unit === 'day') return startOfDay(date) > startOfDay(comparison);
451
- if (unit === 'month') return startOfMonth(date) > startOfMonth(comparison);
452
- if (unit === 'year') return startOfYear(date) > startOfYear(comparison);
453
- return date > comparison;
454
- }
455
- isSame(date: Date, comparison: Date, unit?: 'day' | 'month' | 'year'): boolean {
456
- if (unit === 'day') return isSameDay(date, comparison);
457
- if (unit === 'month') return isSameMonth(date, comparison);
458
- if (unit === 'year') return isSameYear(date, comparison);
459
- return date.getTime() === comparison.getTime();
460
- }
461
- set(date: Date, unit: 'day' | 'month' | 'year', value: number): Date {
462
- if (unit === 'day') return setDate(date, value);
463
- if (unit === 'month') return setMonth(date, value);
464
- return setYear(date, value);
465
- }
466
- get(date: Date, unit: 'day' | 'month' | 'year'): number {
467
- if (unit === 'day') return getDate(date);
468
- if (unit === 'month') return getMonth(date);
469
- return getYear(date);
470
- }
471
- format(date: Date, formatStr: string): string {
472
- const f = formatStr.replace(/YYYY/g, 'yyyy').replace(/YY/g, 'yy').replace(/D/g, 'd');
473
- return format(date, f);
474
- }
475
- getDaysInMonth(date: Date): number { return getDaysInMonth(date); }
476
- toDate(date: Date): Date { return date; }
477
- diff(date: Date, comparison: Date, unit: 'month' | 'year'): number {
478
- if (unit === 'month') return differenceInCalendarMonths(date, comparison);
479
- return differenceInCalendarYears(date, comparison);
480
- }
481
- getMonths(): string[] {
482
- return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
483
- }
484
- getWeekdays(): string[] {
485
- return ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];
486
- }
487
- }
83
+ ## Documentation & Recipes
488
84
 
489
- const customAdapter = new DateFnsAdapter();
85
+ For full API reference, recipes, and interactive demos, check out the documentation package in `packages/docs`.
490
86
 
491
- function CustomAdapterExample() {
492
- return <Calendar adapter={customAdapter} onChange={(date) => console.log(date)} />;
493
- }
87
+ To run the documentation site locally:
88
+ ```bash
89
+ pnpm run dev:docs
494
90
  ```
495
91
 
496
- </details>
497
-
498
92
  ---
499
93
 
500
- ## Contributors
501
-
502
- We welcome contributions! Here’s how you can get started:
94
+ ## Development
503
95
 
504
96
  ### Installation
505
97
 
506
- 1. Clone the repository.
507
- 2. Install dependencies:
508
- ```bash
509
- pnpm install
510
- ```
98
+ ```bash
99
+ pnpm install
100
+ ```
511
101
 
512
- ### Development
102
+ ### Development Server
513
103
 
514
- Start the development server with the example app:
104
+ Start watching for library changes and run the documentation app:
515
105
  ```bash
516
106
  pnpm run dev
517
107
  ```
518
- This runs `vite` in watch mode for the library and starts the Next.js example app at `http://localhost:3000`.
519
108
 
520
109
  ### Testing
521
110
 
522
- Run end-to-end tests using Playwright:
111
+ Run unit and end-to-end tests:
523
112
  ```bash
524
- pnpm run test:e2e
113
+ pnpm run test
525
114
  ```
526
115
 
527
- ### Documentation & Examples
528
-
529
- - To update documentation, edit the `README.md`.
530
- - To add or modify examples, check the `examples/` directory.
531
-
532
116
  ### Building
533
117
 
534
- Build the package for production:
118
+ Build the package and documentation:
535
119
  ```bash
536
120
  pnpm run build
537
121
  ```
538
122
 
539
123
  ---
540
124
 
541
- License: MIT
125
+ ## License
126
+
127
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./useDates-c17u4Qfs.cjs"),t=require("./utils.cjs");let n=require("react");n=e.i(n,1);let r=require("react/jsx-runtime");var i=({dateObj:e,getDateProps:t,classNames:i,tooltip:a})=>{let[o,s]=(0,n.useState)(!1);if(!e)return(0,r.jsx)(`div`,{className:`aspect-square bg-white`});let{date:c,selected:l,selectable:u,isRangeStart:d,isRangeEnd:f,isRangeBetween:p,isRangeHovering:m,isRangeActive:h}=e,g=i.day,_=`rounded-full`;_=d&&f?`${g.selected} rounded-full`:d?`${g.rangeStart} ${h?`rounded-l-full rounded-r-none`:`rounded-full`}`:f?`${g.rangeEnd} ${h?`rounded-r-full rounded-l-none`:`rounded-full`}`:p?g.rangeBetween||``:m?g.rangeHovering||``:l?g.selected||``:u?g.unselected||``:g.disabled||``;let v=[g.day,_,...(e.modifiers||[]).map(e=>g[e]||e)].filter(Boolean).join(` `);return(0,r.jsxs)(`button`,{...t({dateObj:e,onMouseEnter:()=>s(!0),onMouseLeave:()=>s(!1)}),className:v,children:[c.getDate(),a&&o&&(0,r.jsx)(`div`,{className:`absolute bottom-full left-1/2 -translate-x-1/2 mb-2 hidden group-hover:block z-10`,children:(0,r.jsxs)(`div`,{className:`bg-gray-800 text-white text-xs py-1 px-2 rounded whitespace-nowrap shadow-lg`,children:[a,(0,r.jsx)(`div`,{className:`absolute top-full left-1/2 -translate-x-1/2 border-8 border-transparent border-t-gray-800`})]})})]})};function a(t=e.r,n){return{months:t.getMonths(n),weekdays:t.getWeekdays(n),back:`Previous month`,forward:`Next month`}}function o(t=e.r,n,r){return{...a(t,n),...r}}var s=()=>(0,r.jsx)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,r.jsx)(`polyline`,{points:`15 18 9 12 15 6`})}),c=()=>(0,r.jsx)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,r.jsx)(`polyline`,{points:`9 18 15 12 9 6`})}),l=({calendars:e,getBackProps:t,getForwardProps:n,setView:i,monthNames:a,t:o,classNames:l,slideDirection:u,currentView:d})=>(0,r.jsxs)(`div`,{className:l.header,children:[(0,r.jsx)(`button`,{...t({calendars:e}),onMouseDown:e=>e.preventDefault(),className:`${l.navButton} ${d&&d!==`days`?`invisible pointer-events-none`:``}`,"aria-label":o.back,children:(0,r.jsx)(s,{})}),(0,r.jsx)(`div`,{className:l.monthYearContainer,children:e.length===1?(0,r.jsxs)(`div`,{className:`${l.monthYearLabel} ${u===`left`?`animate-slide-in-left`:u===`right`?`animate-slide-in-right`:``}`,children:[(0,r.jsx)(`button`,{onMouseDown:e=>e.preventDefault(),onClick:()=>i(d===`months`?`days`:`months`),className:l.monthYearButton,children:a[e[0].month]}),(0,r.jsx)(`button`,{onMouseDown:e=>e.preventDefault(),onClick:()=>i(d===`years`?`days`:`years`),className:l.monthYearButton,children:e[0].year})]},`${e[0].month}-${e[0].year}`):(0,r.jsx)(`div`,{className:`${l.monthYearLabel} ${u===`left`?`animate-slide-in-left`:u===`right`?`animate-slide-in-right`:``}`,children:(()=>{let t=e[0],n=e[e.length-1];return e.length===12&&t.month===0&&n.month===11&&t.year===n.year?(0,r.jsx)(`span`,{children:t.year}):t.year===n.year?(0,r.jsxs)(`span`,{children:[a[t.month],` - `,a[n.month],` `,t.year]}):(0,r.jsxs)(`span`,{children:[a[t.month],` `,t.year,` - `,a[n.month],` `,n.year]})})()})}),(0,r.jsx)(`button`,{...n({calendars:e}),onMouseDown:e=>e.preventDefault(),className:`${l.navButton} ${d&&d!==`days`?`invisible pointer-events-none`:``}`,"aria-label":o.forward,children:(0,r.jsx)(c,{})})]}),u={root:`w-fit flex flex-col p-4 bg-white rounded-lg shadow-lg`,header:`flex items-center justify-between border-b-2 border-brand-gray-light/40 pb-2`,calendarsContainer:`flex flex-wrap gap-4 mt-3`,calendarContainer:`flex-1 min-w-[280px] max-w-full`,weekdayGrid:`grid grid-cols-7 gap-1 mb-1 border-b border-brand-gray-light/40`,weekday:`text-center text-xs text-gray-400 py-2`,daysGrid:`grid grid-cols-7 gap-px bg-brand-gray-light/20`,footer:`mt-4`,navButton:`p-2 text-brand-text hover:bg-gray-100 rounded-full transition-colors cursor-pointer disabled:opacity-30 disabled:pointer-events-none`,monthYearContainer:`flex gap-8`,monthYearLabel:`flex gap-1 items-center font-semibold text-brand-text`,monthYearButton:`hover:bg-gray-100 px-2 py-1 rounded cursor-pointer`,day:{day:`aspect-square flex items-center justify-center text-sm font-medium transition-all relative group cursor-pointer p-px`,selected:`bg-brand-gold text-white rounded-full`,unselected:`bg-white hover:bg-brand-gray-light text-brand-text`,disabled:`bg-white text-gray-300 cursor-not-allowed`,rangeStart:`bg-brand-gold text-white`,rangeEnd:`bg-brand-gold text-white`,rangeBetween:`bg-brand-gold/25 text-brand-text`,rangeHovering:`bg-brand-gold/25 text-brand-text`},monthsGrid:`grid grid-cols-3 gap-2 animate-slide-in-top`,monthButton:`py-3 rounded-lg hover:bg-brand-gray-light transition-colors cursor-pointer disabled:opacity-30 disabled:pointer-events-none`,monthButtonSelected:`bg-brand-gold text-white`,monthButtonUnselected:`text-brand-text`,yearsGrid:`grid grid-cols-3 gap-2 max-h-[300px] overflow-y-auto pr-2 animate-slide-in-top`,yearButton:`py-3 rounded-lg hover:bg-brand-gray-light transition-colors cursor-pointer disabled:opacity-30 disabled:pointer-events-none`,yearButtonSelected:`bg-brand-gold text-white`,yearButtonUnselected:`text-brand-text`},d=e=>{let t={...u};if(!e)return t;for(let n in e){let r=n;r===`day`&&e.day?t.day={...u.day,...e.day}:e[r]&&(t[r]=e[r])}return t},f=({year:e,month:t,monthNames:n,minDate:i,maxDate:a,onMonthSelect:o,classNames:s})=>{let c=t=>!!(i&&e===i.getFullYear()&&t<i.getMonth()||a&&e===a.getFullYear()&&t>a.getMonth());return(0,r.jsx)(`div`,{className:s.monthsGrid,children:n.map((e,n)=>{let i=c(n);return(0,r.jsx)(`button`,{onMouseDown:e=>e.preventDefault(),onClick:()=>!i&&o(n),className:`${s.monthButton} ${n===t?s.monthButtonSelected:s.monthButtonUnselected}`,disabled:i,children:e},e)})})},p=({year:e,minDate:t,maxDate:i,adapter:a,onYearSelect:o,classNames:s})=>{let c=(0,n.useRef)(null);(0,n.useEffect)(()=>{if(c.current){let e=c.current.querySelector(`[data-selected="true"]`);e&&e.scrollIntoView({block:`center`})}},[]);let l=t?a.get(a.date(t),`year`):e-50,u=i?a.get(a.date(i),`year`):e+50,d=[];for(let e=l;e<=u;e++)d.push(e);return(0,r.jsx)(`div`,{ref:c,className:s.yearsGrid,children:d.map(t=>(0,r.jsx)(`button`,{"data-selected":t===e,onMouseDown:e=>e.preventDefault(),onClick:()=>o(t),className:`${s.yearButton} ${t===e?s.yearButtonSelected:s.yearButtonUnselected}`,children:t},t))})},m=t=>{let{classNames:a,locale:s,translations:c,adapter:u=e.r,firstDayOfWeek:m=0,header:h,footer:g,renderDayTooltip:_,...v}=t,y=d(a),[b,x]=(0,n.useState)(`days`),[S,C]=(0,n.useState)(null),w=o(u,s,c),T=w.weekdays,E=w.months,{calendars:D,getBackProps:O,getForwardProps:k,getDateProps:A,setOffset:j}=e.t({...v,adapter:u,firstDayOfWeek:m}),M=[...T.slice(m),...T.slice(0,m)],{month:N,year:P}=D[0],F=e=>{let n=u.set(u.set(u.date(t.date||new Date),`year`,P),`month`,N),r=u.set(n,`month`,e),i=u.startOf(u.date(t.date||new Date),`month`),a=u.diff(r,i,`month`);C(null),j(a),x(`days`)},I=e=>{let n=u.set(u.set(u.date(t.date||new Date),`year`,P),`month`,N),r=u.set(n,`year`,e),i=u.startOf(u.date(t.date||new Date),`month`),a=u.diff(r,i,`month`);C(null),j(a),x(`days`)},L=e=>{let t=O(e);return{...t,onClick:e=>{C(`left`),t.onClick?.(e)}}},R=e=>{let t=k(e);return{...t,onClick:e=>{C(`right`),t.onClick?.(e)}}};return(0,r.jsxs)(`div`,{className:`rmdp ${y.root}`,children:[typeof h==`function`?h({calendars:D,getBackProps:L,getForwardProps:R,setView:x,monthNames:E,t:w,slideDirection:S,currentView:b}):h||(0,r.jsx)(l,{calendars:D,getBackProps:L,getForwardProps:R,setView:x,monthNames:E,t:w,classNames:y,slideDirection:S,currentView:b}),(0,r.jsxs)(`div`,{className:y.calendarsContainer,children:[b===`months`&&D.map(e=>(0,r.jsx)(`div`,{className:y.calendarContainer,children:(0,r.jsx)(f,{year:e.year,month:e.month,monthNames:E,minDate:t.minDate,maxDate:t.maxDate,onMonthSelect:F,classNames:y})},`months-${e.year}`)),b===`years`&&D.map(e=>(0,r.jsx)(`div`,{className:y.calendarContainer,children:(0,r.jsx)(p,{year:e.year,minDate:t.minDate,maxDate:t.maxDate,adapter:u,onYearSelect:I,classNames:y})},`years-${e.year}`)),b===`days`&&D.map(e=>(0,r.jsxs)(`div`,{className:y.calendarContainer,children:[D.length>1&&(0,r.jsxs)(`button`,{type:`button`,"aria-label":E[e.month],className:`block w-full text-center font-semibold mb-2 text-brand-text`,children:[E[e.month],` `,D[0].year===D[D.length-1].year?``:e.year]}),(0,r.jsx)(`div`,{className:y.weekdayGrid,children:M.map(e=>(0,r.jsx)(`div`,{className:y.weekday,children:e},e))}),(0,r.jsx)(`div`,{className:`${y.daysGrid} ${S===`left`?`animate-slide-in-left`:S===`right`?`animate-slide-in-right`:``}`,children:e.weeks.map((e,t)=>e.map((e,n)=>(0,r.jsx)(i,{dateObj:e,getDateProps:A,classNames:y,tooltip:e&&_?.(e)},`${t}-${n}`)))})]},`${e.month}-${e.year}`))]}),g&&(0,r.jsx)(`div`,{className:y.footer,children:g})]})};exports.Calendar=m,exports.CalendarHeader=l,exports.ChevronLeftIcon=s,exports.ChevronRightIcon=c,exports.Day=i,exports.DayjsAdapter=e.n,exports.MonthSelection=f,exports.YearSelection=p,exports.addMonth=t.addMonth,exports.composeEventHandlers=t.composeEventHandlers,exports.defaultAdapter=e.r,exports.defaultClassNames=u,exports.getCalendars=t.getCalendars,exports.getDefaults=a,exports.getTranslations=o,exports.isBackDisabled=t.isBackDisabled,exports.isForwardDisabled=t.isForwardDisabled,exports.mergeClassNames=d,exports.subtractMonth=t.subtractMonth,exports.useDates=e.t;
2
+ //# sourceMappingURL=index.cjs.map