laif-ds 0.2.66 → 0.2.68

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.
@@ -26,13 +26,13 @@ export interface AppFormItem {
26
26
  | "async"
27
27
  | "async-multiple"; // Field type
28
28
  name: string; // Field name (used for form state and validation)
29
- inputType?: string; // HTML input type for "input" component (e.g. "text", "email", "password", "number")
29
+ inputType?: ComponentProps<"input">["type"]; // HTML input type for "input" component (e.g. "text", "email", "password", "number", "url", "search", "tel")
30
30
  defaultValue?: string | boolean | number | string[] | Date | number[]; // Initial value
31
31
  options?: AppSelectOption[]; // Options for select/multiselect/radio
32
32
  disabled?: boolean; // Disables the field
33
33
  placeholder?: string; // Placeholder text
34
34
  caption?: string; // Helper text below the field
35
- calendarRange?: [Date, Date]; // Date range for datepicker
35
+ calendarRange?: [Date, Date]; // Date range for datepicker (enables range mode)
36
36
  min?: number; // Minimum value for slider
37
37
  max?: number; // Maximum value for slider
38
38
  step?: number; // Step value for slider
@@ -41,10 +41,11 @@ export interface AppFormItem {
41
41
  resolveOptionValue?: (option: any) => string; // Value extractor for async option
42
42
  renderSelectedValue?: (option: any) => React.ReactNode; // Customize render of selected async option
43
43
  initialOptions?: any[]; // Optional cache for async select hydration
44
- notFound?: React.ReactNode;
45
- noResultsMessage?: string;
46
- debounce?: number;
47
- clearable?: boolean;
44
+ notFound?: React.ReactNode; // Custom not found message for async select
45
+ noResultsMessage?: string; // No results message for async select
46
+ debounce?: number; // Debounce time for async select search
47
+ clearable?: boolean; // Allow clearing async select value
48
+ datePickerProps?: Partial<ComponentProps<typeof DatePicker>>; // Additional DatePicker props (locale, dateFormat, numberOfMonths, minDate, maxDate, etc.)
48
49
  }
49
50
  ```
50
51
 
@@ -199,7 +200,50 @@ Ricorda che il fetch parte solo quando il menu è aperto; eventuali valori inizi
199
200
 
200
201
  ### datepicker
201
202
 
202
- Date picker component with optional range selection via `calendarRange`
203
+ Date picker component with optional range selection via `calendarRange`. Use `datePickerProps` to customize the DatePicker behavior such as locale, date format, number of months displayed, min/max dates, etc.
204
+
205
+ **Available datePickerProps options:**
206
+
207
+ - `locale`: Locale object from `date-fns/locale` (e.g., `enUS`, `it`, `fr`)
208
+ - `dateFormat`: Date format string (e.g., `"MM/dd/yyyy"`, `"dd/MM/yyyy"`)
209
+ - `numberOfMonths`: Number of months to display in the calendar
210
+ - `minDate`: Minimum selectable date
211
+ - `maxDate`: Maximum selectable date
212
+ - `firstDate`: First available date (disables dates before)
213
+ - `lastDate`: Last available date (disables dates after)
214
+ - `availableDates`: Array of specific dates that are selectable
215
+ - And other DatePicker props
216
+
217
+ **Example with English locale:**
218
+
219
+ ```tsx
220
+ import { enUS } from "date-fns/locale";
221
+
222
+ const items: AppFormItem[] = [
223
+ {
224
+ label: "Appointment Date",
225
+ component: "datepicker",
226
+ name: "appointmentDate",
227
+ placeholder: "Pick a date",
228
+ datePickerProps: {
229
+ locale: enUS,
230
+ dateFormat: "MM/dd/yyyy",
231
+ },
232
+ },
233
+ {
234
+ label: "Event Date Range",
235
+ component: "datepicker",
236
+ name: "eventRange",
237
+ placeholder: "Select date range",
238
+ calendarRange: [new Date(), new Date()],
239
+ datePickerProps: {
240
+ locale: enUS,
241
+ dateFormat: "MM/dd/yyyy",
242
+ numberOfMonths: 2,
243
+ },
244
+ },
245
+ ];
246
+ ```
203
247
 
204
248
  ### radio
205
249
 
@@ -358,6 +402,84 @@ export function DateRangeForm() {
358
402
  }
359
403
  ```
360
404
 
405
+ ### External Form Control
406
+
407
+ You can access the form instance to programmatically control values, watch changes, and reset the form:
408
+
409
+ ```tsx
410
+ import { AppForm, Button } from "laif-ds";
411
+ import { useForm } from "react-hook-form";
412
+ import { useState, useEffect } from "react";
413
+
414
+ export function ExternalControlForm() {
415
+ const [formValues, setFormValues] = useState({});
416
+ const [watchedValues, setWatchedValues] = useState({});
417
+
418
+ const form = useForm({
419
+ defaultValues: {
420
+ name: "",
421
+ email: "",
422
+ },
423
+ });
424
+
425
+ const { watch, setValue, reset } = form;
426
+
427
+ // Watch specific fields
428
+ const nameValue = watch("name");
429
+ const emailValue = watch("email");
430
+
431
+ // Auto-fill handler
432
+ const handleAutoFill = () => {
433
+ setValue("name", "Mario Rossi");
434
+ setValue("email", "mario@example.com");
435
+ };
436
+
437
+ // Reset handler
438
+ const handleReset = () => {
439
+ reset();
440
+ setFormValues({});
441
+ setWatchedValues({});
442
+ };
443
+
444
+ // Watch all form values
445
+ useEffect(() => {
446
+ const subscription = watch((values) => {
447
+ setWatchedValues(values);
448
+ });
449
+ return () => subscription.unsubscribe();
450
+ }, [watch]);
451
+
452
+ return (
453
+ <div>
454
+ <div className="mb-4 flex gap-2">
455
+ <Button type="button" variant="outline" onClick={handleAutoFill}>
456
+ Auto-fill
457
+ </Button>
458
+ <Button type="button" variant="outline" onClick={handleReset}>
459
+ Reset
460
+ </Button>
461
+ </div>
462
+
463
+ <AppForm
464
+ form={form}
465
+ items={[
466
+ { label: "Name", component: "input", name: "name" },
467
+ { label: "Email", component: "input", name: "email" },
468
+ ]}
469
+ onSubmit={(data) => setFormValues(data)}
470
+ showSubmitButton
471
+ />
472
+
473
+ <div className="mt-4">
474
+ <p>Name: {nameValue || "(empty)"}</p>
475
+ <p>Email: {emailValue || "(empty)"}</p>
476
+ <pre>{JSON.stringify(watchedValues, null, 2)}</pre>
477
+ </div>
478
+ </div>
479
+ );
480
+ }
481
+ ```
482
+
361
483
  ---
362
484
 
363
485
  ## Notes
@@ -2,45 +2,72 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- Single-date picker composed of a trigger with calendar icon and a `Calendar` component in a popover. Supports min/max date constraints, allowed dates, custom display format, sizes, localization, and initial calendar month.
5
+ Date picker component that supports both **single date** and **date range** selection. Composed of a trigger with calendar icon and a `Calendar` component in a popover. Supports min/max date constraints, allowed dates, custom display format, sizes, localization, and initial calendar month.
6
6
 
7
7
  ---
8
8
 
9
9
  ## Props
10
10
 
11
- | Prop | Type | Default | Description |
12
- | ---------------------- | ----------------------------------------------------------------------------- | ------------------ | ------------------------------------------------------------ |
13
- | `value` | `Date` | `undefined` | Controlled selected date. |
14
- | `onChange` | `(date: Date \| undefined) => void` | `undefined` | Called when the date changes. |
15
- | `placeholder` | `string` | `"Seleziona data"` | Text when no date is selected. |
16
- | `dateFormat` | `string` | `"dd/MM/yyyy"` | `date-fns` format string for the trigger text. |
17
- | `className` | `string` | `""` | Additional classes for the trigger. |
18
- | `wrpClassName` | `string` | `""` | Additional classes for the wrapper container. |
19
- | `label` | `string \| React.ReactNode` | `undefined` | Label displayed above the date picker. |
20
- | `buttonVariant` | `"default" \| "destructive" \| "outline" \| "secondary" \| "ghost" \| "link"` | `"default"` | Variant of the trigger button (deprecated, not used). |
21
- | `disabled` | `boolean` | `false` | Disables interactions and the popover. |
22
- | `size` | `"sm" \| "default" \| "lg"` | `"default"` | Trigger size affecting height and icon size. |
23
- | `firstDate` | `Date` | `undefined` | Minimum selectable date (legacy prop, use `minDate`). |
24
- | `lastDate` | `Date` | `undefined` | Maximum selectable date (legacy prop, use `maxDate`). |
25
- | `minDate` | `Date` | `undefined` | Minimum selectable date. |
26
- | `maxDate` | `Date` | `undefined` | Maximum selectable date. |
27
- | `availableDates` | `Date[]` | `undefined` | Only these dates are selectable. |
28
- | `locale` | `Partial<Locale>` | `it` (Italian) | Locale for date formatting (from date-fns). |
29
- | `initialCalendarMonth` | `Date` | `undefined` | Initial month to display in calendar (overridden by value). |
30
- | `customCalendarProps` | `React.ComponentProps<typeof Calendar>` | `undefined` | Custom props to pass to the Calendar component. |
31
- | `id` | `string` | `undefined` | HTML id attribute for the trigger (useful for testing). |
32
- | `data-testid` | `string` | `undefined` | Test identifier attribute for E2E testing (e.g. Playwright). |
11
+ ### Common Props
12
+
13
+ | Prop | Type | Default | Description |
14
+ | ---------------------- | --------------------------------------- | ------------------ | ------------------------------------------------------------ |
15
+ | `mode` | `"single" \| "range"` | `"single"` | Selection mode: single date or date range. |
16
+ | `placeholder` | `string` | `"Seleziona data"` | Text when no date is selected. |
17
+ | `dateFormat` | `string` | `"dd/MM/yyyy"` | `date-fns` format string for the trigger text. |
18
+ | `className` | `string` | `""` | Additional classes for the trigger. |
19
+ | `wrpClassName` | `string` | `""` | Additional classes for the wrapper container. |
20
+ | `label` | `string \| React.ReactNode` | `undefined` | Label displayed above the date picker. |
21
+ | `disabled` | `boolean` | `false` | Disables interactions and the popover. |
22
+ | `size` | `"sm" \| "default" \| "lg"` | `"default"` | Trigger size affecting height and icon size. |
23
+ | `firstDate` | `Date` | `undefined` | Minimum selectable date (legacy prop, use `minDate`). |
24
+ | `lastDate` | `Date` | `undefined` | Maximum selectable date (legacy prop, use `maxDate`). |
25
+ | `minDate` | `Date` | `undefined` | Minimum selectable date. |
26
+ | `maxDate` | `Date` | `undefined` | Maximum selectable date. |
27
+ | `availableDates` | `Date[]` | `undefined` | Only these dates are selectable. |
28
+ | `locale` | `Partial<Locale>` | `it` (Italian) | Locale for date formatting (from date-fns). |
29
+ | `initialCalendarMonth` | `Date` | `undefined` | Initial month to display in calendar (overridden by value). |
30
+ | `numberOfMonths` | `number` | `1` | Number of months to display (useful for range mode). |
31
+ | `customCalendarProps` | `React.ComponentProps<typeof Calendar>` | `undefined` | Custom props to pass to the Calendar component. |
32
+ | `id` | `string` | `undefined` | HTML id attribute for the trigger (useful for testing). |
33
+ | `data-testid` | `string` | `undefined` | Test identifier attribute for E2E testing (e.g. Playwright). |
34
+
35
+ ### Single Mode Props (mode="single" or undefined)
36
+
37
+ | Prop | Type | Default | Description |
38
+ | ---------- | ----------------------------------- | ----------- | ----------------------------- |
39
+ | `value` | `Date` | `undefined` | Controlled selected date. |
40
+ | `onChange` | `(date: Date \| undefined) => void` | `undefined` | Called when the date changes. |
41
+
42
+ ### Range Mode Props (mode="range")
43
+
44
+ | Prop | Type | Default | Description |
45
+ | ---------- | ------------------------------------------ | ----------- | ----------------------------------- |
46
+ | `value` | `DateRange` (`{ from?: Date, to?: Date }`) | `undefined` | Controlled selected date range. |
47
+ | `onChange` | `(range: DateRange \| undefined) => void` | `undefined` | Called when the date range changes. |
33
48
 
34
49
  ---
35
50
 
36
51
  ## Behavior
37
52
 
53
+ ### Single Mode
54
+
55
+ - **Selection**: Click a date to select it. The selected date is highlighted.
56
+ - **Display**: Shows the formatted date in the trigger (e.g., "13/01/2025").
57
+
58
+ ### Range Mode
59
+
60
+ - **Selection**: Click to set the start date, click again to set the end date. The range is highlighted.
61
+ - **Display**: Shows "from - to" format in the trigger (e.g., "13/01/2025 - 20/01/2025").
62
+ - **Multiple months**: Use `numberOfMonths={2}` to show two months side by side for easier range selection.
63
+
64
+ ### Common Behavior
65
+
38
66
  - **Disabled dates**: `firstDate`, `lastDate`, `minDate`, `maxDate`, and `availableDates` are combined into the `Calendar`'s `disabled` matcher array.
39
67
  - **Disabled state**: When `disabled` is true, the popover will not open and the trigger is non-interactive with reduced opacity.
40
- - **Formatting**: `dateFormat` is applied via `date-fns/format` to the selected date in the trigger.
41
- - **Calendar month**: The calendar displays the month of the selected date, or `initialCalendarMonth` if no date is selected.
68
+ - **Formatting**: `dateFormat` is applied via `date-fns/format` to the selected date(s) in the trigger.
69
+ - **Calendar month**: The calendar displays the month of the selected date (or `from` date in range mode), or `initialCalendarMonth` if no date is selected.
42
70
  - **State synchronization**: The component syncs internal state with the `value` prop via useEffect.
43
- - **Custom calendar**: Use `customCalendarProps` to override default Calendar props (mode, selected, onSelect).
44
71
  - **Localization**: The `locale` prop affects both the calendar display and the formatted date in the trigger.
45
72
 
46
73
  ---
@@ -79,6 +106,80 @@ export function ControlledDatePicker() {
79
106
  }
80
107
  ```
81
108
 
109
+ ### Range Mode - Basic
110
+
111
+ ```tsx
112
+ import { DatePicker } from "laif-ds";
113
+ import { useState } from "react";
114
+ import { DateRange } from "react-day-picker";
115
+
116
+ export function RangeDatePicker() {
117
+ const [range, setRange] = useState<DateRange | undefined>();
118
+
119
+ return (
120
+ <DatePicker
121
+ mode="range"
122
+ value={range}
123
+ onChange={setRange}
124
+ placeholder="Seleziona intervallo"
125
+ />
126
+ );
127
+ }
128
+ ```
129
+
130
+ ### Range Mode - With Two Months
131
+
132
+ ```tsx
133
+ import { DatePicker } from "laif-ds";
134
+ import { addDays } from "date-fns";
135
+ import { useState } from "react";
136
+ import { DateRange } from "react-day-picker";
137
+
138
+ export function RangeWithTwoMonths() {
139
+ const [range, setRange] = useState<DateRange | undefined>({
140
+ from: new Date(),
141
+ to: addDays(new Date(), 7),
142
+ });
143
+
144
+ return (
145
+ <DatePicker
146
+ mode="range"
147
+ value={range}
148
+ onChange={setRange}
149
+ placeholder="Seleziona intervallo"
150
+ numberOfMonths={2}
151
+ label="Periodo di prenotazione"
152
+ />
153
+ );
154
+ }
155
+ ```
156
+
157
+ ### Range Mode - With Constraints
158
+
159
+ ```tsx
160
+ import { DatePicker } from "laif-ds";
161
+ import { addDays } from "date-fns";
162
+ import { useState } from "react";
163
+ import { DateRange } from "react-day-picker";
164
+
165
+ export function RangeWithConstraints() {
166
+ const today = new Date();
167
+ const [range, setRange] = useState<DateRange | undefined>();
168
+
169
+ return (
170
+ <DatePicker
171
+ mode="range"
172
+ value={range}
173
+ onChange={setRange}
174
+ placeholder="Seleziona (prossimi 30 giorni)"
175
+ firstDate={today}
176
+ lastDate={addDays(today, 30)}
177
+ numberOfMonths={2}
178
+ />
179
+ );
180
+ }
181
+ ```
182
+
82
183
  ### Configurable
83
184
 
84
185
  ```tsx
@@ -245,3 +346,6 @@ export function DatePickerInDialog() {
245
346
  - **Button variant**: The `buttonVariant` prop is deprecated and not used in the current implementation.
246
347
  - **Accessibility**: The trigger has proper ARIA attributes and keyboard navigation support.
247
348
  - **State management**: Component maintains internal state but syncs with external `value` prop.
349
+ - **Range mode**: Use `mode="range"` for date range selection. The `value` and `onChange` types change accordingly.
350
+ - **Multiple months**: In range mode, use `numberOfMonths={2}` to display two months side by side for better UX.
351
+ - **DateRange type**: Import `DateRange` from `react-day-picker` when using range mode: `{ from?: Date, to?: Date }`.
@@ -1,55 +1,55 @@
1
1
  "use client";
2
2
  import { jsxs as l, jsx as a } from "react/jsx-runtime";
3
- import { cn as s } from "../../lib/utils.js";
4
- import { Controller as w } from "../../node_modules/react-hook-form/dist/index.esm.js";
5
- import { AppSelect as v } from "./app-select.js";
6
- import { AsyncSelect as O } from "./async-select.js";
7
- import { Button as I } from "./button.js";
8
- import { Checkbox as A } from "./checkbox.js";
9
- import { DatePicker as F } from "./date-picker.js";
10
- import { Input as R } from "./input.js";
3
+ import { cn as d } from "../../lib/utils.js";
4
+ import { Controller as I } from "../../node_modules/react-hook-form/dist/index.esm.js";
5
+ import { AppSelect as b } from "./app-select.js";
6
+ import { AsyncSelect as A } from "./async-select.js";
7
+ import { Button as F } from "./button.js";
8
+ import { Checkbox as R } from "./checkbox.js";
9
+ import { DatePicker as j } from "./date-picker.js";
10
+ import { Input as M } from "./input.js";
11
11
  import { Label as t } from "./label.js";
12
- import { RadioGroup as j, RadioGroupItem as M } from "./radio-group.js";
13
- import { Slider as B } from "./slider.js";
14
- import { Switch as T } from "./switch.js";
15
- import { Textarea as $ } from "./textarea.js";
12
+ import { RadioGroup as B, RadioGroupItem as D } from "./radio-group.js";
13
+ import { Slider as T } from "./slider.js";
14
+ import { Switch as $ } from "./switch.js";
15
+ import { Textarea as G } from "./textarea.js";
16
16
  import { Typo as i } from "./typo.js";
17
- const Z = ({
18
- items: u,
19
- cols: b = "2",
20
- form: m,
21
- submitText: g = "Invia",
22
- onSubmit: x,
23
- isSubmitting: p = !1,
24
- showSubmitButton: C = !1
17
+ const ne = ({
18
+ items: h,
19
+ cols: m = "2",
20
+ form: g,
21
+ submitText: x = "Invia",
22
+ onSubmit: C,
23
+ isSubmitting: v = !1,
24
+ showSubmitButton: N = !1
25
25
  }) => {
26
26
  const {
27
- control: N,
28
- handleSubmit: y,
29
- formState: { errors: f, isValid: S, isDirty: V }
30
- } = m, k = (e) => {
31
- const c = f[e.name]?.message, d = c ? String(c) : void 0;
27
+ control: y,
28
+ handleSubmit: f,
29
+ formState: { errors: S, isValid: V, isDirty: k }
30
+ } = g, w = (e) => {
31
+ const c = S[e.name]?.message, s = c ? String(c) : void 0;
32
32
  return /* @__PURE__ */ a("div", { children: /* @__PURE__ */ a(
33
- w,
33
+ I,
34
34
  {
35
35
  name: e.name,
36
- control: N,
36
+ control: y,
37
37
  render: ({ field: r }) => {
38
38
  const o = /* @__PURE__ */ l("div", { className: "mb-2 flex items-center justify-between", children: [
39
39
  /* @__PURE__ */ a(t, { children: e.label }),
40
- d && /* @__PURE__ */ a("span", { className: "text-d-destructive text-xs", children: d })
40
+ s && /* @__PURE__ */ a("span", { className: "text-d-destructive text-xs", children: s })
41
41
  ] });
42
42
  switch (e.component) {
43
43
  case "input":
44
44
  return /* @__PURE__ */ l("div", { children: [
45
45
  o,
46
46
  /* @__PURE__ */ a(
47
- R,
47
+ M,
48
48
  {
49
49
  ...r,
50
50
  type: e.inputType,
51
51
  placeholder: e.placeholder,
52
- className: s(d && "border-d-destructive"),
52
+ className: d(s && "border-d-destructive"),
53
53
  disabled: e.disabled
54
54
  }
55
55
  )
@@ -65,7 +65,7 @@ const Z = ({
65
65
  return /* @__PURE__ */ l("div", { children: [
66
66
  o,
67
67
  /* @__PURE__ */ a(
68
- O,
68
+ A,
69
69
  {
70
70
  multiple: n,
71
71
  fetcher: e.fetcher,
@@ -89,11 +89,11 @@ const Z = ({
89
89
  return /* @__PURE__ */ l("div", { children: [
90
90
  o,
91
91
  /* @__PURE__ */ a(
92
- $,
92
+ G,
93
93
  {
94
94
  ...r,
95
95
  placeholder: e.placeholder,
96
- className: s(d && "border-d-destructive"),
96
+ className: d(s && "border-d-destructive"),
97
97
  disabled: e.disabled
98
98
  }
99
99
  )
@@ -102,23 +102,23 @@ const Z = ({
102
102
  return /* @__PURE__ */ l("div", { children: [
103
103
  o,
104
104
  /* @__PURE__ */ a(
105
- j,
105
+ B,
106
106
  {
107
107
  value: r.value != null ? String(r.value) : "",
108
108
  onValueChange: (n) => r.onChange(n),
109
109
  className: "space-y-2",
110
110
  disabled: e.disabled,
111
111
  children: (e.options ?? []).map((n) => {
112
- const h = `${e.name}-${n.value}`;
112
+ const p = `${e.name}-${n.value}`;
113
113
  return /* @__PURE__ */ l(
114
114
  "div",
115
115
  {
116
116
  className: "flex items-center gap-2",
117
117
  children: [
118
118
  /* @__PURE__ */ a(
119
- M,
119
+ D,
120
120
  {
121
- id: h,
121
+ id: p,
122
122
  value: String(n.value),
123
123
  disabled: e.disabled
124
124
  }
@@ -126,8 +126,8 @@ const Z = ({
126
126
  /* @__PURE__ */ a(
127
127
  t,
128
128
  {
129
- htmlFor: h,
130
- className: s(
129
+ htmlFor: p,
130
+ className: d(
131
131
  "cursor-pointer",
132
132
  e.disabled && "cursor-not-allowed opacity-60"
133
133
  ),
@@ -146,7 +146,7 @@ const Z = ({
146
146
  return /* @__PURE__ */ l("div", { children: [
147
147
  o,
148
148
  /* @__PURE__ */ a(
149
- v,
149
+ b,
150
150
  {
151
151
  ...r,
152
152
  onValueChange: (n) => r.onChange(n),
@@ -160,7 +160,7 @@ const Z = ({
160
160
  return /* @__PURE__ */ l("div", { children: [
161
161
  o,
162
162
  /* @__PURE__ */ a(
163
- v,
163
+ b,
164
164
  {
165
165
  ...r,
166
166
  multiple: !0,
@@ -171,32 +171,38 @@ const Z = ({
171
171
  }
172
172
  )
173
173
  ] });
174
- case "datepicker":
174
+ case "datepicker": {
175
+ const {
176
+ mode: n,
177
+ value: p,
178
+ onChange: L,
179
+ customCalendarProps: E,
180
+ ...O
181
+ } = e.datePickerProps || {}, P = {
182
+ value: r.value,
183
+ onChange: e.disabled || e.calendarRange ? void 0 : (u) => r.onChange(u),
184
+ placeholder: e.placeholder,
185
+ disabled: e.disabled,
186
+ customCalendarProps: e.disabled ? {
187
+ disabled: !0,
188
+ mode: "single"
189
+ } : e.calendarRange ? {
190
+ mode: "range",
191
+ selected: r.value,
192
+ onSelect: (u) => r.onChange(u)
193
+ } : void 0,
194
+ ...O
195
+ };
175
196
  return /* @__PURE__ */ l("div", { className: "relative", children: [
176
197
  o,
177
- /* @__PURE__ */ a(
178
- F,
179
- {
180
- value: r.value,
181
- onChange: e.disabled || e.calendarRange ? void 0 : (n) => r.onChange(n),
182
- placeholder: e.placeholder,
183
- disabled: e.disabled,
184
- customCalendarProps: e.disabled ? {
185
- disabled: !0,
186
- mode: "single"
187
- } : e.calendarRange ? {
188
- mode: "range",
189
- selected: r.value,
190
- onSelect: (n) => r.onChange(n)
191
- } : void 0
192
- }
193
- )
198
+ /* @__PURE__ */ a(j, { ...P })
194
199
  ] });
200
+ }
195
201
  case "checkbox":
196
202
  return /* @__PURE__ */ l("div", { className: "space-y-1.5", children: [
197
203
  /* @__PURE__ */ l("div", { className: "flex items-center gap-2", children: [
198
204
  /* @__PURE__ */ a(
199
- A,
205
+ R,
200
206
  {
201
207
  ...r,
202
208
  id: e.name,
@@ -209,14 +215,14 @@ const Z = ({
209
215
  t,
210
216
  {
211
217
  htmlFor: e.name,
212
- className: s(
218
+ className: d(
213
219
  "cursor-pointer",
214
220
  e.disabled && "cursor-not-allowed opacity-60"
215
221
  ),
216
222
  children: e.label
217
223
  }
218
224
  ),
219
- d && /* @__PURE__ */ a("span", { className: "text-d-destructive text-xs", children: d })
225
+ s && /* @__PURE__ */ a("span", { className: "text-d-destructive text-xs", children: s })
220
226
  ] }),
221
227
  e.caption && /* @__PURE__ */ a(
222
228
  i,
@@ -242,7 +248,7 @@ const Z = ({
242
248
  )
243
249
  ] }),
244
250
  /* @__PURE__ */ a(
245
- T,
251
+ $,
246
252
  {
247
253
  id: e.name,
248
254
  checked: !!r.value,
@@ -251,13 +257,13 @@ const Z = ({
251
257
  }
252
258
  )
253
259
  ] }),
254
- d && /* @__PURE__ */ a("span", { className: "text-d-destructive text-xs", children: d })
260
+ s && /* @__PURE__ */ a("span", { className: "text-d-destructive text-xs", children: s })
255
261
  ] });
256
262
  case "slider":
257
263
  return /* @__PURE__ */ l("div", { children: [
258
264
  o,
259
265
  /* @__PURE__ */ a(
260
- B,
266
+ T,
261
267
  {
262
268
  value: Array.isArray(r.value) ? r.value : [r.value || e.min || 0],
263
269
  onValueChange: (n) => r.onChange(n[0]),
@@ -282,26 +288,26 @@ const Z = ({
282
288
  }
283
289
  ) });
284
290
  };
285
- return /* @__PURE__ */ l("form", { onSubmit: y((e) => x?.(e)), children: [
286
- /* @__PURE__ */ a("div", { className: s("grid gap-4", `grid-cols-${b}`), children: u.map((e, c) => /* @__PURE__ */ a(
291
+ return /* @__PURE__ */ l("form", { onSubmit: f((e) => C?.(e)), children: [
292
+ /* @__PURE__ */ a("div", { className: d("grid gap-4", `grid-cols-${m}`), children: h.map((e, c) => /* @__PURE__ */ a(
287
293
  "div",
288
294
  {
289
- className: s(c === u.length - 1 && "col-span-full"),
290
- children: k(e)
295
+ className: d(c === h.length - 1 && "col-span-full"),
296
+ children: w(e)
291
297
  },
292
298
  e.name
293
299
  )) }),
294
- C && /* @__PURE__ */ a("div", { className: "mt-4 flex justify-end", children: /* @__PURE__ */ a(
295
- I,
300
+ N && /* @__PURE__ */ a("div", { className: "mt-4 flex justify-end", children: /* @__PURE__ */ a(
301
+ F,
296
302
  {
297
303
  type: "submit",
298
- disabled: !S || !V || p,
299
- isLoading: p,
300
- children: g
304
+ disabled: !V || !k || v,
305
+ isLoading: v,
306
+ children: x
301
307
  }
302
308
  ) })
303
309
  ] });
304
310
  };
305
311
  export {
306
- Z as AppForm
312
+ ne as AppForm
307
313
  };
@@ -1,109 +1,135 @@
1
1
  "use client";
2
- import { jsxs as m, jsx as t } from "react/jsx-runtime";
3
- import { designTokens as o } from "../design-tokens.js";
4
- import { Calendar as B } from "./calendar.js";
5
- import { Icon as F } from "./icon.js";
6
- import { Label as G } from "./label.js";
7
- import { Popover as H, PopoverTrigger as J, PopoverContent as K } from "./popover.js";
8
- import { cn as C } from "../../lib/utils.js";
2
+ import { jsxs as h, jsx as n } from "react/jsx-runtime";
3
+ import { designTokens as r } from "../design-tokens.js";
4
+ import { Calendar as O } from "./calendar.js";
5
+ import { Icon as J } from "./icon.js";
6
+ import { Label as K } from "./label.js";
7
+ import { Popover as Q, PopoverTrigger as U, PopoverContent as W } from "./popover.js";
8
+ import { cn as k } from "../../lib/utils.js";
9
9
  import * as d from "react";
10
- import { useEffect as Q } from "react";
11
- import { it as U } from "../../node_modules/date-fns/locale/it.js";
12
- import { formatDate as a } from "../../node_modules/date-fns/format.js";
13
- import { isSameDay as V } from "../../node_modules/date-fns/isSameDay.js";
14
- function re({
15
- value: e,
16
- onChange: l,
17
- placeholder: P = "Seleziona data",
18
- dateFormat: f = "dd/MM/yyyy",
19
- className: k,
20
- disabled: r = !1,
21
- size: i = "default",
22
- firstDate: u,
23
- lastDate: h,
24
- availableDates: g,
25
- locale: N = U,
26
- initialCalendarMonth: p,
27
- customCalendarProps: j,
28
- label: x,
29
- wrpClassName: M,
30
- id: O,
31
- "data-testid": R,
32
- minDate: w,
33
- maxDate: z
34
- }) {
35
- const [c, y] = d.useState(e), [T, I] = d.useState(
36
- p
37
- ), [S, q] = d.useState(!1), E = (s) => {
38
- y(s), s && I(s), l && l(s);
10
+ import { useEffect as X } from "react";
11
+ import { it as Y } from "../../node_modules/date-fns/locale/it.js";
12
+ import { formatDate as v } from "../../node_modules/date-fns/format.js";
13
+ import { isSameDay as Z } from "../../node_modules/date-fns/isSameDay.js";
14
+ function de(e) {
15
+ const {
16
+ placeholder: F = "Seleziona data",
17
+ dateFormat: g = "dd/MM/yyyy",
18
+ className: R,
19
+ disabled: s = !1,
20
+ size: m = "default",
21
+ firstDate: p,
22
+ lastDate: b,
23
+ availableDates: C,
24
+ locale: l = Y,
25
+ initialCalendarMonth: c,
26
+ customCalendarProps: x,
27
+ label: D,
28
+ wrpClassName: T,
29
+ id: j,
30
+ "data-testid": V,
31
+ minDate: M,
32
+ maxDate: S,
33
+ numberOfMonths: q
34
+ } = e, a = e.mode === "range", [f, y] = d.useState(
35
+ a ? void 0 : e.value
36
+ ), [o, I] = d.useState(
37
+ a ? e.value : void 0
38
+ ), [z, u] = d.useState(
39
+ c
40
+ ), [N, E] = d.useState(!1), L = (t) => {
41
+ y(t), t && u(t), !a && e.onChange && e.onChange(t);
42
+ }, w = (t) => {
43
+ I(t), t?.from && u(t.from), a && e.onChange && e.onChange(t);
39
44
  };
40
- let n = [];
41
- u && n.push({ before: u }), h && n.push({ after: h }), g?.length && n.push(
42
- (s) => !g.some(
43
- (A) => V(A, s)
45
+ let i = [];
46
+ p && i.push({ before: p }), b && i.push({ after: b }), C?.length && i.push(
47
+ (t) => !C.some(
48
+ (H) => Z(H, t)
44
49
  )
45
- ), r && (n = [!0]), Q(() => {
46
- y(e), I(e ?? p);
47
- }, [e, p]);
48
- const L = d.useId(), b = O ?? L;
49
- return /* @__PURE__ */ m("div", { className: C("flex flex-col gap-1.5", M), children: [
50
- x && /* @__PURE__ */ t(G, { htmlFor: b, children: x }),
51
- /* @__PURE__ */ m(H, { open: r ? !1 : S, onOpenChange: q, children: [
52
- /* @__PURE__ */ t(J, { asChild: !0, children: /* @__PURE__ */ m(
50
+ ), s && (i = [!0]), X(() => {
51
+ if (a) {
52
+ I(e.value);
53
+ const t = e.value?.from;
54
+ u(t ?? c);
55
+ } else
56
+ y(e.value), u(
57
+ e.value ?? c
58
+ );
59
+ }, [e.value, a, c]);
60
+ const A = d.useId(), P = j ?? A, B = a ? !!o?.from : !!f, G = () => a && o ? /* @__PURE__ */ h("span", { children: [
61
+ o.from && v(o.from, g, { locale: l }),
62
+ o.from && o.to && " - ",
63
+ o.to && v(o.to, g, { locale: l })
64
+ ] }) : !a && f ? /* @__PURE__ */ n("span", { children: v(f, g, { locale: l }) }) : /* @__PURE__ */ n("span", { className: "text-d-muted-foreground", children: F });
65
+ return /* @__PURE__ */ h("div", { className: k("flex flex-col gap-1.5", T), children: [
66
+ D && /* @__PURE__ */ n(K, { htmlFor: P, children: D }),
67
+ /* @__PURE__ */ h(Q, { open: s ? !1 : N, onOpenChange: E, children: [
68
+ /* @__PURE__ */ n(U, { asChild: !0, children: /* @__PURE__ */ h(
53
69
  "div",
54
70
  {
55
- id: b,
56
- "data-testid": R,
57
- className: C(
58
- o.input.base,
59
- o.radius.default,
60
- o.text.base,
61
- o.interaction.disabled,
71
+ id: P,
72
+ "data-testid": V,
73
+ className: k(
74
+ r.input.base,
75
+ r.radius.default,
76
+ r.text.base,
77
+ r.interaction.disabled,
62
78
  "flex items-center gap-2 font-normal whitespace-nowrap [&>span]:line-clamp-1",
63
- o.focusRing,
64
- S && o.activeRing,
79
+ r.focusRing,
80
+ N && r.activeRing,
65
81
  "hover:border-d-ring cursor-pointer transition-colors",
66
- !c && "text-d-muted-foreground",
67
- r && "cursor-not-allowed opacity-50",
68
- i === "default" && o.sizes.default,
69
- i === "sm" && o.sizes.sm,
70
- i === "lg" && o.sizes.lg,
71
- k
82
+ !B && "text-d-muted-foreground",
83
+ s && "cursor-not-allowed opacity-50",
84
+ m === "default" && r.sizes.default,
85
+ m === "sm" && r.sizes.sm,
86
+ m === "lg" && r.sizes.lg,
87
+ R
72
88
  ),
73
- "aria-disabled": r,
89
+ "aria-disabled": s,
74
90
  role: "button",
75
- tabIndex: r ? -1 : 0,
76
- onClick: r ? void 0 : () => {
91
+ tabIndex: s ? -1 : 0,
92
+ onClick: s ? void 0 : () => {
77
93
  },
78
94
  children: [
79
- /* @__PURE__ */ t(F, { name: "Calendar", size: i === "lg" ? "sm" : "xs" }),
80
- /* @__PURE__ */ t("div", { children: e && typeof e == "object" && "from" in e ? /* @__PURE__ */ m("span", { children: [
81
- e.from && a(e.from, f),
82
- e.from && e.to && " - ",
83
- e.to && a(e.to, f)
84
- ] }) : c ? /* @__PURE__ */ t("span", { children: a(c, f) }) : /* @__PURE__ */ t("span", { className: "text-d-muted-foreground", children: P }) })
95
+ /* @__PURE__ */ n(J, { name: "Calendar", size: m === "lg" ? "sm" : "xs" }),
96
+ /* @__PURE__ */ n("div", { children: G() })
85
97
  ]
86
98
  }
87
99
  ) }),
88
- /* @__PURE__ */ t(K, { className: "w-auto p-0 shadow", children: /* @__PURE__ */ t(
89
- B,
100
+ /* @__PURE__ */ n(W, { className: "w-auto p-0 shadow", children: a ? /* @__PURE__ */ n(
101
+ O,
90
102
  {
91
- ...j || {
92
- mode: "single",
93
- selected: c,
94
- onSelect: E
95
- },
103
+ ...x || {},
104
+ mode: "range",
105
+ selected: o,
106
+ onSelect: w,
107
+ autoFocus: !0,
108
+ disabled: i,
109
+ locale: l,
110
+ defaultMonth: z,
111
+ numberOfMonths: q ?? 1,
112
+ minDate: M,
113
+ maxDate: S
114
+ }
115
+ ) : /* @__PURE__ */ n(
116
+ O,
117
+ {
118
+ ...x || {},
119
+ mode: "single",
120
+ selected: f,
121
+ onSelect: L,
96
122
  autoFocus: !0,
97
- disabled: n,
98
- locale: N,
99
- defaultMonth: T,
100
- minDate: w,
101
- maxDate: z
123
+ disabled: i,
124
+ locale: l,
125
+ defaultMonth: z,
126
+ minDate: M,
127
+ maxDate: S
102
128
  }
103
129
  ) })
104
130
  ] })
105
131
  ] });
106
132
  }
107
133
  export {
108
- re as DatePicker
134
+ de as DatePicker
109
135
  };
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ import { Command as Command_2 } from 'cmdk';
11
11
  import { ComponentProps } from 'react';
12
12
  import * as ContextMenuPrimitive from '@radix-ui/react-context-menu';
13
13
  import { ControllerProps } from 'react-hook-form';
14
+ import { DateRange } from 'react-day-picker';
14
15
  import { DayPicker } from 'react-day-picker';
15
16
  import { default as default_2 } from 'react';
16
17
  import { default as default_3 } from 'embla-carousel-react';
@@ -244,6 +245,7 @@ export declare interface AppFormItem {
244
245
  noResultsMessage?: string;
245
246
  debounce?: number;
246
247
  clearable?: boolean;
248
+ datePickerProps?: Partial<ComponentProps<typeof DatePicker>>;
247
249
  }
248
250
 
249
251
  declare interface AppFormProps {
@@ -1548,11 +1550,9 @@ export declare interface DataTableState<TData = Record<string, unknown>> {
1548
1550
  columnVisibility?: Partial<Record<keyof TData, boolean>>;
1549
1551
  }
1550
1552
 
1551
- export declare function DatePicker({ value, onChange, placeholder, dateFormat, className, disabled, size, firstDate, lastDate, availableDates, locale, initialCalendarMonth, customCalendarProps, label, wrpClassName, id, "data-testid": dataTestId, minDate, maxDate, }: DatePickerProps): JSX.Element;
1553
+ export declare function DatePicker(props: DatePickerProps): JSX.Element;
1552
1554
 
1553
- export declare interface DatePickerProps {
1554
- value?: Date;
1555
- onChange?: (date: Date | undefined) => void;
1555
+ declare interface DatePickerBaseProps {
1556
1556
  placeholder?: string;
1557
1557
  dateFormat?: string;
1558
1558
  className?: string;
@@ -1571,6 +1571,21 @@ export declare interface DatePickerProps {
1571
1571
  "data-testid"?: string;
1572
1572
  minDate?: Date;
1573
1573
  maxDate?: Date;
1574
+ numberOfMonths?: number;
1575
+ }
1576
+
1577
+ export declare type DatePickerProps = DatePickerSingleProps | DatePickerRangeProps;
1578
+
1579
+ declare interface DatePickerRangeProps extends DatePickerBaseProps {
1580
+ mode: "range";
1581
+ value?: DateRange;
1582
+ onChange?: (range: DateRange | undefined) => void;
1583
+ }
1584
+
1585
+ declare interface DatePickerSingleProps extends DatePickerBaseProps {
1586
+ mode?: "single";
1587
+ value?: Date;
1588
+ onChange?: (date: Date | undefined) => void;
1574
1589
  }
1575
1590
 
1576
1591
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "laif-ds",
3
3
  "private": false,
4
- "version": "0.2.66",
4
+ "version": "0.2.68",
5
5
  "type": "module",
6
6
  "main": "dist/index.es.js",
7
7
  "module": "dist/index.es.js",