@datum-cloud/datum-ui 0.4.0 → 0.6.0-alpha.a49f238
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 +78 -39
- package/dist/adapter-context-BFqfq4Io.mjs +25 -0
- package/dist/alert/index.mjs +2 -3
- package/dist/{alert-BC2Mccfo.mjs → alert-BDj6od5I.mjs} +2 -4
- package/dist/app-navigation/index.mjs +4 -12
- package/dist/{app-navigation-DsCKgfPe.mjs → app-navigation-84ro28PU.mjs} +5 -8
- package/dist/autocomplete/index.mjs +2 -7
- package/dist/{autocomplete-DRB_kSVx.mjs → autocomplete-V5-qslzS.mjs} +5 -7
- package/dist/avatar/index.mjs +2 -4
- package/dist/{avatar-DyLq0xkt.mjs → avatar-BtKVcvO4.mjs} +2 -4
- package/dist/avatar-stack/index.mjs +2 -6
- package/dist/{avatar-stack-BT0dBswq.mjs → avatar-stack-oVr8tsU7.mjs} +4 -6
- package/dist/badge/index.mjs +2 -3
- package/dist/{badge-BgFj4Nsc.mjs → badge-DJR33ftJ.mjs} +2 -4
- package/dist/breadcrumb/index.mjs +2 -4
- package/dist/{breadcrumb-CJNaYyk1.mjs → breadcrumb-B-9G347O.mjs} +2 -4
- package/dist/button/index.mjs +3 -4
- package/dist/{button-0N61fmAR.mjs → button-BllvE9Lm.mjs} +3 -5
- package/dist/{button-D6AORsOz.mjs → button-D3RrsMfQ.mjs} +2 -4
- package/dist/{link-button-Cby0p4LW.mjs → button-fO8nazJE.mjs} +3 -5
- package/dist/button-group/index.mjs +2 -5
- package/dist/{button-group-BDk8btAy.mjs → button-group-CYPka2zz.mjs} +3 -5
- package/dist/calendar/index.mjs +2 -5
- package/dist/{calendar-BtfraIvX.mjs → calendar-DEkCw7I1.mjs} +4 -6
- package/dist/{calendar-date-picker-B9mxJM7f.mjs → calendar-date-picker-DWK94_DC.mjs} +6 -8
- package/dist/card/index.mjs +2 -4
- package/dist/{card-BiHXFt4s.mjs → card-DKG1Cwlj.mjs} +3 -6
- package/dist/chart/index.mjs +2 -4
- package/dist/{chart-CL0i-xIt.mjs → chart-CUa21ynK.mjs} +2 -4
- package/dist/checkbox/index.mjs +2 -4
- package/dist/{checkbox-CQrjygFt.mjs → checkbox-I5BvrMPe.mjs} +3 -6
- package/dist/{close.icon-D2r5q3bj.mjs → close.icon-HCfS4Y-N.mjs} +2 -4
- package/dist/{cn-DWCc1QRE.mjs → cn-D2KYQ917.mjs} +1 -3
- package/dist/code-editor/index.mjs +2 -0
- package/dist/{col-C9PDhvm5.mjs → col-CiSpQPUT.mjs} +2 -7
- package/dist/collapsible/index.mjs +2 -3
- package/dist/{collapsible-Dw71o2um.mjs → collapsible-CUphkSBt.mjs} +1 -3
- package/dist/command/index.mjs +2 -5
- package/dist/{command-DVroicgn.mjs → command-DqHWukGK.mjs} +3 -5
- package/dist/components/features/code-editor/code-editor-tabs.d.ts +63 -0
- package/dist/components/features/code-editor/code-editor-tabs.d.ts.map +1 -0
- package/dist/components/features/code-editor/code-editor.d.ts +58 -0
- package/dist/components/features/code-editor/code-editor.d.ts.map +1 -0
- package/dist/components/features/code-editor/index.d.ts +6 -0
- package/dist/components/features/code-editor/index.d.ts.map +1 -0
- package/dist/components/features/code-editor/lib/editor.d.ts +7 -0
- package/dist/components/features/code-editor/lib/editor.d.ts.map +1 -0
- package/dist/components/features/code-editor/types.d.ts +98 -0
- package/dist/components/features/code-editor/types.d.ts.map +1 -0
- package/dist/components/features/form/adapter-context.d.ts +17 -0
- package/dist/components/features/form/adapter-context.d.ts.map +1 -0
- package/dist/components/features/form/adapter-types.d.ts +120 -0
- package/dist/components/features/form/adapter-types.d.ts.map +1 -0
- package/dist/components/features/form/adapters/conform/conform-adapter.d.ts +9 -0
- package/dist/components/features/form/adapters/conform/conform-adapter.d.ts.map +1 -0
- package/dist/components/features/form/adapters/conform/conform-provider.d.ts +22 -0
- package/dist/components/features/form/adapters/conform/conform-provider.d.ts.map +1 -0
- package/dist/components/features/form/adapters/conform/index.d.ts +3 -0
- package/dist/components/features/form/adapters/conform/index.d.ts.map +1 -0
- package/dist/components/features/form/adapters/rhf/index.d.ts +3 -0
- package/dist/components/features/form/adapters/rhf/index.d.ts.map +1 -0
- package/dist/components/features/form/adapters/rhf/rhf-adapter.d.ts +10 -0
- package/dist/components/features/form/adapters/rhf/rhf-adapter.d.ts.map +1 -0
- package/dist/components/features/form/adapters/rhf/rhf-provider.d.ts +22 -0
- package/dist/components/features/form/adapters/rhf/rhf-provider.d.ts.map +1 -0
- package/dist/components/features/form/components/form-autocomplete.d.ts.map +1 -1
- package/dist/components/features/form/components/form-checkbox.d.ts.map +1 -1
- package/dist/components/features/form/components/form-copy-box.d.ts.map +1 -1
- package/dist/components/features/form/components/form-custom.d.ts.map +1 -1
- package/dist/components/features/form/components/form-field-array.d.ts +5 -17
- package/dist/components/features/form/components/form-field-array.d.ts.map +1 -1
- package/dist/components/features/form/components/form-field.d.ts +7 -21
- package/dist/components/features/form/components/form-field.d.ts.map +1 -1
- package/dist/components/features/form/components/form-input-group.d.ts +4 -4
- package/dist/components/features/form/components/form-input-group.d.ts.map +1 -1
- package/dist/components/features/form/components/form-input.d.ts.map +1 -1
- package/dist/components/features/form/components/form-radio-group.d.ts.map +1 -1
- package/dist/components/features/form/components/form-root.d.ts +5 -25
- package/dist/components/features/form/components/form-root.d.ts.map +1 -1
- package/dist/components/features/form/components/form-select.d.ts.map +1 -1
- package/dist/components/features/form/components/form-switch.d.ts.map +1 -1
- package/dist/components/features/form/components/form-textarea.d.ts.map +1 -1
- package/dist/components/features/form/components/index.d.ts +0 -1
- package/dist/components/features/form/components/index.d.ts.map +1 -1
- package/dist/components/features/form/components/stepper/form-stepper.d.ts.map +1 -1
- package/dist/components/features/form/context/form-context.d.ts +2 -2
- package/dist/components/features/form/context/form-context.d.ts.map +1 -1
- package/dist/components/features/form/hooks/index.d.ts +1 -1
- package/dist/components/features/form/hooks/index.d.ts.map +1 -1
- package/dist/components/features/form/hooks/use-field.d.ts +12 -18
- package/dist/components/features/form/hooks/use-field.d.ts.map +1 -1
- package/dist/components/features/form/hooks/use-form-state.d.ts +36 -0
- package/dist/components/features/form/hooks/use-form-state.d.ts.map +1 -0
- package/dist/components/features/form/hooks/use-watch.d.ts +9 -20
- package/dist/components/features/form/hooks/use-watch.d.ts.map +1 -1
- package/dist/components/features/form/index.d.ts +63 -44
- package/dist/components/features/form/index.d.ts.map +1 -1
- package/dist/components/features/form/stepper/index.d.ts +17 -0
- package/dist/components/features/form/stepper/index.d.ts.map +1 -0
- package/dist/components/features/form/types/index.d.ts +68 -32
- package/dist/components/features/form/types/index.d.ts.map +1 -1
- package/dist/components/features/form/utils/get-field-constraints.d.ts +11 -0
- package/dist/components/features/form/utils/get-field-constraints.d.ts.map +1 -0
- package/dist/components/features/form/utils/get-schema-defaults.d.ts +24 -0
- package/dist/components/features/form/utils/get-schema-defaults.d.ts.map +1 -0
- package/dist/components/features/index.d.ts +1 -0
- package/dist/components/features/index.d.ts.map +1 -1
- package/dist/components/toast.d.ts +2 -0
- package/dist/components/toast.d.ts.map +1 -0
- package/dist/data-table/index.mjs +21 -51
- package/dist/date-picker/index.mjs +3 -10
- package/dist/dialog/index.mjs +2 -5
- package/dist/{dialog-B0B3Kbfk.mjs → dialog-Bm2H9lrx.mjs} +4 -6
- package/dist/{dialog-DdrHeboM.mjs → dialog-DASRaFxD.mjs} +2 -4
- package/dist/dropdown/index.mjs +2 -3
- package/dist/{dropdown-Cdx7rOKv.mjs → dropdown-DZiAt-jS.mjs} +3 -5
- package/dist/{dropdown-menu-CdShrDz_.mjs → dropdown-menu-lALvDnab.mjs} +5 -7
- package/dist/dropzone/index.mjs +2 -5
- package/dist/{dropzone-B6kSN3DY.mjs → dropzone-ogtpQ4fy.mjs} +5 -8
- package/dist/empty-content/index.mjs +2 -3
- package/dist/{empty-content-B1lwLr40.mjs → empty-content-C63GPJ5d.mjs} +3 -9
- package/dist/form/adapters/conform/index.mjs +320 -0
- package/dist/form/adapters/rhf/index.mjs +275 -0
- package/dist/form/index.mjs +3 -146
- package/dist/form/stepper/index.mjs +542 -0
- package/dist/form-C6AOB2f4.mjs +1397 -0
- package/dist/form-context-Ccxm-wqL.mjs +17 -0
- package/dist/get-field-constraints-D4xnXJEg.mjs +48 -0
- package/dist/grid/index.mjs +2 -3
- package/dist/hooks/index.mjs +3 -4
- package/dist/{use-debounce-MnfjH51L.mjs → hooks-DNjmSsJT.mjs} +1 -3
- package/dist/hover-card/index.mjs +2 -4
- package/dist/{hover-card-CEIauuie.mjs → hover-card-DDWWD5Hx.mjs} +2 -4
- package/dist/{icon-wrapper-BBK4z4tj.mjs → icon-wrapper-DuLp3RM1.mjs} +1 -3
- package/dist/icons/index.mjs +4 -5
- package/dist/index.mjs +66 -71
- package/dist/input/index.mjs +2 -5
- package/dist/{input-DEMoi_8F.mjs → input-DOmNpcQJ.mjs} +2 -4
- package/dist/{input-CYFN0Ap2.mjs → input-FKGqZypx.mjs} +3 -5
- package/dist/input-group/index.mjs +2 -7
- package/dist/{input-group-DJgYpOlq.mjs → input-group-DDtz-RT7.mjs} +5 -7
- package/dist/input-number/index.mjs +2 -6
- package/dist/{input-number-Cuy9CCg_.mjs → input-number-BTQdHqVZ.mjs} +4 -6
- package/dist/input-with-addons/index.mjs +28 -3
- package/dist/label/index.mjs +2 -4
- package/dist/{label-mOg07fuQ.mjs → label-cnAhY-ej.mjs} +3 -6
- package/dist/loader-overlay/index.mjs +2 -3
- package/dist/{loader-overlay-8IWX_1Ga.mjs → loader-overlay-BTFdkp7W.mjs} +3 -5
- package/dist/map/index.mjs +2 -14
- package/dist/{map-CaI1EshG.mjs → map-BqpteT_8.mjs} +10 -14
- package/dist/{map-leaflet-imports-J7w1V7mh.mjs → map-leaflet-imports-CT4SpoDi.mjs} +1 -2
- package/dist/more-actions/index.mjs +2 -5
- package/dist/{more-actions-BO5ikUxY.mjs → more-actions-CucrYUnA.mjs} +5 -7
- package/dist/nprogress/index.mjs +1 -3
- package/dist/page-title/index.mjs +2 -3
- package/dist/{page-title-DWteBy1E.mjs → page-title-CmsIi_A3.mjs} +2 -4
- package/dist/popover/index.mjs +2 -4
- package/dist/{popover-ugw5MpuT.mjs → popover-FJAcbYoH.mjs} +2 -4
- package/dist/radio-group/index.mjs +2 -4
- package/dist/{radio-group-_gMymwnb.mjs → radio-group-CiITR0LO.mjs} +3 -6
- package/dist/select/index.mjs +2 -4
- package/dist/{select-BZOKWjlH.mjs → select-CiLR_DiQ.mjs} +3 -6
- package/dist/separator/index.mjs +2 -4
- package/dist/{separator-BzyALya2.mjs → separator-DXVTncCK.mjs} +2 -4
- package/dist/sheet/index.mjs +3 -5
- package/dist/{sheet-BX6lae56.mjs → sheet-BzXksqYY.mjs} +4 -6
- package/dist/{sheet-DAcFjaGw.mjs → sheet-Di3b-oPu.mjs} +2 -4
- package/dist/sidebar/index.mjs +2 -10
- package/dist/{sidebar-B3EV33mG.mjs → sidebar-BnhnjvfO.mjs} +10 -14
- package/dist/skeleton/index.mjs +2 -5
- package/dist/{skeleton-2vQ0vFQk.mjs → skeleton-BKl4mfJt.mjs} +2 -4
- package/dist/{skeleton-BgOwIgE0.mjs → skeleton-D1MUhAVo.mjs} +3 -5
- package/dist/spinner/index.mjs +2 -4
- package/dist/{spinner-osyXAlhr.mjs → spinner-OyOf9-Yu.mjs} +2 -4
- package/dist/{spinner.icon-C0MbtgqX.mjs → spinner.icon-C-vjSM6o.mjs} +2 -4
- package/dist/stepper/index.mjs +2 -5
- package/dist/{stepper-BMsn7I78.mjs → stepper-C92Ib8Iy.mjs} +3 -5
- package/dist/switch/index.mjs +2 -4
- package/dist/{switch-C60FpEal.mjs → switch-DQJQhPIQ.mjs} +3 -6
- package/dist/table/index.mjs +2 -4
- package/dist/{table-Cl3UzIhI.mjs → table-Cdsh-39-.mjs} +2 -4
- package/dist/tabs/index.mjs +50 -3
- package/dist/tag-input/index.mjs +2 -5
- package/dist/{tag-input-DR2gukhL.mjs → tag-input-B91C2wdr.mjs} +5 -7
- package/dist/task-queue/index.mjs +2 -7
- package/dist/{task-queue-dropdown-C9KHKbGh.mjs → task-queue-dropdown-OOFuJcHb.mjs} +10 -30
- package/dist/textarea/index.mjs +2 -5
- package/dist/{textarea-CVo38n3S.mjs → textarea-94vq_G_S.mjs} +2 -4
- package/dist/{textarea-CZF5n57i.mjs → textarea-BwD-MmTV.mjs} +3 -5
- package/dist/theme/index.mjs +2 -3
- package/dist/{theme.provider-TUHlMsjM.mjs → themes-DG1md8FI.mjs} +1 -6
- package/dist/{to-api-format-naIpF-NI.mjs → to-api-format-P0gmlqe8.mjs} +9 -18
- package/dist/toast/index.mjs +3 -3
- package/dist/{use-toast-By9HuFwP.mjs → toast-BWnN5fax.mjs} +5 -42
- package/dist/toast-DpxlFNNx.mjs +37 -0
- package/dist/tooltip/index.mjs +2 -4
- package/dist/{tooltip-CuX2jQA9.mjs → tooltip-Cruvl5F6.mjs} +3 -6
- package/dist/types-BZNk3q65.mjs +357 -0
- package/dist/typography/index.mjs +2 -3
- package/dist/{typography-Iap9fU5P.mjs → typography-ClB8k55E.mjs} +2 -4
- package/dist/{use-copy-to-clipboard-n29wJwvW.mjs → use-copy-to-clipboard-C2IEmhDn.mjs} +2 -4
- package/dist/utils/index.mjs +2 -3
- package/dist/{utils-DJboNGQM.mjs → utils-C8KwMfT_.mjs} +1 -3
- package/dist/visually-hidden/index.mjs +2 -3
- package/dist/{visuallyhidden-BJsQCmg-.mjs → visuallyhidden-BLUsJpYH.mjs} +1 -3
- package/package.json +49 -3
- package/dist/input-with-addons-B8rzNhpq.mjs +0 -30
- package/dist/tabs-DJU7JA3h.mjs +0 -52
- package/dist/use-stepper-DigoyHhX.mjs +0 -2017
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { t as FormAdapterProvider } from "../../../adapter-context-BFqfq4Io.mjs";
|
|
2
|
+
import { t as getFieldConstraints } from "../../../get-field-constraints-D4xnXJEg.mjs";
|
|
3
|
+
import * as React$1 from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
6
|
+
import { FormProvider, useController, useFieldArray, useForm, useFormContext, useWatch } from "react-hook-form";
|
|
7
|
+
//#region src/components/features/form/utils/get-schema-defaults.ts
|
|
8
|
+
/**
|
|
9
|
+
* Derive default values from a Zod schema that match what React Hook Form's
|
|
10
|
+
* `useController` will produce when fields register.
|
|
11
|
+
*
|
|
12
|
+
* This is critical for RHF's `isDirty` tracking: RHF compares current values
|
|
13
|
+
* against `_defaultValues`. Without explicit defaults, RHF uses `{}` as the
|
|
14
|
+
* baseline, so when `useController` registers fields (e.g. `username: ''`),
|
|
15
|
+
* the form is immediately considered dirty.
|
|
16
|
+
*
|
|
17
|
+
* By passing these schema-derived defaults to `useForm({ defaultValues })`,
|
|
18
|
+
* the baseline matches the registered values and `isDirty` starts as `false`.
|
|
19
|
+
*
|
|
20
|
+
* Maps Zod field types to their `useController` registration values:
|
|
21
|
+
* - string -> `''`
|
|
22
|
+
* - number -> `undefined`
|
|
23
|
+
* - boolean -> `false`
|
|
24
|
+
* - array -> `[]`
|
|
25
|
+
* - object -> `{}` (recursive)
|
|
26
|
+
* - optional/nullable wrappers -> unwrap and derive inner default
|
|
27
|
+
* - `.default()` -> use the provided default value
|
|
28
|
+
*/
|
|
29
|
+
function getSchemaDefaults(schema) {
|
|
30
|
+
const shape = getObjectShape(schema);
|
|
31
|
+
if (!shape) return {};
|
|
32
|
+
const defaults = {};
|
|
33
|
+
for (const [key, fieldSchema] of Object.entries(shape)) defaults[key] = getFieldDefault(fieldSchema);
|
|
34
|
+
return defaults;
|
|
35
|
+
}
|
|
36
|
+
function getObjectShape(schema) {
|
|
37
|
+
const { def } = schema;
|
|
38
|
+
if (def.type === "object") return schema.shape;
|
|
39
|
+
if (def.type === "intersection") {
|
|
40
|
+
const intersectionDef = def;
|
|
41
|
+
const leftShape = getObjectShape(intersectionDef.left);
|
|
42
|
+
const rightShape = getObjectShape(intersectionDef.right);
|
|
43
|
+
return {
|
|
44
|
+
...leftShape,
|
|
45
|
+
...rightShape
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (def.type === "pipe") return getObjectShape(def.in);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the default value for a Zod field type that matches what RHF's
|
|
53
|
+
* `useController` will produce when registering the field.
|
|
54
|
+
*
|
|
55
|
+
* Unwraps optional/nullable/default wrappers to find the inner type,
|
|
56
|
+
* then returns the natural "empty" value for that type.
|
|
57
|
+
*/
|
|
58
|
+
function getFieldDefault(schema) {
|
|
59
|
+
const { type } = schema.def;
|
|
60
|
+
if (type === "default") return schema.def.defaultValue;
|
|
61
|
+
if (type === "optional" || type === "nullable") {
|
|
62
|
+
const innerDef = schema.def;
|
|
63
|
+
return getFieldDefault(innerDef.innerType);
|
|
64
|
+
}
|
|
65
|
+
if (type === "pipe") {
|
|
66
|
+
const pipeDef = schema.def;
|
|
67
|
+
return getFieldDefault(pipeDef.in);
|
|
68
|
+
}
|
|
69
|
+
if (type === "string") return "";
|
|
70
|
+
if (type === "number" || type === "bigint" || type === "nan") return void 0;
|
|
71
|
+
if (type === "boolean") return false;
|
|
72
|
+
if (type === "array") return [];
|
|
73
|
+
if (type === "object") return getSchemaDefaults(schema);
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/components/features/form/adapters/rhf/rhf-adapter.tsx
|
|
77
|
+
/** Create a React Hook Form instance and normalize it to the adapter interface. */
|
|
78
|
+
function useRHFCreateForm(props) {
|
|
79
|
+
const { schema, defaultValues, mode, id, onSubmit, formRef } = props;
|
|
80
|
+
const modeMap = {
|
|
81
|
+
onBlur: "onBlur",
|
|
82
|
+
onChange: "onChange",
|
|
83
|
+
onSubmit: "onSubmit"
|
|
84
|
+
};
|
|
85
|
+
const schemaDefaults = React$1.useMemo(() => getSchemaDefaults(schema), [schema]);
|
|
86
|
+
const mergedDefaults = React$1.useMemo(() => ({
|
|
87
|
+
...schemaDefaults,
|
|
88
|
+
...defaultValues
|
|
89
|
+
}), [schemaDefaults, defaultValues]);
|
|
90
|
+
const form = useForm({
|
|
91
|
+
resolver: zodResolver(schema),
|
|
92
|
+
defaultValues: mergedDefaults,
|
|
93
|
+
mode: modeMap[mode]
|
|
94
|
+
});
|
|
95
|
+
const { errors, isDirty, isValid, dirtyFields, touchedFields } = form.formState;
|
|
96
|
+
const constraints = React$1.useMemo(() => getFieldConstraints(schema), [schema]);
|
|
97
|
+
const onSubmitRef = React$1.useRef(onSubmit);
|
|
98
|
+
onSubmitRef.current = onSubmit;
|
|
99
|
+
const normalizedFields = React$1.useMemo(() => {
|
|
100
|
+
const result = {};
|
|
101
|
+
for (const [key, constraint] of Object.entries(constraints)) {
|
|
102
|
+
const fieldError = errors[key];
|
|
103
|
+
result[key] = {
|
|
104
|
+
id: `${id ?? "form"}-${key}`,
|
|
105
|
+
errors: fieldError?.message ? [String(fieldError.message)] : [],
|
|
106
|
+
required: constraint.required,
|
|
107
|
+
isDirty: false,
|
|
108
|
+
isTouched: false
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
}, [
|
|
113
|
+
constraints,
|
|
114
|
+
errors,
|
|
115
|
+
id
|
|
116
|
+
]);
|
|
117
|
+
const formState = React$1.useMemo(() => ({
|
|
118
|
+
isDirty,
|
|
119
|
+
isValid,
|
|
120
|
+
isSubmitted: false,
|
|
121
|
+
submitCount: 0,
|
|
122
|
+
dirtyFields: Object.fromEntries(Object.entries(dirtyFields).map(([k, v]) => [k, Boolean(v)])),
|
|
123
|
+
touchedFields: Object.fromEntries(Object.entries(touchedFields).map(([k, v]) => [k, Boolean(v)]))
|
|
124
|
+
}), [
|
|
125
|
+
isDirty,
|
|
126
|
+
isValid,
|
|
127
|
+
dirtyFields,
|
|
128
|
+
touchedFields
|
|
129
|
+
]);
|
|
130
|
+
const handleSubmit = React$1.useMemo(() => form.handleSubmit((data) => {
|
|
131
|
+
onSubmitRef.current?.(data);
|
|
132
|
+
}), [form]);
|
|
133
|
+
const formProps = React$1.useMemo(() => ({
|
|
134
|
+
id,
|
|
135
|
+
onSubmit: handleSubmit,
|
|
136
|
+
noValidate: true
|
|
137
|
+
}), [id, handleSubmit]);
|
|
138
|
+
return React$1.useMemo(() => ({
|
|
139
|
+
id: id ?? "form",
|
|
140
|
+
fields: normalizedFields,
|
|
141
|
+
formProps,
|
|
142
|
+
formState,
|
|
143
|
+
submit: () => formRef?.current?.requestSubmit(),
|
|
144
|
+
reset: () => form.reset(),
|
|
145
|
+
getValues: () => form.getValues(),
|
|
146
|
+
raw: form
|
|
147
|
+
}), [
|
|
148
|
+
id,
|
|
149
|
+
normalizedFields,
|
|
150
|
+
formProps,
|
|
151
|
+
formState,
|
|
152
|
+
form,
|
|
153
|
+
formRef
|
|
154
|
+
]);
|
|
155
|
+
}
|
|
156
|
+
/** Resolve a field by name and return its normalized state. */
|
|
157
|
+
function useRHFField(name) {
|
|
158
|
+
const { field, fieldState } = useController({
|
|
159
|
+
name,
|
|
160
|
+
control: useFormContext().control
|
|
161
|
+
});
|
|
162
|
+
return React$1.useMemo(() => ({
|
|
163
|
+
name: field.name,
|
|
164
|
+
id: name,
|
|
165
|
+
errors: fieldState.error?.message ? [String(fieldState.error.message)] : [],
|
|
166
|
+
required: false,
|
|
167
|
+
isDirty: fieldState.isDirty,
|
|
168
|
+
isTouched: fieldState.isTouched,
|
|
169
|
+
value: field.value,
|
|
170
|
+
change: (value) => field.onChange(value),
|
|
171
|
+
blur: () => field.onBlur(),
|
|
172
|
+
focus: () => {}
|
|
173
|
+
}), [
|
|
174
|
+
field,
|
|
175
|
+
fieldState,
|
|
176
|
+
name
|
|
177
|
+
]);
|
|
178
|
+
}
|
|
179
|
+
/** Watch a single field's value reactively. */
|
|
180
|
+
function useRHFWatchHook(name) {
|
|
181
|
+
return useWatch({
|
|
182
|
+
name,
|
|
183
|
+
control: useFormContext().control
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/** Watch multiple fields' values reactively. */
|
|
187
|
+
function useRHFWatchAllHook(names) {
|
|
188
|
+
const values = useWatch({
|
|
189
|
+
name: names,
|
|
190
|
+
control: useFormContext().control
|
|
191
|
+
});
|
|
192
|
+
return React$1.useMemo(() => {
|
|
193
|
+
const result = {};
|
|
194
|
+
names.forEach((n, index) => {
|
|
195
|
+
result[n] = values[index];
|
|
196
|
+
});
|
|
197
|
+
return result;
|
|
198
|
+
}, [names, values]);
|
|
199
|
+
}
|
|
200
|
+
/** Get field array helpers for a given array field name. */
|
|
201
|
+
function useRHFFieldArrayHook(name) {
|
|
202
|
+
const { fields, append, remove, move } = useFieldArray({
|
|
203
|
+
name,
|
|
204
|
+
control: useFormContext().control
|
|
205
|
+
});
|
|
206
|
+
return {
|
|
207
|
+
items: React$1.useMemo(() => fields.map((field, index) => ({
|
|
208
|
+
id: field.id,
|
|
209
|
+
key: field.id,
|
|
210
|
+
name: `${name}.${index}`
|
|
211
|
+
})), [fields, name]),
|
|
212
|
+
append: React$1.useCallback((defaultValue) => {
|
|
213
|
+
append(defaultValue ?? {});
|
|
214
|
+
}, [append]),
|
|
215
|
+
remove: React$1.useCallback((index) => {
|
|
216
|
+
remove(index);
|
|
217
|
+
}, [remove]),
|
|
218
|
+
move: React$1.useCallback((from, to) => {
|
|
219
|
+
move(from, to);
|
|
220
|
+
}, [move])
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Wraps children in React Hook Form's FormProvider so that useFormContext()
|
|
225
|
+
* and useController() work inside field components.
|
|
226
|
+
*/
|
|
227
|
+
function RHFFormProviderWrapper({ instance, children }) {
|
|
228
|
+
const form = instance.raw;
|
|
229
|
+
return /* @__PURE__ */ jsx(FormProvider, {
|
|
230
|
+
...form,
|
|
231
|
+
children
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* React Hook Form adapter implementing the `FormAdapter` interface.
|
|
236
|
+
*
|
|
237
|
+
* Maps react-hook-form's `useForm` / `useController` / `useWatch` APIs
|
|
238
|
+
* to the normalized form adapter contract. Uses `@hookform/resolvers/zod`
|
|
239
|
+
* for Zod schema validation.
|
|
240
|
+
*/
|
|
241
|
+
const rhfAdapter = {
|
|
242
|
+
name: "React Hook Form",
|
|
243
|
+
useCreateForm: useRHFCreateForm,
|
|
244
|
+
useField: useRHFField,
|
|
245
|
+
useWatch: useRHFWatchHook,
|
|
246
|
+
useWatchAll: useRHFWatchAllHook,
|
|
247
|
+
useFieldArray: useRHFFieldArrayHook,
|
|
248
|
+
FormProvider: RHFFormProviderWrapper
|
|
249
|
+
};
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/components/features/form/adapters/rhf/rhf-provider.tsx
|
|
252
|
+
/**
|
|
253
|
+
* Wrap your application with this provider to use React Hook Form as the form backend.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```tsx
|
|
257
|
+
* import { RHFAdapter } from '@datum-cloud/datum-ui/form/adapters/rhf'
|
|
258
|
+
*
|
|
259
|
+
* function App() {
|
|
260
|
+
* return (
|
|
261
|
+
* <RHFAdapter>
|
|
262
|
+
* <MyApp />
|
|
263
|
+
* </RHFAdapter>
|
|
264
|
+
* )
|
|
265
|
+
* }
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
function RHFAdapter({ children }) {
|
|
269
|
+
return /* @__PURE__ */ jsx(FormAdapterProvider, {
|
|
270
|
+
adapter: rhfAdapter,
|
|
271
|
+
children
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
//#endregion
|
|
275
|
+
export { RHFAdapter, rhfAdapter };
|
package/dist/form/index.mjs
CHANGED
|
@@ -1,146 +1,3 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import "../
|
|
3
|
-
|
|
4
|
-
import "../dialog-DdrHeboM.mjs";
|
|
5
|
-
import "../command-DVroicgn.mjs";
|
|
6
|
-
import "../input-DEMoi_8F.mjs";
|
|
7
|
-
import "../textarea-CVo38n3S.mjs";
|
|
8
|
-
import "../label-mOg07fuQ.mjs";
|
|
9
|
-
import "../popover-ugw5MpuT.mjs";
|
|
10
|
-
import "../radio-group-_gMymwnb.mjs";
|
|
11
|
-
import "../select-BZOKWjlH.mjs";
|
|
12
|
-
import "../tooltip-CuX2jQA9.mjs";
|
|
13
|
-
import "../switch-C60FpEal.mjs";
|
|
14
|
-
import { A as FormButton, C as FormField, D as FormCustom, E as FormDescription, O as FormCopyBox, S as FormFieldArray, T as FormDialog, _ as FormSelectItem, a as FormInputGroup, b as FormRadioItem, c as FormStep, d as useWatch, f as useWatchAll, g as FormSelect, h as FormSubmit, i as useField, j as FormAutocomplete, k as FormCheckbox, l as FormStepper, m as FormSwitch, n as useFormContext, o as StepperNavigation, p as FormTextarea, r as useFieldContext, s as StepperControls, t as useStepper, u as FormWhen, v as FormRoot, w as FormError, x as FormInput, y as FormRadioGroup } from "../use-stepper-DigoyHhX.mjs";
|
|
15
|
-
|
|
16
|
-
//#region src/components/features/form/index.ts
|
|
17
|
-
/**
|
|
18
|
-
* Datum Form Library
|
|
19
|
-
*
|
|
20
|
-
* A compound component pattern form library built on top of Conform.js and Zod
|
|
21
|
-
* for easy form creation with built-in validation, error handling, and accessibility features.
|
|
22
|
-
*
|
|
23
|
-
* @example Basic Usage
|
|
24
|
-
* ```tsx
|
|
25
|
-
* import { Form } from './';
|
|
26
|
-
* import { z } from 'zod';
|
|
27
|
-
*
|
|
28
|
-
* const userSchema = z.object({
|
|
29
|
-
* name: z.string().min(2),
|
|
30
|
-
* email: z.string().email(),
|
|
31
|
-
* });
|
|
32
|
-
*
|
|
33
|
-
* function UserForm() {
|
|
34
|
-
* return (
|
|
35
|
-
* <Form.Root schema={userSchema} onSubmit={(data) => console.log(data)}>
|
|
36
|
-
* <Form.Field name="name" label="Name" required>
|
|
37
|
-
* <Form.Input />
|
|
38
|
-
* </Form.Field>
|
|
39
|
-
* <Form.Field name="email" label="Email" required>
|
|
40
|
-
* <Form.Input type="email" />
|
|
41
|
-
* </Form.Field>
|
|
42
|
-
* <Form.Submit>Save</Form.Submit>
|
|
43
|
-
* </Form.Root>
|
|
44
|
-
* );
|
|
45
|
-
* }
|
|
46
|
-
* ```
|
|
47
|
-
*
|
|
48
|
-
* @example Multi-Step Form
|
|
49
|
-
* ```tsx
|
|
50
|
-
* const steps = [
|
|
51
|
-
* { id: 'account', label: 'Account', schema: accountSchema },
|
|
52
|
-
* { id: 'profile', label: 'Profile', schema: profileSchema },
|
|
53
|
-
* ];
|
|
54
|
-
*
|
|
55
|
-
* <Form.Stepper steps={steps} onComplete={handleComplete}>
|
|
56
|
-
* <Form.StepperNavigation />
|
|
57
|
-
* <Form.Step id="account">...</Form.Step>
|
|
58
|
-
* <Form.Step id="profile">...</Form.Step>
|
|
59
|
-
* <Form.StepperControls />
|
|
60
|
-
* </Form.Stepper>
|
|
61
|
-
* ```
|
|
62
|
-
*
|
|
63
|
-
* @example Conditional Fields
|
|
64
|
-
* ```tsx
|
|
65
|
-
* <Form.Field name="contactMethod">
|
|
66
|
-
* <Form.Select>
|
|
67
|
-
* <Form.SelectItem value="email">Email</Form.SelectItem>
|
|
68
|
-
* <Form.SelectItem value="phone">Phone</Form.SelectItem>
|
|
69
|
-
* </Form.Select>
|
|
70
|
-
* </Form.Field>
|
|
71
|
-
*
|
|
72
|
-
* <Form.When field="contactMethod" is="email">
|
|
73
|
-
* <Form.Field name="email"><Form.Input type="email" /></Form.Field>
|
|
74
|
-
* </Form.When>
|
|
75
|
-
* ```
|
|
76
|
-
*/
|
|
77
|
-
/**
|
|
78
|
-
* Form compound component
|
|
79
|
-
*
|
|
80
|
-
* Contains all form-related components as properties:
|
|
81
|
-
* - Form.Root - Main form container
|
|
82
|
-
* - Form.Field - Field wrapper with label and error handling
|
|
83
|
-
* - Form.Input - Text input
|
|
84
|
-
* - Form.Textarea - Multi-line text input
|
|
85
|
-
* - Form.Select - Dropdown select
|
|
86
|
-
* - Form.SelectItem - Select option
|
|
87
|
-
* - Form.Checkbox - Checkbox input
|
|
88
|
-
* - Form.Switch - Toggle switch
|
|
89
|
-
* - Form.RadioGroup - Radio button group
|
|
90
|
-
* - Form.RadioItem - Radio button option
|
|
91
|
-
* - Form.Submit - Submit button with loading state
|
|
92
|
-
* - Form.Error - Error display
|
|
93
|
-
* - Form.Description - Helper text
|
|
94
|
-
* - Form.Autocomplete - Searchable select with virtualization
|
|
95
|
-
* - Form.When - Conditional rendering
|
|
96
|
-
* - Form.FieldArray - Dynamic array of fields
|
|
97
|
-
* - Form.Custom - Escape hatch for custom implementations
|
|
98
|
-
* - Form.Stepper - Multi-step form container
|
|
99
|
-
* - Form.Step - Individual step content
|
|
100
|
-
* - Form.StepperNavigation - Step progress indicators
|
|
101
|
-
* - Form.StepperControls - Previous/Next/Submit buttons
|
|
102
|
-
*
|
|
103
|
-
* Hooks available:
|
|
104
|
-
* - Form.useFormContext - Access form context
|
|
105
|
-
* - Form.useFieldContext - Access field context
|
|
106
|
-
* - Form.useField - Access and control a specific field
|
|
107
|
-
* - Form.useWatch - Watch a field's value
|
|
108
|
-
* - Form.useWatchAll - Watch multiple fields
|
|
109
|
-
* - Form.useStepper - Access stepper context
|
|
110
|
-
*/
|
|
111
|
-
const Form = {
|
|
112
|
-
Root: FormRoot,
|
|
113
|
-
Field: FormField,
|
|
114
|
-
Submit: FormSubmit,
|
|
115
|
-
Button: FormButton,
|
|
116
|
-
Error: FormError,
|
|
117
|
-
Description: FormDescription,
|
|
118
|
-
Input: FormInput,
|
|
119
|
-
Textarea: FormTextarea,
|
|
120
|
-
Select: FormSelect,
|
|
121
|
-
SelectItem: FormSelectItem,
|
|
122
|
-
Checkbox: FormCheckbox,
|
|
123
|
-
Switch: FormSwitch,
|
|
124
|
-
RadioGroup: FormRadioGroup,
|
|
125
|
-
RadioItem: FormRadioItem,
|
|
126
|
-
CopyBox: FormCopyBox,
|
|
127
|
-
Autocomplete: FormAutocomplete,
|
|
128
|
-
InputGroup: FormInputGroup,
|
|
129
|
-
When: FormWhen,
|
|
130
|
-
FieldArray: FormFieldArray,
|
|
131
|
-
Custom: FormCustom,
|
|
132
|
-
Stepper: FormStepper,
|
|
133
|
-
Step: FormStep,
|
|
134
|
-
StepperNavigation,
|
|
135
|
-
StepperControls,
|
|
136
|
-
Dialog: FormDialog,
|
|
137
|
-
useFormContext,
|
|
138
|
-
useFieldContext,
|
|
139
|
-
useField,
|
|
140
|
-
useWatch,
|
|
141
|
-
useWatchAll,
|
|
142
|
-
useStepper
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
//#endregion
|
|
146
|
-
export { Form, FormAutocomplete, FormButton, FormCheckbox, FormCopyBox, FormCustom, FormDescription, FormDialog, FormError, FormField, FormFieldArray, FormInput, FormRadioGroup, FormRadioItem, FormRoot, FormSelect, FormSelectItem, FormStep, FormStepper, FormSubmit, FormSwitch, FormTextarea, FormWhen, StepperControls, StepperNavigation, useField, useFieldContext, useFormContext, useStepper, useWatch, useWatchAll };
|
|
1
|
+
import { C as FormCustom, D as FormAutocomplete, E as FormButton, S as FormDescription, T as FormCheckbox, _ as FormInput, a as useField, b as FormError, c as useWatchAll, d as FormSubmit, f as FormSelect, g as FormRadioItem, h as FormRadioGroup, i as useFieldContext, l as FormTextarea, m as FormRoot, n as useFormState, o as FormWhen, p as FormSelectItem, r as useFormContext, s as useWatch, t as Form, u as FormSwitch, v as FormFieldArray, w as FormCopyBox, x as FormDialog, y as FormField } from "../form-C6AOB2f4.mjs";
|
|
2
|
+
import { n as useAdapter, t as FormAdapterProvider } from "../adapter-context-BFqfq4Io.mjs";
|
|
3
|
+
export { Form, FormAdapterProvider, FormAutocomplete, FormButton, FormCheckbox, FormCopyBox, FormCustom, FormDescription, FormDialog, FormError, FormField, FormFieldArray, FormInput, FormRadioGroup, FormRadioItem, FormRoot, FormSelect, FormSelectItem, FormSubmit, FormSwitch, FormTextarea, FormWhen, useAdapter, useField, useFieldContext, useFormContext, useFormState, useWatch, useWatchAll };
|