@radix-solid-js/form 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,454 @@
1
+ 'use strict';
2
+
3
+ var solidJs = require('solid-js');
4
+ var primitive = require('@radix-solid-js/primitive');
5
+ var composeRefs = require('@radix-solid-js/compose-refs');
6
+ var context = require('@radix-solid-js/context');
7
+ var id = require('@radix-solid-js/id');
8
+ var label = require('@radix-solid-js/label');
9
+ var primitiveComponent = require('@radix-solid-js/primitive-component');
10
+
11
+ // src/form.tsx
12
+ var [createFormContext, createFormScope] = context.createContextScope("Form");
13
+ var FORM_NAME = "Form";
14
+ var [ValidationProvider, useValidationContext] = createFormContext(FORM_NAME);
15
+ var [AriaDescriptionProvider, useAriaDescriptionContext] = createFormContext(FORM_NAME);
16
+ function Form(props) {
17
+ const [local, rest] = solidJs.splitProps(props, [
18
+ "__scopeForm",
19
+ "ref",
20
+ "onClearServerErrors",
21
+ "onInvalid",
22
+ "onSubmit",
23
+ "onReset"
24
+ ]);
25
+ const onClearServerErrors = local.onClearServerErrors ?? (() => {
26
+ });
27
+ const [validityMap, setValidityMap] = solidJs.createSignal({});
28
+ const getFieldValidity = (fieldName) => validityMap()[fieldName];
29
+ const handleFieldValidityChange = (fieldName, validity) => {
30
+ setValidityMap((prev) => ({
31
+ ...prev,
32
+ [fieldName]: { ...prev[fieldName] ?? {}, ...validity }
33
+ }));
34
+ };
35
+ const handleFieldValiditionClear = (fieldName) => {
36
+ setValidityMap((prev) => ({ ...prev, [fieldName]: void 0 }));
37
+ setCustomErrorsMap((prev) => ({ ...prev, [fieldName]: {} }));
38
+ };
39
+ const [customMatcherEntriesMap, setCustomMatcherEntriesMap] = solidJs.createSignal({});
40
+ const getFieldCustomMatcherEntries = (fieldName) => customMatcherEntriesMap()[fieldName] ?? [];
41
+ const handleFieldCustomMatcherAdd = (fieldName, matcherEntry) => {
42
+ setCustomMatcherEntriesMap((prev) => ({
43
+ ...prev,
44
+ [fieldName]: [...prev[fieldName] ?? [], matcherEntry]
45
+ }));
46
+ };
47
+ const handleFieldCustomMatcherRemove = (fieldName, matcherEntryId) => {
48
+ setCustomMatcherEntriesMap((prev) => ({
49
+ ...prev,
50
+ [fieldName]: (prev[fieldName] ?? []).filter((entry) => entry.id !== matcherEntryId)
51
+ }));
52
+ };
53
+ const [customErrorsMap, setCustomErrorsMap] = solidJs.createSignal({});
54
+ const getFieldCustomErrors = (fieldName) => customErrorsMap()[fieldName] ?? {};
55
+ const handleFieldCustomErrorsChange = (fieldName, customErrors) => {
56
+ setCustomErrorsMap((prev) => ({
57
+ ...prev,
58
+ [fieldName]: { ...prev[fieldName] ?? {}, ...customErrors }
59
+ }));
60
+ };
61
+ const [messageIdsMap, setMessageIdsMap] = solidJs.createSignal({});
62
+ const handleFieldMessageIdAdd = (fieldName, id) => {
63
+ setMessageIdsMap((prev) => {
64
+ const fieldDescriptionIds = new Set(prev[fieldName]).add(id);
65
+ return { ...prev, [fieldName]: fieldDescriptionIds };
66
+ });
67
+ };
68
+ const handleFieldMessageIdRemove = (fieldName, id) => {
69
+ setMessageIdsMap((prev) => {
70
+ const fieldDescriptionIds = new Set(prev[fieldName]);
71
+ fieldDescriptionIds.delete(id);
72
+ return { ...prev, [fieldName]: fieldDescriptionIds };
73
+ });
74
+ };
75
+ const getFieldDescription = (fieldName) => Array.from(messageIdsMap()[fieldName] ?? []).join(" ") || void 0;
76
+ return /* @__PURE__ */ React.createElement(
77
+ ValidationProvider,
78
+ {
79
+ scope: local.__scopeForm,
80
+ getFieldValidity,
81
+ onFieldValidityChange: handleFieldValidityChange,
82
+ getFieldCustomMatcherEntries,
83
+ onFieldCustomMatcherEntryAdd: handleFieldCustomMatcherAdd,
84
+ onFieldCustomMatcherEntryRemove: handleFieldCustomMatcherRemove,
85
+ getFieldCustomErrors,
86
+ onFieldCustomErrorsChange: handleFieldCustomErrorsChange,
87
+ onFieldValiditionClear: handleFieldValiditionClear
88
+ },
89
+ /* @__PURE__ */ React.createElement(
90
+ AriaDescriptionProvider,
91
+ {
92
+ scope: local.__scopeForm,
93
+ onFieldMessageIdAdd: handleFieldMessageIdAdd,
94
+ onFieldMessageIdRemove: handleFieldMessageIdRemove,
95
+ getFieldDescription
96
+ },
97
+ /* @__PURE__ */ React.createElement(
98
+ primitiveComponent.Primitive.form,
99
+ {
100
+ ...rest,
101
+ ref: local.ref,
102
+ onInvalid: primitive.composeEventHandlers(local.onInvalid, (event) => {
103
+ const target = event.currentTarget;
104
+ const firstInvalidControl = getFirstInvalidControl(target);
105
+ if (firstInvalidControl === event.target) firstInvalidControl.focus();
106
+ event.preventDefault();
107
+ }),
108
+ onSubmit: primitive.composeEventHandlers(local.onSubmit, onClearServerErrors, {
109
+ checkForDefaultPrevented: false
110
+ }),
111
+ onReset: primitive.composeEventHandlers(local.onReset, onClearServerErrors)
112
+ }
113
+ )
114
+ )
115
+ );
116
+ }
117
+ var FIELD_NAME = "FormField";
118
+ var [FormFieldProvider, useFormFieldContext] = createFormContext(FIELD_NAME);
119
+ function FormField(props) {
120
+ const [local, rest] = solidJs.splitProps(props, ["__scopeForm", "name", "serverInvalid"]);
121
+ const validationContext = useValidationContext(FIELD_NAME, local.__scopeForm);
122
+ const validity = () => validationContext.getFieldValidity(local.name);
123
+ const id$1 = id.createId();
124
+ return /* @__PURE__ */ React.createElement(
125
+ FormFieldProvider,
126
+ {
127
+ scope: local.__scopeForm,
128
+ id: id$1,
129
+ name: local.name,
130
+ serverInvalid: local.serverInvalid ?? false
131
+ },
132
+ /* @__PURE__ */ React.createElement(
133
+ primitiveComponent.Primitive.div,
134
+ {
135
+ "data-valid": getValidAttribute(validity(), local.serverInvalid ?? false),
136
+ "data-invalid": getInvalidAttribute(validity(), local.serverInvalid ?? false),
137
+ ...rest
138
+ }
139
+ )
140
+ );
141
+ }
142
+ var LABEL_NAME = "FormLabel";
143
+ function FormLabel(props) {
144
+ const [local, rest] = solidJs.splitProps(props, ["__scopeForm", "for"]);
145
+ const validationContext = useValidationContext(LABEL_NAME, local.__scopeForm);
146
+ const fieldContext = useFormFieldContext(LABEL_NAME, local.__scopeForm);
147
+ const htmlFor = () => local.for || fieldContext.id;
148
+ const validity = () => validationContext.getFieldValidity(fieldContext.name);
149
+ return /* @__PURE__ */ React.createElement(
150
+ label.Label,
151
+ {
152
+ "data-valid": getValidAttribute(validity(), fieldContext.serverInvalid),
153
+ "data-invalid": getInvalidAttribute(validity(), fieldContext.serverInvalid),
154
+ ...rest,
155
+ for: htmlFor()
156
+ }
157
+ );
158
+ }
159
+ var CONTROL_NAME = "FormControl";
160
+ function FormControl(props) {
161
+ const [local, rest] = solidJs.splitProps(props, [
162
+ "__scopeForm",
163
+ "ref",
164
+ "name",
165
+ "id",
166
+ "onInvalid",
167
+ "onChange"
168
+ ]);
169
+ const validationContext = useValidationContext(CONTROL_NAME, local.__scopeForm);
170
+ const fieldContext = useFormFieldContext(CONTROL_NAME, local.__scopeForm);
171
+ const ariaDescriptionContext = useAriaDescriptionContext(CONTROL_NAME, local.__scopeForm);
172
+ let controlRef;
173
+ const name = () => local.name || fieldContext.name;
174
+ const id = () => local.id || fieldContext.id;
175
+ const customMatcherEntries = () => validationContext.getFieldCustomMatcherEntries(name());
176
+ const updateControlValidity = async (control) => {
177
+ if (hasBuiltInError(control.validity)) {
178
+ const controlValidity2 = validityStateToObject(control.validity);
179
+ validationContext.onFieldValidityChange(name(), controlValidity2);
180
+ return;
181
+ }
182
+ const formData = control.form ? new FormData(control.form) : new FormData();
183
+ const matcherArgs = [control.value, formData];
184
+ const syncCustomMatcherEntries = [];
185
+ const asyncCustomMatcherEntries = [];
186
+ customMatcherEntries().forEach((customMatcherEntry) => {
187
+ if (isAsyncCustomMatcherEntry(customMatcherEntry, matcherArgs)) {
188
+ asyncCustomMatcherEntries.push(customMatcherEntry);
189
+ } else if (isSyncCustomMatcherEntry(customMatcherEntry)) {
190
+ syncCustomMatcherEntries.push(customMatcherEntry);
191
+ }
192
+ });
193
+ const syncCustomErrors = syncCustomMatcherEntries.map(({ id: id2, match }) => {
194
+ return [id2, match(...matcherArgs)];
195
+ });
196
+ const syncCustomErrorsById = Object.fromEntries(syncCustomErrors);
197
+ const hasSyncCustomErrors = Object.values(syncCustomErrorsById).some(Boolean);
198
+ const hasCustomError = hasSyncCustomErrors;
199
+ control.setCustomValidity(hasCustomError ? DEFAULT_INVALID_MESSAGE : "");
200
+ const controlValidity = validityStateToObject(control.validity);
201
+ validationContext.onFieldValidityChange(name(), controlValidity);
202
+ validationContext.onFieldCustomErrorsChange(name(), syncCustomErrorsById);
203
+ if (!hasSyncCustomErrors && asyncCustomMatcherEntries.length > 0) {
204
+ const promisedCustomErrors = asyncCustomMatcherEntries.map(
205
+ ({ id: id2, match }) => match(...matcherArgs).then((matches) => [id2, matches])
206
+ );
207
+ const asyncCustomErrors = await Promise.all(promisedCustomErrors);
208
+ const asyncCustomErrorsById = Object.fromEntries(asyncCustomErrors);
209
+ const hasAsyncCustomErrors = Object.values(asyncCustomErrorsById).some(Boolean);
210
+ const hasCustomError2 = hasAsyncCustomErrors;
211
+ control.setCustomValidity(hasCustomError2 ? DEFAULT_INVALID_MESSAGE : "");
212
+ const controlValidity2 = validityStateToObject(control.validity);
213
+ validationContext.onFieldValidityChange(name(), controlValidity2);
214
+ validationContext.onFieldCustomErrorsChange(name(), asyncCustomErrorsById);
215
+ }
216
+ };
217
+ solidJs.createEffect(() => {
218
+ const control = controlRef;
219
+ if (control) {
220
+ const handleChange = () => updateControlValidity(control);
221
+ control.addEventListener("change", handleChange);
222
+ solidJs.onCleanup(() => control.removeEventListener("change", handleChange));
223
+ }
224
+ });
225
+ const resetControlValidity = () => {
226
+ const control = controlRef;
227
+ if (control) {
228
+ control.setCustomValidity("");
229
+ validationContext.onFieldValiditionClear(name());
230
+ }
231
+ };
232
+ solidJs.createEffect(() => {
233
+ const form = controlRef?.form;
234
+ if (form) {
235
+ form.addEventListener("reset", resetControlValidity);
236
+ solidJs.onCleanup(() => form.removeEventListener("reset", resetControlValidity));
237
+ }
238
+ });
239
+ solidJs.createEffect(() => {
240
+ const control = controlRef;
241
+ const form = control?.closest("form");
242
+ if (form && fieldContext.serverInvalid) {
243
+ const firstInvalidControl = getFirstInvalidControl(form);
244
+ if (firstInvalidControl === control) firstInvalidControl.focus();
245
+ }
246
+ });
247
+ const validity = () => validationContext.getFieldValidity(name());
248
+ return /* @__PURE__ */ React.createElement(
249
+ primitiveComponent.Primitive.input,
250
+ {
251
+ "data-valid": getValidAttribute(validity(), fieldContext.serverInvalid),
252
+ "data-invalid": getInvalidAttribute(validity(), fieldContext.serverInvalid),
253
+ "aria-invalid": fieldContext.serverInvalid ? true : void 0,
254
+ "aria-describedby": ariaDescriptionContext.getFieldDescription(name()),
255
+ title: "",
256
+ ...rest,
257
+ ref: composeRefs.mergeRefs(local.ref, (el) => controlRef = el),
258
+ id: id(),
259
+ name: name(),
260
+ onInvalid: primitive.composeEventHandlers(local.onInvalid, (event) => {
261
+ const control = event.currentTarget;
262
+ updateControlValidity(control);
263
+ }),
264
+ onChange: primitive.composeEventHandlers(local.onChange, () => {
265
+ resetControlValidity();
266
+ })
267
+ }
268
+ );
269
+ }
270
+ var DEFAULT_INVALID_MESSAGE = "This value is not valid";
271
+ var DEFAULT_BUILT_IN_MESSAGES = {
272
+ badInput: DEFAULT_INVALID_MESSAGE,
273
+ patternMismatch: "This value does not match the required pattern",
274
+ rangeOverflow: "This value is too large",
275
+ rangeUnderflow: "This value is too small",
276
+ stepMismatch: "This value does not match the required step",
277
+ tooLong: "This value is too long",
278
+ tooShort: "This value is too short",
279
+ typeMismatch: "This value does not match the required type",
280
+ valid: void 0,
281
+ valueMissing: "This value is missing"
282
+ };
283
+ var MESSAGE_NAME = "FormMessage";
284
+ function FormMessage(props) {
285
+ const [local, rest] = solidJs.splitProps(props, ["__scopeForm", "match", "name", "forceMatch", "children"]);
286
+ const fieldContext = useFormFieldContext(MESSAGE_NAME, local.__scopeForm);
287
+ const name = () => local.name ?? fieldContext.name;
288
+ if (local.match === void 0) {
289
+ return /* @__PURE__ */ React.createElement(FormMessageImpl, { ...rest, __scopeForm: local.__scopeForm, name: name() }, local.children || DEFAULT_INVALID_MESSAGE);
290
+ } else if (typeof local.match === "function") {
291
+ return /* @__PURE__ */ React.createElement(
292
+ FormCustomMessage,
293
+ {
294
+ match: local.match,
295
+ forceMatch: local.forceMatch,
296
+ ...rest,
297
+ __scopeForm: local.__scopeForm,
298
+ name: name()
299
+ },
300
+ local.children
301
+ );
302
+ } else {
303
+ return /* @__PURE__ */ React.createElement(
304
+ FormBuiltInMessage,
305
+ {
306
+ match: local.match,
307
+ forceMatch: local.forceMatch,
308
+ ...rest,
309
+ __scopeForm: local.__scopeForm,
310
+ name: name()
311
+ },
312
+ local.children
313
+ );
314
+ }
315
+ }
316
+ function FormBuiltInMessage(props) {
317
+ const [local, rest] = solidJs.splitProps(props, ["__scopeForm", "match", "forceMatch", "name", "children"]);
318
+ const validationContext = useValidationContext(MESSAGE_NAME, local.__scopeForm);
319
+ const validity = () => validationContext.getFieldValidity(local.name);
320
+ const matches = () => local.forceMatch || validity()?.[local.match];
321
+ return /* @__PURE__ */ React.createElement(solidJs.Show, { when: matches() }, /* @__PURE__ */ React.createElement(FormMessageImpl, { ...rest, __scopeForm: local.__scopeForm, name: local.name }, local.children ?? DEFAULT_BUILT_IN_MESSAGES[local.match]));
322
+ }
323
+ function FormCustomMessage(props) {
324
+ const [local, rest] = solidJs.splitProps(props, [
325
+ "__scopeForm",
326
+ "match",
327
+ "forceMatch",
328
+ "name",
329
+ "id",
330
+ "ref",
331
+ "children"
332
+ ]);
333
+ const validationContext = useValidationContext(MESSAGE_NAME, local.__scopeForm);
334
+ const _id = id.createId();
335
+ const id$1 = () => local.id ?? _id;
336
+ solidJs.createEffect(() => {
337
+ const customMatcherEntry = { id: id$1(), match: local.match };
338
+ validationContext.onFieldCustomMatcherEntryAdd(local.name, customMatcherEntry);
339
+ solidJs.onCleanup(() => validationContext.onFieldCustomMatcherEntryRemove(local.name, customMatcherEntry.id));
340
+ });
341
+ const validity = () => validationContext.getFieldValidity(local.name);
342
+ const customErrors = () => validationContext.getFieldCustomErrors(local.name);
343
+ const hasMatchingCustomError = () => customErrors()[id$1()];
344
+ const matches = () => local.forceMatch || validity() && !hasBuiltInError(validity()) && hasMatchingCustomError();
345
+ return /* @__PURE__ */ React.createElement(solidJs.Show, { when: matches() }, /* @__PURE__ */ React.createElement(
346
+ FormMessageImpl,
347
+ {
348
+ id: id$1(),
349
+ ref: local.ref,
350
+ ...rest,
351
+ __scopeForm: local.__scopeForm,
352
+ name: local.name
353
+ },
354
+ local.children ?? DEFAULT_INVALID_MESSAGE
355
+ ));
356
+ }
357
+ function FormMessageImpl(props) {
358
+ const [local, rest] = solidJs.splitProps(props, ["__scopeForm", "id", "name"]);
359
+ const ariaDescriptionContext = useAriaDescriptionContext(MESSAGE_NAME, local.__scopeForm);
360
+ const _id = id.createId();
361
+ const id$1 = () => local.id ?? _id;
362
+ solidJs.createEffect(() => {
363
+ ariaDescriptionContext.onFieldMessageIdAdd(local.name, id$1());
364
+ solidJs.onCleanup(() => ariaDescriptionContext.onFieldMessageIdRemove(local.name, id$1()));
365
+ });
366
+ return /* @__PURE__ */ React.createElement(primitiveComponent.Primitive.span, { id: id$1(), ...rest });
367
+ }
368
+ var VALIDITY_STATE_NAME = "FormValidityState";
369
+ function FormValidityState(props) {
370
+ const [local] = solidJs.splitProps(props, ["__scopeForm", "name", "children"]);
371
+ const validationContext = useValidationContext(VALIDITY_STATE_NAME, local.__scopeForm);
372
+ const fieldContext = useFormFieldContext(VALIDITY_STATE_NAME, local.__scopeForm);
373
+ const name = () => local.name ?? fieldContext.name;
374
+ const validity = () => validationContext.getFieldValidity(name());
375
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, local.children(validity()));
376
+ }
377
+ function FormSubmit(props) {
378
+ const [, rest] = solidJs.splitProps(props, ["__scopeForm"]);
379
+ return /* @__PURE__ */ React.createElement(primitiveComponent.Primitive.button, { type: "submit", ...rest });
380
+ }
381
+ function validityStateToObject(validity) {
382
+ const object = {};
383
+ for (const key in validity) {
384
+ object[key] = validity[key];
385
+ }
386
+ return object;
387
+ }
388
+ function isHTMLElement(element) {
389
+ return element instanceof HTMLElement;
390
+ }
391
+ function isFormControl(element) {
392
+ return "validity" in element;
393
+ }
394
+ function isInvalid(control) {
395
+ return isFormControl(control) && (control.validity.valid === false || control.getAttribute("aria-invalid") === "true");
396
+ }
397
+ function getFirstInvalidControl(form) {
398
+ const elements = form.elements;
399
+ const [firstInvalidControl] = Array.from(elements).filter(isHTMLElement).filter(isInvalid);
400
+ return firstInvalidControl;
401
+ }
402
+ function isAsyncCustomMatcherEntry(entry, args) {
403
+ return entry.match.constructor.name === "AsyncFunction" || returnsPromise(entry.match, args);
404
+ }
405
+ function isSyncCustomMatcherEntry(entry) {
406
+ return entry.match.constructor.name === "Function";
407
+ }
408
+ function returnsPromise(func, args) {
409
+ return func(...args) instanceof Promise;
410
+ }
411
+ function hasBuiltInError(validity) {
412
+ let error = false;
413
+ for (const validityKey in validity) {
414
+ const key = validityKey;
415
+ if (key !== "valid" && key !== "customError" && validity[key]) {
416
+ error = true;
417
+ break;
418
+ }
419
+ }
420
+ return error;
421
+ }
422
+ function getValidAttribute(validity, serverInvalid) {
423
+ if (validity?.valid === true && !serverInvalid) return true;
424
+ return void 0;
425
+ }
426
+ function getInvalidAttribute(validity, serverInvalid) {
427
+ if (validity?.valid === false || serverInvalid) return true;
428
+ return void 0;
429
+ }
430
+ var Root = Form;
431
+ var Field = FormField;
432
+ var Label = FormLabel;
433
+ var Control = FormControl;
434
+ var Message = FormMessage;
435
+ var ValidityState = FormValidityState;
436
+ var Submit = FormSubmit;
437
+
438
+ exports.Control = Control;
439
+ exports.Field = Field;
440
+ exports.Form = Form;
441
+ exports.FormControl = FormControl;
442
+ exports.FormField = FormField;
443
+ exports.FormLabel = FormLabel;
444
+ exports.FormMessage = FormMessage;
445
+ exports.FormSubmit = FormSubmit;
446
+ exports.FormValidityState = FormValidityState;
447
+ exports.Label = Label;
448
+ exports.Message = Message;
449
+ exports.Root = Root;
450
+ exports.Submit = Submit;
451
+ exports.ValidityState = ValidityState;
452
+ exports.createFormScope = createFormScope;
453
+ //# sourceMappingURL=index.cjs.map
454
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/form.tsx"],"names":["createContextScope","splitProps","createSignal","Primitive","composeEventHandlers","id","createId","LabelPrimitive","controlValidity","hasCustomError","createEffect","onCleanup","mergeRefs","Show"],"mappings":"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","file":"index.cjs","sourcesContent":["import { type JSX, splitProps, createSignal, createEffect, onCleanup, Show } from 'solid-js';\nimport { composeEventHandlers } from '@radix-solid-js/primitive';\nimport { mergeRefs } from '@radix-solid-js/compose-refs';\nimport { createContextScope } from '@radix-solid-js/context';\nimport { createId } from '@radix-solid-js/id';\nimport { Label as LabelPrimitive, type LabelProps } from '@radix-solid-js/label';\nimport { Primitive, type PrimitiveProps } from '@radix-solid-js/primitive-component';\n\nimport type { Scope } from '@radix-solid-js/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\ninterface FormProps extends PrimitiveProps<'form'> {\n onClearServerErrors?(): void;\n}\n\nfunction Form(props: ScopedProps<FormProps>) {\n const [local, rest] = splitProps(props, [\n '__scopeForm',\n 'ref',\n 'onClearServerErrors',\n 'onInvalid',\n 'onSubmit',\n 'onReset',\n ]);\n\n const onClearServerErrors = local.onClearServerErrors ?? (() => {});\n\n // native validity per field\n const [validityMap, setValidityMap] = createSignal<ValidityMap>({});\n const getFieldValidity = (fieldName: string) => validityMap()[fieldName];\n const handleFieldValidityChange = (fieldName: string, validity: ValidityState) => {\n setValidityMap((prev) => ({\n ...prev,\n [fieldName]: { ...(prev[fieldName] ?? {}), ...validity },\n }));\n };\n const handleFieldValiditionClear = (fieldName: string) => {\n setValidityMap((prev) => ({ ...prev, [fieldName]: undefined }));\n setCustomErrorsMap((prev) => ({ ...prev, [fieldName]: {} }));\n };\n\n // custom matcher entries per field\n const [customMatcherEntriesMap, setCustomMatcherEntriesMap] =\n createSignal<CustomMatcherEntriesMap>({});\n const getFieldCustomMatcherEntries = (fieldName: string) =>\n customMatcherEntriesMap()[fieldName] ?? [];\n const handleFieldCustomMatcherAdd = (fieldName: string, matcherEntry: CustomMatcherEntry) => {\n setCustomMatcherEntriesMap((prev) => ({\n ...prev,\n [fieldName]: [...(prev[fieldName] ?? []), matcherEntry],\n }));\n };\n const handleFieldCustomMatcherRemove = (fieldName: string, matcherEntryId: string) => {\n setCustomMatcherEntriesMap((prev) => ({\n ...prev,\n [fieldName]: (prev[fieldName] ?? []).filter((entry) => entry.id !== matcherEntryId),\n }));\n };\n\n // custom errors per field\n const [customErrorsMap, setCustomErrorsMap] = createSignal<CustomErrorsMap>({});\n const getFieldCustomErrors = (fieldName: string) => customErrorsMap()[fieldName] ?? {};\n const handleFieldCustomErrorsChange = (fieldName: string, customErrors: Record<string, boolean>) => {\n setCustomErrorsMap((prev) => ({\n ...prev,\n [fieldName]: { ...(prev[fieldName] ?? {}), ...customErrors },\n }));\n };\n\n // messageIds per field\n const [messageIdsMap, setMessageIdsMap] = createSignal<MessageIdsMap>({});\n const handleFieldMessageIdAdd = (fieldName: string, id: string) => {\n setMessageIdsMap((prev) => {\n const fieldDescriptionIds = new Set(prev[fieldName]).add(id);\n return { ...prev, [fieldName]: fieldDescriptionIds };\n });\n };\n const handleFieldMessageIdRemove = (fieldName: string, id: string) => {\n setMessageIdsMap((prev) => {\n const fieldDescriptionIds = new Set(prev[fieldName]);\n fieldDescriptionIds.delete(id);\n return { ...prev, [fieldName]: fieldDescriptionIds };\n });\n };\n const getFieldDescription = (fieldName: string) =>\n Array.from(messageIdsMap()[fieldName] ?? []).join(' ') || undefined;\n\n return (\n <ValidationProvider\n scope={local.__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={local.__scopeForm}\n onFieldMessageIdAdd={handleFieldMessageIdAdd}\n onFieldMessageIdRemove={handleFieldMessageIdRemove}\n getFieldDescription={getFieldDescription}\n >\n <Primitive.form\n {...rest}\n ref={local.ref}\n // focus first invalid control when the form is submitted\n onInvalid={composeEventHandlers(local.onInvalid as any, (event: Event) => {\n const target = event.currentTarget as HTMLFormElement;\n const firstInvalidControl = getFirstInvalidControl(target);\n if (firstInvalidControl === event.target) firstInvalidControl.focus();\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(local.onSubmit as any, onClearServerErrors as any, {\n checkForDefaultPrevented: false,\n })}\n // clear server errors when the form is reset\n onReset={composeEventHandlers(local.onReset as any, onClearServerErrors as any)}\n />\n </AriaDescriptionProvider>\n </ValidationProvider>\n );\n}\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\ninterface FormFieldProps extends PrimitiveProps<'div'> {\n name: string;\n serverInvalid?: boolean;\n}\n\nfunction FormField(props: ScopedProps<FormFieldProps>) {\n const [local, rest] = splitProps(props, ['__scopeForm', 'name', 'serverInvalid']);\n const validationContext = useValidationContext(FIELD_NAME, local.__scopeForm);\n const validity = () => validationContext.getFieldValidity(local.name);\n const id = createId();\n\n return (\n <FormFieldProvider\n scope={local.__scopeForm}\n id={id}\n name={local.name}\n serverInvalid={local.serverInvalid ?? false}\n >\n <Primitive.div\n data-valid={getValidAttribute(validity(), local.serverInvalid ?? false)}\n data-invalid={getInvalidAttribute(validity(), local.serverInvalid ?? false)}\n {...rest}\n />\n </FormFieldProvider>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormLabel\n * -----------------------------------------------------------------------------------------------*/\n\nconst LABEL_NAME = 'FormLabel';\n\ninterface FormLabelProps extends LabelProps {}\n\nfunction FormLabel(props: ScopedProps<FormLabelProps>) {\n const [local, rest] = splitProps(props, ['__scopeForm', 'for']);\n const validationContext = useValidationContext(LABEL_NAME, local.__scopeForm);\n const fieldContext = useFormFieldContext(LABEL_NAME, local.__scopeForm);\n const htmlFor = () => local.for || 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 {...rest}\n for={htmlFor()}\n />\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormControl\n * -----------------------------------------------------------------------------------------------*/\n\nconst CONTROL_NAME = 'FormControl';\n\ninterface FormControlProps extends PrimitiveProps<'input'> {}\n\nfunction FormControl(props: ScopedProps<FormControlProps>) {\n const [local, rest] = splitProps(props, [\n '__scopeForm',\n 'ref',\n 'name',\n 'id',\n 'onInvalid',\n 'onChange',\n ]);\n\n const validationContext = useValidationContext(CONTROL_NAME, local.__scopeForm);\n const fieldContext = useFormFieldContext(CONTROL_NAME, local.__scopeForm);\n const ariaDescriptionContext = useAriaDescriptionContext(CONTROL_NAME, local.__scopeForm);\n\n let controlRef!: HTMLInputElement;\n const name = () => local.name || fieldContext.name;\n const id = () => local.id || fieldContext.id;\n const customMatcherEntries = () => validationContext.getFieldCustomMatcherEntries(name());\n\n const updateControlValidity = async (control: HTMLInputElement) => {\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 validationContext.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 asyncCustomMatcherEntries: Array<AsyncCustomMatcherEntry> = [];\n customMatcherEntries().forEach((customMatcherEntry) => {\n if (isAsyncCustomMatcherEntry(customMatcherEntry, matcherArgs)) {\n asyncCustomMatcherEntries.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 validationContext.onFieldValidityChange(name(), controlValidity);\n validationContext.onFieldCustomErrorsChange(name(), syncCustomErrorsById);\n\n //--------------------------------------------------------------------------------------------\n // 5. run async custom matchers and update control validity / internal validity + errors\n\n if (!hasSyncCustomErrors && asyncCustomMatcherEntries.length > 0) {\n const promisedCustomErrors = asyncCustomMatcherEntries.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 validationContext.onFieldValidityChange(name(), controlValidity);\n validationContext.onFieldCustomErrorsChange(name(), asyncCustomErrorsById);\n }\n };\n\n // Listen to native 'change' event for validation (not Solid's onChange which fires on input)\n createEffect(() => {\n const control = controlRef;\n if (control) {\n const handleChange = () => updateControlValidity(control);\n control.addEventListener('change', handleChange);\n onCleanup(() => control.removeEventListener('change', handleChange));\n }\n });\n\n const resetControlValidity = () => {\n const control = controlRef;\n if (control) {\n control.setCustomValidity('');\n validationContext.onFieldValiditionClear(name());\n }\n };\n\n // reset validity and errors when the form is reset\n createEffect(() => {\n const form = controlRef?.form;\n if (form) {\n form.addEventListener('reset', resetControlValidity);\n onCleanup(() => form.removeEventListener('reset', resetControlValidity));\n }\n });\n\n // focus first invalid control when fields are set as invalid by server\n createEffect(() => {\n const control = controlRef;\n const form = control?.closest('form');\n if (form && fieldContext.serverInvalid) {\n const firstInvalidControl = getFirstInvalidControl(form);\n if (firstInvalidControl === control) firstInvalidControl.focus();\n }\n });\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 {...rest}\n ref={mergeRefs(local.ref, (el) => (controlRef = el as HTMLInputElement))}\n id={id()}\n name={name()}\n onInvalid={composeEventHandlers(local.onInvalid as any, (event: Event) => {\n const control = event.currentTarget as HTMLInputElement;\n updateControlValidity(control);\n })}\n onChange={composeEventHandlers(local.onChange as any, () => {\n // reset validity when user changes value\n resetControlValidity();\n })}\n />\n );\n}\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\ninterface FormMessageProps extends Omit<FormMessageImplProps, 'name'> {\n match?: ValidityMatcher | CustomMatcher;\n forceMatch?: boolean;\n name?: string;\n}\n\nfunction FormMessage(props: ScopedProps<FormMessageProps>) {\n const [local, rest] = splitProps(props, ['__scopeForm', 'match', 'name', 'forceMatch', 'children']);\n const fieldContext = useFormFieldContext(MESSAGE_NAME, local.__scopeForm);\n const name = () => local.name ?? fieldContext.name;\n\n if (local.match === undefined) {\n return (\n <FormMessageImpl {...rest} __scopeForm={local.__scopeForm} name={name()}>\n {local.children || DEFAULT_INVALID_MESSAGE}\n </FormMessageImpl>\n );\n } else if (typeof local.match === 'function') {\n return (\n <FormCustomMessage\n match={local.match}\n forceMatch={local.forceMatch}\n {...rest}\n __scopeForm={local.__scopeForm}\n name={name()}\n >\n {local.children}\n </FormCustomMessage>\n );\n } else {\n return (\n <FormBuiltInMessage\n match={local.match}\n forceMatch={local.forceMatch}\n {...rest}\n __scopeForm={local.__scopeForm}\n name={name()}\n >\n {local.children}\n </FormBuiltInMessage>\n );\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormBuiltInMessage\n * -----------------------------------------------------------------------------------------------*/\n\ninterface FormBuiltInMessageProps extends FormMessageImplProps {\n match: ValidityMatcher;\n forceMatch?: boolean;\n name: string;\n}\n\nfunction FormBuiltInMessage(props: ScopedProps<FormBuiltInMessageProps>) {\n const [local, rest] = splitProps(props, ['__scopeForm', 'match', 'forceMatch', 'name', 'children']);\n const validationContext = useValidationContext(MESSAGE_NAME, local.__scopeForm);\n const validity = () => validationContext.getFieldValidity(local.name);\n const matches = () => local.forceMatch || validity()?.[local.match];\n\n return (\n <Show when={matches()}>\n <FormMessageImpl {...rest} __scopeForm={local.__scopeForm} name={local.name}>\n {local.children ?? DEFAULT_BUILT_IN_MESSAGES[local.match]}\n </FormMessageImpl>\n </Show>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormCustomMessage\n * -----------------------------------------------------------------------------------------------*/\n\ninterface FormCustomMessageProps extends FormMessageImplProps {\n match: CustomMatcher;\n forceMatch?: boolean;\n name: string;\n}\n\nfunction FormCustomMessage(props: ScopedProps<FormCustomMessageProps>) {\n const [local, rest] = splitProps(props, [\n '__scopeForm',\n 'match',\n 'forceMatch',\n 'name',\n 'id',\n 'ref',\n 'children',\n ]);\n const validationContext = useValidationContext(MESSAGE_NAME, local.__scopeForm);\n\n const _id = createId();\n const id = () => local.id ?? _id;\n\n // Register / unregister the custom matcher entry\n createEffect(() => {\n const customMatcherEntry: CustomMatcherEntry = { id: id(), match: local.match };\n validationContext.onFieldCustomMatcherEntryAdd(local.name, customMatcherEntry);\n onCleanup(() => validationContext.onFieldCustomMatcherEntryRemove(local.name, customMatcherEntry.id));\n });\n\n const validity = () => validationContext.getFieldValidity(local.name);\n const customErrors = () => validationContext.getFieldCustomErrors(local.name);\n const hasMatchingCustomError = () => customErrors()[id()];\n const matches = () =>\n local.forceMatch || (validity() && !hasBuiltInError(validity()!) && hasMatchingCustomError());\n\n return (\n <Show when={matches()}>\n <FormMessageImpl\n id={id()}\n ref={local.ref}\n {...rest}\n __scopeForm={local.__scopeForm}\n name={local.name}\n >\n {local.children ?? DEFAULT_INVALID_MESSAGE}\n </FormMessageImpl>\n </Show>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormMessageImpl\n * -----------------------------------------------------------------------------------------------*/\n\ninterface FormMessageImplProps extends PrimitiveProps<'span'> {\n name: string;\n}\n\nfunction FormMessageImpl(props: ScopedProps<FormMessageImplProps>) {\n const [local, rest] = splitProps(props, ['__scopeForm', 'id', 'name']);\n const ariaDescriptionContext = useAriaDescriptionContext(MESSAGE_NAME, local.__scopeForm);\n const _id = createId();\n const id = () => local.id ?? _id;\n\n // Register / unregister the message ID for aria-describedby\n createEffect(() => {\n ariaDescriptionContext.onFieldMessageIdAdd(local.name, id());\n onCleanup(() => ariaDescriptionContext.onFieldMessageIdRemove(local.name, id()));\n });\n\n return <Primitive.span id={id()} {...rest} />;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormValidityState\n * -----------------------------------------------------------------------------------------------*/\n\nconst VALIDITY_STATE_NAME = 'FormValidityState';\n\ninterface FormValidityStateProps {\n children(validity: ValidityState | undefined): JSX.Element;\n name?: string;\n}\n\nfunction FormValidityState(props: ScopedProps<FormValidityStateProps>) {\n const [local] = splitProps(props, ['__scopeForm', 'name', 'children']);\n const validationContext = useValidationContext(VALIDITY_STATE_NAME, local.__scopeForm);\n const fieldContext = useFormFieldContext(VALIDITY_STATE_NAME, local.__scopeForm);\n const name = () => local.name ?? fieldContext.name;\n const validity = () => validationContext.getFieldValidity(name());\n return <>{local.children(validity())}</>;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormSubmit\n * -----------------------------------------------------------------------------------------------*/\n\ninterface FormSubmitProps extends PrimitiveProps<'button'> {}\n\nfunction FormSubmit(props: ScopedProps<FormSubmitProps>) {\n const [, rest] = splitProps(props, ['__scopeForm']);\n return <Primitive.button type=\"submit\" {...rest} />;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Helper types and functions\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}\n\nfunction getInvalidAttribute(validity: ValidityState | undefined, serverInvalid: boolean) {\n if (validity?.valid === false || serverInvalid) return true;\n return undefined;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Aliases\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"]}
@@ -0,0 +1,56 @@
1
+ import * as _radix_solid_js_context from '@radix-solid-js/context';
2
+ import { Scope } from '@radix-solid-js/context';
3
+ import { JSX } from 'solid-js';
4
+ import { LabelProps } from '@radix-solid-js/label';
5
+ import { PrimitiveProps } from '@radix-solid-js/primitive-component';
6
+
7
+ type ScopedProps<P> = P & {
8
+ __scopeForm?: Scope;
9
+ };
10
+ declare const createFormScope: _radix_solid_js_context.CreateScope;
11
+ interface FormProps extends PrimitiveProps<'form'> {
12
+ onClearServerErrors?(): void;
13
+ }
14
+ declare function Form(props: ScopedProps<FormProps>): JSX.Element;
15
+ interface FormFieldProps extends PrimitiveProps<'div'> {
16
+ name: string;
17
+ serverInvalid?: boolean;
18
+ }
19
+ declare function FormField(props: ScopedProps<FormFieldProps>): JSX.Element;
20
+ interface FormLabelProps extends LabelProps {
21
+ }
22
+ declare function FormLabel(props: ScopedProps<FormLabelProps>): JSX.Element;
23
+ interface FormControlProps extends PrimitiveProps<'input'> {
24
+ }
25
+ declare function FormControl(props: ScopedProps<FormControlProps>): JSX.Element;
26
+ declare const _validityMatchers: readonly ["badInput", "patternMismatch", "rangeOverflow", "rangeUnderflow", "stepMismatch", "tooLong", "tooShort", "typeMismatch", "valid", "valueMissing"];
27
+ type ValidityMatcher = (typeof _validityMatchers)[number];
28
+ interface FormMessageProps extends Omit<FormMessageImplProps, 'name'> {
29
+ match?: ValidityMatcher | CustomMatcher;
30
+ forceMatch?: boolean;
31
+ name?: string;
32
+ }
33
+ declare function FormMessage(props: ScopedProps<FormMessageProps>): JSX.Element;
34
+ interface FormMessageImplProps extends PrimitiveProps<'span'> {
35
+ name: string;
36
+ }
37
+ interface FormValidityStateProps {
38
+ children(validity: ValidityState | undefined): JSX.Element;
39
+ name?: string;
40
+ }
41
+ declare function FormValidityState(props: ScopedProps<FormValidityStateProps>): JSX.Element;
42
+ interface FormSubmitProps extends PrimitiveProps<'button'> {
43
+ }
44
+ declare function FormSubmit(props: ScopedProps<FormSubmitProps>): JSX.Element;
45
+ type SyncCustomMatcher = (value: string, formData: FormData) => boolean;
46
+ type AsyncCustomMatcher = (value: string, formData: FormData) => Promise<boolean>;
47
+ type CustomMatcher = SyncCustomMatcher | AsyncCustomMatcher;
48
+ declare const Root: typeof Form;
49
+ declare const Field: typeof FormField;
50
+ declare const Label: typeof FormLabel;
51
+ declare const Control: typeof FormControl;
52
+ declare const Message: typeof FormMessage;
53
+ declare const ValidityState: typeof FormValidityState;
54
+ declare const Submit: typeof FormSubmit;
55
+
56
+ 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,56 @@
1
+ import * as _radix_solid_js_context from '@radix-solid-js/context';
2
+ import { Scope } from '@radix-solid-js/context';
3
+ import { JSX } from 'solid-js';
4
+ import { LabelProps } from '@radix-solid-js/label';
5
+ import { PrimitiveProps } from '@radix-solid-js/primitive-component';
6
+
7
+ type ScopedProps<P> = P & {
8
+ __scopeForm?: Scope;
9
+ };
10
+ declare const createFormScope: _radix_solid_js_context.CreateScope;
11
+ interface FormProps extends PrimitiveProps<'form'> {
12
+ onClearServerErrors?(): void;
13
+ }
14
+ declare function Form(props: ScopedProps<FormProps>): JSX.Element;
15
+ interface FormFieldProps extends PrimitiveProps<'div'> {
16
+ name: string;
17
+ serverInvalid?: boolean;
18
+ }
19
+ declare function FormField(props: ScopedProps<FormFieldProps>): JSX.Element;
20
+ interface FormLabelProps extends LabelProps {
21
+ }
22
+ declare function FormLabel(props: ScopedProps<FormLabelProps>): JSX.Element;
23
+ interface FormControlProps extends PrimitiveProps<'input'> {
24
+ }
25
+ declare function FormControl(props: ScopedProps<FormControlProps>): JSX.Element;
26
+ declare const _validityMatchers: readonly ["badInput", "patternMismatch", "rangeOverflow", "rangeUnderflow", "stepMismatch", "tooLong", "tooShort", "typeMismatch", "valid", "valueMissing"];
27
+ type ValidityMatcher = (typeof _validityMatchers)[number];
28
+ interface FormMessageProps extends Omit<FormMessageImplProps, 'name'> {
29
+ match?: ValidityMatcher | CustomMatcher;
30
+ forceMatch?: boolean;
31
+ name?: string;
32
+ }
33
+ declare function FormMessage(props: ScopedProps<FormMessageProps>): JSX.Element;
34
+ interface FormMessageImplProps extends PrimitiveProps<'span'> {
35
+ name: string;
36
+ }
37
+ interface FormValidityStateProps {
38
+ children(validity: ValidityState | undefined): JSX.Element;
39
+ name?: string;
40
+ }
41
+ declare function FormValidityState(props: ScopedProps<FormValidityStateProps>): JSX.Element;
42
+ interface FormSubmitProps extends PrimitiveProps<'button'> {
43
+ }
44
+ declare function FormSubmit(props: ScopedProps<FormSubmitProps>): JSX.Element;
45
+ type SyncCustomMatcher = (value: string, formData: FormData) => boolean;
46
+ type AsyncCustomMatcher = (value: string, formData: FormData) => Promise<boolean>;
47
+ type CustomMatcher = SyncCustomMatcher | AsyncCustomMatcher;
48
+ declare const Root: typeof Form;
49
+ declare const Field: typeof FormField;
50
+ declare const Label: typeof FormLabel;
51
+ declare const Control: typeof FormControl;
52
+ declare const Message: typeof FormMessage;
53
+ declare const ValidityState: typeof FormValidityState;
54
+ declare const Submit: typeof FormSubmit;
55
+
56
+ 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,438 @@
1
+ import { splitProps, createSignal, createEffect, Show, onCleanup } from 'solid-js';
2
+ import { composeEventHandlers } from '@radix-solid-js/primitive';
3
+ import { mergeRefs } from '@radix-solid-js/compose-refs';
4
+ import { createContextScope } from '@radix-solid-js/context';
5
+ import { createId } from '@radix-solid-js/id';
6
+ import { Label as Label$1 } from '@radix-solid-js/label';
7
+ import { Primitive } from '@radix-solid-js/primitive-component';
8
+
9
+ // src/form.tsx
10
+ var [createFormContext, createFormScope] = createContextScope("Form");
11
+ var FORM_NAME = "Form";
12
+ var [ValidationProvider, useValidationContext] = createFormContext(FORM_NAME);
13
+ var [AriaDescriptionProvider, useAriaDescriptionContext] = createFormContext(FORM_NAME);
14
+ function Form(props) {
15
+ const [local, rest] = splitProps(props, [
16
+ "__scopeForm",
17
+ "ref",
18
+ "onClearServerErrors",
19
+ "onInvalid",
20
+ "onSubmit",
21
+ "onReset"
22
+ ]);
23
+ const onClearServerErrors = local.onClearServerErrors ?? (() => {
24
+ });
25
+ const [validityMap, setValidityMap] = createSignal({});
26
+ const getFieldValidity = (fieldName) => validityMap()[fieldName];
27
+ const handleFieldValidityChange = (fieldName, validity) => {
28
+ setValidityMap((prev) => ({
29
+ ...prev,
30
+ [fieldName]: { ...prev[fieldName] ?? {}, ...validity }
31
+ }));
32
+ };
33
+ const handleFieldValiditionClear = (fieldName) => {
34
+ setValidityMap((prev) => ({ ...prev, [fieldName]: void 0 }));
35
+ setCustomErrorsMap((prev) => ({ ...prev, [fieldName]: {} }));
36
+ };
37
+ const [customMatcherEntriesMap, setCustomMatcherEntriesMap] = createSignal({});
38
+ const getFieldCustomMatcherEntries = (fieldName) => customMatcherEntriesMap()[fieldName] ?? [];
39
+ const handleFieldCustomMatcherAdd = (fieldName, matcherEntry) => {
40
+ setCustomMatcherEntriesMap((prev) => ({
41
+ ...prev,
42
+ [fieldName]: [...prev[fieldName] ?? [], matcherEntry]
43
+ }));
44
+ };
45
+ const handleFieldCustomMatcherRemove = (fieldName, matcherEntryId) => {
46
+ setCustomMatcherEntriesMap((prev) => ({
47
+ ...prev,
48
+ [fieldName]: (prev[fieldName] ?? []).filter((entry) => entry.id !== matcherEntryId)
49
+ }));
50
+ };
51
+ const [customErrorsMap, setCustomErrorsMap] = createSignal({});
52
+ const getFieldCustomErrors = (fieldName) => customErrorsMap()[fieldName] ?? {};
53
+ const handleFieldCustomErrorsChange = (fieldName, customErrors) => {
54
+ setCustomErrorsMap((prev) => ({
55
+ ...prev,
56
+ [fieldName]: { ...prev[fieldName] ?? {}, ...customErrors }
57
+ }));
58
+ };
59
+ const [messageIdsMap, setMessageIdsMap] = createSignal({});
60
+ const handleFieldMessageIdAdd = (fieldName, id) => {
61
+ setMessageIdsMap((prev) => {
62
+ const fieldDescriptionIds = new Set(prev[fieldName]).add(id);
63
+ return { ...prev, [fieldName]: fieldDescriptionIds };
64
+ });
65
+ };
66
+ const handleFieldMessageIdRemove = (fieldName, id) => {
67
+ setMessageIdsMap((prev) => {
68
+ const fieldDescriptionIds = new Set(prev[fieldName]);
69
+ fieldDescriptionIds.delete(id);
70
+ return { ...prev, [fieldName]: fieldDescriptionIds };
71
+ });
72
+ };
73
+ const getFieldDescription = (fieldName) => Array.from(messageIdsMap()[fieldName] ?? []).join(" ") || void 0;
74
+ return /* @__PURE__ */ React.createElement(
75
+ ValidationProvider,
76
+ {
77
+ scope: local.__scopeForm,
78
+ getFieldValidity,
79
+ onFieldValidityChange: handleFieldValidityChange,
80
+ getFieldCustomMatcherEntries,
81
+ onFieldCustomMatcherEntryAdd: handleFieldCustomMatcherAdd,
82
+ onFieldCustomMatcherEntryRemove: handleFieldCustomMatcherRemove,
83
+ getFieldCustomErrors,
84
+ onFieldCustomErrorsChange: handleFieldCustomErrorsChange,
85
+ onFieldValiditionClear: handleFieldValiditionClear
86
+ },
87
+ /* @__PURE__ */ React.createElement(
88
+ AriaDescriptionProvider,
89
+ {
90
+ scope: local.__scopeForm,
91
+ onFieldMessageIdAdd: handleFieldMessageIdAdd,
92
+ onFieldMessageIdRemove: handleFieldMessageIdRemove,
93
+ getFieldDescription
94
+ },
95
+ /* @__PURE__ */ React.createElement(
96
+ Primitive.form,
97
+ {
98
+ ...rest,
99
+ ref: local.ref,
100
+ onInvalid: composeEventHandlers(local.onInvalid, (event) => {
101
+ const target = event.currentTarget;
102
+ const firstInvalidControl = getFirstInvalidControl(target);
103
+ if (firstInvalidControl === event.target) firstInvalidControl.focus();
104
+ event.preventDefault();
105
+ }),
106
+ onSubmit: composeEventHandlers(local.onSubmit, onClearServerErrors, {
107
+ checkForDefaultPrevented: false
108
+ }),
109
+ onReset: composeEventHandlers(local.onReset, onClearServerErrors)
110
+ }
111
+ )
112
+ )
113
+ );
114
+ }
115
+ var FIELD_NAME = "FormField";
116
+ var [FormFieldProvider, useFormFieldContext] = createFormContext(FIELD_NAME);
117
+ function FormField(props) {
118
+ const [local, rest] = splitProps(props, ["__scopeForm", "name", "serverInvalid"]);
119
+ const validationContext = useValidationContext(FIELD_NAME, local.__scopeForm);
120
+ const validity = () => validationContext.getFieldValidity(local.name);
121
+ const id = createId();
122
+ return /* @__PURE__ */ React.createElement(
123
+ FormFieldProvider,
124
+ {
125
+ scope: local.__scopeForm,
126
+ id,
127
+ name: local.name,
128
+ serverInvalid: local.serverInvalid ?? false
129
+ },
130
+ /* @__PURE__ */ React.createElement(
131
+ Primitive.div,
132
+ {
133
+ "data-valid": getValidAttribute(validity(), local.serverInvalid ?? false),
134
+ "data-invalid": getInvalidAttribute(validity(), local.serverInvalid ?? false),
135
+ ...rest
136
+ }
137
+ )
138
+ );
139
+ }
140
+ var LABEL_NAME = "FormLabel";
141
+ function FormLabel(props) {
142
+ const [local, rest] = splitProps(props, ["__scopeForm", "for"]);
143
+ const validationContext = useValidationContext(LABEL_NAME, local.__scopeForm);
144
+ const fieldContext = useFormFieldContext(LABEL_NAME, local.__scopeForm);
145
+ const htmlFor = () => local.for || fieldContext.id;
146
+ const validity = () => validationContext.getFieldValidity(fieldContext.name);
147
+ return /* @__PURE__ */ React.createElement(
148
+ Label$1,
149
+ {
150
+ "data-valid": getValidAttribute(validity(), fieldContext.serverInvalid),
151
+ "data-invalid": getInvalidAttribute(validity(), fieldContext.serverInvalid),
152
+ ...rest,
153
+ for: htmlFor()
154
+ }
155
+ );
156
+ }
157
+ var CONTROL_NAME = "FormControl";
158
+ function FormControl(props) {
159
+ const [local, rest] = splitProps(props, [
160
+ "__scopeForm",
161
+ "ref",
162
+ "name",
163
+ "id",
164
+ "onInvalid",
165
+ "onChange"
166
+ ]);
167
+ const validationContext = useValidationContext(CONTROL_NAME, local.__scopeForm);
168
+ const fieldContext = useFormFieldContext(CONTROL_NAME, local.__scopeForm);
169
+ const ariaDescriptionContext = useAriaDescriptionContext(CONTROL_NAME, local.__scopeForm);
170
+ let controlRef;
171
+ const name = () => local.name || fieldContext.name;
172
+ const id = () => local.id || fieldContext.id;
173
+ const customMatcherEntries = () => validationContext.getFieldCustomMatcherEntries(name());
174
+ const updateControlValidity = async (control) => {
175
+ if (hasBuiltInError(control.validity)) {
176
+ const controlValidity2 = validityStateToObject(control.validity);
177
+ validationContext.onFieldValidityChange(name(), controlValidity2);
178
+ return;
179
+ }
180
+ const formData = control.form ? new FormData(control.form) : new FormData();
181
+ const matcherArgs = [control.value, formData];
182
+ const syncCustomMatcherEntries = [];
183
+ const asyncCustomMatcherEntries = [];
184
+ customMatcherEntries().forEach((customMatcherEntry) => {
185
+ if (isAsyncCustomMatcherEntry(customMatcherEntry, matcherArgs)) {
186
+ asyncCustomMatcherEntries.push(customMatcherEntry);
187
+ } else if (isSyncCustomMatcherEntry(customMatcherEntry)) {
188
+ syncCustomMatcherEntries.push(customMatcherEntry);
189
+ }
190
+ });
191
+ const syncCustomErrors = syncCustomMatcherEntries.map(({ id: id2, match }) => {
192
+ return [id2, match(...matcherArgs)];
193
+ });
194
+ const syncCustomErrorsById = Object.fromEntries(syncCustomErrors);
195
+ const hasSyncCustomErrors = Object.values(syncCustomErrorsById).some(Boolean);
196
+ const hasCustomError = hasSyncCustomErrors;
197
+ control.setCustomValidity(hasCustomError ? DEFAULT_INVALID_MESSAGE : "");
198
+ const controlValidity = validityStateToObject(control.validity);
199
+ validationContext.onFieldValidityChange(name(), controlValidity);
200
+ validationContext.onFieldCustomErrorsChange(name(), syncCustomErrorsById);
201
+ if (!hasSyncCustomErrors && asyncCustomMatcherEntries.length > 0) {
202
+ const promisedCustomErrors = asyncCustomMatcherEntries.map(
203
+ ({ id: id2, match }) => match(...matcherArgs).then((matches) => [id2, matches])
204
+ );
205
+ const asyncCustomErrors = await Promise.all(promisedCustomErrors);
206
+ const asyncCustomErrorsById = Object.fromEntries(asyncCustomErrors);
207
+ const hasAsyncCustomErrors = Object.values(asyncCustomErrorsById).some(Boolean);
208
+ const hasCustomError2 = hasAsyncCustomErrors;
209
+ control.setCustomValidity(hasCustomError2 ? DEFAULT_INVALID_MESSAGE : "");
210
+ const controlValidity2 = validityStateToObject(control.validity);
211
+ validationContext.onFieldValidityChange(name(), controlValidity2);
212
+ validationContext.onFieldCustomErrorsChange(name(), asyncCustomErrorsById);
213
+ }
214
+ };
215
+ createEffect(() => {
216
+ const control = controlRef;
217
+ if (control) {
218
+ const handleChange = () => updateControlValidity(control);
219
+ control.addEventListener("change", handleChange);
220
+ onCleanup(() => control.removeEventListener("change", handleChange));
221
+ }
222
+ });
223
+ const resetControlValidity = () => {
224
+ const control = controlRef;
225
+ if (control) {
226
+ control.setCustomValidity("");
227
+ validationContext.onFieldValiditionClear(name());
228
+ }
229
+ };
230
+ createEffect(() => {
231
+ const form = controlRef?.form;
232
+ if (form) {
233
+ form.addEventListener("reset", resetControlValidity);
234
+ onCleanup(() => form.removeEventListener("reset", resetControlValidity));
235
+ }
236
+ });
237
+ createEffect(() => {
238
+ const control = controlRef;
239
+ const form = control?.closest("form");
240
+ if (form && fieldContext.serverInvalid) {
241
+ const firstInvalidControl = getFirstInvalidControl(form);
242
+ if (firstInvalidControl === control) firstInvalidControl.focus();
243
+ }
244
+ });
245
+ const validity = () => validationContext.getFieldValidity(name());
246
+ return /* @__PURE__ */ React.createElement(
247
+ Primitive.input,
248
+ {
249
+ "data-valid": getValidAttribute(validity(), fieldContext.serverInvalid),
250
+ "data-invalid": getInvalidAttribute(validity(), fieldContext.serverInvalid),
251
+ "aria-invalid": fieldContext.serverInvalid ? true : void 0,
252
+ "aria-describedby": ariaDescriptionContext.getFieldDescription(name()),
253
+ title: "",
254
+ ...rest,
255
+ ref: mergeRefs(local.ref, (el) => controlRef = el),
256
+ id: id(),
257
+ name: name(),
258
+ onInvalid: composeEventHandlers(local.onInvalid, (event) => {
259
+ const control = event.currentTarget;
260
+ updateControlValidity(control);
261
+ }),
262
+ onChange: composeEventHandlers(local.onChange, () => {
263
+ resetControlValidity();
264
+ })
265
+ }
266
+ );
267
+ }
268
+ var DEFAULT_INVALID_MESSAGE = "This value is not valid";
269
+ var DEFAULT_BUILT_IN_MESSAGES = {
270
+ badInput: DEFAULT_INVALID_MESSAGE,
271
+ patternMismatch: "This value does not match the required pattern",
272
+ rangeOverflow: "This value is too large",
273
+ rangeUnderflow: "This value is too small",
274
+ stepMismatch: "This value does not match the required step",
275
+ tooLong: "This value is too long",
276
+ tooShort: "This value is too short",
277
+ typeMismatch: "This value does not match the required type",
278
+ valid: void 0,
279
+ valueMissing: "This value is missing"
280
+ };
281
+ var MESSAGE_NAME = "FormMessage";
282
+ function FormMessage(props) {
283
+ const [local, rest] = splitProps(props, ["__scopeForm", "match", "name", "forceMatch", "children"]);
284
+ const fieldContext = useFormFieldContext(MESSAGE_NAME, local.__scopeForm);
285
+ const name = () => local.name ?? fieldContext.name;
286
+ if (local.match === void 0) {
287
+ return /* @__PURE__ */ React.createElement(FormMessageImpl, { ...rest, __scopeForm: local.__scopeForm, name: name() }, local.children || DEFAULT_INVALID_MESSAGE);
288
+ } else if (typeof local.match === "function") {
289
+ return /* @__PURE__ */ React.createElement(
290
+ FormCustomMessage,
291
+ {
292
+ match: local.match,
293
+ forceMatch: local.forceMatch,
294
+ ...rest,
295
+ __scopeForm: local.__scopeForm,
296
+ name: name()
297
+ },
298
+ local.children
299
+ );
300
+ } else {
301
+ return /* @__PURE__ */ React.createElement(
302
+ FormBuiltInMessage,
303
+ {
304
+ match: local.match,
305
+ forceMatch: local.forceMatch,
306
+ ...rest,
307
+ __scopeForm: local.__scopeForm,
308
+ name: name()
309
+ },
310
+ local.children
311
+ );
312
+ }
313
+ }
314
+ function FormBuiltInMessage(props) {
315
+ const [local, rest] = splitProps(props, ["__scopeForm", "match", "forceMatch", "name", "children"]);
316
+ const validationContext = useValidationContext(MESSAGE_NAME, local.__scopeForm);
317
+ const validity = () => validationContext.getFieldValidity(local.name);
318
+ const matches = () => local.forceMatch || validity()?.[local.match];
319
+ return /* @__PURE__ */ React.createElement(Show, { when: matches() }, /* @__PURE__ */ React.createElement(FormMessageImpl, { ...rest, __scopeForm: local.__scopeForm, name: local.name }, local.children ?? DEFAULT_BUILT_IN_MESSAGES[local.match]));
320
+ }
321
+ function FormCustomMessage(props) {
322
+ const [local, rest] = splitProps(props, [
323
+ "__scopeForm",
324
+ "match",
325
+ "forceMatch",
326
+ "name",
327
+ "id",
328
+ "ref",
329
+ "children"
330
+ ]);
331
+ const validationContext = useValidationContext(MESSAGE_NAME, local.__scopeForm);
332
+ const _id = createId();
333
+ const id = () => local.id ?? _id;
334
+ createEffect(() => {
335
+ const customMatcherEntry = { id: id(), match: local.match };
336
+ validationContext.onFieldCustomMatcherEntryAdd(local.name, customMatcherEntry);
337
+ onCleanup(() => validationContext.onFieldCustomMatcherEntryRemove(local.name, customMatcherEntry.id));
338
+ });
339
+ const validity = () => validationContext.getFieldValidity(local.name);
340
+ const customErrors = () => validationContext.getFieldCustomErrors(local.name);
341
+ const hasMatchingCustomError = () => customErrors()[id()];
342
+ const matches = () => local.forceMatch || validity() && !hasBuiltInError(validity()) && hasMatchingCustomError();
343
+ return /* @__PURE__ */ React.createElement(Show, { when: matches() }, /* @__PURE__ */ React.createElement(
344
+ FormMessageImpl,
345
+ {
346
+ id: id(),
347
+ ref: local.ref,
348
+ ...rest,
349
+ __scopeForm: local.__scopeForm,
350
+ name: local.name
351
+ },
352
+ local.children ?? DEFAULT_INVALID_MESSAGE
353
+ ));
354
+ }
355
+ function FormMessageImpl(props) {
356
+ const [local, rest] = splitProps(props, ["__scopeForm", "id", "name"]);
357
+ const ariaDescriptionContext = useAriaDescriptionContext(MESSAGE_NAME, local.__scopeForm);
358
+ const _id = createId();
359
+ const id = () => local.id ?? _id;
360
+ createEffect(() => {
361
+ ariaDescriptionContext.onFieldMessageIdAdd(local.name, id());
362
+ onCleanup(() => ariaDescriptionContext.onFieldMessageIdRemove(local.name, id()));
363
+ });
364
+ return /* @__PURE__ */ React.createElement(Primitive.span, { id: id(), ...rest });
365
+ }
366
+ var VALIDITY_STATE_NAME = "FormValidityState";
367
+ function FormValidityState(props) {
368
+ const [local] = splitProps(props, ["__scopeForm", "name", "children"]);
369
+ const validationContext = useValidationContext(VALIDITY_STATE_NAME, local.__scopeForm);
370
+ const fieldContext = useFormFieldContext(VALIDITY_STATE_NAME, local.__scopeForm);
371
+ const name = () => local.name ?? fieldContext.name;
372
+ const validity = () => validationContext.getFieldValidity(name());
373
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, local.children(validity()));
374
+ }
375
+ function FormSubmit(props) {
376
+ const [, rest] = splitProps(props, ["__scopeForm"]);
377
+ return /* @__PURE__ */ React.createElement(Primitive.button, { type: "submit", ...rest });
378
+ }
379
+ function validityStateToObject(validity) {
380
+ const object = {};
381
+ for (const key in validity) {
382
+ object[key] = validity[key];
383
+ }
384
+ return object;
385
+ }
386
+ function isHTMLElement(element) {
387
+ return element instanceof HTMLElement;
388
+ }
389
+ function isFormControl(element) {
390
+ return "validity" in element;
391
+ }
392
+ function isInvalid(control) {
393
+ return isFormControl(control) && (control.validity.valid === false || control.getAttribute("aria-invalid") === "true");
394
+ }
395
+ function getFirstInvalidControl(form) {
396
+ const elements = form.elements;
397
+ const [firstInvalidControl] = Array.from(elements).filter(isHTMLElement).filter(isInvalid);
398
+ return firstInvalidControl;
399
+ }
400
+ function isAsyncCustomMatcherEntry(entry, args) {
401
+ return entry.match.constructor.name === "AsyncFunction" || returnsPromise(entry.match, args);
402
+ }
403
+ function isSyncCustomMatcherEntry(entry) {
404
+ return entry.match.constructor.name === "Function";
405
+ }
406
+ function returnsPromise(func, args) {
407
+ return func(...args) instanceof Promise;
408
+ }
409
+ function hasBuiltInError(validity) {
410
+ let error = false;
411
+ for (const validityKey in validity) {
412
+ const key = validityKey;
413
+ if (key !== "valid" && key !== "customError" && validity[key]) {
414
+ error = true;
415
+ break;
416
+ }
417
+ }
418
+ return error;
419
+ }
420
+ function getValidAttribute(validity, serverInvalid) {
421
+ if (validity?.valid === true && !serverInvalid) return true;
422
+ return void 0;
423
+ }
424
+ function getInvalidAttribute(validity, serverInvalid) {
425
+ if (validity?.valid === false || serverInvalid) return true;
426
+ return void 0;
427
+ }
428
+ var Root = Form;
429
+ var Field = FormField;
430
+ var Label = FormLabel;
431
+ var Control = FormControl;
432
+ var Message = FormMessage;
433
+ var ValidityState = FormValidityState;
434
+ var Submit = FormSubmit;
435
+
436
+ export { Control, Field, Form, FormControl, FormField, FormLabel, FormMessage, FormSubmit, FormValidityState, Label, Message, Root, Submit, ValidityState, createFormScope };
437
+ //# sourceMappingURL=index.js.map
438
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/form.tsx"],"names":["LabelPrimitive","controlValidity","id","hasCustomError"],"mappings":"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","file":"index.js","sourcesContent":["import { type JSX, splitProps, createSignal, createEffect, onCleanup, Show } from 'solid-js';\nimport { composeEventHandlers } from '@radix-solid-js/primitive';\nimport { mergeRefs } from '@radix-solid-js/compose-refs';\nimport { createContextScope } from '@radix-solid-js/context';\nimport { createId } from '@radix-solid-js/id';\nimport { Label as LabelPrimitive, type LabelProps } from '@radix-solid-js/label';\nimport { Primitive, type PrimitiveProps } from '@radix-solid-js/primitive-component';\n\nimport type { Scope } from '@radix-solid-js/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\ninterface FormProps extends PrimitiveProps<'form'> {\n onClearServerErrors?(): void;\n}\n\nfunction Form(props: ScopedProps<FormProps>) {\n const [local, rest] = splitProps(props, [\n '__scopeForm',\n 'ref',\n 'onClearServerErrors',\n 'onInvalid',\n 'onSubmit',\n 'onReset',\n ]);\n\n const onClearServerErrors = local.onClearServerErrors ?? (() => {});\n\n // native validity per field\n const [validityMap, setValidityMap] = createSignal<ValidityMap>({});\n const getFieldValidity = (fieldName: string) => validityMap()[fieldName];\n const handleFieldValidityChange = (fieldName: string, validity: ValidityState) => {\n setValidityMap((prev) => ({\n ...prev,\n [fieldName]: { ...(prev[fieldName] ?? {}), ...validity },\n }));\n };\n const handleFieldValiditionClear = (fieldName: string) => {\n setValidityMap((prev) => ({ ...prev, [fieldName]: undefined }));\n setCustomErrorsMap((prev) => ({ ...prev, [fieldName]: {} }));\n };\n\n // custom matcher entries per field\n const [customMatcherEntriesMap, setCustomMatcherEntriesMap] =\n createSignal<CustomMatcherEntriesMap>({});\n const getFieldCustomMatcherEntries = (fieldName: string) =>\n customMatcherEntriesMap()[fieldName] ?? [];\n const handleFieldCustomMatcherAdd = (fieldName: string, matcherEntry: CustomMatcherEntry) => {\n setCustomMatcherEntriesMap((prev) => ({\n ...prev,\n [fieldName]: [...(prev[fieldName] ?? []), matcherEntry],\n }));\n };\n const handleFieldCustomMatcherRemove = (fieldName: string, matcherEntryId: string) => {\n setCustomMatcherEntriesMap((prev) => ({\n ...prev,\n [fieldName]: (prev[fieldName] ?? []).filter((entry) => entry.id !== matcherEntryId),\n }));\n };\n\n // custom errors per field\n const [customErrorsMap, setCustomErrorsMap] = createSignal<CustomErrorsMap>({});\n const getFieldCustomErrors = (fieldName: string) => customErrorsMap()[fieldName] ?? {};\n const handleFieldCustomErrorsChange = (fieldName: string, customErrors: Record<string, boolean>) => {\n setCustomErrorsMap((prev) => ({\n ...prev,\n [fieldName]: { ...(prev[fieldName] ?? {}), ...customErrors },\n }));\n };\n\n // messageIds per field\n const [messageIdsMap, setMessageIdsMap] = createSignal<MessageIdsMap>({});\n const handleFieldMessageIdAdd = (fieldName: string, id: string) => {\n setMessageIdsMap((prev) => {\n const fieldDescriptionIds = new Set(prev[fieldName]).add(id);\n return { ...prev, [fieldName]: fieldDescriptionIds };\n });\n };\n const handleFieldMessageIdRemove = (fieldName: string, id: string) => {\n setMessageIdsMap((prev) => {\n const fieldDescriptionIds = new Set(prev[fieldName]);\n fieldDescriptionIds.delete(id);\n return { ...prev, [fieldName]: fieldDescriptionIds };\n });\n };\n const getFieldDescription = (fieldName: string) =>\n Array.from(messageIdsMap()[fieldName] ?? []).join(' ') || undefined;\n\n return (\n <ValidationProvider\n scope={local.__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={local.__scopeForm}\n onFieldMessageIdAdd={handleFieldMessageIdAdd}\n onFieldMessageIdRemove={handleFieldMessageIdRemove}\n getFieldDescription={getFieldDescription}\n >\n <Primitive.form\n {...rest}\n ref={local.ref}\n // focus first invalid control when the form is submitted\n onInvalid={composeEventHandlers(local.onInvalid as any, (event: Event) => {\n const target = event.currentTarget as HTMLFormElement;\n const firstInvalidControl = getFirstInvalidControl(target);\n if (firstInvalidControl === event.target) firstInvalidControl.focus();\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(local.onSubmit as any, onClearServerErrors as any, {\n checkForDefaultPrevented: false,\n })}\n // clear server errors when the form is reset\n onReset={composeEventHandlers(local.onReset as any, onClearServerErrors as any)}\n />\n </AriaDescriptionProvider>\n </ValidationProvider>\n );\n}\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\ninterface FormFieldProps extends PrimitiveProps<'div'> {\n name: string;\n serverInvalid?: boolean;\n}\n\nfunction FormField(props: ScopedProps<FormFieldProps>) {\n const [local, rest] = splitProps(props, ['__scopeForm', 'name', 'serverInvalid']);\n const validationContext = useValidationContext(FIELD_NAME, local.__scopeForm);\n const validity = () => validationContext.getFieldValidity(local.name);\n const id = createId();\n\n return (\n <FormFieldProvider\n scope={local.__scopeForm}\n id={id}\n name={local.name}\n serverInvalid={local.serverInvalid ?? false}\n >\n <Primitive.div\n data-valid={getValidAttribute(validity(), local.serverInvalid ?? false)}\n data-invalid={getInvalidAttribute(validity(), local.serverInvalid ?? false)}\n {...rest}\n />\n </FormFieldProvider>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormLabel\n * -----------------------------------------------------------------------------------------------*/\n\nconst LABEL_NAME = 'FormLabel';\n\ninterface FormLabelProps extends LabelProps {}\n\nfunction FormLabel(props: ScopedProps<FormLabelProps>) {\n const [local, rest] = splitProps(props, ['__scopeForm', 'for']);\n const validationContext = useValidationContext(LABEL_NAME, local.__scopeForm);\n const fieldContext = useFormFieldContext(LABEL_NAME, local.__scopeForm);\n const htmlFor = () => local.for || 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 {...rest}\n for={htmlFor()}\n />\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormControl\n * -----------------------------------------------------------------------------------------------*/\n\nconst CONTROL_NAME = 'FormControl';\n\ninterface FormControlProps extends PrimitiveProps<'input'> {}\n\nfunction FormControl(props: ScopedProps<FormControlProps>) {\n const [local, rest] = splitProps(props, [\n '__scopeForm',\n 'ref',\n 'name',\n 'id',\n 'onInvalid',\n 'onChange',\n ]);\n\n const validationContext = useValidationContext(CONTROL_NAME, local.__scopeForm);\n const fieldContext = useFormFieldContext(CONTROL_NAME, local.__scopeForm);\n const ariaDescriptionContext = useAriaDescriptionContext(CONTROL_NAME, local.__scopeForm);\n\n let controlRef!: HTMLInputElement;\n const name = () => local.name || fieldContext.name;\n const id = () => local.id || fieldContext.id;\n const customMatcherEntries = () => validationContext.getFieldCustomMatcherEntries(name());\n\n const updateControlValidity = async (control: HTMLInputElement) => {\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 validationContext.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 asyncCustomMatcherEntries: Array<AsyncCustomMatcherEntry> = [];\n customMatcherEntries().forEach((customMatcherEntry) => {\n if (isAsyncCustomMatcherEntry(customMatcherEntry, matcherArgs)) {\n asyncCustomMatcherEntries.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 validationContext.onFieldValidityChange(name(), controlValidity);\n validationContext.onFieldCustomErrorsChange(name(), syncCustomErrorsById);\n\n //--------------------------------------------------------------------------------------------\n // 5. run async custom matchers and update control validity / internal validity + errors\n\n if (!hasSyncCustomErrors && asyncCustomMatcherEntries.length > 0) {\n const promisedCustomErrors = asyncCustomMatcherEntries.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 validationContext.onFieldValidityChange(name(), controlValidity);\n validationContext.onFieldCustomErrorsChange(name(), asyncCustomErrorsById);\n }\n };\n\n // Listen to native 'change' event for validation (not Solid's onChange which fires on input)\n createEffect(() => {\n const control = controlRef;\n if (control) {\n const handleChange = () => updateControlValidity(control);\n control.addEventListener('change', handleChange);\n onCleanup(() => control.removeEventListener('change', handleChange));\n }\n });\n\n const resetControlValidity = () => {\n const control = controlRef;\n if (control) {\n control.setCustomValidity('');\n validationContext.onFieldValiditionClear(name());\n }\n };\n\n // reset validity and errors when the form is reset\n createEffect(() => {\n const form = controlRef?.form;\n if (form) {\n form.addEventListener('reset', resetControlValidity);\n onCleanup(() => form.removeEventListener('reset', resetControlValidity));\n }\n });\n\n // focus first invalid control when fields are set as invalid by server\n createEffect(() => {\n const control = controlRef;\n const form = control?.closest('form');\n if (form && fieldContext.serverInvalid) {\n const firstInvalidControl = getFirstInvalidControl(form);\n if (firstInvalidControl === control) firstInvalidControl.focus();\n }\n });\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 {...rest}\n ref={mergeRefs(local.ref, (el) => (controlRef = el as HTMLInputElement))}\n id={id()}\n name={name()}\n onInvalid={composeEventHandlers(local.onInvalid as any, (event: Event) => {\n const control = event.currentTarget as HTMLInputElement;\n updateControlValidity(control);\n })}\n onChange={composeEventHandlers(local.onChange as any, () => {\n // reset validity when user changes value\n resetControlValidity();\n })}\n />\n );\n}\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\ninterface FormMessageProps extends Omit<FormMessageImplProps, 'name'> {\n match?: ValidityMatcher | CustomMatcher;\n forceMatch?: boolean;\n name?: string;\n}\n\nfunction FormMessage(props: ScopedProps<FormMessageProps>) {\n const [local, rest] = splitProps(props, ['__scopeForm', 'match', 'name', 'forceMatch', 'children']);\n const fieldContext = useFormFieldContext(MESSAGE_NAME, local.__scopeForm);\n const name = () => local.name ?? fieldContext.name;\n\n if (local.match === undefined) {\n return (\n <FormMessageImpl {...rest} __scopeForm={local.__scopeForm} name={name()}>\n {local.children || DEFAULT_INVALID_MESSAGE}\n </FormMessageImpl>\n );\n } else if (typeof local.match === 'function') {\n return (\n <FormCustomMessage\n match={local.match}\n forceMatch={local.forceMatch}\n {...rest}\n __scopeForm={local.__scopeForm}\n name={name()}\n >\n {local.children}\n </FormCustomMessage>\n );\n } else {\n return (\n <FormBuiltInMessage\n match={local.match}\n forceMatch={local.forceMatch}\n {...rest}\n __scopeForm={local.__scopeForm}\n name={name()}\n >\n {local.children}\n </FormBuiltInMessage>\n );\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormBuiltInMessage\n * -----------------------------------------------------------------------------------------------*/\n\ninterface FormBuiltInMessageProps extends FormMessageImplProps {\n match: ValidityMatcher;\n forceMatch?: boolean;\n name: string;\n}\n\nfunction FormBuiltInMessage(props: ScopedProps<FormBuiltInMessageProps>) {\n const [local, rest] = splitProps(props, ['__scopeForm', 'match', 'forceMatch', 'name', 'children']);\n const validationContext = useValidationContext(MESSAGE_NAME, local.__scopeForm);\n const validity = () => validationContext.getFieldValidity(local.name);\n const matches = () => local.forceMatch || validity()?.[local.match];\n\n return (\n <Show when={matches()}>\n <FormMessageImpl {...rest} __scopeForm={local.__scopeForm} name={local.name}>\n {local.children ?? DEFAULT_BUILT_IN_MESSAGES[local.match]}\n </FormMessageImpl>\n </Show>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormCustomMessage\n * -----------------------------------------------------------------------------------------------*/\n\ninterface FormCustomMessageProps extends FormMessageImplProps {\n match: CustomMatcher;\n forceMatch?: boolean;\n name: string;\n}\n\nfunction FormCustomMessage(props: ScopedProps<FormCustomMessageProps>) {\n const [local, rest] = splitProps(props, [\n '__scopeForm',\n 'match',\n 'forceMatch',\n 'name',\n 'id',\n 'ref',\n 'children',\n ]);\n const validationContext = useValidationContext(MESSAGE_NAME, local.__scopeForm);\n\n const _id = createId();\n const id = () => local.id ?? _id;\n\n // Register / unregister the custom matcher entry\n createEffect(() => {\n const customMatcherEntry: CustomMatcherEntry = { id: id(), match: local.match };\n validationContext.onFieldCustomMatcherEntryAdd(local.name, customMatcherEntry);\n onCleanup(() => validationContext.onFieldCustomMatcherEntryRemove(local.name, customMatcherEntry.id));\n });\n\n const validity = () => validationContext.getFieldValidity(local.name);\n const customErrors = () => validationContext.getFieldCustomErrors(local.name);\n const hasMatchingCustomError = () => customErrors()[id()];\n const matches = () =>\n local.forceMatch || (validity() && !hasBuiltInError(validity()!) && hasMatchingCustomError());\n\n return (\n <Show when={matches()}>\n <FormMessageImpl\n id={id()}\n ref={local.ref}\n {...rest}\n __scopeForm={local.__scopeForm}\n name={local.name}\n >\n {local.children ?? DEFAULT_INVALID_MESSAGE}\n </FormMessageImpl>\n </Show>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormMessageImpl\n * -----------------------------------------------------------------------------------------------*/\n\ninterface FormMessageImplProps extends PrimitiveProps<'span'> {\n name: string;\n}\n\nfunction FormMessageImpl(props: ScopedProps<FormMessageImplProps>) {\n const [local, rest] = splitProps(props, ['__scopeForm', 'id', 'name']);\n const ariaDescriptionContext = useAriaDescriptionContext(MESSAGE_NAME, local.__scopeForm);\n const _id = createId();\n const id = () => local.id ?? _id;\n\n // Register / unregister the message ID for aria-describedby\n createEffect(() => {\n ariaDescriptionContext.onFieldMessageIdAdd(local.name, id());\n onCleanup(() => ariaDescriptionContext.onFieldMessageIdRemove(local.name, id()));\n });\n\n return <Primitive.span id={id()} {...rest} />;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormValidityState\n * -----------------------------------------------------------------------------------------------*/\n\nconst VALIDITY_STATE_NAME = 'FormValidityState';\n\ninterface FormValidityStateProps {\n children(validity: ValidityState | undefined): JSX.Element;\n name?: string;\n}\n\nfunction FormValidityState(props: ScopedProps<FormValidityStateProps>) {\n const [local] = splitProps(props, ['__scopeForm', 'name', 'children']);\n const validationContext = useValidationContext(VALIDITY_STATE_NAME, local.__scopeForm);\n const fieldContext = useFormFieldContext(VALIDITY_STATE_NAME, local.__scopeForm);\n const name = () => local.name ?? fieldContext.name;\n const validity = () => validationContext.getFieldValidity(name());\n return <>{local.children(validity())}</>;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FormSubmit\n * -----------------------------------------------------------------------------------------------*/\n\ninterface FormSubmitProps extends PrimitiveProps<'button'> {}\n\nfunction FormSubmit(props: ScopedProps<FormSubmitProps>) {\n const [, rest] = splitProps(props, ['__scopeForm']);\n return <Primitive.button type=\"submit\" {...rest} />;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Helper types and functions\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}\n\nfunction getInvalidAttribute(validity: ValidityState | undefined, serverInvalid: boolean) {\n if (validity?.valid === false || serverInvalid) return true;\n return undefined;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Aliases\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"]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@radix-solid-js/form",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "sideEffects": false,
25
+ "scripts": {
26
+ "build": "tsup",
27
+ "clean": "rm -rf dist",
28
+ "typecheck": "tsc --noEmit",
29
+ "test": "vitest run"
30
+ },
31
+ "dependencies": {
32
+ "@radix-solid-js/primitive": "workspace:*",
33
+ "@radix-solid-js/compose-refs": "workspace:*",
34
+ "@radix-solid-js/context": "workspace:*",
35
+ "@radix-solid-js/id": "workspace:*",
36
+ "@radix-solid-js/label": "workspace:*",
37
+ "@radix-solid-js/primitive-component": "workspace:*"
38
+ },
39
+ "peerDependencies": {
40
+ "solid-js": "^1.8.0"
41
+ },
42
+ "devDependencies": {
43
+ "@repo/tsconfig": "workspace:*",
44
+ "tsup": "^8.3.6",
45
+ "typescript": "^5.7.3",
46
+ "solid-js": "^1.9.3",
47
+ "vitest": "^2.1.8"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "https://github.com/ljho01/shadcn-solid-js.git",
55
+ "directory": "packages/solid/form"
56
+ }
57
+ }