@huin-core/react-form 1.0.2 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,79 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { Label as Label$1 } from '@huin-core/react-label';
4
+ import { Primitive } from '@huin-core/react-primitive';
5
+ import { Scope as Scope$1 } from '@huin-core/react-context';
6
+
7
+ type Scope<C = any> = {
8
+ [scopeName: string]: React.Context<C>[];
9
+ } | undefined;
10
+ type ScopeHook = (scope: Scope) => {
11
+ [__scopeProp: string]: Scope;
12
+ };
13
+ interface CreateScope {
14
+ scopeName: string;
15
+ (): ScopeHook;
16
+ }
17
+
18
+ type ScopedProps<P> = P & {
19
+ __scopeForm?: Scope$1;
20
+ };
21
+ declare const createFormScope: CreateScope;
22
+ type PrimitiveFormProps = React.ComponentPropsWithoutRef<typeof Primitive.form>;
23
+ interface FormProps extends PrimitiveFormProps {
24
+ onClearServerErrors?(): void;
25
+ }
26
+ declare const Form: React.ForwardRefExoticComponent<FormProps & React.RefAttributes<HTMLFormElement>>;
27
+ type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
28
+ interface FormFieldProps extends PrimitiveDivProps {
29
+ name: string;
30
+ serverInvalid?: boolean;
31
+ }
32
+ declare const FormField: React.ForwardRefExoticComponent<FormFieldProps & React.RefAttributes<HTMLDivElement>>;
33
+ type LabelProps = React.ComponentPropsWithoutRef<typeof Label$1>;
34
+ interface FormLabelProps extends LabelProps {
35
+ }
36
+ declare const FormLabel: React.ForwardRefExoticComponent<FormLabelProps & React.RefAttributes<HTMLLabelElement>>;
37
+ type PrimitiveInputProps = React.ComponentPropsWithoutRef<typeof Primitive.input>;
38
+ interface FormControlProps extends PrimitiveInputProps {
39
+ }
40
+ declare const FormControl: React.ForwardRefExoticComponent<FormControlProps & React.RefAttributes<HTMLInputElement>>;
41
+ declare const validityMatchers: readonly ["badInput", "patternMismatch", "rangeOverflow", "rangeUnderflow", "stepMismatch", "tooLong", "tooShort", "typeMismatch", "valid", "valueMissing"];
42
+ type ValidityMatcher = (typeof validityMatchers)[number];
43
+ interface FormMessageProps extends Omit<FormMessageImplProps, 'name'> {
44
+ match?: ValidityMatcher | CustomMatcher;
45
+ forceMatch?: boolean;
46
+ name?: string;
47
+ }
48
+ declare const FormMessage: React.ForwardRefExoticComponent<FormMessageProps & React.RefAttributes<HTMLSpanElement>>;
49
+ type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
50
+ interface FormMessageImplProps extends PrimitiveSpanProps {
51
+ name: string;
52
+ }
53
+ interface FormValidityStateProps {
54
+ children(validity: ValidityState | undefined): React.ReactNode;
55
+ name?: string;
56
+ }
57
+ declare const FormValidityState: {
58
+ (props: ScopedProps<FormValidityStateProps>): react_jsx_runtime.JSX.Element;
59
+ displayName: string;
60
+ };
61
+ type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
62
+ interface FormSubmitProps extends PrimitiveButtonProps {
63
+ }
64
+ declare const FormSubmit: React.ForwardRefExoticComponent<FormSubmitProps & React.RefAttributes<HTMLButtonElement>>;
65
+ type SyncCustomMatcher = (value: string, formData: FormData) => boolean;
66
+ type AsyncCustomMatcher = (value: string, formData: FormData) => Promise<boolean>;
67
+ type CustomMatcher = SyncCustomMatcher | AsyncCustomMatcher;
68
+ declare const Root: React.ForwardRefExoticComponent<FormProps & React.RefAttributes<HTMLFormElement>>;
69
+ declare const Field: React.ForwardRefExoticComponent<FormFieldProps & React.RefAttributes<HTMLDivElement>>;
70
+ declare const Label: React.ForwardRefExoticComponent<FormLabelProps & React.RefAttributes<HTMLLabelElement>>;
71
+ declare const Control: React.ForwardRefExoticComponent<FormControlProps & React.RefAttributes<HTMLInputElement>>;
72
+ declare const Message: React.ForwardRefExoticComponent<FormMessageProps & React.RefAttributes<HTMLSpanElement>>;
73
+ declare const ValidityState: {
74
+ (props: ScopedProps<FormValidityStateProps>): react_jsx_runtime.JSX.Element;
75
+ displayName: string;
76
+ };
77
+ declare const Submit: React.ForwardRefExoticComponent<FormSubmitProps & React.RefAttributes<HTMLButtonElement>>;
78
+
79
+ export { Control, Field, Form, FormControl, type FormControlProps, FormField, type FormFieldProps, FormLabel, type FormLabelProps, FormMessage, type FormMessageProps, type FormProps, FormSubmit, type FormSubmitProps, FormValidityState, type FormValidityStateProps, Label, Message, Root, Submit, ValidityState, createFormScope };
@@ -0,0 +1,79 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { Label as Label$1 } from '@huin-core/react-label';
4
+ import { Primitive } from '@huin-core/react-primitive';
5
+ import { Scope as Scope$1 } from '@huin-core/react-context';
6
+
7
+ type Scope<C = any> = {
8
+ [scopeName: string]: React.Context<C>[];
9
+ } | undefined;
10
+ type ScopeHook = (scope: Scope) => {
11
+ [__scopeProp: string]: Scope;
12
+ };
13
+ interface CreateScope {
14
+ scopeName: string;
15
+ (): ScopeHook;
16
+ }
17
+
18
+ type ScopedProps<P> = P & {
19
+ __scopeForm?: Scope$1;
20
+ };
21
+ declare const createFormScope: CreateScope;
22
+ type PrimitiveFormProps = React.ComponentPropsWithoutRef<typeof Primitive.form>;
23
+ interface FormProps extends PrimitiveFormProps {
24
+ onClearServerErrors?(): void;
25
+ }
26
+ declare const Form: React.ForwardRefExoticComponent<FormProps & React.RefAttributes<HTMLFormElement>>;
27
+ type PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;
28
+ interface FormFieldProps extends PrimitiveDivProps {
29
+ name: string;
30
+ serverInvalid?: boolean;
31
+ }
32
+ declare const FormField: React.ForwardRefExoticComponent<FormFieldProps & React.RefAttributes<HTMLDivElement>>;
33
+ type LabelProps = React.ComponentPropsWithoutRef<typeof Label$1>;
34
+ interface FormLabelProps extends LabelProps {
35
+ }
36
+ declare const FormLabel: React.ForwardRefExoticComponent<FormLabelProps & React.RefAttributes<HTMLLabelElement>>;
37
+ type PrimitiveInputProps = React.ComponentPropsWithoutRef<typeof Primitive.input>;
38
+ interface FormControlProps extends PrimitiveInputProps {
39
+ }
40
+ declare const FormControl: React.ForwardRefExoticComponent<FormControlProps & React.RefAttributes<HTMLInputElement>>;
41
+ declare const validityMatchers: readonly ["badInput", "patternMismatch", "rangeOverflow", "rangeUnderflow", "stepMismatch", "tooLong", "tooShort", "typeMismatch", "valid", "valueMissing"];
42
+ type ValidityMatcher = (typeof validityMatchers)[number];
43
+ interface FormMessageProps extends Omit<FormMessageImplProps, 'name'> {
44
+ match?: ValidityMatcher | CustomMatcher;
45
+ forceMatch?: boolean;
46
+ name?: string;
47
+ }
48
+ declare const FormMessage: React.ForwardRefExoticComponent<FormMessageProps & React.RefAttributes<HTMLSpanElement>>;
49
+ type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;
50
+ interface FormMessageImplProps extends PrimitiveSpanProps {
51
+ name: string;
52
+ }
53
+ interface FormValidityStateProps {
54
+ children(validity: ValidityState | undefined): React.ReactNode;
55
+ name?: string;
56
+ }
57
+ declare const FormValidityState: {
58
+ (props: ScopedProps<FormValidityStateProps>): react_jsx_runtime.JSX.Element;
59
+ displayName: string;
60
+ };
61
+ type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;
62
+ interface FormSubmitProps extends PrimitiveButtonProps {
63
+ }
64
+ declare const FormSubmit: React.ForwardRefExoticComponent<FormSubmitProps & React.RefAttributes<HTMLButtonElement>>;
65
+ type SyncCustomMatcher = (value: string, formData: FormData) => boolean;
66
+ type AsyncCustomMatcher = (value: string, formData: FormData) => Promise<boolean>;
67
+ type CustomMatcher = SyncCustomMatcher | AsyncCustomMatcher;
68
+ declare const Root: React.ForwardRefExoticComponent<FormProps & React.RefAttributes<HTMLFormElement>>;
69
+ declare const Field: React.ForwardRefExoticComponent<FormFieldProps & React.RefAttributes<HTMLDivElement>>;
70
+ declare const Label: React.ForwardRefExoticComponent<FormLabelProps & React.RefAttributes<HTMLLabelElement>>;
71
+ declare const Control: React.ForwardRefExoticComponent<FormControlProps & React.RefAttributes<HTMLInputElement>>;
72
+ declare const Message: React.ForwardRefExoticComponent<FormMessageProps & React.RefAttributes<HTMLSpanElement>>;
73
+ declare const ValidityState: {
74
+ (props: ScopedProps<FormValidityStateProps>): react_jsx_runtime.JSX.Element;
75
+ displayName: string;
76
+ };
77
+ declare const Submit: React.ForwardRefExoticComponent<FormSubmitProps & React.RefAttributes<HTMLButtonElement>>;
78
+
79
+ export { Control, Field, Form, FormControl, type FormControlProps, FormField, type FormFieldProps, FormLabel, type FormLabelProps, FormMessage, type FormMessageProps, type FormProps, FormSubmit, type FormSubmitProps, FormValidityState, type FormValidityStateProps, Label, Message, Root, Submit, ValidityState, createFormScope };
package/dist/index.js ADDED
@@ -0,0 +1,483 @@
1
+ "use strict";
2
+ "use client";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // packages/react/form/src/index.ts
32
+ var src_exports = {};
33
+ __export(src_exports, {
34
+ Control: () => Control,
35
+ Field: () => Field,
36
+ Form: () => Form,
37
+ FormControl: () => FormControl,
38
+ FormField: () => FormField,
39
+ FormLabel: () => FormLabel,
40
+ FormMessage: () => FormMessage,
41
+ FormSubmit: () => FormSubmit,
42
+ FormValidityState: () => FormValidityState,
43
+ Label: () => Label,
44
+ Message: () => Message,
45
+ Root: () => Root,
46
+ Submit: () => Submit,
47
+ ValidityState: () => ValidityState,
48
+ createFormScope: () => createFormScope
49
+ });
50
+ module.exports = __toCommonJS(src_exports);
51
+
52
+ // packages/react/form/src/Form.tsx
53
+ var React = __toESM(require("react"));
54
+ var import_primitive = require("@huin-core/primitive");
55
+ var import_react_compose_refs = require("@huin-core/react-compose-refs");
56
+ var import_react_context = require("@huin-core/react-context");
57
+ var import_react_id = require("@huin-core/react-id");
58
+ var import_react_label = require("@huin-core/react-label");
59
+ var import_react_primitive = require("@huin-core/react-primitive");
60
+ var import_jsx_runtime = require("react/jsx-runtime");
61
+ var [createFormContext, createFormScope] = (0, import_react_context.createContextScope)("Form");
62
+ var FORM_NAME = "Form";
63
+ var [ValidationProvider, useValidationContext] = createFormContext(FORM_NAME);
64
+ var [AriaDescriptionProvider, useAriaDescriptionContext] = createFormContext(FORM_NAME);
65
+ var Form = React.forwardRef(
66
+ (props, forwardedRef) => {
67
+ const { __scopeForm, onClearServerErrors = () => {
68
+ }, ...rootProps } = props;
69
+ const formRef = React.useRef(null);
70
+ const composedFormRef = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, formRef);
71
+ const [validityMap, setValidityMap] = React.useState({});
72
+ const getFieldValidity = React.useCallback(
73
+ (fieldName) => validityMap[fieldName],
74
+ [validityMap]
75
+ );
76
+ const handleFieldValidityChange = React.useCallback(
77
+ (fieldName, validity) => setValidityMap((prevValidityMap) => ({
78
+ ...prevValidityMap,
79
+ [fieldName]: { ...prevValidityMap[fieldName] ?? {}, ...validity }
80
+ })),
81
+ []
82
+ );
83
+ const handleFieldValiditionClear = React.useCallback((fieldName) => {
84
+ setValidityMap((prevValidityMap) => ({ ...prevValidityMap, [fieldName]: void 0 }));
85
+ setCustomErrorsMap((prevCustomErrorsMap) => ({ ...prevCustomErrorsMap, [fieldName]: {} }));
86
+ }, []);
87
+ const [customMatcherEntriesMap, setCustomMatcherEntriesMap] = React.useState({});
88
+ const getFieldCustomMatcherEntries = React.useCallback(
89
+ (fieldName) => customMatcherEntriesMap[fieldName] ?? [],
90
+ [customMatcherEntriesMap]
91
+ );
92
+ const handleFieldCustomMatcherAdd = React.useCallback((fieldName, matcherEntry) => {
93
+ setCustomMatcherEntriesMap((prevCustomMatcherEntriesMap) => ({
94
+ ...prevCustomMatcherEntriesMap,
95
+ [fieldName]: [...prevCustomMatcherEntriesMap[fieldName] ?? [], matcherEntry]
96
+ }));
97
+ }, []);
98
+ const handleFieldCustomMatcherRemove = React.useCallback((fieldName, matcherEntryId) => {
99
+ setCustomMatcherEntriesMap((prevCustomMatcherEntriesMap) => ({
100
+ ...prevCustomMatcherEntriesMap,
101
+ [fieldName]: (prevCustomMatcherEntriesMap[fieldName] ?? []).filter(
102
+ (matcherEntry) => matcherEntry.id !== matcherEntryId
103
+ )
104
+ }));
105
+ }, []);
106
+ const [customErrorsMap, setCustomErrorsMap] = React.useState({});
107
+ const getFieldCustomErrors = React.useCallback(
108
+ (fieldName) => customErrorsMap[fieldName] ?? {},
109
+ [customErrorsMap]
110
+ );
111
+ const handleFieldCustomErrorsChange = React.useCallback((fieldName, customErrors) => {
112
+ setCustomErrorsMap((prevCustomErrorsMap) => ({
113
+ ...prevCustomErrorsMap,
114
+ [fieldName]: { ...prevCustomErrorsMap[fieldName] ?? {}, ...customErrors }
115
+ }));
116
+ }, []);
117
+ const [messageIdsMap, setMessageIdsMap] = React.useState({});
118
+ const handleFieldMessageIdAdd = React.useCallback((fieldName, id) => {
119
+ setMessageIdsMap((prevMessageIdsMap) => {
120
+ const fieldDescriptionIds = new Set(prevMessageIdsMap[fieldName]).add(id);
121
+ return { ...prevMessageIdsMap, [fieldName]: fieldDescriptionIds };
122
+ });
123
+ }, []);
124
+ const handleFieldMessageIdRemove = React.useCallback((fieldName, id) => {
125
+ setMessageIdsMap((prevMessageIdsMap) => {
126
+ const fieldDescriptionIds = new Set(prevMessageIdsMap[fieldName]);
127
+ fieldDescriptionIds.delete(id);
128
+ return { ...prevMessageIdsMap, [fieldName]: fieldDescriptionIds };
129
+ });
130
+ }, []);
131
+ const getFieldDescription = React.useCallback(
132
+ (fieldName) => Array.from(messageIdsMap[fieldName] ?? []).join(" ") || void 0,
133
+ [messageIdsMap]
134
+ );
135
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
136
+ ValidationProvider,
137
+ {
138
+ scope: __scopeForm,
139
+ getFieldValidity,
140
+ onFieldValidityChange: handleFieldValidityChange,
141
+ getFieldCustomMatcherEntries,
142
+ onFieldCustomMatcherEntryAdd: handleFieldCustomMatcherAdd,
143
+ onFieldCustomMatcherEntryRemove: handleFieldCustomMatcherRemove,
144
+ getFieldCustomErrors,
145
+ onFieldCustomErrorsChange: handleFieldCustomErrorsChange,
146
+ onFieldValiditionClear: handleFieldValiditionClear,
147
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
148
+ AriaDescriptionProvider,
149
+ {
150
+ scope: __scopeForm,
151
+ onFieldMessageIdAdd: handleFieldMessageIdAdd,
152
+ onFieldMessageIdRemove: handleFieldMessageIdRemove,
153
+ getFieldDescription,
154
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
155
+ import_react_primitive.Primitive.form,
156
+ {
157
+ ...rootProps,
158
+ ref: composedFormRef,
159
+ onInvalid: (0, import_primitive.composeEventHandlers)(props.onInvalid, (event) => {
160
+ const firstInvalidControl = getFirstInvalidControl(event.currentTarget);
161
+ if (firstInvalidControl === event.target) firstInvalidControl.focus();
162
+ event.preventDefault();
163
+ }),
164
+ onSubmit: (0, import_primitive.composeEventHandlers)(props.onSubmit, onClearServerErrors, {
165
+ checkForDefaultPrevented: false
166
+ }),
167
+ onReset: (0, import_primitive.composeEventHandlers)(props.onReset, onClearServerErrors)
168
+ }
169
+ )
170
+ }
171
+ )
172
+ }
173
+ );
174
+ }
175
+ );
176
+ Form.displayName = FORM_NAME;
177
+ var FIELD_NAME = "FormField";
178
+ var [FormFieldProvider, useFormFieldContext] = createFormContext(FIELD_NAME);
179
+ var FormField = React.forwardRef(
180
+ (props, forwardedRef) => {
181
+ const { __scopeForm, name, serverInvalid = false, ...fieldProps } = props;
182
+ const validationContext = useValidationContext(FIELD_NAME, __scopeForm);
183
+ const validity = validationContext.getFieldValidity(name);
184
+ const id = (0, import_react_id.useId)();
185
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormFieldProvider, { scope: __scopeForm, id, name, serverInvalid, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
186
+ import_react_primitive.Primitive.div,
187
+ {
188
+ "data-valid": getValidAttribute(validity, serverInvalid),
189
+ "data-invalid": getInvalidAttribute(validity, serverInvalid),
190
+ ...fieldProps,
191
+ ref: forwardedRef
192
+ }
193
+ ) });
194
+ }
195
+ );
196
+ FormField.displayName = FIELD_NAME;
197
+ var LABEL_NAME = "FormLabel";
198
+ var FormLabel = React.forwardRef(
199
+ (props, forwardedRef) => {
200
+ const { __scopeForm, ...labelProps } = props;
201
+ const validationContext = useValidationContext(LABEL_NAME, __scopeForm);
202
+ const fieldContext = useFormFieldContext(LABEL_NAME, __scopeForm);
203
+ const htmlFor = labelProps.htmlFor || fieldContext.id;
204
+ const validity = validationContext.getFieldValidity(fieldContext.name);
205
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
206
+ import_react_label.Label,
207
+ {
208
+ "data-valid": getValidAttribute(validity, fieldContext.serverInvalid),
209
+ "data-invalid": getInvalidAttribute(validity, fieldContext.serverInvalid),
210
+ ...labelProps,
211
+ ref: forwardedRef,
212
+ htmlFor
213
+ }
214
+ );
215
+ }
216
+ );
217
+ FormLabel.displayName = LABEL_NAME;
218
+ var CONTROL_NAME = "FormControl";
219
+ var FormControl = React.forwardRef(
220
+ (props, forwardedRef) => {
221
+ const { __scopeForm, ...controlProps } = props;
222
+ const validationContext = useValidationContext(CONTROL_NAME, __scopeForm);
223
+ const fieldContext = useFormFieldContext(CONTROL_NAME, __scopeForm);
224
+ const ariaDescriptionContext = useAriaDescriptionContext(CONTROL_NAME, __scopeForm);
225
+ const ref = React.useRef(null);
226
+ const composedRef = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref);
227
+ const name = controlProps.name || fieldContext.name;
228
+ const id = controlProps.id || fieldContext.id;
229
+ const customMatcherEntries = validationContext.getFieldCustomMatcherEntries(name);
230
+ const { onFieldValidityChange, onFieldCustomErrorsChange, onFieldValiditionClear } = validationContext;
231
+ const updateControlValidity = React.useCallback(
232
+ async (control) => {
233
+ if (hasBuiltInError(control.validity)) {
234
+ const controlValidity2 = validityStateToObject(control.validity);
235
+ onFieldValidityChange(name, controlValidity2);
236
+ return;
237
+ }
238
+ const formData = control.form ? new FormData(control.form) : new FormData();
239
+ const matcherArgs = [control.value, formData];
240
+ const syncCustomMatcherEntries = [];
241
+ const ayncCustomMatcherEntries = [];
242
+ customMatcherEntries.forEach((customMatcherEntry) => {
243
+ if (isAsyncCustomMatcherEntry(customMatcherEntry, matcherArgs)) {
244
+ ayncCustomMatcherEntries.push(customMatcherEntry);
245
+ } else if (isSyncCustomMatcherEntry(customMatcherEntry)) {
246
+ syncCustomMatcherEntries.push(customMatcherEntry);
247
+ }
248
+ });
249
+ const syncCustomErrors = syncCustomMatcherEntries.map(({ id: id2, match }) => {
250
+ return [id2, match(...matcherArgs)];
251
+ });
252
+ const syncCustomErrorsById = Object.fromEntries(syncCustomErrors);
253
+ const hasSyncCustomErrors = Object.values(syncCustomErrorsById).some(Boolean);
254
+ const hasCustomError = hasSyncCustomErrors;
255
+ control.setCustomValidity(hasCustomError ? DEFAULT_INVALID_MESSAGE : "");
256
+ const controlValidity = validityStateToObject(control.validity);
257
+ onFieldValidityChange(name, controlValidity);
258
+ onFieldCustomErrorsChange(name, syncCustomErrorsById);
259
+ if (!hasSyncCustomErrors && ayncCustomMatcherEntries.length > 0) {
260
+ const promisedCustomErrors = ayncCustomMatcherEntries.map(
261
+ ({ id: id2, match }) => match(...matcherArgs).then((matches) => [id2, matches])
262
+ );
263
+ const asyncCustomErrors = await Promise.all(promisedCustomErrors);
264
+ const asyncCustomErrorsById = Object.fromEntries(asyncCustomErrors);
265
+ const hasAsyncCustomErrors = Object.values(asyncCustomErrorsById).some(Boolean);
266
+ const hasCustomError2 = hasAsyncCustomErrors;
267
+ control.setCustomValidity(hasCustomError2 ? DEFAULT_INVALID_MESSAGE : "");
268
+ const controlValidity2 = validityStateToObject(control.validity);
269
+ onFieldValidityChange(name, controlValidity2);
270
+ onFieldCustomErrorsChange(name, asyncCustomErrorsById);
271
+ }
272
+ },
273
+ [customMatcherEntries, name, onFieldCustomErrorsChange, onFieldValidityChange]
274
+ );
275
+ React.useEffect(() => {
276
+ const control = ref.current;
277
+ if (control) {
278
+ const handleChange = () => updateControlValidity(control);
279
+ control.addEventListener("change", handleChange);
280
+ return () => control.removeEventListener("change", handleChange);
281
+ }
282
+ }, [updateControlValidity]);
283
+ const resetControlValidity = React.useCallback(() => {
284
+ const control = ref.current;
285
+ if (control) {
286
+ control.setCustomValidity("");
287
+ onFieldValiditionClear(name);
288
+ }
289
+ }, [name, onFieldValiditionClear]);
290
+ React.useEffect(() => {
291
+ const form = ref.current?.form;
292
+ if (form) {
293
+ form.addEventListener("reset", resetControlValidity);
294
+ return () => form.removeEventListener("reset", resetControlValidity);
295
+ }
296
+ }, [resetControlValidity]);
297
+ React.useEffect(() => {
298
+ const control = ref.current;
299
+ const form = control?.closest("form");
300
+ if (form && fieldContext.serverInvalid) {
301
+ const firstInvalidControl = getFirstInvalidControl(form);
302
+ if (firstInvalidControl === control) firstInvalidControl.focus();
303
+ }
304
+ }, [fieldContext.serverInvalid]);
305
+ const validity = validationContext.getFieldValidity(name);
306
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
307
+ import_react_primitive.Primitive.input,
308
+ {
309
+ "data-valid": getValidAttribute(validity, fieldContext.serverInvalid),
310
+ "data-invalid": getInvalidAttribute(validity, fieldContext.serverInvalid),
311
+ "aria-invalid": fieldContext.serverInvalid ? true : void 0,
312
+ "aria-describedby": ariaDescriptionContext.getFieldDescription(name),
313
+ title: "",
314
+ ...controlProps,
315
+ ref: composedRef,
316
+ id,
317
+ name,
318
+ onInvalid: (0, import_primitive.composeEventHandlers)(props.onInvalid, (event) => {
319
+ const control = event.currentTarget;
320
+ updateControlValidity(control);
321
+ }),
322
+ onChange: (0, import_primitive.composeEventHandlers)(props.onChange, (event) => {
323
+ resetControlValidity();
324
+ })
325
+ }
326
+ );
327
+ }
328
+ );
329
+ FormControl.displayName = CONTROL_NAME;
330
+ var DEFAULT_INVALID_MESSAGE = "This value is not valid";
331
+ var DEFAULT_BUILT_IN_MESSAGES = {
332
+ badInput: DEFAULT_INVALID_MESSAGE,
333
+ patternMismatch: "This value does not match the required pattern",
334
+ rangeOverflow: "This value is too large",
335
+ rangeUnderflow: "This value is too small",
336
+ stepMismatch: "This value does not match the required step",
337
+ tooLong: "This value is too long",
338
+ tooShort: "This value is too short",
339
+ typeMismatch: "This value does not match the required type",
340
+ valid: void 0,
341
+ valueMissing: "This value is missing"
342
+ };
343
+ var MESSAGE_NAME = "FormMessage";
344
+ var FormMessage = React.forwardRef(
345
+ (props, forwardedRef) => {
346
+ const { match, name: nameProp, ...messageProps } = props;
347
+ const fieldContext = useFormFieldContext(MESSAGE_NAME, props.__scopeForm);
348
+ const name = nameProp ?? fieldContext.name;
349
+ if (match === void 0) {
350
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormMessageImpl, { ...messageProps, ref: forwardedRef, name, children: props.children || DEFAULT_INVALID_MESSAGE });
351
+ } else if (typeof match === "function") {
352
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormCustomMessage, { match, ...messageProps, ref: forwardedRef, name });
353
+ } else {
354
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormBuiltInMessage, { match, ...messageProps, ref: forwardedRef, name });
355
+ }
356
+ }
357
+ );
358
+ FormMessage.displayName = MESSAGE_NAME;
359
+ var FormBuiltInMessage = React.forwardRef(
360
+ (props, forwardedRef) => {
361
+ const { match, forceMatch = false, name, children, ...messageProps } = props;
362
+ const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);
363
+ const validity = validationContext.getFieldValidity(name);
364
+ const matches = forceMatch || validity?.[match];
365
+ if (matches) {
366
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormMessageImpl, { ref: forwardedRef, ...messageProps, name, children: children ?? DEFAULT_BUILT_IN_MESSAGES[match] });
367
+ }
368
+ return null;
369
+ }
370
+ );
371
+ var FormCustomMessage = React.forwardRef(
372
+ (props, forwardedRef) => {
373
+ const { match, forceMatch = false, name, id: idProp, children, ...messageProps } = props;
374
+ const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);
375
+ const ref = React.useRef(null);
376
+ const composedRef = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, ref);
377
+ const _id = (0, import_react_id.useId)();
378
+ const id = idProp ?? _id;
379
+ const customMatcherEntry = React.useMemo(() => ({ id, match }), [id, match]);
380
+ const { onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove } = validationContext;
381
+ React.useEffect(() => {
382
+ onFieldCustomMatcherEntryAdd(name, customMatcherEntry);
383
+ return () => onFieldCustomMatcherEntryRemove(name, customMatcherEntry.id);
384
+ }, [customMatcherEntry, name, onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove]);
385
+ const validity = validationContext.getFieldValidity(name);
386
+ const customErrors = validationContext.getFieldCustomErrors(name);
387
+ const hasMatchingCustomError = customErrors[id];
388
+ const matches = forceMatch || validity && !hasBuiltInError(validity) && hasMatchingCustomError;
389
+ if (matches) {
390
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormMessageImpl, { id, ref: composedRef, ...messageProps, name, children: children ?? DEFAULT_INVALID_MESSAGE });
391
+ }
392
+ return null;
393
+ }
394
+ );
395
+ var FormMessageImpl = React.forwardRef(
396
+ (props, forwardedRef) => {
397
+ const { __scopeForm, id: idProp, name, ...messageProps } = props;
398
+ const ariaDescriptionContext = useAriaDescriptionContext(MESSAGE_NAME, __scopeForm);
399
+ const _id = (0, import_react_id.useId)();
400
+ const id = idProp ?? _id;
401
+ const { onFieldMessageIdAdd, onFieldMessageIdRemove } = ariaDescriptionContext;
402
+ React.useEffect(() => {
403
+ onFieldMessageIdAdd(name, id);
404
+ return () => onFieldMessageIdRemove(name, id);
405
+ }, [name, id, onFieldMessageIdAdd, onFieldMessageIdRemove]);
406
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.span, { id, ...messageProps, ref: forwardedRef });
407
+ }
408
+ );
409
+ var VALIDITY_STATE_NAME = "FormValidityState";
410
+ var FormValidityState = (props) => {
411
+ const { __scopeForm, name: nameProp, children } = props;
412
+ const validationContext = useValidationContext(VALIDITY_STATE_NAME, __scopeForm);
413
+ const fieldContext = useFormFieldContext(VALIDITY_STATE_NAME, __scopeForm);
414
+ const name = nameProp ?? fieldContext.name;
415
+ const validity = validationContext.getFieldValidity(name);
416
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: children(validity) });
417
+ };
418
+ FormValidityState.displayName = VALIDITY_STATE_NAME;
419
+ var SUBMIT_NAME = "FormSubmit";
420
+ var FormSubmit = React.forwardRef(
421
+ (props, forwardedRef) => {
422
+ const { __scopeForm, ...submitProps } = props;
423
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.button, { type: "submit", ...submitProps, ref: forwardedRef });
424
+ }
425
+ );
426
+ FormSubmit.displayName = SUBMIT_NAME;
427
+ function validityStateToObject(validity) {
428
+ const object = {};
429
+ for (const key in validity) {
430
+ object[key] = validity[key];
431
+ }
432
+ return object;
433
+ }
434
+ function isHTMLElement(element) {
435
+ return element instanceof HTMLElement;
436
+ }
437
+ function isFormControl(element) {
438
+ return "validity" in element;
439
+ }
440
+ function isInvalid(control) {
441
+ return isFormControl(control) && (control.validity.valid === false || control.getAttribute("aria-invalid") === "true");
442
+ }
443
+ function getFirstInvalidControl(form) {
444
+ const elements = form.elements;
445
+ const [firstInvalidControl] = Array.from(elements).filter(isHTMLElement).filter(isInvalid);
446
+ return firstInvalidControl;
447
+ }
448
+ function isAsyncCustomMatcherEntry(entry, args) {
449
+ return entry.match.constructor.name === "AsyncFunction" || returnsPromise(entry.match, args);
450
+ }
451
+ function isSyncCustomMatcherEntry(entry) {
452
+ return entry.match.constructor.name === "Function";
453
+ }
454
+ function returnsPromise(func, args) {
455
+ return func(...args) instanceof Promise;
456
+ }
457
+ function hasBuiltInError(validity) {
458
+ let error = false;
459
+ for (const validityKey in validity) {
460
+ const key = validityKey;
461
+ if (key !== "valid" && key !== "customError" && validity[key]) {
462
+ error = true;
463
+ break;
464
+ }
465
+ }
466
+ return error;
467
+ }
468
+ function getValidAttribute(validity, serverInvalid) {
469
+ if (validity?.valid === true && !serverInvalid) return true;
470
+ return void 0;
471
+ }
472
+ function getInvalidAttribute(validity, serverInvalid) {
473
+ if (validity?.valid === false || serverInvalid) return true;
474
+ return void 0;
475
+ }
476
+ var Root = Form;
477
+ var Field = FormField;
478
+ var Label = FormLabel;
479
+ var Control = FormControl;
480
+ var Message = FormMessage;
481
+ var ValidityState = FormValidityState;
482
+ var Submit = FormSubmit;
483
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts", "../src/Form.tsx"],
4
+ "sourcesContent": ["'use client';\nexport {\n createFormScope,\n //\n Form,\n FormField,\n FormLabel,\n FormControl,\n FormMessage,\n FormValidityState,\n FormSubmit,\n //\n Root,\n Field,\n Label,\n Control,\n Message,\n ValidityState,\n Submit,\n} from './Form';\n\nexport type {\n FormProps,\n FormFieldProps,\n FormLabelProps,\n FormControlProps,\n FormMessageProps,\n FormValidityStateProps,\n FormSubmitProps,\n} from './Form';\n", "import * as React from 'react';\nimport { composeEventHandlers } from '@huin-core/primitive';\nimport { useComposedRefs } from '@huin-core/react-compose-refs';\nimport { createContextScope } from '@huin-core/react-context';\nimport { useId } from '@huin-core/react-id';\nimport { Label as LabelPrimitive } from '@huin-core/react-label';\nimport { Primitive } from '@huin-core/react-primitive';\n\nimport type { Scope } from '@huin-core/react-context';\n\ntype ScopedProps<P> = P & { __scopeForm?: Scope };\nconst [createFormContext, createFormScope] = createContextScope('Form');\n\n/* -------------------------------------------------------------------------------------------------\n * Form\n * -----------------------------------------------------------------------------------------------*/\n\nconst FORM_NAME = 'Form';\n\ntype ValidityMap = { [fieldName: string]: ValidityState | undefined };\ntype CustomMatcherEntriesMap = { [fieldName: string]: CustomMatcherEntry[] };\ntype CustomErrorsMap = { [fieldName: string]: Record<string, boolean> };\n\ntype ValidationContextValue = {\n getFieldValidity(fieldName: string): ValidityState | undefined;\n onFieldValidityChange(fieldName: string, validity: ValidityState): void;\n\n getFieldCustomMatcherEntries(fieldName: string): CustomMatcherEntry[];\n onFieldCustomMatcherEntryAdd(fieldName: string, matcherEntry: CustomMatcherEntry): void;\n onFieldCustomMatcherEntryRemove(fieldName: string, matcherEntryId: string): void;\n\n getFieldCustomErrors(fieldName: string): Record<string, boolean>;\n onFieldCustomErrorsChange(fieldName: string, errors: Record<string, boolean>): void;\n\n onFieldValiditionClear(fieldName: string): void;\n};\nconst [ValidationProvider, useValidationContext] =\n createFormContext<ValidationContextValue>(FORM_NAME);\n\ntype MessageIdsMap = { [fieldName: string]: Set<string> };\n\ntype AriaDescriptionContextValue = {\n onFieldMessageIdAdd(fieldName: string, id: string): void;\n onFieldMessageIdRemove(fieldName: string, id: string): void;\n getFieldDescription(fieldName: string): string | undefined;\n};\nconst [AriaDescriptionProvider, useAriaDescriptionContext] =\n createFormContext<AriaDescriptionContextValue>(FORM_NAME);\n\ntype FormElement = React.ElementRef<typeof Primitive.form>;\ntype PrimitiveFormProps = React.ComponentPropsWithoutRef<typeof Primitive.form>;\ninterface FormProps extends PrimitiveFormProps {\n onClearServerErrors?(): void;\n}\n\nconst Form = React.forwardRef<FormElement, FormProps>(\n (props: ScopedProps<FormProps>, forwardedRef) => {\n const { __scopeForm, onClearServerErrors = () => {}, ...rootProps } = props;\n const formRef = React.useRef<HTMLFormElement>(null);\n const composedFormRef = useComposedRefs(forwardedRef, formRef);\n\n // native validity per field\n const [validityMap, setValidityMap] = React.useState<ValidityMap>({});\n const getFieldValidity: ValidationContextValue['getFieldValidity'] = React.useCallback(\n (fieldName) => validityMap[fieldName],\n [validityMap]\n );\n const handleFieldValidityChange: ValidationContextValue['onFieldValidityChange'] =\n React.useCallback(\n (fieldName, validity) =>\n setValidityMap((prevValidityMap) => ({\n ...prevValidityMap,\n [fieldName]: { ...(prevValidityMap[fieldName] ?? {}), ...validity },\n })),\n []\n );\n const handleFieldValiditionClear: ValidationContextValue['onFieldValiditionClear'] =\n React.useCallback((fieldName) => {\n setValidityMap((prevValidityMap) => ({ ...prevValidityMap, [fieldName]: undefined }));\n setCustomErrorsMap((prevCustomErrorsMap) => ({ ...prevCustomErrorsMap, [fieldName]: {} }));\n }, []);\n\n // custom matcher entries per field\n const [customMatcherEntriesMap, setCustomMatcherEntriesMap] =\n React.useState<CustomMatcherEntriesMap>({});\n const getFieldCustomMatcherEntries: ValidationContextValue['getFieldCustomMatcherEntries'] =\n React.useCallback(\n (fieldName) => customMatcherEntriesMap[fieldName] ?? [],\n [customMatcherEntriesMap]\n );\n const handleFieldCustomMatcherAdd: ValidationContextValue['onFieldCustomMatcherEntryAdd'] =\n React.useCallback((fieldName, matcherEntry) => {\n setCustomMatcherEntriesMap((prevCustomMatcherEntriesMap) => ({\n ...prevCustomMatcherEntriesMap,\n [fieldName]: [...(prevCustomMatcherEntriesMap[fieldName] ?? []), matcherEntry],\n }));\n }, []);\n const handleFieldCustomMatcherRemove: ValidationContextValue['onFieldCustomMatcherEntryRemove'] =\n React.useCallback((fieldName, matcherEntryId) => {\n setCustomMatcherEntriesMap((prevCustomMatcherEntriesMap) => ({\n ...prevCustomMatcherEntriesMap,\n [fieldName]: (prevCustomMatcherEntriesMap[fieldName] ?? []).filter(\n (matcherEntry) => matcherEntry.id !== matcherEntryId\n ),\n }));\n }, []);\n\n // custom errors per field\n const [customErrorsMap, setCustomErrorsMap] = React.useState<CustomErrorsMap>({});\n const getFieldCustomErrors: ValidationContextValue['getFieldCustomErrors'] = React.useCallback(\n (fieldName) => customErrorsMap[fieldName] ?? {},\n [customErrorsMap]\n );\n const handleFieldCustomErrorsChange: ValidationContextValue['onFieldCustomErrorsChange'] =\n React.useCallback((fieldName, customErrors) => {\n setCustomErrorsMap((prevCustomErrorsMap) => ({\n ...prevCustomErrorsMap,\n [fieldName]: { ...(prevCustomErrorsMap[fieldName] ?? {}), ...customErrors },\n }));\n }, []);\n\n // messageIds per field\n const [messageIdsMap, setMessageIdsMap] = React.useState<MessageIdsMap>({});\n const handleFieldMessageIdAdd: AriaDescriptionContextValue['onFieldMessageIdAdd'] =\n React.useCallback((fieldName, id) => {\n setMessageIdsMap((prevMessageIdsMap) => {\n const fieldDescriptionIds = new Set(prevMessageIdsMap[fieldName]).add(id);\n return { ...prevMessageIdsMap, [fieldName]: fieldDescriptionIds };\n });\n }, []);\n const handleFieldMessageIdRemove: AriaDescriptionContextValue['onFieldMessageIdRemove'] =\n React.useCallback((fieldName, id) => {\n setMessageIdsMap((prevMessageIdsMap) => {\n const fieldDescriptionIds = new Set(prevMessageIdsMap[fieldName]);\n fieldDescriptionIds.delete(id);\n return { ...prevMessageIdsMap, [fieldName]: fieldDescriptionIds };\n });\n }, []);\n const getFieldDescription: AriaDescriptionContextValue['getFieldDescription'] =\n React.useCallback(\n (fieldName) => Array.from(messageIdsMap[fieldName] ?? []).join(' ') || undefined,\n [messageIdsMap]\n );\n\n return (\n <ValidationProvider\n scope={__scopeForm}\n getFieldValidity={getFieldValidity}\n onFieldValidityChange={handleFieldValidityChange}\n getFieldCustomMatcherEntries={getFieldCustomMatcherEntries}\n onFieldCustomMatcherEntryAdd={handleFieldCustomMatcherAdd}\n onFieldCustomMatcherEntryRemove={handleFieldCustomMatcherRemove}\n getFieldCustomErrors={getFieldCustomErrors}\n onFieldCustomErrorsChange={handleFieldCustomErrorsChange}\n onFieldValiditionClear={handleFieldValiditionClear}\n >\n <AriaDescriptionProvider\n scope={__scopeForm}\n onFieldMessageIdAdd={handleFieldMessageIdAdd}\n onFieldMessageIdRemove={handleFieldMessageIdRemove}\n getFieldDescription={getFieldDescription}\n >\n <Primitive.form\n {...rootProps}\n ref={composedFormRef}\n // focus first invalid control when the form is submitted\n onInvalid={composeEventHandlers(props.onInvalid, (event) => {\n const firstInvalidControl = getFirstInvalidControl(event.currentTarget);\n if (firstInvalidControl === event.target) firstInvalidControl.focus();\n\n // prevent default browser UI for form validation\n event.preventDefault();\n })}\n // clear server errors when the form is re-submitted\n onSubmit={composeEventHandlers(props.onSubmit, onClearServerErrors, {\n checkForDefaultPrevented: false,\n })}\n // clear server errors when the form is reset\n onReset={composeEventHandlers(props.onReset, onClearServerErrors)}\n />\n </AriaDescriptionProvider>\n </ValidationProvider>\n );\n }\n);\n\nForm.displayName = FORM_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * FormField\n * -----------------------------------------------------------------------------------------------*/\n\nconst FIELD_NAME = 'FormField';\n\ntype FormFieldContextValue = {\n id: string;\n name: string;\n serverInvalid: boolean;\n};\nconst [FormFieldProvider, useFormFieldContext] =\n createFormContext<FormFieldContextValue>(FIELD_NAME);\n\ntype FormFieldElement = React.ElementRef<typeof Primitive.div>;\ntype PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface FormFieldProps extends PrimitiveDivProps {\n name: string;\n serverInvalid?: boolean;\n}\n\nconst FormField = React.forwardRef<FormFieldElement, FormFieldProps>(\n (props: ScopedProps<FormFieldProps>, forwardedRef) => {\n const { __scopeForm, name, serverInvalid = false, ...fieldProps } = props;\n const validationContext = useValidationContext(FIELD_NAME, __scopeForm);\n const validity = validationContext.getFieldValidity(name);\n const id = useId();\n\n return (\n <FormFieldProvider scope={__scopeForm} id={id} name={name} serverInvalid={serverInvalid}>\n <Primitive.div\n data-valid={getValidAttribute(validity, serverInvalid)}\n data-invalid={getInvalidAttribute(validity, serverInvalid)}\n {...fieldProps}\n ref={forwardedRef}\n />\n </FormFieldProvider>\n );\n }\n);\n\nFormField.displayName = FIELD_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * FormLabel\n * -----------------------------------------------------------------------------------------------*/\n\nconst LABEL_NAME = 'FormLabel';\n\ntype FormLabelElement = React.ElementRef<typeof LabelPrimitive>;\ntype LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive>;\ninterface FormLabelProps extends LabelProps {}\n\nconst FormLabel = React.forwardRef<FormLabelElement, FormLabelProps>(\n (props: ScopedProps<FormLabelProps>, forwardedRef) => {\n const { __scopeForm, ...labelProps } = props;\n const validationContext = useValidationContext(LABEL_NAME, __scopeForm);\n const fieldContext = useFormFieldContext(LABEL_NAME, __scopeForm);\n const htmlFor = labelProps.htmlFor || fieldContext.id;\n const validity = validationContext.getFieldValidity(fieldContext.name);\n\n return (\n <LabelPrimitive\n data-valid={getValidAttribute(validity, fieldContext.serverInvalid)}\n data-invalid={getInvalidAttribute(validity, fieldContext.serverInvalid)}\n {...labelProps}\n ref={forwardedRef}\n htmlFor={htmlFor}\n />\n );\n }\n);\n\nFormLabel.displayName = LABEL_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * FormControl\n * -----------------------------------------------------------------------------------------------*/\n\nconst CONTROL_NAME = 'FormControl';\n\ntype FormControlElement = React.ElementRef<typeof Primitive.input>;\ntype PrimitiveInputProps = React.ComponentPropsWithoutRef<typeof Primitive.input>;\ninterface FormControlProps extends PrimitiveInputProps {}\n\nconst FormControl = React.forwardRef<FormControlElement, FormControlProps>(\n (props: ScopedProps<FormControlProps>, forwardedRef) => {\n const { __scopeForm, ...controlProps } = props;\n\n const validationContext = useValidationContext(CONTROL_NAME, __scopeForm);\n const fieldContext = useFormFieldContext(CONTROL_NAME, __scopeForm);\n const ariaDescriptionContext = useAriaDescriptionContext(CONTROL_NAME, __scopeForm);\n\n const ref = React.useRef<FormControlElement>(null);\n const composedRef = useComposedRefs(forwardedRef, ref);\n const name = controlProps.name || fieldContext.name;\n const id = controlProps.id || fieldContext.id;\n const customMatcherEntries = validationContext.getFieldCustomMatcherEntries(name);\n\n const { onFieldValidityChange, onFieldCustomErrorsChange, onFieldValiditionClear } =\n validationContext;\n const updateControlValidity = React.useCallback(\n async (control: FormControlElement) => {\n //------------------------------------------------------------------------------------------\n // 1. first, if we have built-in errors we stop here\n\n if (hasBuiltInError(control.validity)) {\n const controlValidity = validityStateToObject(control.validity);\n onFieldValidityChange(name, controlValidity);\n return;\n }\n\n //------------------------------------------------------------------------------------------\n // 2. then gather the form data to give to custom matchers for cross-comparisons\n\n const formData = control.form ? new FormData(control.form) : new FormData();\n const matcherArgs: CustomMatcherArgs = [control.value, formData];\n\n //------------------------------------------------------------------------------------------\n // 3. split sync and async custom matcher entries\n\n const syncCustomMatcherEntries: Array<SyncCustomMatcherEntry> = [];\n const ayncCustomMatcherEntries: Array<AsyncCustomMatcherEntry> = [];\n customMatcherEntries.forEach((customMatcherEntry) => {\n if (isAsyncCustomMatcherEntry(customMatcherEntry, matcherArgs)) {\n ayncCustomMatcherEntries.push(customMatcherEntry);\n } else if (isSyncCustomMatcherEntry(customMatcherEntry)) {\n syncCustomMatcherEntries.push(customMatcherEntry);\n }\n });\n\n //------------------------------------------------------------------------------------------\n // 4. run sync custom matchers and update control validity / internal validity + errors\n\n const syncCustomErrors = syncCustomMatcherEntries.map(({ id, match }) => {\n return [id, match(...matcherArgs)] as const;\n });\n const syncCustomErrorsById = Object.fromEntries(syncCustomErrors);\n const hasSyncCustomErrors = Object.values(syncCustomErrorsById).some(Boolean);\n const hasCustomError = hasSyncCustomErrors;\n control.setCustomValidity(hasCustomError ? DEFAULT_INVALID_MESSAGE : '');\n const controlValidity = validityStateToObject(control.validity);\n onFieldValidityChange(name, controlValidity);\n onFieldCustomErrorsChange(name, syncCustomErrorsById);\n\n //------------------------------------------------------------------------------------------\n // 5. run async custom matchers and update control validity / internal validity + errors\n\n if (!hasSyncCustomErrors && ayncCustomMatcherEntries.length > 0) {\n const promisedCustomErrors = ayncCustomMatcherEntries.map(({ id, match }) =>\n match(...matcherArgs).then((matches) => [id, matches] as const)\n );\n const asyncCustomErrors = await Promise.all(promisedCustomErrors);\n const asyncCustomErrorsById = Object.fromEntries(asyncCustomErrors);\n const hasAsyncCustomErrors = Object.values(asyncCustomErrorsById).some(Boolean);\n const hasCustomError = hasAsyncCustomErrors;\n control.setCustomValidity(hasCustomError ? DEFAULT_INVALID_MESSAGE : '');\n const controlValidity = validityStateToObject(control.validity);\n onFieldValidityChange(name, controlValidity);\n onFieldCustomErrorsChange(name, asyncCustomErrorsById);\n }\n },\n [customMatcherEntries, name, onFieldCustomErrorsChange, onFieldValidityChange]\n );\n\n React.useEffect(() => {\n const control = ref.current;\n if (control) {\n // We only want validate on change (native `change` event, not React's `onChange`). This is primarily\n // a UX decision, we don't want to validate on every keystroke and React's `onChange` is the `input` event.\n const handleChange = () => updateControlValidity(control);\n control.addEventListener('change', handleChange);\n return () => control.removeEventListener('change', handleChange);\n }\n }, [updateControlValidity]);\n\n const resetControlValidity = React.useCallback(() => {\n const control = ref.current;\n if (control) {\n control.setCustomValidity('');\n onFieldValiditionClear(name);\n }\n }, [name, onFieldValiditionClear]);\n\n // reset validity and errors when the form is reset\n React.useEffect(() => {\n const form = ref.current?.form;\n if (form) {\n form.addEventListener('reset', resetControlValidity);\n return () => form.removeEventListener('reset', resetControlValidity);\n }\n }, [resetControlValidity]);\n\n // focus first invalid control when fields are set as invalid by server\n React.useEffect(() => {\n const control = ref.current;\n const form = control?.closest('form');\n if (form && fieldContext.serverInvalid) {\n const firstInvalidControl = getFirstInvalidControl(form);\n if (firstInvalidControl === control) firstInvalidControl.focus();\n }\n }, [fieldContext.serverInvalid]);\n\n const validity = validationContext.getFieldValidity(name);\n\n return (\n <Primitive.input\n data-valid={getValidAttribute(validity, fieldContext.serverInvalid)}\n data-invalid={getInvalidAttribute(validity, fieldContext.serverInvalid)}\n aria-invalid={fieldContext.serverInvalid ? true : undefined}\n aria-describedby={ariaDescriptionContext.getFieldDescription(name)}\n // disable default browser behaviour of showing built-in error message on hover\n title=\"\"\n {...controlProps}\n ref={composedRef}\n id={id}\n name={name}\n onInvalid={composeEventHandlers(props.onInvalid, (event) => {\n const control = event.currentTarget;\n updateControlValidity(control);\n })}\n onChange={composeEventHandlers(props.onChange, (event) => {\n // reset validity when user changes value\n resetControlValidity();\n })}\n />\n );\n }\n);\n\nFormControl.displayName = CONTROL_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * FormMessage\n * -----------------------------------------------------------------------------------------------*/\n\nconst validityMatchers = [\n 'badInput',\n 'patternMismatch',\n 'rangeOverflow',\n 'rangeUnderflow',\n 'stepMismatch',\n 'tooLong',\n 'tooShort',\n 'typeMismatch',\n 'valid',\n 'valueMissing',\n] as const;\ntype ValidityMatcher = (typeof validityMatchers)[number];\n\nconst DEFAULT_INVALID_MESSAGE = 'This value is not valid';\nconst DEFAULT_BUILT_IN_MESSAGES: Record<ValidityMatcher, string | undefined> = {\n badInput: DEFAULT_INVALID_MESSAGE,\n patternMismatch: 'This value does not match the required pattern',\n rangeOverflow: 'This value is too large',\n rangeUnderflow: 'This value is too small',\n stepMismatch: 'This value does not match the required step',\n tooLong: 'This value is too long',\n tooShort: 'This value is too short',\n typeMismatch: 'This value does not match the required type',\n valid: undefined,\n valueMissing: 'This value is missing',\n};\n\nconst MESSAGE_NAME = 'FormMessage';\n\ntype FormMessageElement = FormMessageImplElement;\ninterface FormMessageProps extends Omit<FormMessageImplProps, 'name'> {\n match?: ValidityMatcher | CustomMatcher;\n forceMatch?: boolean;\n name?: string;\n}\n\nconst FormMessage = React.forwardRef<FormMessageElement, FormMessageProps>(\n (props: ScopedProps<FormMessageProps>, forwardedRef) => {\n const { match, name: nameProp, ...messageProps } = props;\n const fieldContext = useFormFieldContext(MESSAGE_NAME, props.__scopeForm);\n const name = nameProp ?? fieldContext.name;\n\n if (match === undefined) {\n return (\n <FormMessageImpl {...messageProps} ref={forwardedRef} name={name}>\n {props.children || DEFAULT_INVALID_MESSAGE}\n </FormMessageImpl>\n );\n } else if (typeof match === 'function') {\n return <FormCustomMessage match={match} {...messageProps} ref={forwardedRef} name={name} />;\n } else {\n return <FormBuiltInMessage match={match} {...messageProps} ref={forwardedRef} name={name} />;\n }\n }\n);\n\nFormMessage.displayName = MESSAGE_NAME;\n\ntype FormBuiltInMessageElement = FormMessageImplElement;\ninterface FormBuiltInMessageProps extends FormMessageImplProps {\n match: ValidityMatcher;\n forceMatch?: boolean;\n name: string;\n}\n\nconst FormBuiltInMessage = React.forwardRef<FormBuiltInMessageElement, FormBuiltInMessageProps>(\n (props: ScopedProps<FormBuiltInMessageProps>, forwardedRef) => {\n const { match, forceMatch = false, name, children, ...messageProps } = props;\n const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);\n const validity = validationContext.getFieldValidity(name);\n const matches = forceMatch || validity?.[match];\n\n if (matches) {\n return (\n <FormMessageImpl ref={forwardedRef} {...messageProps} name={name}>\n {children ?? DEFAULT_BUILT_IN_MESSAGES[match]}\n </FormMessageImpl>\n );\n }\n\n return null;\n }\n);\n\ntype FormCustomMessageElement = React.ElementRef<typeof FormMessageImpl>;\ninterface FormCustomMessageProps extends React.ComponentPropsWithoutRef<typeof FormMessageImpl> {\n match: CustomMatcher;\n forceMatch?: boolean;\n name: string;\n}\n\nconst FormCustomMessage = React.forwardRef<FormCustomMessageElement, FormCustomMessageProps>(\n (props: ScopedProps<FormCustomMessageProps>, forwardedRef) => {\n const { match, forceMatch = false, name, id: idProp, children, ...messageProps } = props;\n const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);\n const ref = React.useRef<FormCustomMessageElement>(null);\n const composedRef = useComposedRefs(forwardedRef, ref);\n const _id = useId();\n const id = idProp ?? _id;\n\n const customMatcherEntry = React.useMemo(() => ({ id, match }), [id, match]);\n const { onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove } = validationContext;\n React.useEffect(() => {\n onFieldCustomMatcherEntryAdd(name, customMatcherEntry);\n return () => onFieldCustomMatcherEntryRemove(name, customMatcherEntry.id);\n }, [customMatcherEntry, name, onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove]);\n\n const validity = validationContext.getFieldValidity(name);\n const customErrors = validationContext.getFieldCustomErrors(name);\n const hasMatchingCustomError = customErrors[id];\n const matches =\n forceMatch || (validity && !hasBuiltInError(validity) && hasMatchingCustomError);\n\n if (matches) {\n return (\n <FormMessageImpl id={id} ref={composedRef} {...messageProps} name={name}>\n {children ?? DEFAULT_INVALID_MESSAGE}\n </FormMessageImpl>\n );\n }\n\n return null;\n }\n);\n\ntype FormMessageImplElement = React.ElementRef<typeof Primitive.span>;\ntype PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;\ninterface FormMessageImplProps extends PrimitiveSpanProps {\n name: string;\n}\n\nconst FormMessageImpl = React.forwardRef<FormMessageImplElement, FormMessageImplProps>(\n (props: ScopedProps<FormMessageImplProps>, forwardedRef) => {\n const { __scopeForm, id: idProp, name, ...messageProps } = props;\n const ariaDescriptionContext = useAriaDescriptionContext(MESSAGE_NAME, __scopeForm);\n const _id = useId();\n const id = idProp ?? _id;\n\n const { onFieldMessageIdAdd, onFieldMessageIdRemove } = ariaDescriptionContext;\n React.useEffect(() => {\n onFieldMessageIdAdd(name, id);\n return () => onFieldMessageIdRemove(name, id);\n }, [name, id, onFieldMessageIdAdd, onFieldMessageIdRemove]);\n\n return <Primitive.span id={id} {...messageProps} ref={forwardedRef} />;\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * FormValidityState\n * -----------------------------------------------------------------------------------------------*/\n\nconst VALIDITY_STATE_NAME = 'FormValidityState';\n\ninterface FormValidityStateProps {\n children(validity: ValidityState | undefined): React.ReactNode;\n name?: string;\n}\n\nconst FormValidityState = (props: ScopedProps<FormValidityStateProps>) => {\n const { __scopeForm, name: nameProp, children } = props;\n const validationContext = useValidationContext(VALIDITY_STATE_NAME, __scopeForm);\n const fieldContext = useFormFieldContext(VALIDITY_STATE_NAME, __scopeForm);\n const name = nameProp ?? fieldContext.name;\n const validity = validationContext.getFieldValidity(name);\n return <>{children(validity)}</>;\n};\n\nFormValidityState.displayName = VALIDITY_STATE_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * FormSubmit\n * -----------------------------------------------------------------------------------------------*/\n\nconst SUBMIT_NAME = 'FormSubmit';\n\ntype FormSubmitElement = React.ElementRef<typeof Primitive.button>;\ntype PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;\ninterface FormSubmitProps extends PrimitiveButtonProps {}\n\nconst FormSubmit = React.forwardRef<FormSubmitElement, FormSubmitProps>(\n (props: ScopedProps<FormSubmitProps>, forwardedRef) => {\n const { __scopeForm, ...submitProps } = props;\n return <Primitive.button type=\"submit\" {...submitProps} ref={forwardedRef} />;\n }\n);\n\nFormSubmit.displayName = SUBMIT_NAME;\n\n/* -----------------------------------------------------------------------------------------------*/\n\ntype ValidityStateKey = keyof ValidityState;\ntype SyncCustomMatcher = (value: string, formData: FormData) => boolean;\ntype AsyncCustomMatcher = (value: string, formData: FormData) => Promise<boolean>;\ntype CustomMatcher = SyncCustomMatcher | AsyncCustomMatcher;\ntype CustomMatcherEntry = { id: string; match: CustomMatcher };\ntype SyncCustomMatcherEntry = { id: string; match: SyncCustomMatcher };\ntype AsyncCustomMatcherEntry = { id: string; match: AsyncCustomMatcher };\ntype CustomMatcherArgs = [string, FormData];\n\nfunction validityStateToObject(validity: ValidityState) {\n const object: any = {};\n for (const key in validity) {\n object[key] = validity[key as ValidityStateKey];\n }\n return object as Record<ValidityStateKey, boolean>;\n}\n\nfunction isHTMLElement(element: any): element is HTMLElement {\n return element instanceof HTMLElement;\n}\n\nfunction isFormControl(element: any): element is { validity: ValidityState } {\n return 'validity' in element;\n}\n\nfunction isInvalid(control: HTMLElement) {\n return (\n isFormControl(control) &&\n (control.validity.valid === false || control.getAttribute('aria-invalid') === 'true')\n );\n}\n\nfunction getFirstInvalidControl(form: HTMLFormElement): HTMLElement | undefined {\n const elements = form.elements;\n const [firstInvalidControl] = Array.from(elements).filter(isHTMLElement).filter(isInvalid);\n return firstInvalidControl;\n}\n\nfunction isAsyncCustomMatcherEntry(\n entry: CustomMatcherEntry,\n args: CustomMatcherArgs\n): entry is AsyncCustomMatcherEntry {\n return entry.match.constructor.name === 'AsyncFunction' || returnsPromise(entry.match, args);\n}\n\nfunction isSyncCustomMatcherEntry(entry: CustomMatcherEntry): entry is SyncCustomMatcherEntry {\n return entry.match.constructor.name === 'Function';\n}\n\nfunction returnsPromise(func: Function, args: Array<unknown>) {\n return func(...args) instanceof Promise;\n}\n\nfunction hasBuiltInError(validity: ValidityState) {\n let error = false;\n for (const validityKey in validity) {\n const key = validityKey as ValidityStateKey;\n if (key !== 'valid' && key !== 'customError' && validity[key]) {\n error = true;\n break;\n }\n }\n return error;\n}\n\nfunction getValidAttribute(validity: ValidityState | undefined, serverInvalid: boolean) {\n if (validity?.valid === true && !serverInvalid) return true;\n return undefined;\n}\nfunction getInvalidAttribute(validity: ValidityState | undefined, serverInvalid: boolean) {\n if (validity?.valid === false || serverInvalid) return true;\n return undefined;\n}\n\n/* -----------------------------------------------------------------------------------------------*/\n\nconst Root = Form;\nconst Field = FormField;\nconst Label = FormLabel;\nconst Control = FormControl;\nconst Message = FormMessage;\nconst ValidityState = FormValidityState;\nconst Submit = FormSubmit;\n\nexport {\n createFormScope,\n //\n Form,\n FormField,\n FormLabel,\n FormControl,\n FormMessage,\n FormValidityState,\n FormSubmit,\n //\n Root,\n Field,\n Label,\n Control,\n Message,\n ValidityState,\n Submit,\n};\n\nexport type {\n FormProps,\n FormFieldProps,\n FormLabelProps,\n FormControlProps,\n FormMessageProps,\n FormValidityStateProps,\n FormSubmitProps,\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["LabelPrimitive", "controlValidity", "id", "hasCustomError"]
7
+ }
package/dist/index.mjs ADDED
@@ -0,0 +1,451 @@
1
+ "use client";
2
+
3
+ // packages/react/form/src/Form.tsx
4
+ import * as React from "react";
5
+ import { composeEventHandlers } from "@huin-core/primitive";
6
+ import { useComposedRefs } from "@huin-core/react-compose-refs";
7
+ import { createContextScope } from "@huin-core/react-context";
8
+ import { useId } from "@huin-core/react-id";
9
+ import { Label as LabelPrimitive } from "@huin-core/react-label";
10
+ import { Primitive } from "@huin-core/react-primitive";
11
+ import { Fragment, jsx } from "react/jsx-runtime";
12
+ var [createFormContext, createFormScope] = createContextScope("Form");
13
+ var FORM_NAME = "Form";
14
+ var [ValidationProvider, useValidationContext] = createFormContext(FORM_NAME);
15
+ var [AriaDescriptionProvider, useAriaDescriptionContext] = createFormContext(FORM_NAME);
16
+ var Form = React.forwardRef(
17
+ (props, forwardedRef) => {
18
+ const { __scopeForm, onClearServerErrors = () => {
19
+ }, ...rootProps } = props;
20
+ const formRef = React.useRef(null);
21
+ const composedFormRef = useComposedRefs(forwardedRef, formRef);
22
+ const [validityMap, setValidityMap] = React.useState({});
23
+ const getFieldValidity = React.useCallback(
24
+ (fieldName) => validityMap[fieldName],
25
+ [validityMap]
26
+ );
27
+ const handleFieldValidityChange = React.useCallback(
28
+ (fieldName, validity) => setValidityMap((prevValidityMap) => ({
29
+ ...prevValidityMap,
30
+ [fieldName]: { ...prevValidityMap[fieldName] ?? {}, ...validity }
31
+ })),
32
+ []
33
+ );
34
+ const handleFieldValiditionClear = React.useCallback((fieldName) => {
35
+ setValidityMap((prevValidityMap) => ({ ...prevValidityMap, [fieldName]: void 0 }));
36
+ setCustomErrorsMap((prevCustomErrorsMap) => ({ ...prevCustomErrorsMap, [fieldName]: {} }));
37
+ }, []);
38
+ const [customMatcherEntriesMap, setCustomMatcherEntriesMap] = React.useState({});
39
+ const getFieldCustomMatcherEntries = React.useCallback(
40
+ (fieldName) => customMatcherEntriesMap[fieldName] ?? [],
41
+ [customMatcherEntriesMap]
42
+ );
43
+ const handleFieldCustomMatcherAdd = React.useCallback((fieldName, matcherEntry) => {
44
+ setCustomMatcherEntriesMap((prevCustomMatcherEntriesMap) => ({
45
+ ...prevCustomMatcherEntriesMap,
46
+ [fieldName]: [...prevCustomMatcherEntriesMap[fieldName] ?? [], matcherEntry]
47
+ }));
48
+ }, []);
49
+ const handleFieldCustomMatcherRemove = React.useCallback((fieldName, matcherEntryId) => {
50
+ setCustomMatcherEntriesMap((prevCustomMatcherEntriesMap) => ({
51
+ ...prevCustomMatcherEntriesMap,
52
+ [fieldName]: (prevCustomMatcherEntriesMap[fieldName] ?? []).filter(
53
+ (matcherEntry) => matcherEntry.id !== matcherEntryId
54
+ )
55
+ }));
56
+ }, []);
57
+ const [customErrorsMap, setCustomErrorsMap] = React.useState({});
58
+ const getFieldCustomErrors = React.useCallback(
59
+ (fieldName) => customErrorsMap[fieldName] ?? {},
60
+ [customErrorsMap]
61
+ );
62
+ const handleFieldCustomErrorsChange = React.useCallback((fieldName, customErrors) => {
63
+ setCustomErrorsMap((prevCustomErrorsMap) => ({
64
+ ...prevCustomErrorsMap,
65
+ [fieldName]: { ...prevCustomErrorsMap[fieldName] ?? {}, ...customErrors }
66
+ }));
67
+ }, []);
68
+ const [messageIdsMap, setMessageIdsMap] = React.useState({});
69
+ const handleFieldMessageIdAdd = React.useCallback((fieldName, id) => {
70
+ setMessageIdsMap((prevMessageIdsMap) => {
71
+ const fieldDescriptionIds = new Set(prevMessageIdsMap[fieldName]).add(id);
72
+ return { ...prevMessageIdsMap, [fieldName]: fieldDescriptionIds };
73
+ });
74
+ }, []);
75
+ const handleFieldMessageIdRemove = React.useCallback((fieldName, id) => {
76
+ setMessageIdsMap((prevMessageIdsMap) => {
77
+ const fieldDescriptionIds = new Set(prevMessageIdsMap[fieldName]);
78
+ fieldDescriptionIds.delete(id);
79
+ return { ...prevMessageIdsMap, [fieldName]: fieldDescriptionIds };
80
+ });
81
+ }, []);
82
+ const getFieldDescription = React.useCallback(
83
+ (fieldName) => Array.from(messageIdsMap[fieldName] ?? []).join(" ") || void 0,
84
+ [messageIdsMap]
85
+ );
86
+ return /* @__PURE__ */ jsx(
87
+ ValidationProvider,
88
+ {
89
+ scope: __scopeForm,
90
+ getFieldValidity,
91
+ onFieldValidityChange: handleFieldValidityChange,
92
+ getFieldCustomMatcherEntries,
93
+ onFieldCustomMatcherEntryAdd: handleFieldCustomMatcherAdd,
94
+ onFieldCustomMatcherEntryRemove: handleFieldCustomMatcherRemove,
95
+ getFieldCustomErrors,
96
+ onFieldCustomErrorsChange: handleFieldCustomErrorsChange,
97
+ onFieldValiditionClear: handleFieldValiditionClear,
98
+ children: /* @__PURE__ */ jsx(
99
+ AriaDescriptionProvider,
100
+ {
101
+ scope: __scopeForm,
102
+ onFieldMessageIdAdd: handleFieldMessageIdAdd,
103
+ onFieldMessageIdRemove: handleFieldMessageIdRemove,
104
+ getFieldDescription,
105
+ children: /* @__PURE__ */ jsx(
106
+ Primitive.form,
107
+ {
108
+ ...rootProps,
109
+ ref: composedFormRef,
110
+ onInvalid: composeEventHandlers(props.onInvalid, (event) => {
111
+ const firstInvalidControl = getFirstInvalidControl(event.currentTarget);
112
+ if (firstInvalidControl === event.target) firstInvalidControl.focus();
113
+ event.preventDefault();
114
+ }),
115
+ onSubmit: composeEventHandlers(props.onSubmit, onClearServerErrors, {
116
+ checkForDefaultPrevented: false
117
+ }),
118
+ onReset: composeEventHandlers(props.onReset, onClearServerErrors)
119
+ }
120
+ )
121
+ }
122
+ )
123
+ }
124
+ );
125
+ }
126
+ );
127
+ Form.displayName = FORM_NAME;
128
+ var FIELD_NAME = "FormField";
129
+ var [FormFieldProvider, useFormFieldContext] = createFormContext(FIELD_NAME);
130
+ var FormField = React.forwardRef(
131
+ (props, forwardedRef) => {
132
+ const { __scopeForm, name, serverInvalid = false, ...fieldProps } = props;
133
+ const validationContext = useValidationContext(FIELD_NAME, __scopeForm);
134
+ const validity = validationContext.getFieldValidity(name);
135
+ const id = useId();
136
+ return /* @__PURE__ */ jsx(FormFieldProvider, { scope: __scopeForm, id, name, serverInvalid, children: /* @__PURE__ */ jsx(
137
+ Primitive.div,
138
+ {
139
+ "data-valid": getValidAttribute(validity, serverInvalid),
140
+ "data-invalid": getInvalidAttribute(validity, serverInvalid),
141
+ ...fieldProps,
142
+ ref: forwardedRef
143
+ }
144
+ ) });
145
+ }
146
+ );
147
+ FormField.displayName = FIELD_NAME;
148
+ var LABEL_NAME = "FormLabel";
149
+ var FormLabel = React.forwardRef(
150
+ (props, forwardedRef) => {
151
+ const { __scopeForm, ...labelProps } = props;
152
+ const validationContext = useValidationContext(LABEL_NAME, __scopeForm);
153
+ const fieldContext = useFormFieldContext(LABEL_NAME, __scopeForm);
154
+ const htmlFor = labelProps.htmlFor || fieldContext.id;
155
+ const validity = validationContext.getFieldValidity(fieldContext.name);
156
+ return /* @__PURE__ */ jsx(
157
+ LabelPrimitive,
158
+ {
159
+ "data-valid": getValidAttribute(validity, fieldContext.serverInvalid),
160
+ "data-invalid": getInvalidAttribute(validity, fieldContext.serverInvalid),
161
+ ...labelProps,
162
+ ref: forwardedRef,
163
+ htmlFor
164
+ }
165
+ );
166
+ }
167
+ );
168
+ FormLabel.displayName = LABEL_NAME;
169
+ var CONTROL_NAME = "FormControl";
170
+ var FormControl = React.forwardRef(
171
+ (props, forwardedRef) => {
172
+ const { __scopeForm, ...controlProps } = props;
173
+ const validationContext = useValidationContext(CONTROL_NAME, __scopeForm);
174
+ const fieldContext = useFormFieldContext(CONTROL_NAME, __scopeForm);
175
+ const ariaDescriptionContext = useAriaDescriptionContext(CONTROL_NAME, __scopeForm);
176
+ const ref = React.useRef(null);
177
+ const composedRef = useComposedRefs(forwardedRef, ref);
178
+ const name = controlProps.name || fieldContext.name;
179
+ const id = controlProps.id || fieldContext.id;
180
+ const customMatcherEntries = validationContext.getFieldCustomMatcherEntries(name);
181
+ const { onFieldValidityChange, onFieldCustomErrorsChange, onFieldValiditionClear } = validationContext;
182
+ const updateControlValidity = React.useCallback(
183
+ async (control) => {
184
+ if (hasBuiltInError(control.validity)) {
185
+ const controlValidity2 = validityStateToObject(control.validity);
186
+ onFieldValidityChange(name, controlValidity2);
187
+ return;
188
+ }
189
+ const formData = control.form ? new FormData(control.form) : new FormData();
190
+ const matcherArgs = [control.value, formData];
191
+ const syncCustomMatcherEntries = [];
192
+ const ayncCustomMatcherEntries = [];
193
+ customMatcherEntries.forEach((customMatcherEntry) => {
194
+ if (isAsyncCustomMatcherEntry(customMatcherEntry, matcherArgs)) {
195
+ ayncCustomMatcherEntries.push(customMatcherEntry);
196
+ } else if (isSyncCustomMatcherEntry(customMatcherEntry)) {
197
+ syncCustomMatcherEntries.push(customMatcherEntry);
198
+ }
199
+ });
200
+ const syncCustomErrors = syncCustomMatcherEntries.map(({ id: id2, match }) => {
201
+ return [id2, match(...matcherArgs)];
202
+ });
203
+ const syncCustomErrorsById = Object.fromEntries(syncCustomErrors);
204
+ const hasSyncCustomErrors = Object.values(syncCustomErrorsById).some(Boolean);
205
+ const hasCustomError = hasSyncCustomErrors;
206
+ control.setCustomValidity(hasCustomError ? DEFAULT_INVALID_MESSAGE : "");
207
+ const controlValidity = validityStateToObject(control.validity);
208
+ onFieldValidityChange(name, controlValidity);
209
+ onFieldCustomErrorsChange(name, syncCustomErrorsById);
210
+ if (!hasSyncCustomErrors && ayncCustomMatcherEntries.length > 0) {
211
+ const promisedCustomErrors = ayncCustomMatcherEntries.map(
212
+ ({ id: id2, match }) => match(...matcherArgs).then((matches) => [id2, matches])
213
+ );
214
+ const asyncCustomErrors = await Promise.all(promisedCustomErrors);
215
+ const asyncCustomErrorsById = Object.fromEntries(asyncCustomErrors);
216
+ const hasAsyncCustomErrors = Object.values(asyncCustomErrorsById).some(Boolean);
217
+ const hasCustomError2 = hasAsyncCustomErrors;
218
+ control.setCustomValidity(hasCustomError2 ? DEFAULT_INVALID_MESSAGE : "");
219
+ const controlValidity2 = validityStateToObject(control.validity);
220
+ onFieldValidityChange(name, controlValidity2);
221
+ onFieldCustomErrorsChange(name, asyncCustomErrorsById);
222
+ }
223
+ },
224
+ [customMatcherEntries, name, onFieldCustomErrorsChange, onFieldValidityChange]
225
+ );
226
+ React.useEffect(() => {
227
+ const control = ref.current;
228
+ if (control) {
229
+ const handleChange = () => updateControlValidity(control);
230
+ control.addEventListener("change", handleChange);
231
+ return () => control.removeEventListener("change", handleChange);
232
+ }
233
+ }, [updateControlValidity]);
234
+ const resetControlValidity = React.useCallback(() => {
235
+ const control = ref.current;
236
+ if (control) {
237
+ control.setCustomValidity("");
238
+ onFieldValiditionClear(name);
239
+ }
240
+ }, [name, onFieldValiditionClear]);
241
+ React.useEffect(() => {
242
+ const form = ref.current?.form;
243
+ if (form) {
244
+ form.addEventListener("reset", resetControlValidity);
245
+ return () => form.removeEventListener("reset", resetControlValidity);
246
+ }
247
+ }, [resetControlValidity]);
248
+ React.useEffect(() => {
249
+ const control = ref.current;
250
+ const form = control?.closest("form");
251
+ if (form && fieldContext.serverInvalid) {
252
+ const firstInvalidControl = getFirstInvalidControl(form);
253
+ if (firstInvalidControl === control) firstInvalidControl.focus();
254
+ }
255
+ }, [fieldContext.serverInvalid]);
256
+ const validity = validationContext.getFieldValidity(name);
257
+ return /* @__PURE__ */ jsx(
258
+ Primitive.input,
259
+ {
260
+ "data-valid": getValidAttribute(validity, fieldContext.serverInvalid),
261
+ "data-invalid": getInvalidAttribute(validity, fieldContext.serverInvalid),
262
+ "aria-invalid": fieldContext.serverInvalid ? true : void 0,
263
+ "aria-describedby": ariaDescriptionContext.getFieldDescription(name),
264
+ title: "",
265
+ ...controlProps,
266
+ ref: composedRef,
267
+ id,
268
+ name,
269
+ onInvalid: composeEventHandlers(props.onInvalid, (event) => {
270
+ const control = event.currentTarget;
271
+ updateControlValidity(control);
272
+ }),
273
+ onChange: composeEventHandlers(props.onChange, (event) => {
274
+ resetControlValidity();
275
+ })
276
+ }
277
+ );
278
+ }
279
+ );
280
+ FormControl.displayName = CONTROL_NAME;
281
+ var DEFAULT_INVALID_MESSAGE = "This value is not valid";
282
+ var DEFAULT_BUILT_IN_MESSAGES = {
283
+ badInput: DEFAULT_INVALID_MESSAGE,
284
+ patternMismatch: "This value does not match the required pattern",
285
+ rangeOverflow: "This value is too large",
286
+ rangeUnderflow: "This value is too small",
287
+ stepMismatch: "This value does not match the required step",
288
+ tooLong: "This value is too long",
289
+ tooShort: "This value is too short",
290
+ typeMismatch: "This value does not match the required type",
291
+ valid: void 0,
292
+ valueMissing: "This value is missing"
293
+ };
294
+ var MESSAGE_NAME = "FormMessage";
295
+ var FormMessage = React.forwardRef(
296
+ (props, forwardedRef) => {
297
+ const { match, name: nameProp, ...messageProps } = props;
298
+ const fieldContext = useFormFieldContext(MESSAGE_NAME, props.__scopeForm);
299
+ const name = nameProp ?? fieldContext.name;
300
+ if (match === void 0) {
301
+ return /* @__PURE__ */ jsx(FormMessageImpl, { ...messageProps, ref: forwardedRef, name, children: props.children || DEFAULT_INVALID_MESSAGE });
302
+ } else if (typeof match === "function") {
303
+ return /* @__PURE__ */ jsx(FormCustomMessage, { match, ...messageProps, ref: forwardedRef, name });
304
+ } else {
305
+ return /* @__PURE__ */ jsx(FormBuiltInMessage, { match, ...messageProps, ref: forwardedRef, name });
306
+ }
307
+ }
308
+ );
309
+ FormMessage.displayName = MESSAGE_NAME;
310
+ var FormBuiltInMessage = React.forwardRef(
311
+ (props, forwardedRef) => {
312
+ const { match, forceMatch = false, name, children, ...messageProps } = props;
313
+ const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);
314
+ const validity = validationContext.getFieldValidity(name);
315
+ const matches = forceMatch || validity?.[match];
316
+ if (matches) {
317
+ return /* @__PURE__ */ jsx(FormMessageImpl, { ref: forwardedRef, ...messageProps, name, children: children ?? DEFAULT_BUILT_IN_MESSAGES[match] });
318
+ }
319
+ return null;
320
+ }
321
+ );
322
+ var FormCustomMessage = React.forwardRef(
323
+ (props, forwardedRef) => {
324
+ const { match, forceMatch = false, name, id: idProp, children, ...messageProps } = props;
325
+ const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);
326
+ const ref = React.useRef(null);
327
+ const composedRef = useComposedRefs(forwardedRef, ref);
328
+ const _id = useId();
329
+ const id = idProp ?? _id;
330
+ const customMatcherEntry = React.useMemo(() => ({ id, match }), [id, match]);
331
+ const { onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove } = validationContext;
332
+ React.useEffect(() => {
333
+ onFieldCustomMatcherEntryAdd(name, customMatcherEntry);
334
+ return () => onFieldCustomMatcherEntryRemove(name, customMatcherEntry.id);
335
+ }, [customMatcherEntry, name, onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove]);
336
+ const validity = validationContext.getFieldValidity(name);
337
+ const customErrors = validationContext.getFieldCustomErrors(name);
338
+ const hasMatchingCustomError = customErrors[id];
339
+ const matches = forceMatch || validity && !hasBuiltInError(validity) && hasMatchingCustomError;
340
+ if (matches) {
341
+ return /* @__PURE__ */ jsx(FormMessageImpl, { id, ref: composedRef, ...messageProps, name, children: children ?? DEFAULT_INVALID_MESSAGE });
342
+ }
343
+ return null;
344
+ }
345
+ );
346
+ var FormMessageImpl = React.forwardRef(
347
+ (props, forwardedRef) => {
348
+ const { __scopeForm, id: idProp, name, ...messageProps } = props;
349
+ const ariaDescriptionContext = useAriaDescriptionContext(MESSAGE_NAME, __scopeForm);
350
+ const _id = useId();
351
+ const id = idProp ?? _id;
352
+ const { onFieldMessageIdAdd, onFieldMessageIdRemove } = ariaDescriptionContext;
353
+ React.useEffect(() => {
354
+ onFieldMessageIdAdd(name, id);
355
+ return () => onFieldMessageIdRemove(name, id);
356
+ }, [name, id, onFieldMessageIdAdd, onFieldMessageIdRemove]);
357
+ return /* @__PURE__ */ jsx(Primitive.span, { id, ...messageProps, ref: forwardedRef });
358
+ }
359
+ );
360
+ var VALIDITY_STATE_NAME = "FormValidityState";
361
+ var FormValidityState = (props) => {
362
+ const { __scopeForm, name: nameProp, children } = props;
363
+ const validationContext = useValidationContext(VALIDITY_STATE_NAME, __scopeForm);
364
+ const fieldContext = useFormFieldContext(VALIDITY_STATE_NAME, __scopeForm);
365
+ const name = nameProp ?? fieldContext.name;
366
+ const validity = validationContext.getFieldValidity(name);
367
+ return /* @__PURE__ */ jsx(Fragment, { children: children(validity) });
368
+ };
369
+ FormValidityState.displayName = VALIDITY_STATE_NAME;
370
+ var SUBMIT_NAME = "FormSubmit";
371
+ var FormSubmit = React.forwardRef(
372
+ (props, forwardedRef) => {
373
+ const { __scopeForm, ...submitProps } = props;
374
+ return /* @__PURE__ */ jsx(Primitive.button, { type: "submit", ...submitProps, ref: forwardedRef });
375
+ }
376
+ );
377
+ FormSubmit.displayName = SUBMIT_NAME;
378
+ function validityStateToObject(validity) {
379
+ const object = {};
380
+ for (const key in validity) {
381
+ object[key] = validity[key];
382
+ }
383
+ return object;
384
+ }
385
+ function isHTMLElement(element) {
386
+ return element instanceof HTMLElement;
387
+ }
388
+ function isFormControl(element) {
389
+ return "validity" in element;
390
+ }
391
+ function isInvalid(control) {
392
+ return isFormControl(control) && (control.validity.valid === false || control.getAttribute("aria-invalid") === "true");
393
+ }
394
+ function getFirstInvalidControl(form) {
395
+ const elements = form.elements;
396
+ const [firstInvalidControl] = Array.from(elements).filter(isHTMLElement).filter(isInvalid);
397
+ return firstInvalidControl;
398
+ }
399
+ function isAsyncCustomMatcherEntry(entry, args) {
400
+ return entry.match.constructor.name === "AsyncFunction" || returnsPromise(entry.match, args);
401
+ }
402
+ function isSyncCustomMatcherEntry(entry) {
403
+ return entry.match.constructor.name === "Function";
404
+ }
405
+ function returnsPromise(func, args) {
406
+ return func(...args) instanceof Promise;
407
+ }
408
+ function hasBuiltInError(validity) {
409
+ let error = false;
410
+ for (const validityKey in validity) {
411
+ const key = validityKey;
412
+ if (key !== "valid" && key !== "customError" && validity[key]) {
413
+ error = true;
414
+ break;
415
+ }
416
+ }
417
+ return error;
418
+ }
419
+ function getValidAttribute(validity, serverInvalid) {
420
+ if (validity?.valid === true && !serverInvalid) return true;
421
+ return void 0;
422
+ }
423
+ function getInvalidAttribute(validity, serverInvalid) {
424
+ if (validity?.valid === false || serverInvalid) return true;
425
+ return void 0;
426
+ }
427
+ var Root = Form;
428
+ var Field = FormField;
429
+ var Label = FormLabel;
430
+ var Control = FormControl;
431
+ var Message = FormMessage;
432
+ var ValidityState = FormValidityState;
433
+ var Submit = FormSubmit;
434
+ export {
435
+ Control,
436
+ Field,
437
+ Form,
438
+ FormControl,
439
+ FormField,
440
+ FormLabel,
441
+ FormMessage,
442
+ FormSubmit,
443
+ FormValidityState,
444
+ Label,
445
+ Message,
446
+ Root,
447
+ Submit,
448
+ ValidityState,
449
+ createFormScope
450
+ };
451
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/Form.tsx"],
4
+ "sourcesContent": ["import * as React from 'react';\nimport { composeEventHandlers } from '@huin-core/primitive';\nimport { useComposedRefs } from '@huin-core/react-compose-refs';\nimport { createContextScope } from '@huin-core/react-context';\nimport { useId } from '@huin-core/react-id';\nimport { Label as LabelPrimitive } from '@huin-core/react-label';\nimport { Primitive } from '@huin-core/react-primitive';\n\nimport type { Scope } from '@huin-core/react-context';\n\ntype ScopedProps<P> = P & { __scopeForm?: Scope };\nconst [createFormContext, createFormScope] = createContextScope('Form');\n\n/* -------------------------------------------------------------------------------------------------\n * Form\n * -----------------------------------------------------------------------------------------------*/\n\nconst FORM_NAME = 'Form';\n\ntype ValidityMap = { [fieldName: string]: ValidityState | undefined };\ntype CustomMatcherEntriesMap = { [fieldName: string]: CustomMatcherEntry[] };\ntype CustomErrorsMap = { [fieldName: string]: Record<string, boolean> };\n\ntype ValidationContextValue = {\n getFieldValidity(fieldName: string): ValidityState | undefined;\n onFieldValidityChange(fieldName: string, validity: ValidityState): void;\n\n getFieldCustomMatcherEntries(fieldName: string): CustomMatcherEntry[];\n onFieldCustomMatcherEntryAdd(fieldName: string, matcherEntry: CustomMatcherEntry): void;\n onFieldCustomMatcherEntryRemove(fieldName: string, matcherEntryId: string): void;\n\n getFieldCustomErrors(fieldName: string): Record<string, boolean>;\n onFieldCustomErrorsChange(fieldName: string, errors: Record<string, boolean>): void;\n\n onFieldValiditionClear(fieldName: string): void;\n};\nconst [ValidationProvider, useValidationContext] =\n createFormContext<ValidationContextValue>(FORM_NAME);\n\ntype MessageIdsMap = { [fieldName: string]: Set<string> };\n\ntype AriaDescriptionContextValue = {\n onFieldMessageIdAdd(fieldName: string, id: string): void;\n onFieldMessageIdRemove(fieldName: string, id: string): void;\n getFieldDescription(fieldName: string): string | undefined;\n};\nconst [AriaDescriptionProvider, useAriaDescriptionContext] =\n createFormContext<AriaDescriptionContextValue>(FORM_NAME);\n\ntype FormElement = React.ElementRef<typeof Primitive.form>;\ntype PrimitiveFormProps = React.ComponentPropsWithoutRef<typeof Primitive.form>;\ninterface FormProps extends PrimitiveFormProps {\n onClearServerErrors?(): void;\n}\n\nconst Form = React.forwardRef<FormElement, FormProps>(\n (props: ScopedProps<FormProps>, forwardedRef) => {\n const { __scopeForm, onClearServerErrors = () => {}, ...rootProps } = props;\n const formRef = React.useRef<HTMLFormElement>(null);\n const composedFormRef = useComposedRefs(forwardedRef, formRef);\n\n // native validity per field\n const [validityMap, setValidityMap] = React.useState<ValidityMap>({});\n const getFieldValidity: ValidationContextValue['getFieldValidity'] = React.useCallback(\n (fieldName) => validityMap[fieldName],\n [validityMap]\n );\n const handleFieldValidityChange: ValidationContextValue['onFieldValidityChange'] =\n React.useCallback(\n (fieldName, validity) =>\n setValidityMap((prevValidityMap) => ({\n ...prevValidityMap,\n [fieldName]: { ...(prevValidityMap[fieldName] ?? {}), ...validity },\n })),\n []\n );\n const handleFieldValiditionClear: ValidationContextValue['onFieldValiditionClear'] =\n React.useCallback((fieldName) => {\n setValidityMap((prevValidityMap) => ({ ...prevValidityMap, [fieldName]: undefined }));\n setCustomErrorsMap((prevCustomErrorsMap) => ({ ...prevCustomErrorsMap, [fieldName]: {} }));\n }, []);\n\n // custom matcher entries per field\n const [customMatcherEntriesMap, setCustomMatcherEntriesMap] =\n React.useState<CustomMatcherEntriesMap>({});\n const getFieldCustomMatcherEntries: ValidationContextValue['getFieldCustomMatcherEntries'] =\n React.useCallback(\n (fieldName) => customMatcherEntriesMap[fieldName] ?? [],\n [customMatcherEntriesMap]\n );\n const handleFieldCustomMatcherAdd: ValidationContextValue['onFieldCustomMatcherEntryAdd'] =\n React.useCallback((fieldName, matcherEntry) => {\n setCustomMatcherEntriesMap((prevCustomMatcherEntriesMap) => ({\n ...prevCustomMatcherEntriesMap,\n [fieldName]: [...(prevCustomMatcherEntriesMap[fieldName] ?? []), matcherEntry],\n }));\n }, []);\n const handleFieldCustomMatcherRemove: ValidationContextValue['onFieldCustomMatcherEntryRemove'] =\n React.useCallback((fieldName, matcherEntryId) => {\n setCustomMatcherEntriesMap((prevCustomMatcherEntriesMap) => ({\n ...prevCustomMatcherEntriesMap,\n [fieldName]: (prevCustomMatcherEntriesMap[fieldName] ?? []).filter(\n (matcherEntry) => matcherEntry.id !== matcherEntryId\n ),\n }));\n }, []);\n\n // custom errors per field\n const [customErrorsMap, setCustomErrorsMap] = React.useState<CustomErrorsMap>({});\n const getFieldCustomErrors: ValidationContextValue['getFieldCustomErrors'] = React.useCallback(\n (fieldName) => customErrorsMap[fieldName] ?? {},\n [customErrorsMap]\n );\n const handleFieldCustomErrorsChange: ValidationContextValue['onFieldCustomErrorsChange'] =\n React.useCallback((fieldName, customErrors) => {\n setCustomErrorsMap((prevCustomErrorsMap) => ({\n ...prevCustomErrorsMap,\n [fieldName]: { ...(prevCustomErrorsMap[fieldName] ?? {}), ...customErrors },\n }));\n }, []);\n\n // messageIds per field\n const [messageIdsMap, setMessageIdsMap] = React.useState<MessageIdsMap>({});\n const handleFieldMessageIdAdd: AriaDescriptionContextValue['onFieldMessageIdAdd'] =\n React.useCallback((fieldName, id) => {\n setMessageIdsMap((prevMessageIdsMap) => {\n const fieldDescriptionIds = new Set(prevMessageIdsMap[fieldName]).add(id);\n return { ...prevMessageIdsMap, [fieldName]: fieldDescriptionIds };\n });\n }, []);\n const handleFieldMessageIdRemove: AriaDescriptionContextValue['onFieldMessageIdRemove'] =\n React.useCallback((fieldName, id) => {\n setMessageIdsMap((prevMessageIdsMap) => {\n const fieldDescriptionIds = new Set(prevMessageIdsMap[fieldName]);\n fieldDescriptionIds.delete(id);\n return { ...prevMessageIdsMap, [fieldName]: fieldDescriptionIds };\n });\n }, []);\n const getFieldDescription: AriaDescriptionContextValue['getFieldDescription'] =\n React.useCallback(\n (fieldName) => Array.from(messageIdsMap[fieldName] ?? []).join(' ') || undefined,\n [messageIdsMap]\n );\n\n return (\n <ValidationProvider\n scope={__scopeForm}\n getFieldValidity={getFieldValidity}\n onFieldValidityChange={handleFieldValidityChange}\n getFieldCustomMatcherEntries={getFieldCustomMatcherEntries}\n onFieldCustomMatcherEntryAdd={handleFieldCustomMatcherAdd}\n onFieldCustomMatcherEntryRemove={handleFieldCustomMatcherRemove}\n getFieldCustomErrors={getFieldCustomErrors}\n onFieldCustomErrorsChange={handleFieldCustomErrorsChange}\n onFieldValiditionClear={handleFieldValiditionClear}\n >\n <AriaDescriptionProvider\n scope={__scopeForm}\n onFieldMessageIdAdd={handleFieldMessageIdAdd}\n onFieldMessageIdRemove={handleFieldMessageIdRemove}\n getFieldDescription={getFieldDescription}\n >\n <Primitive.form\n {...rootProps}\n ref={composedFormRef}\n // focus first invalid control when the form is submitted\n onInvalid={composeEventHandlers(props.onInvalid, (event) => {\n const firstInvalidControl = getFirstInvalidControl(event.currentTarget);\n if (firstInvalidControl === event.target) firstInvalidControl.focus();\n\n // prevent default browser UI for form validation\n event.preventDefault();\n })}\n // clear server errors when the form is re-submitted\n onSubmit={composeEventHandlers(props.onSubmit, onClearServerErrors, {\n checkForDefaultPrevented: false,\n })}\n // clear server errors when the form is reset\n onReset={composeEventHandlers(props.onReset, onClearServerErrors)}\n />\n </AriaDescriptionProvider>\n </ValidationProvider>\n );\n }\n);\n\nForm.displayName = FORM_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * FormField\n * -----------------------------------------------------------------------------------------------*/\n\nconst FIELD_NAME = 'FormField';\n\ntype FormFieldContextValue = {\n id: string;\n name: string;\n serverInvalid: boolean;\n};\nconst [FormFieldProvider, useFormFieldContext] =\n createFormContext<FormFieldContextValue>(FIELD_NAME);\n\ntype FormFieldElement = React.ElementRef<typeof Primitive.div>;\ntype PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface FormFieldProps extends PrimitiveDivProps {\n name: string;\n serverInvalid?: boolean;\n}\n\nconst FormField = React.forwardRef<FormFieldElement, FormFieldProps>(\n (props: ScopedProps<FormFieldProps>, forwardedRef) => {\n const { __scopeForm, name, serverInvalid = false, ...fieldProps } = props;\n const validationContext = useValidationContext(FIELD_NAME, __scopeForm);\n const validity = validationContext.getFieldValidity(name);\n const id = useId();\n\n return (\n <FormFieldProvider scope={__scopeForm} id={id} name={name} serverInvalid={serverInvalid}>\n <Primitive.div\n data-valid={getValidAttribute(validity, serverInvalid)}\n data-invalid={getInvalidAttribute(validity, serverInvalid)}\n {...fieldProps}\n ref={forwardedRef}\n />\n </FormFieldProvider>\n );\n }\n);\n\nFormField.displayName = FIELD_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * FormLabel\n * -----------------------------------------------------------------------------------------------*/\n\nconst LABEL_NAME = 'FormLabel';\n\ntype FormLabelElement = React.ElementRef<typeof LabelPrimitive>;\ntype LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive>;\ninterface FormLabelProps extends LabelProps {}\n\nconst FormLabel = React.forwardRef<FormLabelElement, FormLabelProps>(\n (props: ScopedProps<FormLabelProps>, forwardedRef) => {\n const { __scopeForm, ...labelProps } = props;\n const validationContext = useValidationContext(LABEL_NAME, __scopeForm);\n const fieldContext = useFormFieldContext(LABEL_NAME, __scopeForm);\n const htmlFor = labelProps.htmlFor || fieldContext.id;\n const validity = validationContext.getFieldValidity(fieldContext.name);\n\n return (\n <LabelPrimitive\n data-valid={getValidAttribute(validity, fieldContext.serverInvalid)}\n data-invalid={getInvalidAttribute(validity, fieldContext.serverInvalid)}\n {...labelProps}\n ref={forwardedRef}\n htmlFor={htmlFor}\n />\n );\n }\n);\n\nFormLabel.displayName = LABEL_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * FormControl\n * -----------------------------------------------------------------------------------------------*/\n\nconst CONTROL_NAME = 'FormControl';\n\ntype FormControlElement = React.ElementRef<typeof Primitive.input>;\ntype PrimitiveInputProps = React.ComponentPropsWithoutRef<typeof Primitive.input>;\ninterface FormControlProps extends PrimitiveInputProps {}\n\nconst FormControl = React.forwardRef<FormControlElement, FormControlProps>(\n (props: ScopedProps<FormControlProps>, forwardedRef) => {\n const { __scopeForm, ...controlProps } = props;\n\n const validationContext = useValidationContext(CONTROL_NAME, __scopeForm);\n const fieldContext = useFormFieldContext(CONTROL_NAME, __scopeForm);\n const ariaDescriptionContext = useAriaDescriptionContext(CONTROL_NAME, __scopeForm);\n\n const ref = React.useRef<FormControlElement>(null);\n const composedRef = useComposedRefs(forwardedRef, ref);\n const name = controlProps.name || fieldContext.name;\n const id = controlProps.id || fieldContext.id;\n const customMatcherEntries = validationContext.getFieldCustomMatcherEntries(name);\n\n const { onFieldValidityChange, onFieldCustomErrorsChange, onFieldValiditionClear } =\n validationContext;\n const updateControlValidity = React.useCallback(\n async (control: FormControlElement) => {\n //------------------------------------------------------------------------------------------\n // 1. first, if we have built-in errors we stop here\n\n if (hasBuiltInError(control.validity)) {\n const controlValidity = validityStateToObject(control.validity);\n onFieldValidityChange(name, controlValidity);\n return;\n }\n\n //------------------------------------------------------------------------------------------\n // 2. then gather the form data to give to custom matchers for cross-comparisons\n\n const formData = control.form ? new FormData(control.form) : new FormData();\n const matcherArgs: CustomMatcherArgs = [control.value, formData];\n\n //------------------------------------------------------------------------------------------\n // 3. split sync and async custom matcher entries\n\n const syncCustomMatcherEntries: Array<SyncCustomMatcherEntry> = [];\n const ayncCustomMatcherEntries: Array<AsyncCustomMatcherEntry> = [];\n customMatcherEntries.forEach((customMatcherEntry) => {\n if (isAsyncCustomMatcherEntry(customMatcherEntry, matcherArgs)) {\n ayncCustomMatcherEntries.push(customMatcherEntry);\n } else if (isSyncCustomMatcherEntry(customMatcherEntry)) {\n syncCustomMatcherEntries.push(customMatcherEntry);\n }\n });\n\n //------------------------------------------------------------------------------------------\n // 4. run sync custom matchers and update control validity / internal validity + errors\n\n const syncCustomErrors = syncCustomMatcherEntries.map(({ id, match }) => {\n return [id, match(...matcherArgs)] as const;\n });\n const syncCustomErrorsById = Object.fromEntries(syncCustomErrors);\n const hasSyncCustomErrors = Object.values(syncCustomErrorsById).some(Boolean);\n const hasCustomError = hasSyncCustomErrors;\n control.setCustomValidity(hasCustomError ? DEFAULT_INVALID_MESSAGE : '');\n const controlValidity = validityStateToObject(control.validity);\n onFieldValidityChange(name, controlValidity);\n onFieldCustomErrorsChange(name, syncCustomErrorsById);\n\n //------------------------------------------------------------------------------------------\n // 5. run async custom matchers and update control validity / internal validity + errors\n\n if (!hasSyncCustomErrors && ayncCustomMatcherEntries.length > 0) {\n const promisedCustomErrors = ayncCustomMatcherEntries.map(({ id, match }) =>\n match(...matcherArgs).then((matches) => [id, matches] as const)\n );\n const asyncCustomErrors = await Promise.all(promisedCustomErrors);\n const asyncCustomErrorsById = Object.fromEntries(asyncCustomErrors);\n const hasAsyncCustomErrors = Object.values(asyncCustomErrorsById).some(Boolean);\n const hasCustomError = hasAsyncCustomErrors;\n control.setCustomValidity(hasCustomError ? DEFAULT_INVALID_MESSAGE : '');\n const controlValidity = validityStateToObject(control.validity);\n onFieldValidityChange(name, controlValidity);\n onFieldCustomErrorsChange(name, asyncCustomErrorsById);\n }\n },\n [customMatcherEntries, name, onFieldCustomErrorsChange, onFieldValidityChange]\n );\n\n React.useEffect(() => {\n const control = ref.current;\n if (control) {\n // We only want validate on change (native `change` event, not React's `onChange`). This is primarily\n // a UX decision, we don't want to validate on every keystroke and React's `onChange` is the `input` event.\n const handleChange = () => updateControlValidity(control);\n control.addEventListener('change', handleChange);\n return () => control.removeEventListener('change', handleChange);\n }\n }, [updateControlValidity]);\n\n const resetControlValidity = React.useCallback(() => {\n const control = ref.current;\n if (control) {\n control.setCustomValidity('');\n onFieldValiditionClear(name);\n }\n }, [name, onFieldValiditionClear]);\n\n // reset validity and errors when the form is reset\n React.useEffect(() => {\n const form = ref.current?.form;\n if (form) {\n form.addEventListener('reset', resetControlValidity);\n return () => form.removeEventListener('reset', resetControlValidity);\n }\n }, [resetControlValidity]);\n\n // focus first invalid control when fields are set as invalid by server\n React.useEffect(() => {\n const control = ref.current;\n const form = control?.closest('form');\n if (form && fieldContext.serverInvalid) {\n const firstInvalidControl = getFirstInvalidControl(form);\n if (firstInvalidControl === control) firstInvalidControl.focus();\n }\n }, [fieldContext.serverInvalid]);\n\n const validity = validationContext.getFieldValidity(name);\n\n return (\n <Primitive.input\n data-valid={getValidAttribute(validity, fieldContext.serverInvalid)}\n data-invalid={getInvalidAttribute(validity, fieldContext.serverInvalid)}\n aria-invalid={fieldContext.serverInvalid ? true : undefined}\n aria-describedby={ariaDescriptionContext.getFieldDescription(name)}\n // disable default browser behaviour of showing built-in error message on hover\n title=\"\"\n {...controlProps}\n ref={composedRef}\n id={id}\n name={name}\n onInvalid={composeEventHandlers(props.onInvalid, (event) => {\n const control = event.currentTarget;\n updateControlValidity(control);\n })}\n onChange={composeEventHandlers(props.onChange, (event) => {\n // reset validity when user changes value\n resetControlValidity();\n })}\n />\n );\n }\n);\n\nFormControl.displayName = CONTROL_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * FormMessage\n * -----------------------------------------------------------------------------------------------*/\n\nconst validityMatchers = [\n 'badInput',\n 'patternMismatch',\n 'rangeOverflow',\n 'rangeUnderflow',\n 'stepMismatch',\n 'tooLong',\n 'tooShort',\n 'typeMismatch',\n 'valid',\n 'valueMissing',\n] as const;\ntype ValidityMatcher = (typeof validityMatchers)[number];\n\nconst DEFAULT_INVALID_MESSAGE = 'This value is not valid';\nconst DEFAULT_BUILT_IN_MESSAGES: Record<ValidityMatcher, string | undefined> = {\n badInput: DEFAULT_INVALID_MESSAGE,\n patternMismatch: 'This value does not match the required pattern',\n rangeOverflow: 'This value is too large',\n rangeUnderflow: 'This value is too small',\n stepMismatch: 'This value does not match the required step',\n tooLong: 'This value is too long',\n tooShort: 'This value is too short',\n typeMismatch: 'This value does not match the required type',\n valid: undefined,\n valueMissing: 'This value is missing',\n};\n\nconst MESSAGE_NAME = 'FormMessage';\n\ntype FormMessageElement = FormMessageImplElement;\ninterface FormMessageProps extends Omit<FormMessageImplProps, 'name'> {\n match?: ValidityMatcher | CustomMatcher;\n forceMatch?: boolean;\n name?: string;\n}\n\nconst FormMessage = React.forwardRef<FormMessageElement, FormMessageProps>(\n (props: ScopedProps<FormMessageProps>, forwardedRef) => {\n const { match, name: nameProp, ...messageProps } = props;\n const fieldContext = useFormFieldContext(MESSAGE_NAME, props.__scopeForm);\n const name = nameProp ?? fieldContext.name;\n\n if (match === undefined) {\n return (\n <FormMessageImpl {...messageProps} ref={forwardedRef} name={name}>\n {props.children || DEFAULT_INVALID_MESSAGE}\n </FormMessageImpl>\n );\n } else if (typeof match === 'function') {\n return <FormCustomMessage match={match} {...messageProps} ref={forwardedRef} name={name} />;\n } else {\n return <FormBuiltInMessage match={match} {...messageProps} ref={forwardedRef} name={name} />;\n }\n }\n);\n\nFormMessage.displayName = MESSAGE_NAME;\n\ntype FormBuiltInMessageElement = FormMessageImplElement;\ninterface FormBuiltInMessageProps extends FormMessageImplProps {\n match: ValidityMatcher;\n forceMatch?: boolean;\n name: string;\n}\n\nconst FormBuiltInMessage = React.forwardRef<FormBuiltInMessageElement, FormBuiltInMessageProps>(\n (props: ScopedProps<FormBuiltInMessageProps>, forwardedRef) => {\n const { match, forceMatch = false, name, children, ...messageProps } = props;\n const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);\n const validity = validationContext.getFieldValidity(name);\n const matches = forceMatch || validity?.[match];\n\n if (matches) {\n return (\n <FormMessageImpl ref={forwardedRef} {...messageProps} name={name}>\n {children ?? DEFAULT_BUILT_IN_MESSAGES[match]}\n </FormMessageImpl>\n );\n }\n\n return null;\n }\n);\n\ntype FormCustomMessageElement = React.ElementRef<typeof FormMessageImpl>;\ninterface FormCustomMessageProps extends React.ComponentPropsWithoutRef<typeof FormMessageImpl> {\n match: CustomMatcher;\n forceMatch?: boolean;\n name: string;\n}\n\nconst FormCustomMessage = React.forwardRef<FormCustomMessageElement, FormCustomMessageProps>(\n (props: ScopedProps<FormCustomMessageProps>, forwardedRef) => {\n const { match, forceMatch = false, name, id: idProp, children, ...messageProps } = props;\n const validationContext = useValidationContext(MESSAGE_NAME, messageProps.__scopeForm);\n const ref = React.useRef<FormCustomMessageElement>(null);\n const composedRef = useComposedRefs(forwardedRef, ref);\n const _id = useId();\n const id = idProp ?? _id;\n\n const customMatcherEntry = React.useMemo(() => ({ id, match }), [id, match]);\n const { onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove } = validationContext;\n React.useEffect(() => {\n onFieldCustomMatcherEntryAdd(name, customMatcherEntry);\n return () => onFieldCustomMatcherEntryRemove(name, customMatcherEntry.id);\n }, [customMatcherEntry, name, onFieldCustomMatcherEntryAdd, onFieldCustomMatcherEntryRemove]);\n\n const validity = validationContext.getFieldValidity(name);\n const customErrors = validationContext.getFieldCustomErrors(name);\n const hasMatchingCustomError = customErrors[id];\n const matches =\n forceMatch || (validity && !hasBuiltInError(validity) && hasMatchingCustomError);\n\n if (matches) {\n return (\n <FormMessageImpl id={id} ref={composedRef} {...messageProps} name={name}>\n {children ?? DEFAULT_INVALID_MESSAGE}\n </FormMessageImpl>\n );\n }\n\n return null;\n }\n);\n\ntype FormMessageImplElement = React.ElementRef<typeof Primitive.span>;\ntype PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;\ninterface FormMessageImplProps extends PrimitiveSpanProps {\n name: string;\n}\n\nconst FormMessageImpl = React.forwardRef<FormMessageImplElement, FormMessageImplProps>(\n (props: ScopedProps<FormMessageImplProps>, forwardedRef) => {\n const { __scopeForm, id: idProp, name, ...messageProps } = props;\n const ariaDescriptionContext = useAriaDescriptionContext(MESSAGE_NAME, __scopeForm);\n const _id = useId();\n const id = idProp ?? _id;\n\n const { onFieldMessageIdAdd, onFieldMessageIdRemove } = ariaDescriptionContext;\n React.useEffect(() => {\n onFieldMessageIdAdd(name, id);\n return () => onFieldMessageIdRemove(name, id);\n }, [name, id, onFieldMessageIdAdd, onFieldMessageIdRemove]);\n\n return <Primitive.span id={id} {...messageProps} ref={forwardedRef} />;\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * FormValidityState\n * -----------------------------------------------------------------------------------------------*/\n\nconst VALIDITY_STATE_NAME = 'FormValidityState';\n\ninterface FormValidityStateProps {\n children(validity: ValidityState | undefined): React.ReactNode;\n name?: string;\n}\n\nconst FormValidityState = (props: ScopedProps<FormValidityStateProps>) => {\n const { __scopeForm, name: nameProp, children } = props;\n const validationContext = useValidationContext(VALIDITY_STATE_NAME, __scopeForm);\n const fieldContext = useFormFieldContext(VALIDITY_STATE_NAME, __scopeForm);\n const name = nameProp ?? fieldContext.name;\n const validity = validationContext.getFieldValidity(name);\n return <>{children(validity)}</>;\n};\n\nFormValidityState.displayName = VALIDITY_STATE_NAME;\n\n/* -------------------------------------------------------------------------------------------------\n * FormSubmit\n * -----------------------------------------------------------------------------------------------*/\n\nconst SUBMIT_NAME = 'FormSubmit';\n\ntype FormSubmitElement = React.ElementRef<typeof Primitive.button>;\ntype PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;\ninterface FormSubmitProps extends PrimitiveButtonProps {}\n\nconst FormSubmit = React.forwardRef<FormSubmitElement, FormSubmitProps>(\n (props: ScopedProps<FormSubmitProps>, forwardedRef) => {\n const { __scopeForm, ...submitProps } = props;\n return <Primitive.button type=\"submit\" {...submitProps} ref={forwardedRef} />;\n }\n);\n\nFormSubmit.displayName = SUBMIT_NAME;\n\n/* -----------------------------------------------------------------------------------------------*/\n\ntype ValidityStateKey = keyof ValidityState;\ntype SyncCustomMatcher = (value: string, formData: FormData) => boolean;\ntype AsyncCustomMatcher = (value: string, formData: FormData) => Promise<boolean>;\ntype CustomMatcher = SyncCustomMatcher | AsyncCustomMatcher;\ntype CustomMatcherEntry = { id: string; match: CustomMatcher };\ntype SyncCustomMatcherEntry = { id: string; match: SyncCustomMatcher };\ntype AsyncCustomMatcherEntry = { id: string; match: AsyncCustomMatcher };\ntype CustomMatcherArgs = [string, FormData];\n\nfunction validityStateToObject(validity: ValidityState) {\n const object: any = {};\n for (const key in validity) {\n object[key] = validity[key as ValidityStateKey];\n }\n return object as Record<ValidityStateKey, boolean>;\n}\n\nfunction isHTMLElement(element: any): element is HTMLElement {\n return element instanceof HTMLElement;\n}\n\nfunction isFormControl(element: any): element is { validity: ValidityState } {\n return 'validity' in element;\n}\n\nfunction isInvalid(control: HTMLElement) {\n return (\n isFormControl(control) &&\n (control.validity.valid === false || control.getAttribute('aria-invalid') === 'true')\n );\n}\n\nfunction getFirstInvalidControl(form: HTMLFormElement): HTMLElement | undefined {\n const elements = form.elements;\n const [firstInvalidControl] = Array.from(elements).filter(isHTMLElement).filter(isInvalid);\n return firstInvalidControl;\n}\n\nfunction isAsyncCustomMatcherEntry(\n entry: CustomMatcherEntry,\n args: CustomMatcherArgs\n): entry is AsyncCustomMatcherEntry {\n return entry.match.constructor.name === 'AsyncFunction' || returnsPromise(entry.match, args);\n}\n\nfunction isSyncCustomMatcherEntry(entry: CustomMatcherEntry): entry is SyncCustomMatcherEntry {\n return entry.match.constructor.name === 'Function';\n}\n\nfunction returnsPromise(func: Function, args: Array<unknown>) {\n return func(...args) instanceof Promise;\n}\n\nfunction hasBuiltInError(validity: ValidityState) {\n let error = false;\n for (const validityKey in validity) {\n const key = validityKey as ValidityStateKey;\n if (key !== 'valid' && key !== 'customError' && validity[key]) {\n error = true;\n break;\n }\n }\n return error;\n}\n\nfunction getValidAttribute(validity: ValidityState | undefined, serverInvalid: boolean) {\n if (validity?.valid === true && !serverInvalid) return true;\n return undefined;\n}\nfunction getInvalidAttribute(validity: ValidityState | undefined, serverInvalid: boolean) {\n if (validity?.valid === false || serverInvalid) return true;\n return undefined;\n}\n\n/* -----------------------------------------------------------------------------------------------*/\n\nconst Root = Form;\nconst Field = FormField;\nconst Label = FormLabel;\nconst Control = FormControl;\nconst Message = FormMessage;\nconst ValidityState = FormValidityState;\nconst Submit = FormSubmit;\n\nexport {\n createFormScope,\n //\n Form,\n FormField,\n FormLabel,\n FormControl,\n FormMessage,\n FormValidityState,\n FormSubmit,\n //\n Root,\n Field,\n Label,\n Control,\n Message,\n ValidityState,\n Submit,\n};\n\nexport type {\n FormProps,\n FormFieldProps,\n FormLabelProps,\n FormControlProps,\n FormMessageProps,\n FormValidityStateProps,\n FormSubmitProps,\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["controlValidity", "id", "hasCustomError"]
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huin-core/react-form",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": {
@@ -20,7 +20,8 @@
20
20
  "types": "./dist/index.d.ts",
21
21
  "files": [
22
22
  "dist",
23
- "README.md"
23
+ "README.md",
24
+ "package.json"
24
25
  ],
25
26
  "sideEffects": false,
26
27
  "scripts": {