torch-glare 2.4.0 → 2.4.2
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 +8 -0
- package/apps/lib/components/ActionButton.tsx +7 -12
- package/apps/lib/components/ActionsGroup.tsx +4 -15
- package/apps/lib/components/AlertDialog.tsx +173 -191
- package/apps/lib/components/Avatar.tsx +13 -16
- package/apps/lib/components/Badge.tsx +1 -3
- package/apps/lib/components/BadgeField.tsx +76 -71
- package/apps/lib/components/Breadcrumb.tsx +49 -85
- package/apps/lib/components/Button.tsx +21 -20
- package/apps/lib/components/ButtonGroup.tsx +31 -41
- package/apps/lib/components/Calendar.tsx +51 -29
- package/apps/lib/components/Card.tsx +40 -24
- package/apps/lib/components/Checkbox.tsx +9 -16
- package/apps/lib/components/ColorPicker.tsx +441 -0
- package/apps/lib/components/ConclusionHeader.tsx +148 -0
- package/apps/lib/components/ContextMenu.tsx +97 -96
- package/apps/lib/components/CountBadge.tsx +4 -6
- package/apps/lib/components/DataTable.tsx +196 -216
- package/apps/lib/components/DataViews/DataViewRadio.tsx +1 -6
- package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +13 -47
- package/apps/lib/components/DataViews/DataViewsHeader.tsx +1 -3
- package/apps/lib/components/DataViews/DataViewsLayout.tsx +5 -12
- package/apps/lib/components/DataViews/FilterPanel.tsx +155 -149
- package/apps/lib/components/DataViews/HeaderSearch.tsx +1 -5
- package/apps/lib/components/DataViews/InboxView.tsx +22 -68
- package/apps/lib/components/DataViews/InboxViewCard.tsx +68 -77
- package/apps/lib/components/DataViews/KanbanView.tsx +8 -25
- package/apps/lib/components/DataViews/PanelControls.tsx +3 -13
- package/apps/lib/components/DataViews/SettingsPanel.tsx +83 -89
- package/apps/lib/components/DataViews/TableView.tsx +8 -28
- package/apps/lib/components/DataViews/TreeView.tsx +12 -40
- package/apps/lib/components/DataViews/badgeAdapter.ts +32 -28
- package/apps/lib/components/DataViews/fieldRenderers.tsx +106 -141
- package/apps/lib/components/DataViews/filters/DatePickerRangeFilter.tsx +30 -23
- package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +39 -32
- package/apps/lib/components/DataViews/filters/PresetChips.tsx +15 -15
- package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +69 -58
- package/apps/lib/components/DataViews/index.ts +26 -26
- package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +12 -16
- package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +28 -31
- package/apps/lib/components/DataViews/types.ts +104 -115
- package/apps/lib/components/DatePicker.tsx +200 -196
- package/apps/lib/components/Dialog.tsx +92 -105
- package/apps/lib/components/Divider.tsx +21 -24
- package/apps/lib/components/Drawer.tsx +124 -142
- package/apps/lib/components/DropdownMenu.tsx +131 -171
- package/apps/lib/components/FieldHint.tsx +4 -11
- package/apps/lib/components/Form.tsx +146 -155
- package/apps/lib/components/FormBuilder/DisplayField.tsx +40 -0
- package/apps/lib/components/FormBuilder/context.ts +71 -0
- package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +65 -0
- package/apps/lib/components/FormBuilder/fields/ColorField.tsx +76 -0
- package/apps/lib/components/FormBuilder/fields/CustomField.tsx +16 -0
- package/apps/lib/components/FormBuilder/fields/DateField.tsx +34 -0
- package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +79 -0
- package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +174 -0
- package/apps/lib/components/FormBuilder/fields/FileField.tsx +40 -0
- package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +139 -0
- package/apps/lib/components/FormBuilder/fields/OtpField.tsx +32 -0
- package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +82 -0
- package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +37 -0
- package/apps/lib/components/FormBuilder/fields/SelectField.tsx +101 -0
- package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +175 -0
- package/apps/lib/components/FormBuilder/fields/SliderField.tsx +72 -0
- package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +42 -0
- package/apps/lib/components/FormBuilder/fields/TableField.tsx +312 -0
- package/apps/lib/components/FormBuilder/fields/TextField.tsx +222 -0
- package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +49 -0
- package/apps/lib/components/FormBuilder/fields/countries.ts +303 -0
- package/apps/lib/components/FormBuilder/fields/index.ts +25 -0
- package/apps/lib/components/FormBuilder/form-builder.tsx +292 -0
- package/apps/lib/components/FormBuilder/header.tsx +105 -0
- package/apps/lib/components/FormBuilder/index.ts +37 -0
- package/apps/lib/components/FormBuilder/numberFormat.ts +16 -0
- package/apps/lib/components/FormBuilder/stepper.tsx +217 -0
- package/apps/lib/components/FormBuilder/submit.tsx +41 -0
- package/apps/lib/components/FormBuilder/types.ts +264 -0
- package/apps/lib/components/FormBuilder/viewFormat.tsx +137 -0
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +121 -0
- package/apps/lib/components/FormRenderer/form-renderer.tsx +113 -0
- package/apps/lib/components/FormRenderer/index.ts +9 -0
- package/apps/lib/components/FormRenderer/types.ts +79 -0
- package/apps/lib/components/FormStepper.tsx +9 -39
- package/apps/lib/components/FormSummary.tsx +282 -0
- package/apps/lib/components/HeaderBar.tsx +1 -9
- package/apps/lib/components/ImageAttachment.tsx +106 -93
- package/apps/lib/components/InnerLabelField.tsx +20 -16
- package/apps/lib/components/Input.tsx +171 -172
- package/apps/lib/components/InputField.tsx +44 -45
- package/apps/lib/components/InputOTP.tsx +68 -69
- package/apps/lib/components/Label.tsx +61 -58
- package/apps/lib/components/LabelField.tsx +4 -5
- package/apps/lib/components/LabeledCheckBox.tsx +8 -12
- package/apps/lib/components/LabeledRadio.tsx +7 -5
- package/apps/lib/components/LinkButton.tsx +2 -9
- package/apps/lib/components/LoginButton.tsx +4 -9
- package/apps/lib/components/PasswordLevel.tsx +5 -5
- package/apps/lib/components/Popover.tsx +15 -33
- package/apps/lib/components/ProfileMenu.tsx +67 -72
- package/apps/lib/components/Radio.tsx +1 -5
- package/apps/lib/components/RadioCard.tsx +11 -28
- package/apps/lib/components/ScrollArea.tsx +45 -43
- package/apps/lib/components/SearchField.tsx +49 -39
- package/apps/lib/components/SearchableSelect.tsx +16 -16
- package/apps/lib/components/SearchableTable.tsx +108 -118
- package/apps/lib/components/SearchableTree.tsx +469 -0
- package/apps/lib/components/SearchableTreeDialog.tsx +493 -0
- package/apps/lib/components/SectionBlock.tsx +19 -23
- package/apps/lib/components/Select.tsx +80 -186
- package/apps/lib/components/SimpleSelect.tsx +196 -187
- package/apps/lib/components/Skeleton.tsx +9 -12
- package/apps/lib/components/SlideDatePicker.tsx +215 -166
- package/apps/lib/components/SpinLoading.tsx +33 -49
- package/apps/lib/components/Stepper.tsx +13 -56
- package/apps/lib/components/Switch.tsx +8 -10
- package/apps/lib/components/TabFormItem.tsx +3 -12
- package/apps/lib/components/TabSwitch.tsx +7 -34
- package/apps/lib/components/Table.tsx +60 -75
- package/apps/lib/components/{ChartBlockTool.ts → TextEditor/ChartBlockTool.ts} +17 -52
- package/apps/lib/components/TextEditor/RichTextField.tsx +46 -0
- package/apps/lib/components/{TableDnDWrapper.ts → TextEditor/TableDnDWrapper.ts} +15 -48
- package/apps/lib/components/{TextEditor.tsx → TextEditor/TextEditor.tsx} +156 -113
- package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +429 -0
- package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +70 -0
- package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +50 -0
- package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +48 -0
- package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +98 -0
- package/apps/lib/{types → components/TextEditor}/editorjs.d.ts +19 -0
- package/apps/lib/components/TextEditor/index.ts +7 -0
- package/apps/lib/{utils → components/TextEditor}/markdownParser.ts +2 -7
- package/apps/lib/components/Textarea.tsx +9 -13
- package/apps/lib/components/Timeline.tsx +21 -41
- package/apps/lib/components/Toast.tsx +83 -83
- package/apps/lib/components/Toggle.tsx +112 -114
- package/apps/lib/components/ToggleButton.tsx +1 -1
- package/apps/lib/components/Tooltip.tsx +24 -19
- package/apps/lib/components/TransparentLabel.tsx +61 -62
- package/apps/lib/components/TreeDropDown.tsx +86 -52
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +15 -48
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +16 -21
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +9 -20
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +3 -3
- package/apps/lib/components/TreeFolder/icons.tsx +14 -17
- package/apps/lib/components/TreeFolder/index.ts +15 -8
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +47 -52
- package/apps/lib/components/TreeFolder/types.ts +32 -32
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +117 -123
- package/apps/lib/hooks/useActiveTreeItem.ts +52 -55
- package/apps/lib/hooks/useClickOutside.ts +21 -20
- package/apps/lib/hooks/useDataViewsState.ts +86 -80
- package/apps/lib/hooks/useIsMobile.ts +12 -12
- package/apps/lib/hooks/useResize.ts +54 -65
- package/apps/lib/hooks/useTagSelection.ts +201 -201
- package/apps/lib/layouts/CNLayout.tsx +181 -140
- package/apps/lib/layouts/DataViewCard.tsx +4 -18
- package/apps/lib/layouts/FieldSection.tsx +2 -6
- package/apps/lib/layouts/TreeSubLayout.tsx +24 -38
- package/apps/lib/providers/ThemeProvider.tsx +8 -23
- package/apps/lib/registry.json +997 -0
- package/apps/lib/tsconfig.json +9 -0
- package/apps/lib/tsconfig.tsbuildinfo +1 -0
- package/apps/lib/utils/cn.ts +1 -1
- package/apps/lib/utils/color.ts +175 -0
- package/apps/lib/utils/dataViews/columnUtils.ts +46 -44
- package/apps/lib/utils/dataViews/fieldUtils.ts +70 -71
- package/apps/lib/utils/dataViews/nestedDataUtils.tsx +129 -122
- package/apps/lib/utils/dataViews/pathUtils.ts +74 -67
- package/apps/lib/utils/dataViews/rangeUtils.ts +121 -112
- package/apps/lib/utils/dataViews/treeUtils.ts +204 -211
- package/apps/lib/utils/dateFormat.ts +64 -54
- package/apps/lib/utils/resize.ts +21 -25
- package/apps/lib/utils/types.ts +13 -13
- package/dist/bin/index.js +8 -2
- package/dist/bin/index.js.map +1 -1
- package/dist/src/shared/getAvailableFiles.d.ts.map +1 -1
- package/dist/src/shared/getAvailableFiles.js +6 -1
- package/dist/src/shared/getAvailableFiles.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +7 -0
- package/dist/src/shared/loadRegistry.d.ts.map +1 -0
- package/dist/src/shared/loadRegistry.js +31 -0
- package/dist/src/shared/loadRegistry.js.map +1 -0
- package/dist/src/shared/resolveInstallPlan.d.ts +12 -0
- package/dist/src/shared/resolveInstallPlan.d.ts.map +1 -0
- package/dist/src/shared/resolveInstallPlan.js +39 -0
- package/dist/src/shared/resolveInstallPlan.js.map +1 -0
- package/dist/src/types/main.d.ts +24 -0
- package/dist/src/types/main.d.ts.map +1 -1
- package/docs/README.md +10 -2
- package/docs/components/action-button.md +30 -24
- package/docs/components/actions-group.md +26 -20
- package/docs/components/alert-dialog.md +45 -45
- package/docs/components/avatar.md +6 -2
- package/docs/components/badge-field.md +6 -2
- package/docs/components/badge.md +7 -1
- package/docs/components/breadcrumb.md +15 -40
- package/docs/components/button-group.md +13 -10
- package/docs/components/button.md +58 -33
- package/docs/components/calendar.md +26 -19
- package/docs/components/card.md +23 -18
- package/docs/components/chart-block-tool.md +129 -0
- package/docs/components/checkbox.md +16 -8
- package/docs/components/cn-layout.md +7 -1
- package/docs/components/color-picker.md +101 -0
- package/docs/components/conclusion-header.md +80 -0
- package/docs/components/context-menu.md +18 -25
- package/docs/components/count-badge.md +7 -1
- package/docs/components/data-table.md +45 -33
- package/docs/components/data-views-config-panel.md +15 -11
- package/docs/components/data-views-layout.md +13 -16
- package/docs/components/date-picker.md +30 -23
- package/docs/components/dialog.md +43 -42
- package/docs/components/divider.md +10 -4
- package/docs/components/drawer.md +161 -135
- package/docs/components/dropdown-menu.md +25 -34
- package/docs/components/field-hint.md +37 -25
- package/docs/components/field-section.md +9 -3
- package/docs/components/form-builder.md +270 -0
- package/docs/components/form-renderer.md +228 -0
- package/docs/components/form-stepper.md +6 -0
- package/docs/components/form-summary.md +123 -0
- package/docs/components/form.md +17 -20
- package/docs/components/header-bar.md +6 -0
- package/docs/components/image-attachment.md +43 -45
- package/docs/components/inbox-view.md +16 -5
- package/docs/components/inner-label-field.md +34 -24
- package/docs/components/input-field.md +18 -10
- package/docs/components/input-otp.md +14 -11
- package/docs/components/input.md +22 -16
- package/docs/components/kanban-view.md +15 -5
- package/docs/components/label-field.md +32 -22
- package/docs/components/label.md +43 -32
- package/docs/components/labeled-check-box.md +16 -8
- package/docs/components/labeled-radio.md +18 -11
- package/docs/components/link-button.md +7 -1
- package/docs/components/login-button.md +8 -2
- package/docs/components/password-level.md +37 -24
- package/docs/components/popover.md +26 -23
- package/docs/components/profile-menu.md +38 -27
- package/docs/components/radio-card.md +16 -9
- package/docs/components/radio.md +16 -8
- package/docs/components/scroll-area.md +6 -2
- package/docs/components/search-field.md +14 -6
- package/docs/components/searchable-select.md +19 -14
- package/docs/components/searchable-table.md +18 -13
- package/docs/components/searchable-tree-dialog.md +190 -0
- package/docs/components/searchable-tree.md +200 -0
- package/docs/components/section-block.md +12 -4
- package/docs/components/select.md +23 -18
- package/docs/components/simple-select.md +14 -10
- package/docs/components/skeleton.md +43 -33
- package/docs/components/slide-date-picker.md +37 -29
- package/docs/components/spin-loading.md +32 -23
- package/docs/components/stepper.md +6 -0
- package/docs/components/switch.md +14 -6
- package/docs/components/tab-form-item.md +7 -1
- package/docs/components/tab-switch.md +13 -6
- package/docs/components/table-dnd-wrapper.md +107 -0
- package/docs/components/table-view.md +15 -5
- package/docs/components/table.md +28 -28
- package/docs/components/text-editor.md +37 -13
- package/docs/components/textarea.md +15 -7
- package/docs/components/timeline.md +6 -0
- package/docs/components/toast.md +35 -26
- package/docs/components/toggle-button.md +24 -21
- package/docs/components/toggle.md +23 -15
- package/docs/components/tooltip.md +42 -30
- package/docs/components/transparent-label.md +29 -20
- package/docs/components/tree-drop-down.md +31 -23
- package/docs/components/tree-sub-layout.md +6 -2
- package/docs/components/tree-view.md +16 -5
- package/docs/explanation/architecture.md +54 -0
- package/docs/explanation/design-system.md +52 -0
- package/docs/how-to/data-views-from-backend-response.md +6 -4
- package/docs/how-to/form-and-list-recipes.md +26 -19
- package/docs/how-to/forms-with-form-builder.md +408 -0
- package/docs/how-to/guides.md +177 -197
- package/docs/migration/changelog.md +38 -0
- package/docs/reference/cli.md +87 -0
- package/docs/reference/components.md +11 -12
- package/docs/reference/hooks.md +8 -8
- package/docs/reference/providers.md +22 -22
- package/docs/reference/tailwind-plugins.md +2 -2
- package/docs/reference/theme.md +85 -0
- package/docs/reference/types.md +4 -4
- package/docs/reference/utilities.md +19 -26
- package/docs/tutorials/building-first-form.md +170 -172
- package/docs/tutorials/component-composition.md +34 -50
- package/docs/tutorials/getting-started.md +2 -2
- package/docs/tutorials/theming-basics.md +13 -10
- package/package.json +31 -3
- package/dist/src/commands/block.d.ts +0 -5
- package/dist/src/commands/block.d.ts.map +0 -1
- package/dist/src/commands/block.js +0 -255
- package/dist/src/commands/block.js.map +0 -1
- package/dist/src/shared/configureFonts.d.ts +0 -6
- package/dist/src/shared/configureFonts.d.ts.map +0 -1
- package/dist/src/shared/configureFonts.js +0 -106
- package/dist/src/shared/configureFonts.js.map +0 -1
- package/dist/src/shared/configureGlobalCss.d.ts +0 -6
- package/dist/src/shared/configureGlobalCss.d.ts.map +0 -1
- package/dist/src/shared/configureGlobalCss.js +0 -154
- package/dist/src/shared/configureGlobalCss.js.map +0 -1
- package/dist/src/shared/configureTailwind.d.ts +0 -7
- package/dist/src/shared/configureTailwind.d.ts.map +0 -1
- package/dist/src/shared/configureTailwind.js +0 -163
- package/dist/src/shared/configureTailwind.js.map +0 -1
- package/dist/src/shared/detectFramework.d.ts +0 -23
- package/dist/src/shared/detectFramework.d.ts.map +0 -1
- package/dist/src/shared/detectFramework.js +0 -119
- package/dist/src/shared/detectFramework.js.map +0 -1
- package/dist/src/shared/installBaseUtils.d.ts +0 -5
- package/dist/src/shared/installBaseUtils.d.ts.map +0 -1
- package/dist/src/shared/installBaseUtils.js +0 -79
- package/dist/src/shared/installBaseUtils.js.map +0 -1
- package/dist/src/shared/resolveAliases.d.ts +0 -24
- package/dist/src/shared/resolveAliases.d.ts.map +0 -1
- package/dist/src/shared/resolveAliases.js +0 -98
- package/dist/src/shared/resolveAliases.js.map +0 -1
|
@@ -1,191 +1,182 @@
|
|
|
1
|
-
"use client"
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import * as React from "react"
|
|
4
|
-
import * as LabelPrimitive from "@radix-ui/react-label"
|
|
5
|
-
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
5
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "react-hook-form"
|
|
14
|
-
|
|
15
|
-
import { cn } from "../utils/cn"
|
|
16
|
-
import { Label } from "./Label"
|
|
17
|
-
import { Themes } from "../utils/types"
|
|
18
|
-
import { ReactNode } from "react"
|
|
19
|
-
const Form = FormProvider
|
|
7
|
+
Controller,
|
|
8
|
+
FormProvider,
|
|
9
|
+
useFormContext,
|
|
10
|
+
type ControllerProps,
|
|
11
|
+
type FieldPath,
|
|
12
|
+
type FieldValues,
|
|
13
|
+
} from "react-hook-form";
|
|
14
|
+
|
|
15
|
+
import { cn } from "../utils/cn";
|
|
16
|
+
import { Label } from "./Label";
|
|
17
|
+
import { Themes } from "../utils/types";
|
|
18
|
+
import { ReactNode } from "react";
|
|
19
|
+
const Form = FormProvider;
|
|
20
20
|
|
|
21
21
|
type FormFieldContextValue<
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
TFieldValues extends FieldValues = FieldValues,
|
|
23
|
+
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
24
24
|
> = {
|
|
25
|
-
|
|
26
|
-
}
|
|
25
|
+
name: TName;
|
|
26
|
+
};
|
|
27
27
|
|
|
28
|
-
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
|
29
|
-
{} as FormFieldContextValue
|
|
30
|
-
)
|
|
28
|
+
const FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue);
|
|
31
29
|
|
|
32
30
|
const FormField = <
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
TFieldValues extends FieldValues = FieldValues,
|
|
32
|
+
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
35
33
|
>({
|
|
36
|
-
|
|
34
|
+
...props
|
|
37
35
|
}: ControllerProps<TFieldValues, TName>) => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
36
|
+
return (
|
|
37
|
+
<FormFieldContext.Provider value={{ name: props.name }}>
|
|
38
|
+
<Controller {...props} />
|
|
39
|
+
</FormFieldContext.Provider>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
44
42
|
|
|
45
43
|
const useFormField = () => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
const fieldContext = React.useContext(FormFieldContext);
|
|
45
|
+
const itemContext = React.useContext(FormItemContext);
|
|
46
|
+
const { getFieldState, formState } = useFormContext();
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
const fieldState = getFieldState(fieldContext.name, formState);
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
if (!fieldContext) {
|
|
51
|
+
throw new Error("useFormField should be used within <FormField>");
|
|
52
|
+
}
|
|
55
53
|
|
|
56
|
-
|
|
54
|
+
const { id } = itemContext;
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
56
|
+
return {
|
|
57
|
+
id,
|
|
58
|
+
name: fieldContext.name,
|
|
59
|
+
formItemId: `${id}-form-item`,
|
|
60
|
+
formDescriptionId: `${id}-form-item-description`,
|
|
61
|
+
formMessageId: `${id}-form-item-message`,
|
|
62
|
+
...fieldState,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
67
65
|
|
|
68
66
|
type FormItemContextValue = {
|
|
69
|
-
|
|
70
|
-
}
|
|
67
|
+
id: string;
|
|
68
|
+
};
|
|
71
69
|
|
|
72
|
-
const FormItemContext = React.createContext<FormItemContextValue>(
|
|
73
|
-
{} as FormItemContextValue
|
|
74
|
-
)
|
|
70
|
+
const FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue);
|
|
75
71
|
|
|
76
|
-
const FormItem = React.forwardRef<
|
|
77
|
-
|
|
78
|
-
React.
|
|
79
|
-
>(({ className, ...props }, ref) => {
|
|
80
|
-
const id = React.useId()
|
|
72
|
+
const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
73
|
+
({ className, ...props }, ref) => {
|
|
74
|
+
const id = React.useId();
|
|
81
75
|
|
|
82
76
|
return (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
)
|
|
87
|
-
}
|
|
88
|
-
|
|
77
|
+
<FormItemContext.Provider value={{ id }}>
|
|
78
|
+
<div ref={ref} className={cn("space-y-2", className)} {...props} />
|
|
79
|
+
</FormItemContext.Provider>
|
|
80
|
+
);
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
FormItem.displayName = "FormItem";
|
|
89
84
|
|
|
90
85
|
const FormLabel = React.forwardRef<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
86
|
+
React.ElementRef<typeof LabelPrimitive.Root>,
|
|
87
|
+
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & {
|
|
88
|
+
label?: ReactNode; // main label
|
|
89
|
+
requiredLabel?: ReactNode; // normal text with required style
|
|
90
|
+
secondaryLabel?: ReactNode; // normal text with secondary style
|
|
91
|
+
as?: React.ElementType;
|
|
92
|
+
asChild?: boolean;
|
|
93
|
+
size?: "S" | "M" | "L";
|
|
94
|
+
variant?: "SystemStyle" | "PresentationStyle";
|
|
95
|
+
theme?: Themes;
|
|
96
|
+
labelsClassName?: string;
|
|
97
|
+
labelDirections?: "vertical" | "horizontal";
|
|
98
|
+
childrenDirections?: "vertical" | "horizontal";
|
|
99
|
+
}
|
|
105
100
|
>(({ className, ...props }, ref) => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
})
|
|
117
|
-
FormLabel.displayName = "FormLabel"
|
|
101
|
+
const { error, formItemId } = useFormField();
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<Label
|
|
105
|
+
ref={ref}
|
|
106
|
+
className={cn(error && "text-destructive", className)}
|
|
107
|
+
htmlFor={formItemId}
|
|
108
|
+
{...props}
|
|
109
|
+
/>
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
FormLabel.displayName = "FormLabel";
|
|
118
113
|
|
|
119
114
|
const FormControl = React.forwardRef<
|
|
120
|
-
|
|
121
|
-
|
|
115
|
+
React.ElementRef<typeof Slot>,
|
|
116
|
+
React.ComponentPropsWithoutRef<typeof Slot>
|
|
122
117
|
>(({ ...props }, ref) => {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
/>
|
|
137
|
-
)
|
|
138
|
-
})
|
|
139
|
-
FormControl.displayName = "FormControl"
|
|
118
|
+
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<Slot
|
|
122
|
+
ref={ref}
|
|
123
|
+
id={formItemId}
|
|
124
|
+
aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
|
|
125
|
+
aria-invalid={!!error}
|
|
126
|
+
{...props}
|
|
127
|
+
/>
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
FormControl.displayName = "FormControl";
|
|
140
131
|
|
|
141
132
|
const FormDescription = React.forwardRef<
|
|
142
|
-
|
|
143
|
-
|
|
133
|
+
HTMLParagraphElement,
|
|
134
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
144
135
|
>(({ className, ...props }, ref) => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
})
|
|
156
|
-
FormDescription.displayName = "FormDescription"
|
|
136
|
+
const { formDescriptionId } = useFormField();
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<p
|
|
140
|
+
ref={ref}
|
|
141
|
+
id={formDescriptionId}
|
|
142
|
+
className={cn("text-[0.8rem] text-muted-foreground", className)}
|
|
143
|
+
{...props}
|
|
144
|
+
/>
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
FormDescription.displayName = "FormDescription";
|
|
157
148
|
|
|
158
149
|
const FormMessage = React.forwardRef<
|
|
159
|
-
|
|
160
|
-
|
|
150
|
+
HTMLParagraphElement,
|
|
151
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
161
152
|
>(({ className, children, ...props }, ref) => {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
})
|
|
180
|
-
FormMessage.displayName = "FormMessage"
|
|
153
|
+
const { error, formMessageId } = useFormField();
|
|
154
|
+
const body = error ? String(error?.message ?? "") : children;
|
|
155
|
+
|
|
156
|
+
if (!body) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<p
|
|
162
|
+
ref={ref}
|
|
163
|
+
id={formMessageId}
|
|
164
|
+
className={cn("text-[0.8rem] font-medium text-destructive", className)}
|
|
165
|
+
{...props}
|
|
166
|
+
>
|
|
167
|
+
{body}
|
|
168
|
+
</p>
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
FormMessage.displayName = "FormMessage";
|
|
181
172
|
|
|
182
173
|
export {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
174
|
+
useFormField,
|
|
175
|
+
Form,
|
|
176
|
+
FormItem,
|
|
177
|
+
FormLabel,
|
|
178
|
+
FormControl,
|
|
179
|
+
FormDescription,
|
|
180
|
+
FormMessage,
|
|
181
|
+
FormField,
|
|
182
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils/cn";
|
|
4
|
+
|
|
5
|
+
export interface DisplayFieldProps {
|
|
6
|
+
label?: ReactNode;
|
|
7
|
+
/** Plain string value — falls back to an em-dash when empty. */
|
|
8
|
+
value?: string | null;
|
|
9
|
+
/** Rich value (badges, chips, formatted nodes) — takes precedence over `value`. */
|
|
10
|
+
valueNode?: ReactNode;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Read-only field: a label above its value. Used by FormBuilder's `mode: "view"`
|
|
16
|
+
* so the same config renders as a detail view. Mirrors the products-services
|
|
17
|
+
* `DisplayField` (label + value/valueNode, em-dash fallback).
|
|
18
|
+
*/
|
|
19
|
+
export function DisplayField({ label, value, valueNode, className }: DisplayFieldProps) {
|
|
20
|
+
return (
|
|
21
|
+
<div className={cn("flex w-full flex-col gap-1.5", className)}>
|
|
22
|
+
{label != null && (
|
|
23
|
+
<p className="typography-body-small-regular text-content-presentation-global-secondary">
|
|
24
|
+
{label}
|
|
25
|
+
</p>
|
|
26
|
+
)}
|
|
27
|
+
{valueNode != null ? (
|
|
28
|
+
<div className="typography-body-medium-medium text-content-presentation-global-primary">
|
|
29
|
+
{valueNode}
|
|
30
|
+
</div>
|
|
31
|
+
) : (
|
|
32
|
+
<span className="typography-body-medium-medium text-content-presentation-global-primary">
|
|
33
|
+
{value != null && value !== "" ? value : "—"}
|
|
34
|
+
</span>
|
|
35
|
+
)}
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
DisplayField.displayName = "DisplayField";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext } from "react";
|
|
4
|
+
|
|
5
|
+
export type FormBuilderMode = "edit" | "view";
|
|
6
|
+
export type FieldDirection = "horizontal" | "vertical";
|
|
7
|
+
|
|
8
|
+
/** Loading flag — drives the Submit spinner and disables inputs. */
|
|
9
|
+
export const LoadingContext = createContext<boolean>(false);
|
|
10
|
+
export const useLoading = () => useContext(LoadingContext);
|
|
11
|
+
|
|
12
|
+
/** Edit vs read-only. Fields render `DisplayField` in `"view"`. */
|
|
13
|
+
export const ModeContext = createContext<FormBuilderMode>("edit");
|
|
14
|
+
export const useMode = () => useContext(ModeContext);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The `<form>`'s `id`. Provided by the FormBuilder root so a `FormBuilder.Submit` rendered
|
|
18
|
+
* **outside** the `<form>` element — the absolute header's action pill, or the drawer header —
|
|
19
|
+
* can still submit it via native `form={id}` association without the caller wiring an id by hand.
|
|
20
|
+
*/
|
|
21
|
+
export const FormIdContext = createContext<string | undefined>(undefined);
|
|
22
|
+
export const useFormId = () => useContext(FormIdContext);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Field row direction — set via `FormBuilder`'s `fieldDirection` prop. `undefined` (the default)
|
|
26
|
+
* means "don't force one": `FieldSection` then uses its own responsive `flexible` layout, which
|
|
27
|
+
* stacks on small screens and goes two-column at `lg`. Only set this to pin a direction.
|
|
28
|
+
*/
|
|
29
|
+
export const DirectionContext = createContext<FieldDirection | undefined>(undefined);
|
|
30
|
+
export const useDirection = () => useContext(DirectionContext);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Cell mode — set to `true` by `FormBuilder.Table` around each cell's field so `FieldShell`
|
|
34
|
+
* renders just the control (no label/row chrome) and surfaces validation errors as a tooltip
|
|
35
|
+
* on the control instead of a stacked hint. Off (`false`) everywhere else, so normal fields
|
|
36
|
+
* keep their full `FieldSection` layout.
|
|
37
|
+
*/
|
|
38
|
+
export const CellContext = createContext<boolean>(false);
|
|
39
|
+
export const useCell = () => useContext(CellContext);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Step registry — a `FormBuilder.Step` provides this so the fields rendered
|
|
43
|
+
* inside it can register their `name`. `FormBuilder.Next` then validates just
|
|
44
|
+
* those names before advancing. `null` when not inside a stepper.
|
|
45
|
+
*/
|
|
46
|
+
export interface StepRegistry {
|
|
47
|
+
register: (name: string) => void;
|
|
48
|
+
unregister: (name: string) => void;
|
|
49
|
+
}
|
|
50
|
+
export const StepContext = createContext<StepRegistry | null>(null);
|
|
51
|
+
export const useStepRegistry = () => useContext(StepContext);
|
|
52
|
+
|
|
53
|
+
/** Stepper state shared by the nav + Back/Next/Submit buttons. */
|
|
54
|
+
export interface StepperContextValue {
|
|
55
|
+
currentStep: number;
|
|
56
|
+
totalSteps: number;
|
|
57
|
+
titles: string[];
|
|
58
|
+
isFirstStep: boolean;
|
|
59
|
+
isLastStep: boolean;
|
|
60
|
+
goToNext: () => void | Promise<void>;
|
|
61
|
+
goToPrevious: () => void;
|
|
62
|
+
goToStep: (index: number) => void;
|
|
63
|
+
/** Field names registered per step, for per-step validation. */
|
|
64
|
+
stepFields: Record<number, Set<string>>;
|
|
65
|
+
}
|
|
66
|
+
export const StepperContext = createContext<StepperContextValue | null>(null);
|
|
67
|
+
export const useStepper = () => {
|
|
68
|
+
const ctx = useContext(StepperContext);
|
|
69
|
+
if (!ctx) throw new Error("FormBuilder.Step/Back/Next must be used within FormBuilder.Stepper");
|
|
70
|
+
return ctx;
|
|
71
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { LabeledCheckBox } from "../../LabeledCheckBox";
|
|
4
|
+
import { RadioGroup } from "../../Radio";
|
|
5
|
+
import { RadioCard } from "../../RadioCard";
|
|
6
|
+
import { useLoading } from "../context";
|
|
7
|
+
import { formatFieldView } from "../viewFormat";
|
|
8
|
+
import type { CheckboxFieldProps, RadioCardsFieldProps } from "../types";
|
|
9
|
+
import { FieldShell } from "./FieldShell";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* `FormBuilder.Checkbox` — a single boolean checkbox. The field `label` sits in the
|
|
13
|
+
* normal label column; an optional `subLabel` renders inline beside the checkbox (via
|
|
14
|
+
* the clickable `LabeledCheckBox`).
|
|
15
|
+
*/
|
|
16
|
+
export function CheckboxField({ subLabel, ...props }: CheckboxFieldProps) {
|
|
17
|
+
const loading = useLoading();
|
|
18
|
+
return (
|
|
19
|
+
<FieldShell {...props} view={(v) => formatFieldView({ kind: "boolean", value: v })}>
|
|
20
|
+
{(field) => (
|
|
21
|
+
<div className="flex w-full items-center ps-2.5">
|
|
22
|
+
<LabeledCheckBox
|
|
23
|
+
id={props.name}
|
|
24
|
+
label={subLabel ?? ""}
|
|
25
|
+
checked={!!field.value}
|
|
26
|
+
size="S"
|
|
27
|
+
onCheckedChange={(checked) => field.onChange(checked === true)}
|
|
28
|
+
disabled={props.disabled || loading}
|
|
29
|
+
/>
|
|
30
|
+
</div>
|
|
31
|
+
)}
|
|
32
|
+
</FieldShell>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** `FormBuilder.RadioCards` — radio options rendered as cards (Glare `RadioCard`). */
|
|
37
|
+
export function RadioCardsField(props: RadioCardsFieldProps) {
|
|
38
|
+
const loading = useLoading();
|
|
39
|
+
const options = props.options.map((o) => ({
|
|
40
|
+
label: typeof o.label === "string" ? o.label : String(o.value),
|
|
41
|
+
value: o.value,
|
|
42
|
+
}));
|
|
43
|
+
return (
|
|
44
|
+
<FieldShell {...props} view={(v) => formatFieldView({ kind: "option", value: v, options })}>
|
|
45
|
+
{(field) => (
|
|
46
|
+
<RadioGroup
|
|
47
|
+
value={field.value ?? ""}
|
|
48
|
+
onValueChange={field.onChange}
|
|
49
|
+
className="grid w-full grid-cols-2 gap-3"
|
|
50
|
+
>
|
|
51
|
+
{props.options.map((opt) => (
|
|
52
|
+
<RadioCard
|
|
53
|
+
key={opt.value}
|
|
54
|
+
id={`${props.name}-${opt.value}`}
|
|
55
|
+
value={opt.value}
|
|
56
|
+
headerLabel={opt.label}
|
|
57
|
+
description={opt.description}
|
|
58
|
+
disabled={opt.disabled || props.disabled || loading}
|
|
59
|
+
/>
|
|
60
|
+
))}
|
|
61
|
+
</RadioGroup>
|
|
62
|
+
)}
|
|
63
|
+
</FieldShell>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { InputField } from "../../InputField";
|
|
4
|
+
import { ColorPicker, CHECKERBOARD } from "../../ColorPicker";
|
|
5
|
+
import { useLoading } from "../context";
|
|
6
|
+
import type { ColorFieldProps } from "../types";
|
|
7
|
+
import { FieldShell } from "./FieldShell";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `FormBuilder.Color` — an `InputField` holding the hex text, with a trailing action button that
|
|
11
|
+
* carries the colour itself. That button is the `ColorPicker` trigger: clicking it opens the full
|
|
12
|
+
* palette. Value is a hex string.
|
|
13
|
+
*/
|
|
14
|
+
export function ColorField(props: ColorFieldProps) {
|
|
15
|
+
const loading = useLoading();
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<FieldShell
|
|
19
|
+
{...props}
|
|
20
|
+
view={(v) =>
|
|
21
|
+
v
|
|
22
|
+
? {
|
|
23
|
+
valueNode: (
|
|
24
|
+
<span className="inline-flex items-center gap-2">
|
|
25
|
+
<span
|
|
26
|
+
className="h-4 w-4 rounded-[4px] border border-border-presentation-action-primary"
|
|
27
|
+
style={{ background: String(v) }}
|
|
28
|
+
/>
|
|
29
|
+
{String(v)}
|
|
30
|
+
</span>
|
|
31
|
+
),
|
|
32
|
+
}
|
|
33
|
+
: { value: "" }
|
|
34
|
+
}
|
|
35
|
+
>
|
|
36
|
+
{(field) => {
|
|
37
|
+
const value = typeof field.value === "string" ? field.value : "";
|
|
38
|
+
const disabled = props.disabled || loading;
|
|
39
|
+
return (
|
|
40
|
+
// The InputField IS the trigger: ColorPicker detects it as an input (it takes a `value`)
|
|
41
|
+
// and feeds it the hex, so clicking the field opens the palette.
|
|
42
|
+
<ColorPicker
|
|
43
|
+
value={value || undefined}
|
|
44
|
+
onChange={field.onChange}
|
|
45
|
+
presets={props.presets}
|
|
46
|
+
alpha={props.alpha ?? true}
|
|
47
|
+
disabled={disabled}
|
|
48
|
+
>
|
|
49
|
+
<InputField
|
|
50
|
+
// Explicit — otherwise Radix's trigger `type="button"` would land on the input.
|
|
51
|
+
type="text"
|
|
52
|
+
value={value}
|
|
53
|
+
onChange={(e) => field.onChange(e.target.value)}
|
|
54
|
+
placeholder={props.placeholder ?? "#000000"}
|
|
55
|
+
disabled={disabled}
|
|
56
|
+
className="w-full"
|
|
57
|
+
// The trailing action button holds the colour itself.
|
|
58
|
+
childrenSide={
|
|
59
|
+
<span
|
|
60
|
+
aria-hidden
|
|
61
|
+
className="block h-[26px] w-[26px] shrink-0 overflow-hidden rounded-[6px] border border-border-presentation-action-primary"
|
|
62
|
+
style={CHECKERBOARD}
|
|
63
|
+
>
|
|
64
|
+
<span
|
|
65
|
+
className="block h-full w-full"
|
|
66
|
+
style={{ backgroundColor: value || "#000000" }}
|
|
67
|
+
/>
|
|
68
|
+
</span>
|
|
69
|
+
}
|
|
70
|
+
/>
|
|
71
|
+
</ColorPicker>
|
|
72
|
+
);
|
|
73
|
+
}}
|
|
74
|
+
</FieldShell>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { CustomFieldProps } from "../types";
|
|
4
|
+
import { FieldShell } from "./FieldShell";
|
|
5
|
+
|
|
6
|
+
/** `FormBuilder.Custom` — render any control, keeping the FieldSection + validation wiring. */
|
|
7
|
+
export function CustomField(props: CustomFieldProps) {
|
|
8
|
+
return (
|
|
9
|
+
<FieldShell
|
|
10
|
+
{...props}
|
|
11
|
+
view={(v) => ({ valueNode: props.formatView ? props.formatView(v) : String(v ?? "—") })}
|
|
12
|
+
>
|
|
13
|
+
{(field, fieldState) => props.render({ field, fieldState })}
|
|
14
|
+
</FieldShell>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { DatePicker } from "../../DatePicker";
|
|
4
|
+
import { useCell } from "../context";
|
|
5
|
+
import { formatFieldView } from "../viewFormat";
|
|
6
|
+
import type { DateFieldProps } from "../types";
|
|
7
|
+
import { FieldShell } from "./FieldShell";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `FormBuilder.Date` (single) — and, via `mode`/`timePicker`, the presets
|
|
11
|
+
* `.DateRange` (value `{from,to}`), `.DateMultiple` (value `Date[]`), and
|
|
12
|
+
* `.DateTime` (date + time). All back onto the one Glare `DatePicker`.
|
|
13
|
+
*/
|
|
14
|
+
export function DateField(props: DateFieldProps) {
|
|
15
|
+
const kind = props.mode === "range" ? "daterange" : props.mode === "multiple" ? "dates" : "date";
|
|
16
|
+
const cell = useCell();
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<FieldShell {...props} view={(v) => formatFieldView({ kind, value: v })}>
|
|
20
|
+
{(field) => (
|
|
21
|
+
<DatePicker
|
|
22
|
+
mode={props.mode ?? "single"}
|
|
23
|
+
timePicker={props.timePicker}
|
|
24
|
+
dateFormat={props.dateFormat}
|
|
25
|
+
value={field.value}
|
|
26
|
+
onTable={cell}
|
|
27
|
+
onChange={(e) =>
|
|
28
|
+
field.onChange((e as unknown as { target: { value: unknown } }).target.value)
|
|
29
|
+
}
|
|
30
|
+
/>
|
|
31
|
+
)}
|
|
32
|
+
</FieldShell>
|
|
33
|
+
);
|
|
34
|
+
}
|