@mihcm/ui 0.14.1 → 0.15.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/dist/CheckboxGrid.native.d.ts.map +1 -1
- package/dist/CheckboxGrid.native.js +2 -1
- package/dist/CheckboxGrid.native.js.map +1 -1
- package/dist/Combobox.native.d.ts.map +1 -1
- package/dist/Combobox.native.js +2 -1
- package/dist/Combobox.native.js.map +1 -1
- package/dist/DataTable/column-filter.d.ts +8 -0
- package/dist/DataTable/column-filter.d.ts.map +1 -0
- package/dist/DataTable/column-filter.js +67 -0
- package/dist/DataTable/column-filter.js.map +1 -0
- package/dist/DataTable/column-header.d.ts +16 -0
- package/dist/DataTable/column-header.d.ts.map +1 -0
- package/dist/DataTable/column-header.js +11 -0
- package/dist/DataTable/column-header.js.map +1 -0
- package/dist/DataTable/column-visibility.d.ts +7 -0
- package/dist/DataTable/column-visibility.d.ts.map +1 -0
- package/dist/DataTable/column-visibility.js +35 -0
- package/dist/DataTable/column-visibility.js.map +1 -0
- package/dist/DataTable/index.d.ts +5 -0
- package/dist/DataTable/index.d.ts.map +1 -0
- package/dist/DataTable/index.js +5 -0
- package/dist/DataTable/index.js.map +1 -0
- package/dist/DataTable/pinning.d.ts +13 -0
- package/dist/DataTable/pinning.d.ts.map +1 -0
- package/dist/DataTable/pinning.js +29 -0
- package/dist/DataTable/pinning.js.map +1 -0
- package/dist/DataTable.d.ts +3 -7
- package/dist/DataTable.d.ts.map +1 -1
- package/dist/DataTable.js +7 -126
- package/dist/DataTable.js.map +1 -1
- package/dist/Dialog.native.d.ts +3 -1
- package/dist/Dialog.native.d.ts.map +1 -1
- package/dist/Dialog.native.js +2 -2
- package/dist/Dialog.native.js.map +1 -1
- package/dist/Form/building-blocks.d.ts +26 -0
- package/dist/Form/building-blocks.d.ts.map +1 -0
- package/dist/Form/building-blocks.js +29 -0
- package/dist/Form/building-blocks.js.map +1 -0
- package/dist/Form/fields-choice.d.ts +72 -0
- package/dist/Form/fields-choice.d.ts.map +1 -0
- package/dist/Form/fields-choice.js +69 -0
- package/dist/Form/fields-choice.js.map +1 -0
- package/dist/Form/fields-complex.d.ts +28 -0
- package/dist/Form/fields-complex.d.ts.map +1 -0
- package/dist/Form/fields-complex.js +38 -0
- package/dist/Form/fields-complex.js.map +1 -0
- package/dist/Form/fields-date.d.ts +46 -0
- package/dist/Form/fields-date.d.ts.map +1 -0
- package/dist/Form/fields-date.js +41 -0
- package/dist/Form/fields-date.js.map +1 -0
- package/dist/Form/fields-text.d.ts +47 -0
- package/dist/Form/fields-text.d.ts.map +1 -0
- package/dist/Form/fields-text.js +46 -0
- package/dist/Form/fields-text.js.map +1 -0
- package/dist/Form/fields-toggle.d.ts +24 -0
- package/dist/Form/fields-toggle.d.ts.map +1 -0
- package/dist/Form/fields-toggle.js +32 -0
- package/dist/Form/fields-toggle.js.map +1 -0
- package/dist/Form/helpers.d.ts +66 -0
- package/dist/Form/helpers.d.ts.map +1 -0
- package/dist/Form/helpers.js +44 -0
- package/dist/Form/helpers.js.map +1 -0
- package/dist/Form/types.d.ts +25 -0
- package/dist/Form/types.d.ts.map +1 -0
- package/dist/Form/types.js +8 -0
- package/dist/Form/types.js.map +1 -0
- package/dist/Form.d.ts +24 -298
- package/dist/Form.d.ts.map +1 -1
- package/dist/Form.js +30 -246
- package/dist/Form.js.map +1 -1
- package/dist/IconSidebar.d.ts +6 -46
- package/dist/IconSidebar.d.ts.map +1 -1
- package/dist/IconSidebar.js +6 -116
- package/dist/IconSidebar.js.map +1 -1
- package/dist/MainSidebar/back-button.d.ts +14 -0
- package/dist/MainSidebar/back-button.d.ts.map +1 -0
- package/dist/MainSidebar/back-button.js +14 -0
- package/dist/MainSidebar/back-button.js.map +1 -0
- package/dist/MainSidebar/breadcrumb.d.ts +10 -0
- package/dist/MainSidebar/breadcrumb.d.ts.map +1 -0
- package/dist/MainSidebar/breadcrumb.js +24 -0
- package/dist/MainSidebar/breadcrumb.js.map +1 -0
- package/dist/MainSidebar/columns.d.ts +3 -0
- package/dist/MainSidebar/columns.d.ts.map +1 -0
- package/dist/MainSidebar/columns.js +198 -0
- package/dist/MainSidebar/columns.js.map +1 -0
- package/dist/MainSidebar/command.d.ts +3 -0
- package/dist/MainSidebar/command.d.ts.map +1 -0
- package/dist/MainSidebar/command.js +193 -0
- package/dist/MainSidebar/command.js.map +1 -0
- package/dist/MainSidebar/drilldown.d.ts +3 -0
- package/dist/MainSidebar/drilldown.d.ts.map +1 -0
- package/dist/MainSidebar/drilldown.js +154 -0
- package/dist/MainSidebar/drilldown.js.map +1 -0
- package/dist/MainSidebar/expanded.d.ts +7 -0
- package/dist/MainSidebar/expanded.d.ts.map +1 -0
- package/dist/MainSidebar/expanded.js +102 -0
- package/dist/MainSidebar/expanded.js.map +1 -0
- package/dist/MainSidebar/floating.d.ts +3 -0
- package/dist/MainSidebar/floating.d.ts.map +1 -0
- package/dist/MainSidebar/floating.js +116 -0
- package/dist/MainSidebar/floating.js.map +1 -0
- package/dist/MainSidebar/helpers.d.ts +50 -0
- package/dist/MainSidebar/helpers.d.ts.map +1 -0
- package/dist/MainSidebar/helpers.js +150 -0
- package/dist/MainSidebar/helpers.js.map +1 -0
- package/dist/MainSidebar/hover.d.ts +3 -0
- package/dist/MainSidebar/hover.d.ts.map +1 -0
- package/dist/MainSidebar/hover.js +177 -0
- package/dist/MainSidebar/hover.js.map +1 -0
- package/dist/MainSidebar/index.d.ts +6 -0
- package/dist/MainSidebar/index.d.ts.map +1 -0
- package/dist/MainSidebar/index.js +108 -0
- package/dist/MainSidebar/index.js.map +1 -0
- package/dist/MainSidebar/mobile.d.ts +29 -0
- package/dist/MainSidebar/mobile.d.ts.map +1 -0
- package/dist/MainSidebar/mobile.js +38 -0
- package/dist/MainSidebar/mobile.js.map +1 -0
- package/dist/MainSidebar/motion.d.ts +23 -0
- package/dist/MainSidebar/motion.d.ts.map +1 -0
- package/dist/MainSidebar/motion.js +40 -0
- package/dist/MainSidebar/motion.js.map +1 -0
- package/dist/MainSidebar/rail.d.ts +24 -0
- package/dist/MainSidebar/rail.d.ts.map +1 -0
- package/dist/MainSidebar/rail.js +29 -0
- package/dist/MainSidebar/rail.js.map +1 -0
- package/dist/MainSidebar/search.d.ts +19 -0
- package/dist/MainSidebar/search.d.ts.map +1 -0
- package/dist/MainSidebar/search.js +33 -0
- package/dist/MainSidebar/search.js.map +1 -0
- package/dist/MainSidebar/types.d.ts +161 -0
- package/dist/MainSidebar/types.d.ts.map +1 -0
- package/dist/MainSidebar/types.js +2 -0
- package/dist/MainSidebar/types.js.map +1 -0
- package/dist/MainSidebar.d.ts +6 -1
- package/dist/MainSidebar.d.ts.map +1 -1
- package/dist/MainSidebar.js +6 -1
- package/dist/MainSidebar.js.map +1 -1
- package/dist/NavigationMenu.js +1 -1
- package/dist/NavigationMenu.js.map +1 -1
- package/dist/RichTextEditor/theme.d.ts +44 -0
- package/dist/RichTextEditor/theme.d.ts.map +1 -0
- package/dist/RichTextEditor/theme.js +41 -0
- package/dist/RichTextEditor/theme.js.map +1 -0
- package/dist/RichTextEditor/toolbar-icons.d.ts +21 -0
- package/dist/RichTextEditor/toolbar-icons.d.ts.map +1 -0
- package/dist/RichTextEditor/toolbar-icons.js +21 -0
- package/dist/RichTextEditor/toolbar-icons.js.map +1 -0
- package/dist/RichTextEditor/toolbar.d.ts +5 -0
- package/dist/RichTextEditor/toolbar.d.ts.map +1 -0
- package/dist/RichTextEditor/toolbar.js +116 -0
- package/dist/RichTextEditor/toolbar.js.map +1 -0
- package/dist/RichTextEditor.d.ts +16 -9
- package/dist/RichTextEditor.d.ts.map +1 -1
- package/dist/RichTextEditor.js +18 -164
- package/dist/RichTextEditor.js.map +1 -1
- package/dist/Select/content.d.ts +9 -0
- package/dist/Select/content.d.ts.map +1 -0
- package/dist/Select/content.js +80 -0
- package/dist/Select/content.js.map +1 -0
- package/dist/Select/context.d.ts +27 -0
- package/dist/Select/context.d.ts.map +1 -0
- package/dist/Select/context.js +35 -0
- package/dist/Select/context.js.map +1 -0
- package/dist/Select/item.d.ts +13 -0
- package/dist/Select/item.d.ts.map +1 -0
- package/dist/Select/item.js +39 -0
- package/dist/Select/item.js.map +1 -0
- package/dist/Select/parts.d.ts +14 -0
- package/dist/Select/parts.d.ts.map +1 -0
- package/dist/Select/parts.js +17 -0
- package/dist/Select/parts.js.map +1 -0
- package/dist/Select/react-select.d.ts +25 -0
- package/dist/Select/react-select.d.ts.map +1 -0
- package/dist/Select/react-select.js +66 -0
- package/dist/Select/react-select.js.map +1 -0
- package/dist/Select/root.d.ts +15 -0
- package/dist/Select/root.d.ts.map +1 -0
- package/dist/Select/root.js +41 -0
- package/dist/Select/root.js.map +1 -0
- package/dist/Select/trigger.d.ts +15 -0
- package/dist/Select/trigger.d.ts.map +1 -0
- package/dist/Select/trigger.js +61 -0
- package/dist/Select/trigger.js.map +1 -0
- package/dist/Select.d.ts +14 -62
- package/dist/Select.d.ts.map +1 -1
- package/dist/Select.js +14 -293
- package/dist/Select.js.map +1 -1
- package/dist/Sidebar/context.d.ts +28 -0
- package/dist/Sidebar/context.d.ts.map +1 -0
- package/dist/Sidebar/context.js +37 -0
- package/dist/Sidebar/context.js.map +1 -0
- package/dist/Sidebar/group.d.ts +13 -0
- package/dist/Sidebar/group.d.ts.map +1 -0
- package/dist/Sidebar/group.js +20 -0
- package/dist/Sidebar/group.js.map +1 -0
- package/dist/Sidebar/icons.d.ts +7 -0
- package/dist/Sidebar/icons.d.ts.map +1 -0
- package/dist/Sidebar/icons.js +12 -0
- package/dist/Sidebar/icons.js.map +1 -0
- package/dist/Sidebar/layout.d.ts +9 -0
- package/dist/Sidebar/layout.d.ts.map +1 -0
- package/dist/Sidebar/layout.js +21 -0
- package/dist/Sidebar/layout.js.map +1 -0
- package/dist/Sidebar/menu.d.ts +29 -0
- package/dist/Sidebar/menu.d.ts.map +1 -0
- package/dist/Sidebar/menu.js +55 -0
- package/dist/Sidebar/menu.js.map +1 -0
- package/dist/Sidebar/provider.d.ts +33 -0
- package/dist/Sidebar/provider.d.ts.map +1 -0
- package/dist/Sidebar/provider.js +110 -0
- package/dist/Sidebar/provider.js.map +1 -0
- package/dist/Sidebar/sidebar.d.ts +17 -0
- package/dist/Sidebar/sidebar.d.ts.map +1 -0
- package/dist/Sidebar/sidebar.js +51 -0
- package/dist/Sidebar/sidebar.js.map +1 -0
- package/dist/Sidebar/submenu.d.ts +13 -0
- package/dist/Sidebar/submenu.d.ts.map +1 -0
- package/dist/Sidebar/submenu.js +17 -0
- package/dist/Sidebar/submenu.js.map +1 -0
- package/dist/Sidebar/trigger.d.ts +9 -0
- package/dist/Sidebar/trigger.d.ts.map +1 -0
- package/dist/Sidebar/trigger.js +33 -0
- package/dist/Sidebar/trigger.js.map +1 -0
- package/dist/Sidebar.d.ts +14 -104
- package/dist/Sidebar.d.ts.map +1 -1
- package/dist/Sidebar.js +14 -300
- package/dist/Sidebar.js.map +1 -1
- package/dist/StatCard.d.ts +67 -9
- package/dist/StatCard.d.ts.map +1 -1
- package/dist/StatCard.js +111 -9
- package/dist/StatCard.js.map +1 -1
- package/dist/TransferList.native.d.ts.map +1 -1
- package/dist/TransferList.native.js +2 -1
- package/dist/TransferList.native.js.map +1 -1
- package/package.json +2 -2
- package/src/CheckboxGrid.native.tsx +2 -1
- package/src/Combobox.native.tsx +2 -1
- package/src/DataTable/column-filter.tsx +134 -0
- package/src/DataTable/column-header.tsx +67 -0
- package/src/DataTable/column-visibility.tsx +87 -0
- package/src/DataTable/index.ts +4 -0
- package/src/DataTable/pinning.ts +40 -0
- package/src/DataTable.tsx +14 -297
- package/src/Dialog.native.tsx +4 -2
- package/src/Form/building-blocks.tsx +97 -0
- package/src/Form/fields-choice.tsx +312 -0
- package/src/Form/fields-complex.tsx +195 -0
- package/src/Form/fields-date.tsx +195 -0
- package/src/Form/fields-text.tsx +218 -0
- package/src/Form/fields-toggle.tsx +123 -0
- package/src/Form/helpers.tsx +189 -0
- package/src/Form/types.ts +26 -0
- package/src/Form.tsx +91 -1308
- package/src/IconSidebar.tsx +20 -442
- package/src/MainSidebar/back-button.tsx +58 -0
- package/src/MainSidebar/breadcrumb.tsx +53 -0
- package/src/MainSidebar/columns.tsx +350 -0
- package/src/MainSidebar/command.tsx +404 -0
- package/src/MainSidebar/drilldown.tsx +373 -0
- package/src/MainSidebar/expanded.tsx +414 -0
- package/src/MainSidebar/floating.tsx +268 -0
- package/src/MainSidebar/helpers.ts +166 -0
- package/src/MainSidebar/hover.tsx +334 -0
- package/src/MainSidebar/index.tsx +191 -0
- package/src/MainSidebar/mobile.tsx +117 -0
- package/src/MainSidebar/motion.ts +64 -0
- package/src/MainSidebar/rail.tsx +137 -0
- package/src/MainSidebar/search.tsx +99 -0
- package/src/MainSidebar/types.ts +208 -0
- package/src/MainSidebar.tsx +15 -4
- package/src/NavigationMenu.tsx +1 -1
- package/src/RichTextEditor/theme.ts +43 -0
- package/src/RichTextEditor/toolbar-icons.tsx +40 -0
- package/src/RichTextEditor/toolbar.tsx +271 -0
- package/src/RichTextEditor.tsx +23 -371
- package/src/Select/content.tsx +111 -0
- package/src/Select/context.tsx +66 -0
- package/src/Select/item.tsx +97 -0
- package/src/Select/parts.tsx +43 -0
- package/src/Select/react-select.tsx +216 -0
- package/src/Select/root.tsx +75 -0
- package/src/Select/trigger.tsx +122 -0
- package/src/Select.tsx +34 -692
- package/src/Sidebar/context.tsx +72 -0
- package/src/Sidebar/group.tsx +69 -0
- package/src/Sidebar/icons.tsx +42 -0
- package/src/Sidebar/layout.tsx +64 -0
- package/src/Sidebar/menu.tsx +171 -0
- package/src/Sidebar/provider.tsx +224 -0
- package/src/Sidebar/sidebar.tsx +178 -0
- package/src/Sidebar/submenu.tsx +58 -0
- package/src/Sidebar/trigger.tsx +104 -0
- package/src/Sidebar.tsx +44 -927
- package/src/StatCard.tsx +365 -20
- package/src/TransferList.native.tsx +2 -1
- package/dist/TiptapEditor.d.ts +0 -24
- package/dist/TiptapEditor.d.ts.map +0 -1
- package/dist/TiptapEditor.js +0 -84
- package/dist/TiptapEditor.js.map +0 -1
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Single-choice fields integrated with TanStack Form: FormSelect, FormCombobox,
|
|
5
|
+
* FormRadioGroup, FormRadioCardGroup.
|
|
6
|
+
*/
|
|
7
|
+
import { useId } from 'react';
|
|
8
|
+
import { Combobox, type ComboboxOption } from '../Combobox.js';
|
|
9
|
+
import { RadioCardGroup, type RadioCardOption } from '../RadioCardGroup.js';
|
|
10
|
+
import { RadioGroup, RadioGroupItem } from '../RadioGroup.js';
|
|
11
|
+
import { Select, SelectContent, SelectItem, SelectTrigger } from '../Select.js';
|
|
12
|
+
import {
|
|
13
|
+
FormDescription,
|
|
14
|
+
FormItem,
|
|
15
|
+
FormLabel,
|
|
16
|
+
FormMessage,
|
|
17
|
+
} from './building-blocks.js';
|
|
18
|
+
import type { AnyFormApi, FieldRenderProps, FormFieldValidators } from './types.js';
|
|
19
|
+
|
|
20
|
+
/* ── FormSelect ──────────────────────────────────────────────────── */
|
|
21
|
+
|
|
22
|
+
export interface FormSelectOption {
|
|
23
|
+
value: string;
|
|
24
|
+
label: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface FormSelectProps {
|
|
28
|
+
form: AnyFormApi;
|
|
29
|
+
name: string;
|
|
30
|
+
label: string;
|
|
31
|
+
options: FormSelectOption[];
|
|
32
|
+
description?: string;
|
|
33
|
+
required?: boolean;
|
|
34
|
+
placeholder?: string;
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
className?: string;
|
|
37
|
+
validators?: FormFieldValidators;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Select dropdown field integrated with TanStack Form. */
|
|
41
|
+
export function FormSelect({
|
|
42
|
+
form,
|
|
43
|
+
name,
|
|
44
|
+
label,
|
|
45
|
+
options,
|
|
46
|
+
description,
|
|
47
|
+
required,
|
|
48
|
+
placeholder,
|
|
49
|
+
disabled,
|
|
50
|
+
className,
|
|
51
|
+
validators,
|
|
52
|
+
}: FormSelectProps) {
|
|
53
|
+
const id = useId();
|
|
54
|
+
const descId = `${id}-desc`;
|
|
55
|
+
const msgId = `${id}-msg`;
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<form.Field name={name} {...(validators !== undefined && { validators })}>
|
|
59
|
+
{(field: FieldRenderProps<string>) => {
|
|
60
|
+
const errors = field.state.meta.isTouched ? field.state.meta.errors : [];
|
|
61
|
+
const hasError = errors.length > 0;
|
|
62
|
+
return (
|
|
63
|
+
<FormItem {...(className !== undefined && { className })}>
|
|
64
|
+
<FormLabel htmlFor={id} {...(required !== undefined && { required })}>
|
|
65
|
+
{label}
|
|
66
|
+
</FormLabel>
|
|
67
|
+
<Select
|
|
68
|
+
value={field.state.value ?? ''}
|
|
69
|
+
onValueChange={(v) => {
|
|
70
|
+
field.handleChange(v);
|
|
71
|
+
field.handleBlur();
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
<SelectTrigger
|
|
75
|
+
id={id}
|
|
76
|
+
{...(placeholder !== undefined && { placeholder })}
|
|
77
|
+
{...(disabled !== undefined && { disabled })}
|
|
78
|
+
variant={hasError ? 'destructive' : 'default'}
|
|
79
|
+
aria-describedby={hasError ? msgId : description !== undefined ? descId : undefined}
|
|
80
|
+
/>
|
|
81
|
+
<SelectContent>
|
|
82
|
+
{options.map((opt) => (
|
|
83
|
+
<SelectItem key={opt.value} value={opt.value}>
|
|
84
|
+
{opt.label}
|
|
85
|
+
</SelectItem>
|
|
86
|
+
))}
|
|
87
|
+
</SelectContent>
|
|
88
|
+
</Select>
|
|
89
|
+
{description !== undefined ? (
|
|
90
|
+
<FormDescription id={descId}>{description}</FormDescription>
|
|
91
|
+
) : null}
|
|
92
|
+
{hasError ? <FormMessage id={msgId} errors={errors} /> : null}
|
|
93
|
+
</FormItem>
|
|
94
|
+
);
|
|
95
|
+
}}
|
|
96
|
+
</form.Field>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* ── FormRadioGroup ──────────────────────────────────────────────── */
|
|
101
|
+
|
|
102
|
+
export interface FormRadioGroupOption {
|
|
103
|
+
value: string;
|
|
104
|
+
label: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface FormRadioGroupProps {
|
|
108
|
+
form: AnyFormApi;
|
|
109
|
+
name: string;
|
|
110
|
+
label: string;
|
|
111
|
+
options: FormRadioGroupOption[];
|
|
112
|
+
description?: string;
|
|
113
|
+
required?: boolean;
|
|
114
|
+
orientation?: 'horizontal' | 'vertical';
|
|
115
|
+
disabled?: boolean;
|
|
116
|
+
className?: string;
|
|
117
|
+
validators?: FormFieldValidators;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** RadioGroup field integrated with TanStack Form. */
|
|
121
|
+
export function FormRadioGroup({
|
|
122
|
+
form,
|
|
123
|
+
name,
|
|
124
|
+
label,
|
|
125
|
+
options,
|
|
126
|
+
description,
|
|
127
|
+
required,
|
|
128
|
+
orientation,
|
|
129
|
+
disabled,
|
|
130
|
+
className,
|
|
131
|
+
validators,
|
|
132
|
+
}: FormRadioGroupProps) {
|
|
133
|
+
const id = useId();
|
|
134
|
+
const descId = `${id}-desc`;
|
|
135
|
+
const msgId = `${id}-msg`;
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<form.Field name={name} {...(validators !== undefined && { validators })}>
|
|
139
|
+
{(field: FieldRenderProps<string>) => {
|
|
140
|
+
const errors = field.state.meta.isTouched ? field.state.meta.errors : [];
|
|
141
|
+
const hasError = errors.length > 0;
|
|
142
|
+
return (
|
|
143
|
+
<FormItem {...(className !== undefined && { className })}>
|
|
144
|
+
<FormLabel {...(required !== undefined && { required })}>{label}</FormLabel>
|
|
145
|
+
<RadioGroup
|
|
146
|
+
value={field.state.value ?? ''}
|
|
147
|
+
onValueChange={(v) => {
|
|
148
|
+
field.handleChange(v);
|
|
149
|
+
field.handleBlur();
|
|
150
|
+
}}
|
|
151
|
+
{...(orientation !== undefined && { orientation })}
|
|
152
|
+
{...(disabled !== undefined && { disabled })}
|
|
153
|
+
aria-describedby={hasError ? msgId : description !== undefined ? descId : undefined}
|
|
154
|
+
>
|
|
155
|
+
{options.map((opt) => (
|
|
156
|
+
<RadioGroupItem key={opt.value} value={opt.value}>
|
|
157
|
+
{opt.label}
|
|
158
|
+
</RadioGroupItem>
|
|
159
|
+
))}
|
|
160
|
+
</RadioGroup>
|
|
161
|
+
{description !== undefined ? (
|
|
162
|
+
<FormDescription id={descId}>{description}</FormDescription>
|
|
163
|
+
) : null}
|
|
164
|
+
{hasError ? <FormMessage id={msgId} errors={errors} /> : null}
|
|
165
|
+
</FormItem>
|
|
166
|
+
);
|
|
167
|
+
}}
|
|
168
|
+
</form.Field>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* ── FormRadioCardGroup ──────────────────────────────────────────── */
|
|
173
|
+
|
|
174
|
+
export interface FormRadioCardGroupProps {
|
|
175
|
+
form: AnyFormApi;
|
|
176
|
+
name: string;
|
|
177
|
+
label: string;
|
|
178
|
+
options: RadioCardOption[];
|
|
179
|
+
description?: string;
|
|
180
|
+
required?: boolean;
|
|
181
|
+
orientation?: 'horizontal' | 'vertical';
|
|
182
|
+
columns?: 1 | 2 | 3 | 4;
|
|
183
|
+
tone?: 'primary' | 'accent';
|
|
184
|
+
disabled?: boolean;
|
|
185
|
+
className?: string;
|
|
186
|
+
validators?: FormFieldValidators;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Card-style radio group integrated with TanStack Form. */
|
|
190
|
+
export function FormRadioCardGroup({
|
|
191
|
+
form,
|
|
192
|
+
name,
|
|
193
|
+
label,
|
|
194
|
+
options,
|
|
195
|
+
description,
|
|
196
|
+
required,
|
|
197
|
+
orientation,
|
|
198
|
+
columns,
|
|
199
|
+
tone,
|
|
200
|
+
disabled,
|
|
201
|
+
className,
|
|
202
|
+
validators,
|
|
203
|
+
}: FormRadioCardGroupProps) {
|
|
204
|
+
const id = useId();
|
|
205
|
+
const descId = `${id}-desc`;
|
|
206
|
+
const msgId = `${id}-msg`;
|
|
207
|
+
|
|
208
|
+
return (
|
|
209
|
+
<form.Field name={name} {...(validators !== undefined && { validators })}>
|
|
210
|
+
{(field: FieldRenderProps<string>) => {
|
|
211
|
+
const errors = field.state.meta.isTouched ? field.state.meta.errors : [];
|
|
212
|
+
const hasError = errors.length > 0;
|
|
213
|
+
return (
|
|
214
|
+
<FormItem {...(className !== undefined && { className })}>
|
|
215
|
+
<FormLabel {...(required !== undefined && { required })}>{label}</FormLabel>
|
|
216
|
+
<RadioCardGroup
|
|
217
|
+
options={options}
|
|
218
|
+
value={field.state.value ?? ''}
|
|
219
|
+
onValueChange={(value) => {
|
|
220
|
+
field.handleChange(value);
|
|
221
|
+
field.handleBlur();
|
|
222
|
+
}}
|
|
223
|
+
{...(orientation !== undefined && { orientation })}
|
|
224
|
+
{...(columns !== undefined && { columns })}
|
|
225
|
+
{...(tone !== undefined && { tone })}
|
|
226
|
+
{...(disabled !== undefined && { disabled })}
|
|
227
|
+
aria-describedby={hasError ? msgId : description !== undefined ? descId : undefined}
|
|
228
|
+
aria-invalid={hasError}
|
|
229
|
+
/>
|
|
230
|
+
{description !== undefined ? (
|
|
231
|
+
<FormDescription id={descId}>{description}</FormDescription>
|
|
232
|
+
) : null}
|
|
233
|
+
{hasError ? <FormMessage id={msgId} errors={errors} /> : null}
|
|
234
|
+
</FormItem>
|
|
235
|
+
);
|
|
236
|
+
}}
|
|
237
|
+
</form.Field>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* ── FormCombobox ────────────────────────────────────────────────── */
|
|
242
|
+
|
|
243
|
+
export interface FormComboboxProps {
|
|
244
|
+
form: AnyFormApi;
|
|
245
|
+
name: string;
|
|
246
|
+
label: string;
|
|
247
|
+
options: ComboboxOption[];
|
|
248
|
+
description?: string;
|
|
249
|
+
required?: boolean;
|
|
250
|
+
placeholder?: string;
|
|
251
|
+
searchPlaceholder?: string;
|
|
252
|
+
emptyText?: string;
|
|
253
|
+
disabled?: boolean;
|
|
254
|
+
className?: string;
|
|
255
|
+
validators?: FormFieldValidators;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** Combobox field integrated with TanStack Form. */
|
|
259
|
+
export function FormCombobox({
|
|
260
|
+
form,
|
|
261
|
+
name,
|
|
262
|
+
label,
|
|
263
|
+
options,
|
|
264
|
+
description,
|
|
265
|
+
required,
|
|
266
|
+
placeholder,
|
|
267
|
+
searchPlaceholder,
|
|
268
|
+
emptyText,
|
|
269
|
+
disabled,
|
|
270
|
+
className,
|
|
271
|
+
validators,
|
|
272
|
+
}: FormComboboxProps) {
|
|
273
|
+
const id = useId();
|
|
274
|
+
const descId = `${id}-desc`;
|
|
275
|
+
const msgId = `${id}-msg`;
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<form.Field name={name} {...(validators !== undefined && { validators })}>
|
|
279
|
+
{(field: FieldRenderProps<string>) => {
|
|
280
|
+
const errors = field.state.meta.isTouched ? field.state.meta.errors : [];
|
|
281
|
+
const hasError = errors.length > 0;
|
|
282
|
+
return (
|
|
283
|
+
<FormItem {...(className !== undefined && { className })}>
|
|
284
|
+
<FormLabel htmlFor={id} {...(required !== undefined && { required })}>
|
|
285
|
+
{label}
|
|
286
|
+
</FormLabel>
|
|
287
|
+
<Combobox
|
|
288
|
+
id={id}
|
|
289
|
+
aria-label={label}
|
|
290
|
+
options={options}
|
|
291
|
+
value={field.state.value ?? ''}
|
|
292
|
+
onValueChange={(value) => {
|
|
293
|
+
field.handleChange(value);
|
|
294
|
+
field.handleBlur();
|
|
295
|
+
}}
|
|
296
|
+
{...(placeholder !== undefined && { placeholder })}
|
|
297
|
+
{...(searchPlaceholder !== undefined && { searchPlaceholder })}
|
|
298
|
+
{...(emptyText !== undefined && { emptyText })}
|
|
299
|
+
{...(disabled !== undefined && { disabled })}
|
|
300
|
+
aria-describedby={hasError ? msgId : description !== undefined ? descId : undefined}
|
|
301
|
+
aria-invalid={hasError}
|
|
302
|
+
/>
|
|
303
|
+
{description !== undefined ? (
|
|
304
|
+
<FormDescription id={descId}>{description}</FormDescription>
|
|
305
|
+
) : null}
|
|
306
|
+
{hasError ? <FormMessage id={msgId} errors={errors} /> : null}
|
|
307
|
+
</FormItem>
|
|
308
|
+
);
|
|
309
|
+
}}
|
|
310
|
+
</form.Field>
|
|
311
|
+
);
|
|
312
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Complex multi-value fields integrated with TanStack Form: FormCheckboxGrid,
|
|
5
|
+
* FormDropzone.
|
|
6
|
+
*/
|
|
7
|
+
import { useId } from 'react';
|
|
8
|
+
import {
|
|
9
|
+
CheckboxGrid,
|
|
10
|
+
type CheckboxGridProps,
|
|
11
|
+
type CheckboxGridSelection,
|
|
12
|
+
} from '../CheckboxGrid.js';
|
|
13
|
+
import { Dropzone, type DropzoneProps } from '../Dropzone.js';
|
|
14
|
+
import {
|
|
15
|
+
FormDescription,
|
|
16
|
+
FormItem,
|
|
17
|
+
FormLabel,
|
|
18
|
+
FormMessage,
|
|
19
|
+
} from './building-blocks.js';
|
|
20
|
+
import type { AnyFormApi, FieldRenderProps, FormFieldValidators } from './types.js';
|
|
21
|
+
|
|
22
|
+
/* ── FormCheckboxGrid ────────────────────────────────────────────── */
|
|
23
|
+
|
|
24
|
+
export interface FormCheckboxGridProps extends Pick<
|
|
25
|
+
CheckboxGridProps,
|
|
26
|
+
| 'items'
|
|
27
|
+
| 'columns'
|
|
28
|
+
| 'layout'
|
|
29
|
+
| 'density'
|
|
30
|
+
| 'showToolbar'
|
|
31
|
+
| 'searchPlaceholder'
|
|
32
|
+
| 'maxHeight'
|
|
33
|
+
| 'emptyState'
|
|
34
|
+
| 'getItemClassName'
|
|
35
|
+
> {
|
|
36
|
+
form: AnyFormApi;
|
|
37
|
+
name: string;
|
|
38
|
+
label: string;
|
|
39
|
+
description?: string;
|
|
40
|
+
required?: boolean;
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
className?: string;
|
|
43
|
+
validators?: FormFieldValidators;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Multi-select CheckboxGrid integrated with TanStack Form. */
|
|
47
|
+
export function FormCheckboxGrid({
|
|
48
|
+
form,
|
|
49
|
+
name,
|
|
50
|
+
label,
|
|
51
|
+
description,
|
|
52
|
+
required,
|
|
53
|
+
disabled,
|
|
54
|
+
className,
|
|
55
|
+
validators,
|
|
56
|
+
items,
|
|
57
|
+
columns,
|
|
58
|
+
layout,
|
|
59
|
+
density,
|
|
60
|
+
showToolbar,
|
|
61
|
+
searchPlaceholder,
|
|
62
|
+
maxHeight,
|
|
63
|
+
emptyState,
|
|
64
|
+
getItemClassName,
|
|
65
|
+
}: FormCheckboxGridProps) {
|
|
66
|
+
const descId = useId();
|
|
67
|
+
const msgId = `${descId}-msg`;
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<form.Field name={name} {...(validators !== undefined && { validators })}>
|
|
71
|
+
{(field: FieldRenderProps<CheckboxGridSelection>) => {
|
|
72
|
+
const errors = field.state.meta.isTouched ? field.state.meta.errors : [];
|
|
73
|
+
const hasError = errors.length > 0;
|
|
74
|
+
return (
|
|
75
|
+
<FormItem {...(className !== undefined && { className })}>
|
|
76
|
+
<FormLabel {...(required !== undefined && { required })}>{label}</FormLabel>
|
|
77
|
+
<CheckboxGrid
|
|
78
|
+
items={items}
|
|
79
|
+
selected={field.state.value ?? {}}
|
|
80
|
+
onSelectedChange={(next) => {
|
|
81
|
+
if (!disabled) field.handleChange(next);
|
|
82
|
+
field.handleBlur();
|
|
83
|
+
}}
|
|
84
|
+
{...(columns !== undefined && { columns })}
|
|
85
|
+
{...(layout !== undefined && { layout })}
|
|
86
|
+
{...(density !== undefined && { density })}
|
|
87
|
+
{...(showToolbar !== undefined && { showToolbar })}
|
|
88
|
+
{...(searchPlaceholder !== undefined && { searchPlaceholder })}
|
|
89
|
+
{...(maxHeight !== undefined && { maxHeight })}
|
|
90
|
+
{...(emptyState !== undefined && { emptyState })}
|
|
91
|
+
{...(getItemClassName !== undefined && { getItemClassName })}
|
|
92
|
+
aria-disabled={disabled}
|
|
93
|
+
aria-describedby={hasError ? msgId : description !== undefined ? descId : undefined}
|
|
94
|
+
aria-invalid={hasError}
|
|
95
|
+
/>
|
|
96
|
+
{description !== undefined ? (
|
|
97
|
+
<FormDescription id={descId}>{description}</FormDescription>
|
|
98
|
+
) : null}
|
|
99
|
+
{hasError ? <FormMessage id={msgId} errors={errors} /> : null}
|
|
100
|
+
</FormItem>
|
|
101
|
+
);
|
|
102
|
+
}}
|
|
103
|
+
</form.Field>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* ── FormDropzone ────────────────────────────────────────────────── */
|
|
108
|
+
|
|
109
|
+
export interface FormDropzoneProps extends Pick<
|
|
110
|
+
DropzoneProps,
|
|
111
|
+
| 'accept'
|
|
112
|
+
| 'maxFiles'
|
|
113
|
+
| 'maxSize'
|
|
114
|
+
| 'minSize'
|
|
115
|
+
| 'multiple'
|
|
116
|
+
| 'validator'
|
|
117
|
+
| 'heading'
|
|
118
|
+
| 'description'
|
|
119
|
+
| 'browseLabel'
|
|
120
|
+
| 'children'
|
|
121
|
+
> {
|
|
122
|
+
form: AnyFormApi;
|
|
123
|
+
name: string;
|
|
124
|
+
label: string;
|
|
125
|
+
fieldDescription?: string;
|
|
126
|
+
required?: boolean;
|
|
127
|
+
disabled?: boolean;
|
|
128
|
+
className?: string;
|
|
129
|
+
validators?: FormFieldValidators;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** File-list Dropzone integrated with TanStack Form. Field value is `File[]`. */
|
|
133
|
+
export function FormDropzone({
|
|
134
|
+
form,
|
|
135
|
+
name,
|
|
136
|
+
label,
|
|
137
|
+
fieldDescription,
|
|
138
|
+
required,
|
|
139
|
+
disabled,
|
|
140
|
+
className,
|
|
141
|
+
validators,
|
|
142
|
+
accept,
|
|
143
|
+
maxFiles,
|
|
144
|
+
maxSize,
|
|
145
|
+
minSize,
|
|
146
|
+
multiple,
|
|
147
|
+
validator,
|
|
148
|
+
heading,
|
|
149
|
+
description,
|
|
150
|
+
browseLabel,
|
|
151
|
+
children,
|
|
152
|
+
}: FormDropzoneProps) {
|
|
153
|
+
const descId = useId();
|
|
154
|
+
const msgId = `${descId}-msg`;
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<form.Field name={name} {...(validators !== undefined && { validators })}>
|
|
158
|
+
{(field: FieldRenderProps<File[]>) => {
|
|
159
|
+
const errors = field.state.meta.isTouched ? field.state.meta.errors : [];
|
|
160
|
+
const hasError = errors.length > 0;
|
|
161
|
+
return (
|
|
162
|
+
<FormItem {...(className !== undefined && { className })}>
|
|
163
|
+
<FormLabel {...(required !== undefined && { required })}>{label}</FormLabel>
|
|
164
|
+
<Dropzone
|
|
165
|
+
{...(accept !== undefined && { accept })}
|
|
166
|
+
{...(maxFiles !== undefined && { maxFiles })}
|
|
167
|
+
{...(maxSize !== undefined && { maxSize })}
|
|
168
|
+
{...(minSize !== undefined && { minSize })}
|
|
169
|
+
{...(multiple !== undefined && { multiple })}
|
|
170
|
+
{...(validator !== undefined && { validator })}
|
|
171
|
+
{...(heading !== undefined && { heading })}
|
|
172
|
+
{...(description !== undefined && { description })}
|
|
173
|
+
{...(browseLabel !== undefined && { browseLabel })}
|
|
174
|
+
{...(children !== undefined && { children })}
|
|
175
|
+
{...(disabled !== undefined && { disabled })}
|
|
176
|
+
onFilesAccepted={(files) => {
|
|
177
|
+
field.handleChange(files);
|
|
178
|
+
field.handleBlur();
|
|
179
|
+
}}
|
|
180
|
+
onFilesRejected={() => field.handleBlur()}
|
|
181
|
+
aria-describedby={
|
|
182
|
+
hasError ? msgId : fieldDescription !== undefined ? descId : undefined
|
|
183
|
+
}
|
|
184
|
+
aria-invalid={hasError}
|
|
185
|
+
/>
|
|
186
|
+
{fieldDescription !== undefined ? (
|
|
187
|
+
<FormDescription id={descId}>{fieldDescription}</FormDescription>
|
|
188
|
+
) : null}
|
|
189
|
+
{hasError ? <FormMessage id={msgId} errors={errors} /> : null}
|
|
190
|
+
</FormItem>
|
|
191
|
+
);
|
|
192
|
+
}}
|
|
193
|
+
</form.Field>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Date fields integrated with TanStack Form: FormDatePicker, FormDateRangePicker.
|
|
5
|
+
*/
|
|
6
|
+
import { useId } from 'react';
|
|
7
|
+
import { cn } from '../internal/cn.js';
|
|
8
|
+
import { DatePicker, type DatePickerProps } from '../DatePicker.js';
|
|
9
|
+
import {
|
|
10
|
+
FormDescription,
|
|
11
|
+
FormItem,
|
|
12
|
+
FormLabel,
|
|
13
|
+
FormMessage,
|
|
14
|
+
} from './building-blocks.js';
|
|
15
|
+
import type { AnyFormApi, FieldRenderProps, FormFieldValidators } from './types.js';
|
|
16
|
+
|
|
17
|
+
/* ── FormDatePicker ──────────────────────────────────────────────── */
|
|
18
|
+
|
|
19
|
+
export interface FormDatePickerProps {
|
|
20
|
+
form: AnyFormApi;
|
|
21
|
+
name: string;
|
|
22
|
+
label: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
required?: boolean;
|
|
25
|
+
placeholder?: string;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
/** Show time selection alongside date. */
|
|
28
|
+
showTimeSelect?: boolean;
|
|
29
|
+
/** Date format string (default: "MM/dd/yyyy"). */
|
|
30
|
+
dateFormat?: string;
|
|
31
|
+
className?: string;
|
|
32
|
+
validators?: FormFieldValidators;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** DatePicker field integrated with TanStack Form. Uses the mihcm DatePicker primitive. */
|
|
36
|
+
export function FormDatePicker({
|
|
37
|
+
form,
|
|
38
|
+
name,
|
|
39
|
+
label,
|
|
40
|
+
description,
|
|
41
|
+
required,
|
|
42
|
+
placeholder,
|
|
43
|
+
disabled,
|
|
44
|
+
showTimeSelect,
|
|
45
|
+
dateFormat,
|
|
46
|
+
className,
|
|
47
|
+
validators,
|
|
48
|
+
}: FormDatePickerProps) {
|
|
49
|
+
const id = useId();
|
|
50
|
+
const descId = `${id}-desc`;
|
|
51
|
+
const msgId = `${id}-msg`;
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<form.Field name={name} {...(validators !== undefined && { validators })}>
|
|
55
|
+
{(field: FieldRenderProps<Date | null>) => {
|
|
56
|
+
const errors = field.state.meta.isTouched ? field.state.meta.errors : [];
|
|
57
|
+
const hasError = errors.length > 0;
|
|
58
|
+
return (
|
|
59
|
+
<FormItem {...(className !== undefined && { className })}>
|
|
60
|
+
<FormLabel htmlFor={id} {...(required !== undefined && { required })}>
|
|
61
|
+
{label}
|
|
62
|
+
</FormLabel>
|
|
63
|
+
<DatePicker
|
|
64
|
+
id={id}
|
|
65
|
+
selected={field.state.value}
|
|
66
|
+
onChange={(date: Date | null) => field.handleChange(date)}
|
|
67
|
+
onBlur={field.handleBlur}
|
|
68
|
+
{...(placeholder !== undefined && { placeholderText: placeholder })}
|
|
69
|
+
{...(disabled !== undefined && { disabled })}
|
|
70
|
+
{...(showTimeSelect !== undefined && { showTimeSelect })}
|
|
71
|
+
{...(dateFormat !== undefined && { dateFormat })}
|
|
72
|
+
className={cn(hasError && 'border-destructive focus:ring-destructive')}
|
|
73
|
+
{...(hasError
|
|
74
|
+
? { 'aria-describedby': msgId }
|
|
75
|
+
: description !== undefined
|
|
76
|
+
? { 'aria-describedby': descId }
|
|
77
|
+
: {})}
|
|
78
|
+
/>
|
|
79
|
+
{description !== undefined ? (
|
|
80
|
+
<FormDescription id={descId}>{description}</FormDescription>
|
|
81
|
+
) : null}
|
|
82
|
+
{hasError ? <FormMessage id={msgId} errors={errors} /> : null}
|
|
83
|
+
</FormItem>
|
|
84
|
+
);
|
|
85
|
+
}}
|
|
86
|
+
</form.Field>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* ── FormDateRangePicker ─────────────────────────────────────────── */
|
|
91
|
+
|
|
92
|
+
export interface FormDateRangePickerProps {
|
|
93
|
+
form: AnyFormApi;
|
|
94
|
+
name: string;
|
|
95
|
+
label: string;
|
|
96
|
+
description?: string;
|
|
97
|
+
required?: boolean;
|
|
98
|
+
placeholder?: string;
|
|
99
|
+
disabled?: boolean;
|
|
100
|
+
isClearable?: boolean;
|
|
101
|
+
align?: DatePickerProps['align'];
|
|
102
|
+
showTimeSelect?: boolean;
|
|
103
|
+
showWeekNumbers?: boolean;
|
|
104
|
+
monthsShown?: number;
|
|
105
|
+
minDate?: Date;
|
|
106
|
+
maxDate?: Date;
|
|
107
|
+
disabledDays?: DatePickerProps['disabledDays'];
|
|
108
|
+
dateFormat?: string;
|
|
109
|
+
calendarProps?: DatePickerProps['calendarProps'];
|
|
110
|
+
triggerWidth?: 'auto' | 'full';
|
|
111
|
+
triggerClassName?: string;
|
|
112
|
+
closeOnRangeComplete?: boolean;
|
|
113
|
+
className?: string;
|
|
114
|
+
validators?: FormFieldValidators;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Date range picker integrated with TanStack Form. Field value is `[start, end]`. */
|
|
118
|
+
export function FormDateRangePicker({
|
|
119
|
+
form,
|
|
120
|
+
name,
|
|
121
|
+
label,
|
|
122
|
+
description,
|
|
123
|
+
required,
|
|
124
|
+
placeholder,
|
|
125
|
+
disabled,
|
|
126
|
+
isClearable,
|
|
127
|
+
align,
|
|
128
|
+
showTimeSelect,
|
|
129
|
+
showWeekNumbers,
|
|
130
|
+
monthsShown,
|
|
131
|
+
minDate,
|
|
132
|
+
maxDate,
|
|
133
|
+
disabledDays,
|
|
134
|
+
dateFormat,
|
|
135
|
+
calendarProps,
|
|
136
|
+
triggerWidth,
|
|
137
|
+
triggerClassName,
|
|
138
|
+
closeOnRangeComplete,
|
|
139
|
+
className,
|
|
140
|
+
validators,
|
|
141
|
+
}: FormDateRangePickerProps) {
|
|
142
|
+
const id = useId();
|
|
143
|
+
const descId = `${id}-desc`;
|
|
144
|
+
const msgId = `${id}-msg`;
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<form.Field name={name} {...(validators !== undefined && { validators })}>
|
|
148
|
+
{(field: FieldRenderProps<[Date | null, Date | null]>) => {
|
|
149
|
+
const errors = field.state.meta.isTouched ? field.state.meta.errors : [];
|
|
150
|
+
const hasError = errors.length > 0;
|
|
151
|
+
const [startDate, endDate] = field.state.value ?? [null, null];
|
|
152
|
+
return (
|
|
153
|
+
<FormItem {...(className !== undefined && { className })}>
|
|
154
|
+
<FormLabel htmlFor={id} {...(required !== undefined && { required })}>
|
|
155
|
+
{label}
|
|
156
|
+
</FormLabel>
|
|
157
|
+
<DatePicker
|
|
158
|
+
id={id}
|
|
159
|
+
selectsRange
|
|
160
|
+
startDate={startDate}
|
|
161
|
+
endDate={endDate}
|
|
162
|
+
onChange={(range) => field.handleChange(range)}
|
|
163
|
+
onBlur={field.handleBlur}
|
|
164
|
+
{...(placeholder !== undefined && { placeholderText: placeholder })}
|
|
165
|
+
{...(disabled !== undefined && { disabled })}
|
|
166
|
+
{...(isClearable !== undefined && { isClearable })}
|
|
167
|
+
{...(align !== undefined && { align })}
|
|
168
|
+
{...(showTimeSelect !== undefined && { showTimeSelect })}
|
|
169
|
+
{...(showWeekNumbers !== undefined && { showWeekNumbers })}
|
|
170
|
+
{...(monthsShown !== undefined && { monthsShown })}
|
|
171
|
+
{...(minDate !== undefined && { minDate })}
|
|
172
|
+
{...(maxDate !== undefined && { maxDate })}
|
|
173
|
+
{...(disabledDays !== undefined && { disabledDays })}
|
|
174
|
+
{...(dateFormat !== undefined && { dateFormat })}
|
|
175
|
+
{...(calendarProps !== undefined && { calendarProps })}
|
|
176
|
+
{...(triggerWidth !== undefined && { triggerWidth })}
|
|
177
|
+
{...(triggerClassName !== undefined && { triggerClassName })}
|
|
178
|
+
{...(closeOnRangeComplete !== undefined && { closeOnRangeComplete })}
|
|
179
|
+
className={cn(hasError && 'border-destructive focus:ring-destructive')}
|
|
180
|
+
{...(hasError
|
|
181
|
+
? { 'aria-describedby': msgId }
|
|
182
|
+
: description !== undefined
|
|
183
|
+
? { 'aria-describedby': descId }
|
|
184
|
+
: {})}
|
|
185
|
+
/>
|
|
186
|
+
{description !== undefined ? (
|
|
187
|
+
<FormDescription id={descId}>{description}</FormDescription>
|
|
188
|
+
) : null}
|
|
189
|
+
{hasError ? <FormMessage id={msgId} errors={errors} /> : null}
|
|
190
|
+
</FormItem>
|
|
191
|
+
);
|
|
192
|
+
}}
|
|
193
|
+
</form.Field>
|
|
194
|
+
);
|
|
195
|
+
}
|