Socket
Socket
Sign inDemoInstall

@conform-to/react

Package Overview
Dependencies
Maintainers
1
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@conform-to/react - npm Package Compare versions

Comparing version 0.9.1 to 1.0.0-pre.0

context.d.ts

70

helpers.d.ts

@@ -1,12 +0,7 @@

import { INTENT, VALIDATION_UNDEFINED, VALIDATION_SKIPPED } from '@conform-to/dom';
import type { FieldConfig, Primitive } from './hooks.js';
import type { CSSProperties, HTMLInputTypeAttribute } from 'react';
interface FormElementProps {
id?: string;
import type { FormMetadata, FieldMetadata, Pretty } from './context';
type FormControlProps = {
id: string;
name: string;
form?: string;
'aria-describedby'?: string;
'aria-invalid'?: boolean;
}
interface FormControlProps extends FormElementProps {
form: string;
required?: boolean;

@@ -16,11 +11,13 @@ autoFocus?: boolean;

style?: CSSProperties;
'aria-describedby'?: string;
'aria-invalid'?: boolean;
'aria-hidden'?: boolean;
}
interface InputProps<Schema> extends FormControlProps {
type?: HTMLInputTypeAttribute;
};
type InputProps = Pretty<FormControlProps & {
type?: Exclude<HTMLInputTypeAttribute, 'submit' | 'reset' | 'button'>;
minLength?: number;
maxLength?: number;
min?: Schema extends number ? number : string | number;
max?: Schema extends number ? number : string | number;
step?: Schema extends number ? number : string | number;
min?: string | number;
max?: string | number;
step?: string | number;
pattern?: string;

@@ -31,12 +28,13 @@ multiple?: boolean;

defaultValue?: string;
}
interface SelectProps extends FormControlProps {
}>;
type SelectProps = Pretty<FormControlProps & {
defaultValue?: string | number | readonly string[] | undefined;
multiple?: boolean;
}
interface TextareaProps extends FormControlProps {
}>;
type TextareaProps = Pretty<FormControlProps & {
minLength?: number;
maxLength?: number;
defaultValue?: string;
}
}>;
type Primitive = string | number | boolean | Date | null | undefined;
type BaseOptions = {

@@ -51,2 +49,6 @@ ariaAttributes?: true;

};
type FormOptions<Schema extends Record<string, any>> = BaseOptions & {
onSubmit?: (event: React.FormEvent<HTMLFormElement>, context: ReturnType<FormMetadata<Schema>['onSubmit']>) => void;
onReset?: (event: React.FormEvent<HTMLFormElement>) => void;
};
type InputOptions = ControlOptions & ({

@@ -64,13 +66,23 @@ type: 'checkbox' | 'radio';

};
export declare function input<Schema extends Primitive | unknown>(config: FieldConfig<Schema>, options?: InputOptions): InputProps<Schema>;
export declare function input<Schema extends File | File[]>(config: FieldConfig<Schema>, options: InputOptions & {
export declare function input<Schema extends Primitive | unknown>(field: FieldMetadata<Schema>, options?: InputOptions): InputProps;
export declare function input<Schema extends File | File[]>(field: FieldMetadata<Schema>, options: InputOptions & {
type: 'file';
}): InputProps<Schema>;
export declare function select<Schema extends Primitive | Primitive[] | undefined | unknown>(config: FieldConfig<Schema>, options?: ControlOptions): SelectProps;
export declare function textarea<Schema extends Primitive | undefined | unknown>(config: FieldConfig<Schema>, options?: ControlOptions): TextareaProps;
export declare function fieldset<Schema extends Record<string, unknown> | undefined | unknown>(config: FieldConfig<Schema>, options?: BaseOptions): FormControlProps;
export declare function collection<Schema extends Array<string | boolean> | string | boolean | undefined | unknown>(config: FieldConfig<Schema>, options: BaseOptions & {
}): InputProps;
export declare function select<Schema extends Primitive | Primitive[] | undefined | unknown>(metadata: FieldMetadata<Schema>, options?: ControlOptions): SelectProps;
export declare function textarea<Schema extends Primitive | undefined | unknown>(metadata: FieldMetadata<Schema>, options?: ControlOptions): TextareaProps;
export declare function form<Schema extends Record<string, any>>(metadata: FormMetadata<Schema>, options?: FormOptions<Schema>): {
id: string;
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
onReset: (event: import("react").FormEvent<HTMLFormElement>) => void;
noValidate: boolean;
};
export declare function fieldset<Schema extends Record<string, any> | undefined | unknown>(metadata: FieldMetadata<Schema>, options?: BaseOptions): {
id: string;
name: import("@conform-to/dom").FieldName<Schema>;
form: string;
};
export declare function collection<Schema extends Array<string | boolean> | string | boolean | undefined | unknown>(metadata: FieldMetadata<Schema>, options: BaseOptions & {
type: 'checkbox' | 'radio';
options: string[];
}): Array<InputProps<Schema> & Pick<Required<InputProps<Schema>>, 'type' | 'value'>>;
export { INTENT, VALIDATION_UNDEFINED, VALIDATION_SKIPPED };
}): Array<InputProps & Pick<Required<InputProps>, 'type' | 'value'>>;
export {};

@@ -6,3 +6,2 @@ 'use strict';

var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
var dom = require('@conform-to/dom');

@@ -21,27 +20,21 @@ /**

}
function getFormElementProps(config) {
var _options$ariaAttribut, _config$error, _config$error2;
function getAriaAttributes(metadata) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var hasAriaAttributes = (_options$ariaAttribut = options.ariaAttributes) !== null && _options$ariaAttribut !== void 0 ? _options$ariaAttribut : true;
if (typeof options.ariaAttributes !== 'undefined' && !options.ariaAttributes) {
return {};
}
return cleanup({
id: config.id,
name: config.name,
form: config.form,
'aria-invalid': hasAriaAttributes && config.errorId && (_config$error = config.error) !== null && _config$error !== void 0 && _config$error.length ? true : undefined,
'aria-describedby': hasAriaAttributes ? [config.errorId && (_config$error2 = config.error) !== null && _config$error2 !== void 0 && _config$error2.length ? config.errorId : undefined, config.descriptionId && options.ariaAttributes !== false && options.description ? config.descriptionId : undefined].reduce((result, id) => {
if (!result) {
return id;
}
if (!id) {
return result;
}
return "".concat(result, " ").concat(id);
}) : undefined
'aria-invalid': !metadata.valid || undefined,
'aria-describedby': metadata.valid ? options.description ? metadata.descriptionId : undefined : "".concat(metadata.errorId, " ").concat(options.description ? metadata.descriptionId : '').trim()
});
}
function getFormControlProps(config, options) {
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormElementProps(config, options)), {}, {
required: config.required,
autoFocus: config.initialError && Object.entries(config.initialError).length > 0 ? true : undefined
}, options !== null && options !== void 0 && options.hidden ? hiddenProps : undefined));
function getFormControlProps(metadata, options) {
var _metadata$constraint;
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({
id: metadata.id,
name: metadata.name,
form: metadata.formId,
required: ((_metadata$constraint = metadata.constraint) === null || _metadata$constraint === void 0 ? void 0 : _metadata$constraint.required) || undefined,
autoFocus: !metadata.valid || undefined
}, options !== null && options !== void 0 && options.hidden ? hiddenProps : undefined), getAriaAttributes(metadata, options)));
}

@@ -67,13 +60,14 @@ var hiddenProps = {

};
function input(config) {
function input(field) {
var _field$constraint, _field$constraint2, _field$constraint3, _field$constraint4, _field$constraint5, _field$constraint6, _field$constraint7;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var props = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(config, options)), {}, {
var props = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(field, options)), {}, {
type: options.type,
minLength: config.minLength,
maxLength: config.maxLength,
min: config.min,
max: config.max,
step: config.step,
pattern: config.pattern,
multiple: config.multiple
minLength: (_field$constraint = field.constraint) === null || _field$constraint === void 0 ? void 0 : _field$constraint.minLength,
maxLength: (_field$constraint2 = field.constraint) === null || _field$constraint2 === void 0 ? void 0 : _field$constraint2.maxLength,
min: (_field$constraint3 = field.constraint) === null || _field$constraint3 === void 0 ? void 0 : _field$constraint3.min,
max: (_field$constraint4 = field.constraint) === null || _field$constraint4 === void 0 ? void 0 : _field$constraint4.max,
step: (_field$constraint5 = field.constraint) === null || _field$constraint5 === void 0 ? void 0 : _field$constraint5.step,
pattern: (_field$constraint6 = field.constraint) === null || _field$constraint6 === void 0 ? void 0 : _field$constraint6.pattern,
multiple: (_field$constraint7 = field.constraint) === null || _field$constraint7 === void 0 ? void 0 : _field$constraint7.multiple
});

@@ -83,51 +77,68 @@ if (options.type === 'checkbox' || options.type === 'radio') {

props.value = (_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : 'on';
props.defaultChecked = config.defaultValue === props.value;
props.defaultChecked = typeof field.initialValue === 'boolean' ? field.initialValue : field.initialValue === props.value;
} else if (options.type !== 'file') {
props.defaultValue = config.defaultValue;
var _field$initialValue;
props.defaultValue = (_field$initialValue = field.initialValue) === null || _field$initialValue === void 0 ? void 0 : _field$initialValue.toString();
}
return cleanup(props);
}
function select(config, options) {
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(config, options)), {}, {
defaultValue: config.defaultValue,
multiple: config.multiple
function select(metadata, options) {
var _metadata$initialValu, _metadata$constraint2;
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, {
defaultValue: (_metadata$initialValu = metadata.initialValue) === null || _metadata$initialValu === void 0 ? void 0 : _metadata$initialValu.toString(),
multiple: (_metadata$constraint2 = metadata.constraint) === null || _metadata$constraint2 === void 0 ? void 0 : _metadata$constraint2.multiple
}));
}
function textarea(config, options) {
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(config, options)), {}, {
defaultValue: config.defaultValue,
minLength: config.minLength,
maxLength: config.maxLength
function textarea(metadata, options) {
var _metadata$initialValu2, _metadata$constraint3, _metadata$constraint4;
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, {
defaultValue: (_metadata$initialValu2 = metadata.initialValue) === null || _metadata$initialValu2 === void 0 ? void 0 : _metadata$initialValu2.toString(),
minLength: (_metadata$constraint3 = metadata.constraint) === null || _metadata$constraint3 === void 0 ? void 0 : _metadata$constraint3.minLength,
maxLength: (_metadata$constraint4 = metadata.constraint) === null || _metadata$constraint4 === void 0 ? void 0 : _metadata$constraint4.maxLength
}));
}
function fieldset(config, options) {
return getFormElementProps(config, options);
function form(metadata, options) {
var onSubmit = options === null || options === void 0 ? void 0 : options.onSubmit;
var onReset = options === null || options === void 0 ? void 0 : options.onReset;
return cleanup(_rollupPluginBabelHelpers.objectSpread2({
id: metadata.id,
onSubmit: typeof onSubmit !== 'function' ? metadata.onSubmit : event => {
var context = metadata.onSubmit(event);
if (!event.defaultPrevented) {
onSubmit(event, context);
}
},
onReset: typeof onReset !== 'function' ? metadata.onReset : event => {
metadata.onReset(event);
onReset(event);
},
noValidate: metadata.noValidate
}, getAriaAttributes(metadata, options)));
}
function collection(config, options) {
return options.options.map(value => cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(config, options)), {}, {
id: config.id ? "".concat(config.id, "-").concat(value) : undefined,
type: options.type,
value,
defaultChecked: options.type === 'checkbox' && Array.isArray(config.defaultValue) ? config.defaultValue.includes(value) : config.defaultValue === value,
// The required attribute doesn't make sense for checkbox group
// As it would require all checkboxes to be checked instead of at least one
// overriden with `undefiend` so it gets cleaned up
required: options.type === 'checkbox' ? undefined : config.required
})));
function fieldset(metadata, options) {
return cleanup(_rollupPluginBabelHelpers.objectSpread2({
id: metadata.id,
name: metadata.name,
form: metadata.formId
}, getAriaAttributes(metadata, options)));
}
function collection(metadata, options) {
return options.options.map(value => {
var _metadata$constraint5;
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, {
id: "".concat(metadata.id, "-").concat(value),
type: options.type,
value,
defaultChecked: options.type === 'checkbox' && Array.isArray(metadata.initialValue) ? metadata.initialValue.includes(value) : metadata.initialValue === value,
// The required attribute doesn't make sense for checkbox group
// As it would require all checkboxes to be checked instead of at least one
// It is overriden with `undefiend` so it could be cleaned upW properly
required: options.type === 'checkbox' ? undefined : (_metadata$constraint5 = metadata.constraint) === null || _metadata$constraint5 === void 0 ? void 0 : _metadata$constraint5.required
}));
});
}
Object.defineProperty(exports, 'INTENT', {
enumerable: true,
get: function () { return dom.INTENT; }
});
Object.defineProperty(exports, 'VALIDATION_SKIPPED', {
enumerable: true,
get: function () { return dom.VALIDATION_SKIPPED; }
});
Object.defineProperty(exports, 'VALIDATION_UNDEFINED', {
enumerable: true,
get: function () { return dom.VALIDATION_UNDEFINED; }
});
exports.collection = collection;
exports.fieldset = fieldset;
exports.form = form;
exports.hiddenProps = hiddenProps;

@@ -134,0 +145,0 @@ exports.input = input;

@@ -1,31 +0,12 @@

import { type FieldConstraint, type FieldElement, type FieldsetConstraint, type Submission, type KeysOf, type ResolveType, getFormEncType, getFormMethod, parseIntent } from '@conform-to/dom';
import { type FormEvent, type RefObject } from 'react';
export type Primitive = null | undefined | string | number | boolean | Date;
export interface FieldConfig<Schema> extends FieldConstraint<Schema> {
id?: string;
name: string;
defaultValue?: FieldValue<Schema>;
initialError?: Record<string, string[]>;
form?: string;
descriptionId?: string;
errorId?: string;
import { type UnionKeyof, type UnionKeyType, type FieldName, type Form, type FormOptions } from '@conform-to/dom';
import { useEffect } from 'react';
import { type FormMetadata, type FieldMetadata, type Pretty } from './context';
/**
* useLayoutEffect is client-only.
* This basically makes it a no-op on server
*/
export declare const useSafeLayoutEffect: typeof useEffect;
export declare function useFormId(preferredId?: string): string;
export declare function useForm<Schema extends Record<string, any>>(options: Pretty<FormOptions<Schema> & {
/**
* The frist error of the field
*/
error?: string;
/**
* All of the field errors
*/
errors?: string[];
}
export type FieldValue<Schema> = Schema extends Primitive ? string : Schema extends File ? File : Schema extends Array<infer InnerType> ? Array<FieldValue<InnerType>> : unknown extends Schema ? any : Record<string, any> extends Schema ? {
[Key in KeysOf<Schema>]?: FieldValue<ResolveType<Schema, Key>>;
} : any;
type SubmissionResult = {
intent: Submission['intent'];
payload: Submission['payload'] | null;
error: Submission['error'];
};
export interface FormConfig<Output extends Record<string, any>, Input extends Record<string, any> = Output> {
/**
* If the form id is provided, Id for label,

@@ -36,174 +17,39 @@ * input and error elements will be derived.

/**
* A form ref object. Conform will fallback to its own ref object if it is not provided.
*/
ref?: RefObject<HTMLFormElement>;
/**
* Define when conform should start validation.
* Support "onSubmit", "onInput", "onBlur".
* Enable constraint validation before the dom is hydated.
*
* @default "onSubmit"
* Default to `true`.
*/
shouldValidate?: 'onSubmit' | 'onBlur' | 'onInput';
/**
* Define when conform should revalidate again.
* Support "onSubmit", "onInput", "onBlur".
*
* @default shouldValidate, or "onSubmit" if shouldValidate is not provided.
*/
shouldRevalidate?: 'onSubmit' | 'onBlur' | 'onInput';
/**
* An object representing the initial value of the form.
*/
defaultValue?: FieldValue<Input>;
/**
* An object describing the result of the last submission
*/
lastSubmission?: SubmissionResult | null;
/**
* An object describing the constraint of each field
*/
constraint?: FieldsetConstraint<Input>;
/**
* Enable native validation before hydation.
*
* Default to `false`.
*/
fallbackNative?: boolean;
/**
* Accept form submission regardless of the form validity.
*
* Default to `false`.
*/
noValidate?: boolean;
/**
* A function to be called when the form should be (re)validated.
*/
onValidate?: ({ form, formData, }: {
form: HTMLFormElement;
formData: FormData;
}) => Submission | Submission<Output>;
/**
* The submit event handler of the form. It will be called
* only when the form is considered valid.
*/
onSubmit?: (event: FormEvent<HTMLFormElement>, context: {
formData: FormData;
submission: Submission;
action: string;
encType: ReturnType<typeof getFormEncType>;
method: ReturnType<typeof getFormMethod>;
}) => void;
}
/**
* Properties to be applied to the form element
*/
interface FormProps {
id?: string;
ref: RefObject<HTMLFormElement>;
onSubmit: (event: FormEvent<HTMLFormElement>) => void;
noValidate: boolean;
'aria-invalid'?: 'true';
'aria-describedby'?: string;
}
interface Form {
id?: string;
errorId?: string;
error: string | undefined;
errors: string[];
ref: RefObject<HTMLFormElement>;
props: FormProps;
}
/**
* Returns properties required to hook into form events.
* Applied custom validation and define when error should be reported.
*
* @see https://conform.guide/api/react#useform
*/
export declare function useForm<Output extends Record<string, any>, Input extends Record<string, any> = Output>(config?: FormConfig<Output, Input>): [Form, Fieldset<Input>];
/**
* A set of field configuration
*/
export type Fieldset<Schema extends Record<string, any> | undefined> = {
[Key in KeysOf<Schema>]-?: FieldConfig<ResolveType<Schema, Key>>;
defaultNoValidate?: boolean;
}>): {
form: FormMetadata<Schema>;
context: Form<Schema>;
fields: Pretty<FieldsetMetadata<Schema>>;
};
export interface FieldsetConfig<Schema extends Record<string, any> | undefined> {
/**
* The prefix used to generate the name of nested fields.
*/
name?: string;
/**
* An object representing the initial value of the fieldset.
*/
defaultValue?: FieldValue<Schema>;
/**
* An object describing the initial error of each field
*/
initialError?: Record<string, string[]>;
/**
* An object describing the constraint of each field
*/
constraint?: FieldsetConstraint<Schema>;
/**
* The id of the form, connecting each field to a form remotely
*/
form?: string;
}
/**
* Returns all the information about the fieldset.
*
* @see https://conform.guide/api/react#usefieldset
*/
export declare function useFieldset<Schema extends Record<string, any> | undefined>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldsetConfig<Schema>): Fieldset<Schema>;
export declare function useFieldset<Schema extends Record<string, any> | undefined>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldConfig<Schema>): Fieldset<Schema>;
/**
* Returns a list of key and field config.
*
* @see https://conform.guide/api/react#usefieldlist
*/
export declare function useFieldList<Schema extends Array<any> | undefined>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldConfig<Schema>): Array<{
key: string;
} & FieldConfig<Schema extends Array<infer Item> ? Item : never>>;
interface InputControl {
change: (eventOrValue: {
target: {
value: string;
};
} | string | boolean) => void;
focus: () => void;
blur: () => void;
}
/**
* Returns a ref object and a set of helpers that dispatch corresponding dom event.
*
* @see https://conform.guide/api/react#useinputevent
*/
export declare function useInputEvent(options: {
ref: RefObject<FieldElement> | (() => Element | RadioNodeList | FieldElement | null | undefined);
onInput?: (event: Event) => void;
onFocus?: (event: FocusEvent) => void;
onBlur?: (event: FocusEvent) => void;
onReset?: (event: Event) => void;
}): InputControl;
export declare const FORM_ERROR_ELEMENT_NAME = "__form__";
/**
* Validate the form with the Constraint Validation API
* @see https://conform.guide/api/react#validateconstraint
*/
export declare function validateConstraint(options: {
form: HTMLFormElement;
formData?: FormData;
constraint?: Record<Lowercase<string>, (value: string, context: {
formData: FormData;
attributeValue: string;
}) => boolean>;
formatMessages?: ({ name, validity, constraint, defaultErrors, }: {
name: string;
validity: ValidityState;
constraint: Record<string, boolean>;
defaultErrors: string[];
}) => string[];
}): Submission;
export declare function getUniqueKey(): string;
export declare function reportSubmission(form: HTMLFormElement, submission: SubmissionResult): void;
export declare function getScope(intent: ReturnType<typeof parseIntent>): string | null;
export {};
export declare function useFormMetadata<Schema extends Record<string, any>>(options: {
formId: string;
context?: Form<Schema>;
defaultNoValidate?: boolean;
}): FormMetadata<Schema>;
export type FieldsetMetadata<Schema> = Schema extends Array<any> ? {
[Key in keyof Schema]: FieldMetadata<Schema[Key]>;
} : Schema extends {
[key in string]?: any;
} ? {
[Key in UnionKeyof<Schema>]: FieldMetadata<UnionKeyType<Schema, Key>>;
} : Record<string | number, FieldMetadata<any>>;
export declare function useFieldset<Schema>(options: {
formId: string;
name?: FieldName<Schema>;
context?: Form;
}): Pretty<FieldsetMetadata<Schema>>;
export type Item<List> = List extends Array<infer Item> ? Item : any;
export declare function useFieldList<Schema>(options: {
formId: string;
name: FieldName<Schema>;
context?: Form;
}): Array<FieldMetadata<Item<Schema>>>;
export declare function useField<Schema>(options: {
formId: string;
name: FieldName<Schema>;
context?: Form;
}): FieldMetadata<Schema>;

@@ -5,737 +5,161 @@ 'use strict';

var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
var dom = require('@conform-to/dom');
var react = require('react');
var context = require('./context.js');
/**
* Properties to be applied to the form element
* useLayoutEffect is client-only.
* This basically makes it a no-op on server
*/
var useSafeLayoutEffect = typeof document === 'undefined' ? react.useEffect : react.useLayoutEffect;
function useFormId(preferredId) {
var id = react.useId();
return preferredId !== null && preferredId !== void 0 ? preferredId : id;
}
function useForm(options) {
var formId = useFormId(options.id);
var initializeForm = () => dom.createForm(formId, options);
var [form, setForm] = react.useState(initializeForm);
function useNoValidate(defaultNoValidate, validateBeforeHydrate) {
var [noValidate, setNoValidate] = react.useState(defaultNoValidate || !validateBeforeHydrate);
react.useEffect(() => {
setNoValidate(true);
}, []);
return noValidate;
}
function useFormRef(userProvidedRef) {
var formRef = react.useRef(null);
return userProvidedRef !== null && userProvidedRef !== void 0 ? userProvidedRef : formRef;
}
function useConfigRef(config) {
var ref = react.useRef(config);
// If id changes, reinitialize the form immediately
if (formId !== form.id) {
setForm(initializeForm);
}
var optionsRef = react.useRef(options);
var metadata = useFormMetadata({
formId,
context: form,
defaultNoValidate: options.defaultNoValidate
});
var fields = useFieldset({
formId,
context: form
});
useSafeLayoutEffect(() => form.initialize(), [form]);
useSafeLayoutEffect(() => {
ref.current = config;
});
return ref;
}
function useFormReporter(ref, lastSubmission) {
var [submission, setSubmission] = react.useState(lastSubmission);
var report = react.useCallback((form, submission) => {
var event = new CustomEvent('conform', {
detail: submission.intent
});
form.dispatchEvent(event);
setSubmission(submission);
}, []);
react.useEffect(() => {
var form = ref.current;
if (!form || !lastSubmission) {
if (options.lastResult === optionsRef.current.lastResult) {
// If there is no change, do nothing
return;
}
if (!lastSubmission.payload) {
// If the default value is empty, we can safely reset the form.
// This ensure the behavior is consistent with and without JS.
form.reset();
// There is no need to report the submission anymore.
return;
if (options.lastResult) {
form.report(options.lastResult);
} else {
var _document$forms$named;
(_document$forms$named = document.forms.namedItem(form.id)) === null || _document$forms$named === void 0 ? void 0 : _document$forms$named.reset();
}
report(form, lastSubmission);
}, [ref, lastSubmission, report]);
react.useEffect(() => {
var form = ref.current;
if (!form || !submission) {
return;
}
reportSubmission(form, submission);
}, [ref, submission]);
return report;
}
function useFormError(ref, config) {
var [error, setError] = react.useState(() => {
if (!config.initialError) {
return {};
}
var result = {};
for (var [name, message] of Object.entries(config.initialError)) {
var [path, ...restPaths] = dom.getPaths(name);
if (typeof path !== 'undefined' && restPaths.length === 0) {
result[path] = message;
}
}
return result;
}, [form, options.lastResult]);
useSafeLayoutEffect(() => {
optionsRef.current = options;
form.update(options);
});
react.useEffect(() => {
var handleInvalid = event => {
var _config$name;
var form = dom.getFormElement(ref.current);
var element = event.target;
var prefix = (_config$name = config.name) !== null && _config$name !== void 0 ? _config$name : '';
if (!dom.isFieldElement(element) || element.form !== form || !element.name.startsWith(prefix) || !element.dataset.conformTouched) {
return;
}
var name = element.name.slice(prefix.length);
var [path, ...restPaths] = dom.getPaths(name);
if (typeof path === 'undefined' || restPaths.length > 0) {
return;
}
setError(prev => {
if (element.validationMessage === dom.getValidationMessage(prev[path])) {
return prev;
}
return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, prev), {}, {
[path]: dom.getErrors(element.validationMessage)
});
});
event.preventDefault();
};
var handleReset = event => {
var form = dom.getFormElement(ref.current);
if (form && event.target === form) {
setError({});
}
};
document.addEventListener('reset', handleReset);
document.addEventListener('invalid', handleInvalid, true);
return () => {
document.removeEventListener('reset', handleReset);
document.removeEventListener('invalid', handleInvalid, true);
};
}, [ref, config.name]);
return [error, setError];
return {
context: form,
fields,
form: metadata
};
}
/**
* Returns properties required to hook into form events.
* Applied custom validation and define when error should be reported.
*
* @see https://conform.guide/api/react#useform
*/
function useForm() {
var _config$lastSubmissio3, _config$lastSubmissio4;
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var configRef = useConfigRef(config);
var ref = useFormRef(config.ref);
var noValidate = useNoValidate(config.noValidate, config.fallbackNative);
var report = useFormReporter(ref, config.lastSubmission);
var [errors, setErrors] = react.useState(() => {
var _config$lastSubmissio, _config$lastSubmissio2;
return (_config$lastSubmissio = (_config$lastSubmissio2 = config.lastSubmission) === null || _config$lastSubmissio2 === void 0 ? void 0 : _config$lastSubmissio2.error['']) !== null && _config$lastSubmissio !== void 0 ? _config$lastSubmissio : [];
function useFormMetadata(options) {
var _options$defaultNoVal;
var subjectRef = context.useSubjectRef();
var form = context.useFormStore(options.formId, options.context);
var context$1 = context.useFormContext(form, subjectRef);
var metadata = context.getBaseMetadata(options.formId, context$1, {
subjectRef
});
var initialError = react.useMemo(() => {
var _submission$error$sco;
var submission = config.lastSubmission;
if (!submission) {
return {};
var [noValidate, setNoValidate] = react.useState((_options$defaultNoVal = options.defaultNoValidate) !== null && _options$defaultNoVal !== void 0 ? _options$defaultNoVal : true);
useSafeLayoutEffect(() => {
// This is necessary to fix an issue in strict mode with related to our proxy setup
// It avoids the component from being rerendered without re-rendering the child
// Which reset the proxy but failed to capture its usage within child component
if (!noValidate) {
setNoValidate(true);
}
var intent = dom.parseIntent(submission.intent);
var scope = getScope(intent);
if (typeof scope !== 'string') {
return submission.error;
}
return {
[scope]: (_submission$error$sco = submission.error[scope]) !== null && _submission$error$sco !== void 0 ? _submission$error$sco : []
};
}, [config.lastSubmission]);
// This payload from lastSubmission is only useful before hydration
// After hydration, any new payload on lastSubmission will be ignored
var [defaultValueFromLastSubmission, setDefaultValueFromLastSubmission] = react.useState( // @ts-expect-error defaultValue is not in Submission type
(_config$lastSubmissio3 = (_config$lastSubmissio4 = config.lastSubmission) === null || _config$lastSubmissio4 === void 0 ? void 0 : _config$lastSubmissio4.payload) !== null && _config$lastSubmissio3 !== void 0 ? _config$lastSubmissio3 : null);
var fieldset = useFieldset(ref, {
defaultValue: defaultValueFromLastSubmission !== null && defaultValueFromLastSubmission !== void 0 ? defaultValueFromLastSubmission : config.defaultValue,
initialError,
constraint: config.constraint,
form: config.id
});
react.useEffect(() => {
// custom validate handler
var createValidateHandler = type => event => {
var field = event.target;
var form = ref.current;
var {
shouldValidate = 'onSubmit',
shouldRevalidate = shouldValidate
} = configRef.current;
if (!form || !dom.isFocusableFormControl(field) || field.form !== form || !field.name) {
return;
}
if (field.dataset.conformTouched ? shouldRevalidate === type : shouldValidate === type) {
dom.requestIntent(form, dom.validate(field.name));
}
};
var handleInvalid = event => {
var form = ref.current;
var field = event.target;
if (!form || !dom.isFieldElement(field) || field.form !== form || field.name !== FORM_ERROR_ELEMENT_NAME) {
return;
}
event.preventDefault();
if (field.dataset.conformTouched) {
setErrors(dom.getErrors(field.validationMessage));
}
};
var handleReset = event => {
var form = ref.current;
if (!form || event.target !== form) {
return;
}
// Reset all field state
for (var _element of dom.getFormControls(form)) {
delete _element.dataset.conformTouched;
_element.setCustomValidity('');
}
setErrors([]);
setDefaultValueFromLastSubmission(null);
};
var handleInput = createValidateHandler('onInput');
var handleBlur = createValidateHandler('onBlur');
document.addEventListener('input', handleInput, true);
document.addEventListener('blur', handleBlur, true);
document.addEventListener('invalid', handleInvalid, true);
document.addEventListener('reset', handleReset);
return () => {
document.removeEventListener('input', handleInput, true);
document.removeEventListener('blur', handleBlur, true);
document.removeEventListener('invalid', handleInvalid, true);
document.removeEventListener('reset', handleReset);
};
}, [ref, configRef]);
var form = {
ref,
error: errors[0],
errors,
props: {
ref,
noValidate,
onSubmit(event) {
var form = event.currentTarget;
var nativeEvent = event.nativeEvent;
var submitter = nativeEvent.submitter;
if (event.defaultPrevented) {
return;
}
try {
var _config$onValidate, _config$onValidate2;
var formData = dom.getFormData(form, submitter);
var submission = (_config$onValidate = (_config$onValidate2 = config.onValidate) === null || _config$onValidate2 === void 0 ? void 0 : _config$onValidate2.call(config, {
form,
formData
})) !== null && _config$onValidate !== void 0 ? _config$onValidate : dom.parse(formData);
var {
errors: _errors,
shouldServerValidate
} = Object.entries(submission.error).reduce((result, _ref) => {
var [, error] = _ref;
for (var message of error) {
if (message === dom.VALIDATION_UNDEFINED) {
result.shouldServerValidate = true;
} else if (message !== dom.VALIDATION_SKIPPED) {
result.errors.push(message);
}
}, [noValidate]);
return new Proxy(metadata, {
get(target, key, receiver) {
switch (key) {
case 'onSubmit':
return event => {
var submitEvent = event.nativeEvent;
var result = form.submit(submitEvent);
if (submitEvent.defaultPrevented) {
event.preventDefault();
}
return result;
}, {
errors: [],
shouldServerValidate: false
});
if (
// has client validation
typeof config.onValidate !== 'undefined' &&
// not necessary to validate on the server
!shouldServerValidate && (
// client validation failed or non submit intent
!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && _errors.length > 0 || dom.parseIntent(submission.intent) !== null)) {
report(form, submission);
event.preventDefault();
} else {
var _config$onSubmit;
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, {
formData,
submission,
action: dom.getFormAction(nativeEvent),
encType: dom.getFormEncType(nativeEvent),
method: dom.getFormMethod(nativeEvent)
});
}
} catch (error) {
// eslint-disable-next-line no-console
console.warn('Client validation failed', error);
}
};
case 'onReset':
return event => form.reset(event.nativeEvent);
case 'noValidate':
return noValidate;
}
return Reflect.get(target, key, receiver);
}
};
if (config.id) {
form.id = config.id;
form.errorId = "".concat(config.id, "-error");
form.props.id = form.id;
}
if (form.errorId && form.errors.length > 0) {
form.props['aria-invalid'] = 'true';
form.props['aria-describedby'] = form.errorId;
}
return [form, fieldset];
});
}
/**
* A set of field configuration
*/
/**
* Returns all the information about the fieldset.
*
* @see https://conform.guide/api/react#usefieldset
*/
function useFieldset(ref, config) {
var [error] = useFormError(ref, {
initialError: config.initialError,
name: config.name
});
/**
* This allows us constructing the field at runtime as we have no information
* about which fields would be available. The proxy will also help tracking
* the usage of each field for optimization in the future.
*/
function useFieldset(options) {
var subjectRef = context.useSubjectRef();
var form = context.useFormStore(options.formId, options.context);
var context$1 = context.useFormContext(form, subjectRef);
return new Proxy({}, {
get(_target, key) {
var _fieldsetConfig$const, _fieldsetConfig$initi, _fieldsetConfig$defau;
if (typeof key !== 'string') {
return;
}
var fieldsetConfig = config;
var constraint = (_fieldsetConfig$const = fieldsetConfig.constraint) === null || _fieldsetConfig$const === void 0 ? void 0 : _fieldsetConfig$const[key];
var errors = error === null || error === void 0 ? void 0 : error[key];
var initialError = Object.entries((_fieldsetConfig$initi = fieldsetConfig.initialError) !== null && _fieldsetConfig$initi !== void 0 ? _fieldsetConfig$initi : {}).reduce((result, _ref2) => {
var [name, message] = _ref2;
var [field, ...paths] = dom.getPaths(name);
if (field === key) {
result[dom.getName(paths)] = message;
}
return result;
}, {});
var field = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, constraint), {}, {
name: fieldsetConfig.name ? "".concat(fieldsetConfig.name, ".").concat(key) : key,
// @ts-expect-error The FieldValue type might need a rework
defaultValue: (_fieldsetConfig$defau = fieldsetConfig.defaultValue) === null || _fieldsetConfig$defau === void 0 ? void 0 : _fieldsetConfig$defau[key],
initialError,
error: errors === null || errors === void 0 ? void 0 : errors[0],
errors
get(target, prop, receiver) {
var getMetadata = key => context.getFieldMetadata(options.formId, context$1, {
name: options.name,
key: key,
subjectRef
});
if (fieldsetConfig.form) {
field.form = fieldsetConfig.form;
field.id = "".concat(fieldsetConfig.form, "-").concat(field.name);
field.errorId = "".concat(field.id, "-error");
field.descriptionId = "".concat(field.id, "-description");
}
return field;
}
});
}
/**
* Returns a list of key and field config.
*
* @see https://conform.guide/api/react#usefieldlist
*/
function useFieldList(ref, config) {
var configRef = useConfigRef(config);
var [error, setError] = useFormError(ref, {
initialError: config.initialError,
name: config.name
});
var [entries, setEntries] = react.useState(() => {
var _config$defaultValue;
return Object.entries((_config$defaultValue = config.defaultValue) !== null && _config$defaultValue !== void 0 ? _config$defaultValue : []);
});
react.useEffect(() => {
var conformHandler = event => {
var form = dom.getFormElement(ref.current);
if (!form || event.target !== form) {
return;
// To support array destructuring
if (prop === Symbol.iterator) {
var _index = 0;
return () => ({
next: () => ({
value: getMetadata(_index++),
done: false
})
});
}
var intent = dom.parseIntent(event.detail);
if ((intent === null || intent === void 0 ? void 0 : intent.type) !== 'list' || (intent === null || intent === void 0 ? void 0 : intent.payload.name) !== configRef.current.name) {
return;
var index = Number(prop);
if (typeof prop === 'string') {
return getMetadata(Number.isNaN(index) ? prop : index);
}
setEntries(entries => {
var list = [...entries];
switch (intent.payload.operation) {
case 'append':
case 'prepend':
case 'insert':
case 'replace':
return dom.updateList(list, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, intent.payload), {}, {
defaultValue: [
// Generate a random key to avoid conflicts
getUniqueKey(), intent.payload.defaultValue]
}));
default:
return dom.updateList(list, intent.payload);
}
});
setError(error => {
var errorList = [];
for (var [key, messages] of Object.entries(error)) {
if (typeof key === 'number') {
errorList[key] = messages;
}
}
switch (intent.payload.operation) {
case 'append':
case 'prepend':
case 'insert':
case 'replace':
errorList = dom.updateList(errorList, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, intent.payload), {}, {
defaultValue: undefined
}));
break;
default:
errorList = dom.updateList(errorList, intent.payload);
break;
}
return Object.assign({}, errorList);
});
};
var resetHandler = event => {
var _configRef$current$de;
var form = dom.getFormElement(ref.current);
if (!form || event.target !== form) {
return;
}
setEntries(Object.entries((_configRef$current$de = configRef.current.defaultValue) !== null && _configRef$current$de !== void 0 ? _configRef$current$de : []));
};
// @ts-expect-error Custom event: conform
document.addEventListener('conform', conformHandler, true);
document.addEventListener('reset', resetHandler);
return () => {
// @ts-expect-error Custom event: conform
document.removeEventListener('conform', conformHandler, true);
document.removeEventListener('reset', resetHandler);
};
}, [ref, configRef, setError]);
return entries.map((_ref3, index) => {
var _config$initialError;
var [key, defaultValue] = _ref3;
var errors = error[index];
var initialError = Object.entries((_config$initialError = config.initialError) !== null && _config$initialError !== void 0 ? _config$initialError : {}).reduce((result, _ref4) => {
var [name, message] = _ref4;
var [field, ...paths] = dom.getPaths(name);
if (field === index) {
result[dom.getName(paths)] = message;
}
return result;
}, {});
var fieldConfig = {
name: "".concat(config.name, "[").concat(index, "]"),
defaultValue,
initialError,
error: errors === null || errors === void 0 ? void 0 : errors[0],
errors
};
if (config.form) {
fieldConfig.form = config.form;
fieldConfig.id = "".concat(config.form, "-").concat(config.name, "-").concat(index);
fieldConfig.errorId = "".concat(fieldConfig.id, "-error");
fieldConfig.descriptionId = "".concat(fieldConfig.id, "-description");
return Reflect.get(target, prop, receiver);
}
return _rollupPluginBabelHelpers.objectSpread2({
key
}, fieldConfig);
});
}
/**
* useLayoutEffect is client-only.
* This basically makes it a no-op on server
*/
var useSafeLayoutEffect = typeof document === 'undefined' ? react.useEffect : react.useLayoutEffect;
/**
* Returns a ref object and a set of helpers that dispatch corresponding dom event.
*
* @see https://conform.guide/api/react#useinputevent
*/
function useInputEvent(options) {
var optionsRef = useConfigRef(options);
var eventDispatched = react.useRef({
onInput: false,
onFocus: false,
onBlur: false
});
useSafeLayoutEffect(() => {
var createEventListener = listener => {
return event => {
var _optionsRef$current, _optionsRef$current2, _optionsRef$current3;
var element = typeof ((_optionsRef$current = optionsRef.current) === null || _optionsRef$current === void 0 ? void 0 : _optionsRef$current.ref) === 'function' ? (_optionsRef$current2 = optionsRef.current) === null || _optionsRef$current2 === void 0 ? void 0 : _optionsRef$current2.ref() : (_optionsRef$current3 = optionsRef.current) === null || _optionsRef$current3 === void 0 ? void 0 : _optionsRef$current3.ref.current;
if (dom.isFieldElement(element) && (listener === 'onReset' ? event.target === element.form : event.target === element)) {
var _optionsRef$current4, _optionsRef$current4$;
if (listener !== 'onReset') {
eventDispatched.current[listener] = true;
}
(_optionsRef$current4 = optionsRef.current) === null || _optionsRef$current4 === void 0 || (_optionsRef$current4$ = _optionsRef$current4[listener]) === null || _optionsRef$current4$ === void 0 ? void 0 : _optionsRef$current4$.call(_optionsRef$current4, event);
}
};
};
var inputHandler = createEventListener('onInput');
var focusHandler = createEventListener('onFocus');
var blurHandler = createEventListener('onBlur');
var resetHandler = createEventListener('onReset');
// focus/blur event does not bubble
document.addEventListener('input', inputHandler, true);
document.addEventListener('focus', focusHandler, true);
document.addEventListener('blur', blurHandler, true);
document.addEventListener('reset', resetHandler);
return () => {
document.removeEventListener('input', inputHandler, true);
document.removeEventListener('focus', focusHandler, true);
document.removeEventListener('blur', blurHandler, true);
document.removeEventListener('reset', resetHandler);
};
}, []);
var control = react.useMemo(() => {
var dispatch = (listener, fn) => {
if (!eventDispatched.current[listener]) {
var _optionsRef$current5, _optionsRef$current6, _optionsRef$current7;
var _element2 = typeof ((_optionsRef$current5 = optionsRef.current) === null || _optionsRef$current5 === void 0 ? void 0 : _optionsRef$current5.ref) === 'function' ? (_optionsRef$current6 = optionsRef.current) === null || _optionsRef$current6 === void 0 ? void 0 : _optionsRef$current6.ref() : (_optionsRef$current7 = optionsRef.current) === null || _optionsRef$current7 === void 0 ? void 0 : _optionsRef$current7.ref.current;
if (!dom.isFieldElement(_element2)) {
// eslint-disable-next-line no-console
console.warn('Failed to dispatch event; is the input mounted?');
return;
}
// To avoid recursion
eventDispatched.current[listener] = true;
fn(_element2);
}
eventDispatched.current[listener] = false;
};
return {
change(eventOrValue) {
dispatch('onInput', element => {
if (element instanceof HTMLInputElement && (element.type === 'checkbox' || element.type === 'radio')) {
if (typeof eventOrValue !== 'boolean') {
throw new Error('You should pass a boolean when changing a checkbox or radio input');
}
element.checked = eventOrValue;
} else {
if (typeof eventOrValue === 'boolean') {
throw new Error('You can pass a boolean only when changing a checkbox or radio input');
}
var _value = typeof eventOrValue === 'string' ? eventOrValue : eventOrValue.target.value;
// No change event will triggered on React if `element.value` is updated
// before dispatching the event
if (element.value !== _value) {
/**
* Triggering react custom change event
* Solution based on dom-testing-library
* @see https://github.com/facebook/react/issues/10135#issuecomment-401496776
* @see https://github.com/testing-library/dom-testing-library/blob/main/src/events.js#L104-L123
*/
var {
set: valueSetter
} = Object.getOwnPropertyDescriptor(element, 'value') || {};
var prototype = Object.getPrototypeOf(element);
var {
set: prototypeValueSetter
} = Object.getOwnPropertyDescriptor(prototype, 'value') || {};
if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
prototypeValueSetter.call(element, _value);
} else {
if (valueSetter) {
valueSetter.call(element, _value);
} else {
throw new Error('The given element does not have a value setter');
}
}
}
}
// Dispatch input event with the updated input value
element.dispatchEvent(new InputEvent('input', {
bubbles: true
}));
// Dispatch change event (necessary for select to update the selected option)
element.dispatchEvent(new Event('change', {
bubbles: true
}));
});
},
focus() {
dispatch('onFocus', element => {
element.dispatchEvent(new FocusEvent('focusin', {
bubbles: true
}));
element.dispatchEvent(new FocusEvent('focus'));
});
},
blur() {
dispatch('onBlur', element => {
element.dispatchEvent(new FocusEvent('focusout', {
bubbles: true
}));
element.dispatchEvent(new FocusEvent('blur'));
});
}
};
}, [optionsRef]);
return control;
}
var FORM_ERROR_ELEMENT_NAME = '__form__';
/**
* Validate the form with the Constraint Validation API
* @see https://conform.guide/api/react#validateconstraint
*/
function validateConstraint(options) {
var _options$formData, _options$formatMessag;
var formData = (_options$formData = options === null || options === void 0 ? void 0 : options.formData) !== null && _options$formData !== void 0 ? _options$formData : new FormData(options.form);
var getDefaultErrors = (validity, result) => {
var errors = [];
if (validity.valueMissing) errors.push('required');
if (validity.typeMismatch || validity.badInput) errors.push('type');
if (validity.tooShort) errors.push('minLength');
if (validity.rangeUnderflow) errors.push('min');
if (validity.stepMismatch) errors.push('step');
if (validity.tooLong) errors.push('maxLength');
if (validity.rangeOverflow) errors.push('max');
if (validity.patternMismatch) errors.push('pattern');
for (var [constraintName, valid] of Object.entries(result)) {
if (!valid) {
errors.push(constraintName);
}
function useFieldList(options) {
var _context$initialValue;
var subjectRef = context.useSubjectRef({
initialValue: {
name: [options.name]
}
return errors;
};
var formatMessages = (_options$formatMessag = options === null || options === void 0 ? void 0 : options.formatMessages) !== null && _options$formatMessag !== void 0 ? _options$formatMessag : _ref5 => {
var {
defaultErrors
} = _ref5;
return defaultErrors;
};
return dom.parse(formData, {
resolve() {
var error = {};
var constraintPattern = /^constraint[A-Z][^A-Z]*$/;
var _loop = function _loop(_element3) {
if (dom.isFieldElement(_element3)) {
var name = _element3.name !== FORM_ERROR_ELEMENT_NAME ? _element3.name : '';
var constraint = Object.entries(_element3.dataset).reduce((result, _ref6) => {
var [name, attributeValue = ''] = _ref6;
if (constraintPattern.test(name)) {
var _options$constraint;
var constraintName = name.slice(10).toLowerCase();
var _validate = (_options$constraint = options.constraint) === null || _options$constraint === void 0 ? void 0 : _options$constraint[constraintName];
if (typeof _validate === 'function') {
result[constraintName] = _validate(_element3.value, {
formData,
attributeValue
});
} else {
// eslint-disable-next-line no-console
console.warn("Found an \"".concat(constraintName, "\" constraint with undefined definition; Please specify it on the validateConstraint API."));
}
}
return result;
}, {});
var errors = formatMessages({
name,
validity: _element3.validity,
constraint,
defaultErrors: getDefaultErrors(_element3.validity, constraint)
});
if (errors.length > 0) {
error[name] = errors;
}
}
};
for (var _element3 of options.form.elements) {
_loop(_element3);
}
return {
error
};
}
});
}
function getUniqueKey() {
var [value] = crypto.getRandomValues(new Uint32Array(1));
if (!value) {
throw new Error('Fail to generate an unique key');
var form = context.useFormStore(options.formId, options.context);
var context$1 = context.useFormContext(form, subjectRef);
var initialValue = (_context$initialValue = context$1.initialValue[options.name]) !== null && _context$initialValue !== void 0 ? _context$initialValue : [];
if (!Array.isArray(initialValue)) {
throw new Error('The initial value at the given name is not a list');
}
return value.toString(36);
return Array(initialValue.length).fill(0).map((_, index) => context.getFieldMetadata(options.formId, context$1, {
name: options.name,
key: index,
subjectRef
}));
}
function reportSubmission(form, submission) {
for (var [name, message] of Object.entries(submission.error)) {
// There is no need to create a placeholder button if all we want is to reset the error
if (message.length === 0) {
continue;
}
// We can't use empty string as button name
// As `form.element.namedItem('')` will always returns null
var elementName = name ? name : FORM_ERROR_ELEMENT_NAME;
var item = form.elements.namedItem(elementName);
if (item === null) {
// Create placeholder button to keep the error without contributing to the form data
var button = document.createElement('button');
button.name = elementName;
button.hidden = true;
button.dataset.conformTouched = 'true';
form.appendChild(button);
}
}
var intent = dom.parseIntent(submission.intent);
var scope = getScope(intent);
for (var _element4 of dom.getFormControls(form)) {
var _submission$error$_el;
var _elementName = _element4.name !== FORM_ERROR_ELEMENT_NAME ? _element4.name : '';
var messages = (_submission$error$_el = submission.error[_elementName]) !== null && _submission$error$_el !== void 0 ? _submission$error$_el : [];
if (scope === null || scope === _elementName) {
_element4.dataset.conformTouched = 'true';
}
if (!messages.includes(dom.VALIDATION_SKIPPED) && !messages.includes(dom.VALIDATION_UNDEFINED)) {
var invalidEvent = new Event('invalid', {
cancelable: true
});
_element4.setCustomValidity(dom.getValidationMessage(messages));
_element4.dispatchEvent(invalidEvent);
}
}
if (!intent) {
dom.focusFirstInvalidControl(form);
}
function useField(options) {
var subjectRef = context.useSubjectRef();
var form = context.useFormStore(options.formId, options.context);
var context$1 = context.useFormContext(form, subjectRef);
var metadata = context.getFieldMetadata(options.formId, context$1, {
name: options.name,
subjectRef
});
return metadata;
}
function getScope(intent) {
switch (intent === null || intent === void 0 ? void 0 : intent.type) {
case 'validate':
return intent.payload;
case 'list':
return intent.payload.name;
}
return null;
}
exports.FORM_ERROR_ELEMENT_NAME = FORM_ERROR_ELEMENT_NAME;
exports.getScope = getScope;
exports.getUniqueKey = getUniqueKey;
exports.reportSubmission = reportSubmission;
exports.useField = useField;
exports.useFieldList = useFieldList;
exports.useFieldset = useFieldset;
exports.useForm = useForm;
exports.useInputEvent = useInputEvent;
exports.validateConstraint = validateConstraint;
exports.useFormId = useFormId;
exports.useFormMetadata = useFormMetadata;
exports.useSafeLayoutEffect = useSafeLayoutEffect;

@@ -1,3 +0,6 @@

export { type FieldsetConstraint, type Submission, parse, list, validate, requestIntent, isFieldElement, } from '@conform-to/dom';
export { type Fieldset, type FieldConfig, type FieldsetConfig, type FormConfig, useForm, useFieldset, useFieldList, useInputEvent, validateConstraint, } from './hooks.js';
export * as conform from './helpers.js';
export { type Submission, type FieldName, requestIntent, isFieldElement, } from '@conform-to/dom';
export { type Field, type FieldMetadata as FieldConfig, FormProvider, FormStateInput, } from './context';
export { useForm, useFormMetadata, useFieldset, useFieldList, useField, } from './hooks';
export { useInputEvent } from './integrations';
export * as conform from './helpers';
export * as intent from './intent';

@@ -6,4 +6,7 @@ 'use strict';

var dom = require('@conform-to/dom');
var context = require('./context.js');
var hooks = require('./hooks.js');
var integrations = require('./integrations.js');
var helpers = require('./helpers.js');
var intent = require('./intent.js');

@@ -16,10 +19,2 @@

});
Object.defineProperty(exports, 'list', {
enumerable: true,
get: function () { return dom.list; }
});
Object.defineProperty(exports, 'parse', {
enumerable: true,
get: function () { return dom.parse; }
});
Object.defineProperty(exports, 'requestIntent', {

@@ -29,11 +24,11 @@ enumerable: true,

});
Object.defineProperty(exports, 'validate', {
enumerable: true,
get: function () { return dom.validate; }
});
exports.FormProvider = context.FormProvider;
exports.FormStateInput = context.FormStateInput;
exports.useField = hooks.useField;
exports.useFieldList = hooks.useFieldList;
exports.useFieldset = hooks.useFieldset;
exports.useForm = hooks.useForm;
exports.useInputEvent = hooks.useInputEvent;
exports.validateConstraint = hooks.validateConstraint;
exports.useFormMetadata = hooks.useFormMetadata;
exports.useInputEvent = integrations.useInputEvent;
exports.conform = helpers;
exports.intent = intent;

@@ -6,3 +6,3 @@ {

"license": "MIT",
"version": "0.9.1",
"version": "1.0.0-pre.0",
"main": "index.js",

@@ -34,6 +34,6 @@ "module": "index.mjs",

"dependencies": {
"@conform-to/dom": "0.9.1"
"@conform-to/dom": "1.0.0-pre.0"
},
"peerDependencies": {
"react": ">=16.8"
"react": ">=18"
},

@@ -40,0 +40,0 @@ "keywords": [

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc