Socket
Socket
Sign inDemoInstall

@conform-to/react

Package Overview
Dependencies
4
Maintainers
1
Versions
62
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.3.1 to 0.4.0-pre.0

9

helpers.js

@@ -25,3 +25,3 @@ 'use strict';

if (typeof config.initialError !== 'undefined') {
if (config.initialError && config.initialError.length > 0) {
attributes.autoFocus = true;

@@ -47,7 +47,6 @@ }

required: config.required,
multiple: config.multiple,
autoFocus: typeof config.initialError !== 'undefined' ? Boolean(config.initialError) : undefined
multiple: config.multiple
};
if (typeof config.initialError !== 'undefined') {
if (config.initialError && config.initialError.length > 0) {
attributes.autoFocus = true;

@@ -71,3 +70,3 @@ }

if (typeof config.initialError !== 'undefined') {
if (config.initialError && config.initialError.length > 0) {
attributes.autoFocus = true;

@@ -74,0 +73,0 @@ }

@@ -1,4 +0,9 @@

import { type FieldConfig, type FieldError, type FieldValue, type FieldElement, type FieldsetConstraint, type ListCommand, type Primitive } from '@conform-to/dom';
import { type FieldConfig, type FieldElement, type FieldValue, type FieldsetConstraint, type FormState, type ListCommand, type Primitive, type Submission } from '@conform-to/dom';
import { type InputHTMLAttributes, type FormEvent, type RefObject } from 'react';
export interface FormConfig {
interface FormContext<Schema extends Record<string, any>> {
form: HTMLFormElement;
formData: FormData;
submission: Submission<Schema>;
}
export interface FormConfig<Schema extends Record<string, any>> {
/**

@@ -12,2 +17,10 @@ * Define when the error should be reported initially.

/**
* An object representing the initial value of the form.
*/
defaultValue?: FieldValue<Schema>;
/**
* An object describing the state from the last submission
*/
state?: FormState<Schema>;
/**
* Enable native validation before hydation.

@@ -27,3 +40,3 @@ *

*/
validate?: (form: HTMLFormElement, submitter?: HTMLInputElement | HTMLButtonElement | null) => void;
onValidate?: (context: FormContext<Schema>) => boolean;
/**

@@ -33,3 +46,3 @@ * The submit event handler of the form. It will be called

*/
onSubmit?: (event: FormEvent<HTMLFormElement>) => void;
onSubmit?: (event: FormEvent<HTMLFormElement>, context: FormContext<Schema>) => void;
}

@@ -44,2 +57,8 @@ /**

}
interface Form<Schema extends Record<string, any>> {
ref: RefObject<HTMLFormElement>;
error: string;
props: FormProps;
config: FieldsetConfig<Schema>;
}
/**

@@ -49,5 +68,5 @@ * Returns properties required to hook into form events.

*
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#useform
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#useform
*/
export declare function useForm(config?: FormConfig): FormProps;
export declare function useForm<Schema extends Record<string, any>>(config?: FormConfig<Schema>): Form<Schema>;
/**

@@ -78,3 +97,3 @@ * All the information of the field, including state and config.

*/
initialError?: FieldError<Schema>['details'];
initialError?: Array<[string, string]>;
/**

@@ -92,3 +111,3 @@ * An object describing the constraint of each field

*
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usefieldset
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usefieldset
*/

@@ -120,3 +139,3 @@ export declare function useFieldset<Schema extends Record<string, any>>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config?: FieldsetConfig<Schema>): Fieldset<Schema>;

*
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usefieldlist
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usefieldlist
*/

@@ -151,7 +170,7 @@ export declare function useFieldList<Payload = any>(ref: RefObject<HTMLFormElement | HTMLFieldSetElement>, config: FieldConfig<Array<Payload>>): [

*
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usecontrolledinput
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usecontrolledinput
*/
export declare function useControlledInput<Element extends {
focus: () => void;
} = HTMLInputElement, Schema extends Primitive = Primitive>(field: FieldConfig<Schema>): [ShadowInputProps, InputControl<Element>];
} = HTMLInputElement, Schema extends Primitive = Primitive>(config: FieldConfig<Schema>): [ShadowInputProps, InputControl<Element>];
export {};

@@ -14,24 +14,56 @@ 'use strict';

*
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#useform
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#useform
*/
function useForm() {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var {
validate
} = config;
var configRef = react.useRef(config);
var ref = react.useRef(null);
var [error, setError] = react.useState(() => {
var _config$state$error$f, _config$state, _config$state$error;
var [, message] = (_config$state$error$f = (_config$state = config.state) === null || _config$state === void 0 ? void 0 : (_config$state$error = _config$state.error) === null || _config$state$error === void 0 ? void 0 : _config$state$error.find(_ref => {
var [key] = _ref;
return key === '';
})) !== null && _config$state$error$f !== void 0 ? _config$state$error$f : [];
return message !== null && message !== void 0 ? message : '';
});
var [fieldsetConfig, setFieldsetConfig] = react.useState(() => {
var _config$state$error2, _config$state2, _config$state3, _config$state$value, _config$state4;
var error = (_config$state$error2 = (_config$state2 = config.state) === null || _config$state2 === void 0 ? void 0 : _config$state2.error) !== null && _config$state$error2 !== void 0 ? _config$state$error2 : [];
var scope = (_config$state3 = config.state) === null || _config$state3 === void 0 ? void 0 : _config$state3.scope;
return {
defaultValue: (_config$state$value = (_config$state4 = config.state) === null || _config$state4 === void 0 ? void 0 : _config$state4.value) !== null && _config$state$value !== void 0 ? _config$state$value : config.defaultValue,
initialError: error.filter(_ref2 => {
var [name] = _ref2;
return name !== '' && dom.getSubmissionType(name) === null && (!scope || scope.includes(name));
})
};
});
var [noValidate, setNoValidate] = react.useState(config.noValidate || !config.fallbackNative);
react.useEffect(() => {
configRef.current = config;
});
react.useEffect(() => {
setNoValidate(true);
}, []);
react.useEffect(() => {
// Initialize form validation messages
if (ref.current) {
validate === null || validate === void 0 ? void 0 : validate(ref.current);
} // Revalidate the form when input value is changed
var form = ref.current;
if (!form || !config.state) {
return;
}
if (!dom.reportValidity(form, config.state)) {
dom.focusFirstInvalidField(form, config.state.scope);
}
dom.requestSubmit(form);
}, [config.state]);
react.useEffect(() => {
// Revalidate the form when input value is changed
var handleInput = event => {
var field = event.target;
var form = ref.current;
var formConfig = configRef.current;

@@ -42,16 +74,8 @@ if (!form || !dom.isFieldElement(field) || field.form !== form) {

validate === null || validate === void 0 ? void 0 : validate(form);
if (formConfig.initialReport === 'onChange') {
field.dataset.conformTouched = 'true';
}
if (!config.noValidate) {
if (config.initialReport === 'onChange') {
field.dataset.conformTouched = 'true';
} // Field validity might be changed due to cross reference
for (var _field of form.elements) {
if (dom.isFieldElement(_field) && _field.dataset.conformTouched) {
// Report latest error for all touched fields
_field.checkValidity();
}
}
if (field.dataset.conformTouched) {
dom.requestValidate(form, field.name);
}

@@ -63,13 +87,32 @@ };

var form = ref.current;
var formConfig = configRef.current;
if (!form || !dom.isFieldElement(field) || field.form !== form || config.noValidate || config.initialReport !== 'onBlur') {
if (!form || !dom.isFieldElement(field) || field.form !== form) {
return;
}
field.dataset.conformTouched = 'true';
field.reportValidity();
if (formConfig.initialReport === 'onBlur' && !field.dataset.conformTouched) {
field.dataset.conformTouched = 'true';
dom.requestValidate(form, field.name);
}
};
var handleInvalid = event => {
var form = dom.getFormElement(ref.current);
var field = event.target;
if (!form || !dom.isFieldElement(field) || field.form !== form || field.name !== '') {
return;
}
event.preventDefault();
if (field.dataset.conformTouched) {
setError(field.validationMessage);
}
};
var handleReset = event => {
var form = ref.current;
var formConfig = configRef.current;

@@ -84,13 +127,11 @@ if (!form || event.target !== form) {

delete field.dataset.conformTouched;
field.setCustomValidity('');
}
}
/**
* The reset event is triggered before form reset happens.
* This make sure the form to be revalidated with initial values.
*/
setTimeout(() => {
validate === null || validate === void 0 ? void 0 : validate(form);
}, 0);
setError('');
setFieldsetConfig({
defaultValue: formConfig.defaultValue,
initialError: []
});
};

@@ -107,2 +148,3 @@ /**

document.addEventListener('blur', handleBlur, true);
document.addEventListener('invalid', handleInvalid, true);
document.addEventListener('reset', handleReset);

@@ -112,50 +154,74 @@ return () => {

document.removeEventListener('blur', handleBlur, true);
document.removeEventListener('invalid', handleInvalid, true);
document.removeEventListener('reset', handleReset);
};
}, [validate, config.initialReport, config.noValidate]);
}, []);
return {
ref,
noValidate,
error,
props: {
ref,
noValidate,
onSubmit(event) {
var form = event.currentTarget;
var nativeEvent = event.nativeEvent;
var submitter = nativeEvent.submitter instanceof HTMLButtonElement || nativeEvent.submitter instanceof HTMLInputElement ? nativeEvent.submitter : null; // Validating the form with the submitter value
onSubmit(event) {
var form = event.currentTarget;
var nativeEvent = event.nativeEvent;
var submitter = nativeEvent.submitter;
validate === null || validate === void 0 ? void 0 : validate(form, submitter);
/**
* It checks defaultPrevented to confirm if the submission is intentional
* This is utilized by `useFieldList` to modify the list state when the submit
* event is captured and revalidate the form with new fields without triggering
* a form submission at the same time.
*/
for (var element of form.elements) {
if (dom.isFieldElement(element) && element.name === '') {
setError(element.validationMessage);
break;
}
}
/**
* It checks defaultPrevented to confirm if the submission is intentional
* This is utilized by `useFieldList` to modify the list state when the submit
* event is captured and revalidate the form with new fields without triggering
* a form submission at the same time.
*/
if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && !event.defaultPrevented) {
var focused = false;
for (var field of form.elements) {
if (dom.isFieldElement(field)) {
// Mark the field as touched
field.dataset.conformTouched = 'true'; // Focus on the first invalid field
if (!submitter || event.defaultPrevented) {
event.preventDefault();
return;
}
if (!focused && !field.validity.valid && field.tagName !== 'BUTTON') {
field.focus();
focused = true;
var formData = dom.getFormData(form, submitter);
var submission = dom.parse(formData);
var context = {
form,
formData,
submission
}; // Touch all fields only if the submitter is not a command button
if (!submission.type) {
for (var field of form.elements) {
if (dom.isFieldElement(field)) {
// Mark the field as touched
field.dataset.conformTouched = 'true';
}
}
} // Check the validity of the form
}
if (!event.currentTarget.reportValidity()) {
event.preventDefault();
if (typeof config.onValidate === 'function' && !config.noValidate && !submitter.formNoValidate) {
try {
if (!config.onValidate(context)) {
dom.focusFirstInvalidField(form);
event.preventDefault();
}
} catch (e) {
console.warn(e);
}
}
}
if (!event.defaultPrevented) {
var _config$onSubmit;
if (!event.defaultPrevented) {
var _config$onSubmit;
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event);
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, context);
}
}
}
},
config: fieldsetConfig
};

@@ -168,10 +234,43 @@ }

function useFieldset(ref, config) {
var configRef = react.useRef(config);
var [uncontrolledState, setUncontrolledState] = react.useState( // @ts-expect-error
() => {
var _config$defaultValue;
var initialError = {};
for (var [name, message] of (_config$initialError = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError !== void 0 ? _config$initialError : []) {
var _config$initialError;
var [key, ...paths] = dom.getPaths(name);
if (typeof key === 'string') {
var _initialError$key;
var scopedName = dom.getName(paths);
var entries = (_initialError$key = initialError[key]) !== null && _initialError$key !== void 0 ? _initialError$key : [];
if (scopedName === '' && entries.length > 0 && entries[0][0] !== '') {
initialError[key] = [[scopedName, message], ...entries];
} else {
initialError[key] = [...entries, [scopedName, message]];
}
}
}
return {
defaultValue: (_config$defaultValue = config === null || config === void 0 ? void 0 : config.defaultValue) !== null && _config$defaultValue !== void 0 ? _config$defaultValue : {},
initialError
};
});
var [error, setError] = react.useState(() => {
var result = {};
for (var [key, _error] of Object.entries((_config$initialError = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError !== void 0 ? _config$initialError : {})) {
var _config$initialError;
for (var [key, entries] of Object.entries(uncontrolledState.initialError)) {
var _entries$;
if (_error !== null && _error !== void 0 && _error.message) {
result[key] = _error.message;
var [name, message] = (_entries$ = entries === null || entries === void 0 ? void 0 : entries[0]) !== null && _entries$ !== void 0 ? _entries$ : [];
if (name === '') {
result[key] = message !== null && message !== void 0 ? message : '';
}

@@ -183,2 +282,5 @@ }

react.useEffect(() => {
configRef.current = config;
});
react.useEffect(() => {
/**

@@ -192,9 +294,12 @@ * Reset the error state of each field if its validity is changed.

setError(prev => {
var _configRef$current$na, _configRef$current;
var next = prev;
var fieldsetName = (_configRef$current$na = (_configRef$current = configRef.current) === null || _configRef$current === void 0 ? void 0 : _configRef$current.name) !== null && _configRef$current$na !== void 0 ? _configRef$current$na : '';
for (var field of form.elements) {
if (dom.isFieldElement(field)) {
var key = dom.getKey(field.name, config === null || config === void 0 ? void 0 : config.name);
if (dom.isFieldElement(field) && field.name.startsWith(fieldsetName)) {
var [key, ...paths] = dom.getPaths(fieldsetName.length > 0 ? field.name.slice(fieldsetName.length + 1) : field.name);
if (key) {
if (typeof key === 'string' && paths.length === 0) {
var _next$key, _next;

@@ -235,25 +340,31 @@

var invalidHandler = event => {
var _configRef$current$na2, _configRef$current2;
var form = dom.getFormElement(ref.current);
var field = event.target;
var fieldsetName = (_configRef$current$na2 = (_configRef$current2 = configRef.current) === null || _configRef$current2 === void 0 ? void 0 : _configRef$current2.name) !== null && _configRef$current$na2 !== void 0 ? _configRef$current$na2 : '';
if (!form || !dom.isFieldElement(field) || field.form !== form) {
if (!form || !dom.isFieldElement(field) || field.form !== form || !field.name.startsWith(fieldsetName)) {
return;
}
var key = dom.getKey(field.name, config === null || config === void 0 ? void 0 : config.name); // Update the error only if the field belongs to the fieldset
var [key, ...paths] = dom.getPaths(fieldsetName.length > 0 ? field.name.slice(fieldsetName.length + 1) : field.name); // Update the error only if the field belongs to the fieldset
if (key) {
setError(prev => {
var _prev$key;
if (typeof key === 'string' && paths.length === 0) {
if (field.dataset.conformTouched) {
setError(prev => {
var _prev$key;
var prevMessage = (_prev$key = prev === null || prev === void 0 ? void 0 : prev[key]) !== null && _prev$key !== void 0 ? _prev$key : '';
var prevMessage = (_prev$key = prev === null || prev === void 0 ? void 0 : prev[key]) !== null && _prev$key !== void 0 ? _prev$key : '';
if (prevMessage === field.validationMessage) {
return prev;
}
if (prevMessage === field.validationMessage) {
return prev;
}
return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, prev), {}, {
[key]: field.validationMessage
return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, prev), {}, {
[key]: field.validationMessage
});
});
});
}
event.preventDefault();

@@ -275,2 +386,4 @@ }

var resetHandler = event => {
var _fieldsetConfig$defau;
var form = dom.getFormElement(ref.current);

@@ -282,2 +395,8 @@

var fieldsetConfig = configRef.current;
setUncontrolledState({
// @ts-expect-error
defaultValue: (_fieldsetConfig$defau = fieldsetConfig === null || fieldsetConfig === void 0 ? void 0 : fieldsetConfig.defaultValue) !== null && _fieldsetConfig$defau !== void 0 ? _fieldsetConfig$defau : {},
initialError: {}
});
setError({});

@@ -297,22 +416,3 @@ };

};
}, [ref, config === null || config === void 0 ? void 0 : config.name]);
react.useEffect(() => {
setError(prev => {
var next = prev;
for (var [key, _error2] of Object.entries((_config$initialError2 = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError2 !== void 0 ? _config$initialError2 : {})) {
var _config$initialError2;
if (next[key] !== (_error2 === null || _error2 === void 0 ? void 0 : _error2.message)) {
var _error2$message;
next = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, next), {}, {
[key]: (_error2$message = _error2 === null || _error2 === void 0 ? void 0 : _error2.message) !== null && _error2$message !== void 0 ? _error2$message : ''
});
}
}
return next;
});
}, [config === null || config === void 0 ? void 0 : config.name, config === null || config === void 0 ? void 0 : config.initialError]);
}, [ref]);
/**

@@ -326,3 +426,3 @@ * This allows us constructing the field at runtime as we have no information

get(_target, key) {
var _constraint, _config$defaultValue, _config$initialError$, _config$initialError3, _config$initialError4, _config$initialError5, _config$initialError6, _error$key;
var _fieldsetConfig$const, _error$key;

@@ -333,9 +433,10 @@ if (typeof key !== 'string') {

var constraint = config === null || config === void 0 ? void 0 : (_constraint = config.constraint) === null || _constraint === void 0 ? void 0 : _constraint[key];
var fieldsetConfig = config !== null && config !== void 0 ? config : {};
var constraint = (_fieldsetConfig$const = fieldsetConfig.constraint) === null || _fieldsetConfig$const === void 0 ? void 0 : _fieldsetConfig$const[key];
var field = {
config: _rollupPluginBabelHelpers.objectSpread2({
name: config !== null && config !== void 0 && config.name ? "".concat(config.name, ".").concat(key) : key,
form: config === null || config === void 0 ? void 0 : config.form,
defaultValue: config === null || config === void 0 ? void 0 : (_config$defaultValue = config.defaultValue) === null || _config$defaultValue === void 0 ? void 0 : _config$defaultValue[key],
initialError: (_config$initialError$ = config === null || config === void 0 ? void 0 : (_config$initialError3 = config.initialError) === null || _config$initialError3 === void 0 ? void 0 : (_config$initialError4 = _config$initialError3[key]) === null || _config$initialError4 === void 0 ? void 0 : _config$initialError4.details) !== null && _config$initialError$ !== void 0 ? _config$initialError$ : config === null || config === void 0 ? void 0 : (_config$initialError5 = config.initialError) === null || _config$initialError5 === void 0 ? void 0 : (_config$initialError6 = _config$initialError5[key]) === null || _config$initialError6 === void 0 ? void 0 : _config$initialError6.message
name: fieldsetConfig.name ? "".concat(fieldsetConfig.name, ".").concat(key) : key,
form: fieldsetConfig.form,
defaultValue: uncontrolledState.defaultValue[key],
initialError: uncontrolledState.initialError[key]
}, constraint),

@@ -354,21 +455,51 @@ error: (_error$key = error === null || error === void 0 ? void 0 : error[key]) !== null && _error$key !== void 0 ? _error$key : ''

*
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usefieldlist
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usefieldlist
*/
function useFieldList(ref, config) {
var [entries, setEntries] = react.useState(() => {
var configRef = react.useRef(config);
var [uncontrolledState, setUncontrolledState] = react.useState(() => {
var _config$defaultValue2;
return Object.entries((_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : [undefined]);
var initialError = [];
for (var [name, message] of (_config$initialError2 = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError2 !== void 0 ? _config$initialError2 : []) {
var _config$initialError2;
var [index, ...paths] = dom.getPaths(name);
if (typeof index === 'number') {
var _initialError$index;
var scopedName = dom.getName(paths);
var _entries = (_initialError$index = initialError[index]) !== null && _initialError$index !== void 0 ? _initialError$index : [];
if (scopedName === '' && _entries.length > 0 && _entries[0][0] !== '') {
initialError[index] = [[scopedName, message], ..._entries];
} else {
initialError[index] = [..._entries, [scopedName, message]];
}
}
}
return {
defaultValue: (_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : [],
initialError
};
});
var list = entries.map((_ref, index) => {
var _config$defaultValue3, _config$initialError7, _config$initialError8;
var [entries, setEntries] = react.useState(() => {
var _config$defaultValue3;
var [key, defaultValue] = _ref;
return Object.entries((_config$defaultValue3 = config.defaultValue) !== null && _config$defaultValue3 !== void 0 ? _config$defaultValue3 : [undefined]);
});
var list = entries.map((_ref3, index) => {
var [key, defaultValue] = _ref3;
return {
key,
config: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, config), {}, {
config: {
name: "".concat(config.name, "[").concat(index, "]"),
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : (_config$defaultValue3 = config.defaultValue) === null || _config$defaultValue3 === void 0 ? void 0 : _config$defaultValue3[index],
initialError: (_config$initialError7 = config.initialError) === null || _config$initialError7 === void 0 ? void 0 : (_config$initialError8 = _config$initialError7[index]) === null || _config$initialError8 === void 0 ? void 0 : _config$initialError8.details
})
form: config.form,
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : uncontrolledState.defaultValue[index],
initialError: uncontrolledState.initialError[index]
}
};

@@ -386,5 +517,6 @@ });

return {
name: dom.listCommandKey,
value: dom.serializeListCommand(config.name, {
name: 'conform/list',
value: JSON.stringify({
type,
scope: config.name,
payload

@@ -400,34 +532,15 @@ }),

react.useEffect(() => {
setEntries(prevEntries => {
var _config$defaultValue4;
var nextEntries = Object.entries((_config$defaultValue4 = config.defaultValue) !== null && _config$defaultValue4 !== void 0 ? _config$defaultValue4 : [undefined]);
if (prevEntries.length !== nextEntries.length) {
return nextEntries;
}
for (var i = 0; i < prevEntries.length; i++) {
var [prevKey, prevValue] = prevEntries[i];
var [nextKey, nextValue] = nextEntries[i];
if (prevKey !== nextKey || prevValue !== nextValue) {
return nextEntries;
}
} // No need to rerender in this case
return prevEntries;
});
configRef.current = config;
});
react.useEffect(() => {
var submitHandler = event => {
var form = dom.getFormElement(ref.current);
if (!form || event.target !== form || !(event.submitter instanceof HTMLButtonElement) || event.submitter.name !== dom.listCommandKey) {
if (!form || event.target !== form || !(event.submitter instanceof HTMLButtonElement) || event.submitter.name !== 'conform/list') {
return;
}
var [name, command] = dom.parseListCommand(event.submitter.value);
var command = dom.parseListCommand(event.submitter.value);
if (name !== config.name) {
if (command.scope !== configRef.current.name) {
// Ensure the scope of the listener are limited to specific field name

@@ -437,11 +550,19 @@ return;

switch (command.type) {
case 'append':
case 'prepend':
case 'replace':
command.payload.defaultValue = ["".concat(Date.now()), command.payload.defaultValue];
break;
}
setEntries(entries => {
switch (command.type) {
case 'append':
case 'prepend':
case 'replace':
return dom.updateList([...(entries !== null && entries !== void 0 ? entries : [])], _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, command), {}, {
payload: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, command.payload), {}, {
defaultValue: ["".concat(Date.now()), command.payload.defaultValue]
})
}));
setEntries(entries => dom.updateList([...(entries !== null && entries !== void 0 ? entries : [])], command));
default:
{
return dom.updateList([...(entries !== null && entries !== void 0 ? entries : [])], command);
}
}
});
event.preventDefault();

@@ -451,3 +572,3 @@ };

var resetHandler = event => {
var _config$defaultValue5;
var _fieldConfig$defaultV, _fieldConfig$defaultV2;

@@ -460,3 +581,8 @@ var form = dom.getFormElement(ref.current);

setEntries(Object.entries((_config$defaultValue5 = config.defaultValue) !== null && _config$defaultValue5 !== void 0 ? _config$defaultValue5 : []));
var fieldConfig = configRef.current;
setUncontrolledState({
defaultValue: (_fieldConfig$defaultV = fieldConfig.defaultValue) !== null && _fieldConfig$defaultV !== void 0 ? _fieldConfig$defaultV : [],
initialError: []
});
setEntries(Object.entries((_fieldConfig$defaultV2 = fieldConfig.defaultValue) !== null && _fieldConfig$defaultV2 !== void 0 ? _fieldConfig$defaultV2 : [undefined]));
};

@@ -470,3 +596,3 @@

};
}, [ref, config.name, config.defaultValue]);
}, [ref]);
return [list, control];

@@ -480,10 +606,15 @@ }

*
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usecontrolledinput
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usecontrolledinput
*/
function useControlledInput(field) {
var _field$defaultValue;
function useControlledInput(config) {
var _config$defaultValue4;
var ref = react.useRef(null);
var inputRef = react.useRef(null);
var [value, setValue] = react.useState("".concat((_field$defaultValue = field.defaultValue) !== null && _field$defaultValue !== void 0 ? _field$defaultValue : ''));
var configRef = react.useRef(config);
var [uncontrolledState, setUncontrolledState] = react.useState({
defaultValue: config.defaultValue,
initialError: config.initialError
});
var [value, setValue] = react.useState("".concat((_config$defaultValue4 = config.defaultValue) !== null && _config$defaultValue4 !== void 0 ? _config$defaultValue4 : ''));

@@ -515,2 +646,27 @@ var handleChange = eventOrValue => {

react.useEffect(() => {
configRef.current = config;
});
react.useEffect(() => {
var resetHandler = event => {
var _configRef$current$de;
var form = dom.getFormElement(ref.current);
if (!form || event.target !== form) {
return;
}
setUncontrolledState({
defaultValue: configRef.current.defaultValue,
initialError: configRef.current.initialError
});
setValue("".concat((_configRef$current$de = configRef.current.defaultValue) !== null && _configRef$current$de !== void 0 ? _configRef$current$de : ''));
};
document.addEventListener('reset', resetHandler);
return () => {
document.removeEventListener('reset', resetHandler);
};
}, []);
return [_rollupPluginBabelHelpers.objectSpread2({

@@ -536,3 +692,3 @@ ref,

}, helpers.input(field, {
}, helpers.input(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, config), uncontrolledState), {
type: 'text'

@@ -539,0 +695,0 @@ })), {

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

export { type FormState, type FieldsetConstraint, type Schema, type Submission, createSubmission, createValidate, } from '@conform-to/dom';
export { type FieldsetConstraint, type FormState, type Submission, hasError, isFieldElement, parse, reportValidity, } from '@conform-to/dom';
export * from './hooks';
export * as conform from './helpers';

@@ -11,10 +11,18 @@ 'use strict';

Object.defineProperty(exports, 'createSubmission', {
Object.defineProperty(exports, 'hasError', {
enumerable: true,
get: function () { return dom.createSubmission; }
get: function () { return dom.hasError; }
});
Object.defineProperty(exports, 'createValidate', {
Object.defineProperty(exports, 'isFieldElement', {
enumerable: true,
get: function () { return dom.createValidate; }
get: function () { return dom.isFieldElement; }
});
Object.defineProperty(exports, 'parse', {
enumerable: true,
get: function () { return dom.parse; }
});
Object.defineProperty(exports, 'reportValidity', {
enumerable: true,
get: function () { return dom.reportValidity; }
});
exports.useControlledInput = hooks.useControlledInput;

@@ -21,0 +29,0 @@ exports.useFieldList = hooks.useFieldList;

@@ -21,3 +21,3 @@ function input(config) {

if (typeof config.initialError !== 'undefined') {
if (config.initialError && config.initialError.length > 0) {
attributes.autoFocus = true;

@@ -43,7 +43,6 @@ }

required: config.required,
multiple: config.multiple,
autoFocus: typeof config.initialError !== 'undefined' ? Boolean(config.initialError) : undefined
multiple: config.multiple
};
if (typeof config.initialError !== 'undefined') {
if (config.initialError && config.initialError.length > 0) {
attributes.autoFocus = true;

@@ -67,3 +66,3 @@ }

if (typeof config.initialError !== 'undefined') {
if (config.initialError && config.initialError.length > 0) {
attributes.autoFocus = true;

@@ -70,0 +69,0 @@ }

import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js';
import { isFieldElement, listCommandKey, serializeListCommand, getFormElement, getKey, parseListCommand, updateList } from '@conform-to/dom';
import { getSubmissionType, reportValidity, focusFirstInvalidField, requestSubmit, isFieldElement, getFormData, parse, getPaths, getName, requestValidate, getFormElement, parseListCommand, updateList } from '@conform-to/dom';
import { useRef, useState, useEffect } from 'react';

@@ -10,24 +10,56 @@ import { input } from './helpers.js';

*
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#useform
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#useform
*/
function useForm() {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var {
validate
} = config;
var configRef = useRef(config);
var ref = useRef(null);
var [error, setError] = useState(() => {
var _config$state$error$f, _config$state, _config$state$error;
var [, message] = (_config$state$error$f = (_config$state = config.state) === null || _config$state === void 0 ? void 0 : (_config$state$error = _config$state.error) === null || _config$state$error === void 0 ? void 0 : _config$state$error.find(_ref => {
var [key] = _ref;
return key === '';
})) !== null && _config$state$error$f !== void 0 ? _config$state$error$f : [];
return message !== null && message !== void 0 ? message : '';
});
var [fieldsetConfig, setFieldsetConfig] = useState(() => {
var _config$state$error2, _config$state2, _config$state3, _config$state$value, _config$state4;
var error = (_config$state$error2 = (_config$state2 = config.state) === null || _config$state2 === void 0 ? void 0 : _config$state2.error) !== null && _config$state$error2 !== void 0 ? _config$state$error2 : [];
var scope = (_config$state3 = config.state) === null || _config$state3 === void 0 ? void 0 : _config$state3.scope;
return {
defaultValue: (_config$state$value = (_config$state4 = config.state) === null || _config$state4 === void 0 ? void 0 : _config$state4.value) !== null && _config$state$value !== void 0 ? _config$state$value : config.defaultValue,
initialError: error.filter(_ref2 => {
var [name] = _ref2;
return name !== '' && getSubmissionType(name) === null && (!scope || scope.includes(name));
})
};
});
var [noValidate, setNoValidate] = useState(config.noValidate || !config.fallbackNative);
useEffect(() => {
configRef.current = config;
});
useEffect(() => {
setNoValidate(true);
}, []);
useEffect(() => {
// Initialize form validation messages
if (ref.current) {
validate === null || validate === void 0 ? void 0 : validate(ref.current);
} // Revalidate the form when input value is changed
var form = ref.current;
if (!form || !config.state) {
return;
}
if (!reportValidity(form, config.state)) {
focusFirstInvalidField(form, config.state.scope);
}
requestSubmit(form);
}, [config.state]);
useEffect(() => {
// Revalidate the form when input value is changed
var handleInput = event => {
var field = event.target;
var form = ref.current;
var formConfig = configRef.current;

@@ -38,16 +70,8 @@ if (!form || !isFieldElement(field) || field.form !== form) {

validate === null || validate === void 0 ? void 0 : validate(form);
if (formConfig.initialReport === 'onChange') {
field.dataset.conformTouched = 'true';
}
if (!config.noValidate) {
if (config.initialReport === 'onChange') {
field.dataset.conformTouched = 'true';
} // Field validity might be changed due to cross reference
for (var _field of form.elements) {
if (isFieldElement(_field) && _field.dataset.conformTouched) {
// Report latest error for all touched fields
_field.checkValidity();
}
}
if (field.dataset.conformTouched) {
requestValidate(form, field.name);
}

@@ -59,13 +83,32 @@ };

var form = ref.current;
var formConfig = configRef.current;
if (!form || !isFieldElement(field) || field.form !== form || config.noValidate || config.initialReport !== 'onBlur') {
if (!form || !isFieldElement(field) || field.form !== form) {
return;
}
field.dataset.conformTouched = 'true';
field.reportValidity();
if (formConfig.initialReport === 'onBlur' && !field.dataset.conformTouched) {
field.dataset.conformTouched = 'true';
requestValidate(form, field.name);
}
};
var handleInvalid = event => {
var form = getFormElement(ref.current);
var field = event.target;
if (!form || !isFieldElement(field) || field.form !== form || field.name !== '') {
return;
}
event.preventDefault();
if (field.dataset.conformTouched) {
setError(field.validationMessage);
}
};
var handleReset = event => {
var form = ref.current;
var formConfig = configRef.current;

@@ -80,13 +123,11 @@ if (!form || event.target !== form) {

delete field.dataset.conformTouched;
field.setCustomValidity('');
}
}
/**
* The reset event is triggered before form reset happens.
* This make sure the form to be revalidated with initial values.
*/
setTimeout(() => {
validate === null || validate === void 0 ? void 0 : validate(form);
}, 0);
setError('');
setFieldsetConfig({
defaultValue: formConfig.defaultValue,
initialError: []
});
};

@@ -103,2 +144,3 @@ /**

document.addEventListener('blur', handleBlur, true);
document.addEventListener('invalid', handleInvalid, true);
document.addEventListener('reset', handleReset);

@@ -108,50 +150,74 @@ return () => {

document.removeEventListener('blur', handleBlur, true);
document.removeEventListener('invalid', handleInvalid, true);
document.removeEventListener('reset', handleReset);
};
}, [validate, config.initialReport, config.noValidate]);
}, []);
return {
ref,
noValidate,
error,
props: {
ref,
noValidate,
onSubmit(event) {
var form = event.currentTarget;
var nativeEvent = event.nativeEvent;
var submitter = nativeEvent.submitter instanceof HTMLButtonElement || nativeEvent.submitter instanceof HTMLInputElement ? nativeEvent.submitter : null; // Validating the form with the submitter value
onSubmit(event) {
var form = event.currentTarget;
var nativeEvent = event.nativeEvent;
var submitter = nativeEvent.submitter;
validate === null || validate === void 0 ? void 0 : validate(form, submitter);
/**
* It checks defaultPrevented to confirm if the submission is intentional
* This is utilized by `useFieldList` to modify the list state when the submit
* event is captured and revalidate the form with new fields without triggering
* a form submission at the same time.
*/
for (var element of form.elements) {
if (isFieldElement(element) && element.name === '') {
setError(element.validationMessage);
break;
}
}
/**
* It checks defaultPrevented to confirm if the submission is intentional
* This is utilized by `useFieldList` to modify the list state when the submit
* event is captured and revalidate the form with new fields without triggering
* a form submission at the same time.
*/
if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && !event.defaultPrevented) {
var focused = false;
for (var field of form.elements) {
if (isFieldElement(field)) {
// Mark the field as touched
field.dataset.conformTouched = 'true'; // Focus on the first invalid field
if (!submitter || event.defaultPrevented) {
event.preventDefault();
return;
}
if (!focused && !field.validity.valid && field.tagName !== 'BUTTON') {
field.focus();
focused = true;
var formData = getFormData(form, submitter);
var submission = parse(formData);
var context = {
form,
formData,
submission
}; // Touch all fields only if the submitter is not a command button
if (!submission.type) {
for (var field of form.elements) {
if (isFieldElement(field)) {
// Mark the field as touched
field.dataset.conformTouched = 'true';
}
}
} // Check the validity of the form
}
if (!event.currentTarget.reportValidity()) {
event.preventDefault();
if (typeof config.onValidate === 'function' && !config.noValidate && !submitter.formNoValidate) {
try {
if (!config.onValidate(context)) {
focusFirstInvalidField(form);
event.preventDefault();
}
} catch (e) {
console.warn(e);
}
}
}
if (!event.defaultPrevented) {
var _config$onSubmit;
if (!event.defaultPrevented) {
var _config$onSubmit;
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event);
(_config$onSubmit = config.onSubmit) === null || _config$onSubmit === void 0 ? void 0 : _config$onSubmit.call(config, event, context);
}
}
}
},
config: fieldsetConfig
};

@@ -164,10 +230,43 @@ }

function useFieldset(ref, config) {
var configRef = useRef(config);
var [uncontrolledState, setUncontrolledState] = useState( // @ts-expect-error
() => {
var _config$defaultValue;
var initialError = {};
for (var [name, message] of (_config$initialError = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError !== void 0 ? _config$initialError : []) {
var _config$initialError;
var [key, ...paths] = getPaths(name);
if (typeof key === 'string') {
var _initialError$key;
var scopedName = getName(paths);
var entries = (_initialError$key = initialError[key]) !== null && _initialError$key !== void 0 ? _initialError$key : [];
if (scopedName === '' && entries.length > 0 && entries[0][0] !== '') {
initialError[key] = [[scopedName, message], ...entries];
} else {
initialError[key] = [...entries, [scopedName, message]];
}
}
}
return {
defaultValue: (_config$defaultValue = config === null || config === void 0 ? void 0 : config.defaultValue) !== null && _config$defaultValue !== void 0 ? _config$defaultValue : {},
initialError
};
});
var [error, setError] = useState(() => {
var result = {};
for (var [key, _error] of Object.entries((_config$initialError = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError !== void 0 ? _config$initialError : {})) {
var _config$initialError;
for (var [key, entries] of Object.entries(uncontrolledState.initialError)) {
var _entries$;
if (_error !== null && _error !== void 0 && _error.message) {
result[key] = _error.message;
var [name, message] = (_entries$ = entries === null || entries === void 0 ? void 0 : entries[0]) !== null && _entries$ !== void 0 ? _entries$ : [];
if (name === '') {
result[key] = message !== null && message !== void 0 ? message : '';
}

@@ -179,2 +278,5 @@ }

useEffect(() => {
configRef.current = config;
});
useEffect(() => {
/**

@@ -188,9 +290,12 @@ * Reset the error state of each field if its validity is changed.

setError(prev => {
var _configRef$current$na, _configRef$current;
var next = prev;
var fieldsetName = (_configRef$current$na = (_configRef$current = configRef.current) === null || _configRef$current === void 0 ? void 0 : _configRef$current.name) !== null && _configRef$current$na !== void 0 ? _configRef$current$na : '';
for (var field of form.elements) {
if (isFieldElement(field)) {
var key = getKey(field.name, config === null || config === void 0 ? void 0 : config.name);
if (isFieldElement(field) && field.name.startsWith(fieldsetName)) {
var [key, ...paths] = getPaths(fieldsetName.length > 0 ? field.name.slice(fieldsetName.length + 1) : field.name);
if (key) {
if (typeof key === 'string' && paths.length === 0) {
var _next$key, _next;

@@ -231,25 +336,31 @@

var invalidHandler = event => {
var _configRef$current$na2, _configRef$current2;
var form = getFormElement(ref.current);
var field = event.target;
var fieldsetName = (_configRef$current$na2 = (_configRef$current2 = configRef.current) === null || _configRef$current2 === void 0 ? void 0 : _configRef$current2.name) !== null && _configRef$current$na2 !== void 0 ? _configRef$current$na2 : '';
if (!form || !isFieldElement(field) || field.form !== form) {
if (!form || !isFieldElement(field) || field.form !== form || !field.name.startsWith(fieldsetName)) {
return;
}
var key = getKey(field.name, config === null || config === void 0 ? void 0 : config.name); // Update the error only if the field belongs to the fieldset
var [key, ...paths] = getPaths(fieldsetName.length > 0 ? field.name.slice(fieldsetName.length + 1) : field.name); // Update the error only if the field belongs to the fieldset
if (key) {
setError(prev => {
var _prev$key;
if (typeof key === 'string' && paths.length === 0) {
if (field.dataset.conformTouched) {
setError(prev => {
var _prev$key;
var prevMessage = (_prev$key = prev === null || prev === void 0 ? void 0 : prev[key]) !== null && _prev$key !== void 0 ? _prev$key : '';
var prevMessage = (_prev$key = prev === null || prev === void 0 ? void 0 : prev[key]) !== null && _prev$key !== void 0 ? _prev$key : '';
if (prevMessage === field.validationMessage) {
return prev;
}
if (prevMessage === field.validationMessage) {
return prev;
}
return _objectSpread2(_objectSpread2({}, prev), {}, {
[key]: field.validationMessage
return _objectSpread2(_objectSpread2({}, prev), {}, {
[key]: field.validationMessage
});
});
});
}
event.preventDefault();

@@ -271,2 +382,4 @@ }

var resetHandler = event => {
var _fieldsetConfig$defau;
var form = getFormElement(ref.current);

@@ -278,2 +391,8 @@

var fieldsetConfig = configRef.current;
setUncontrolledState({
// @ts-expect-error
defaultValue: (_fieldsetConfig$defau = fieldsetConfig === null || fieldsetConfig === void 0 ? void 0 : fieldsetConfig.defaultValue) !== null && _fieldsetConfig$defau !== void 0 ? _fieldsetConfig$defau : {},
initialError: {}
});
setError({});

@@ -293,22 +412,3 @@ };

};
}, [ref, config === null || config === void 0 ? void 0 : config.name]);
useEffect(() => {
setError(prev => {
var next = prev;
for (var [key, _error2] of Object.entries((_config$initialError2 = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError2 !== void 0 ? _config$initialError2 : {})) {
var _config$initialError2;
if (next[key] !== (_error2 === null || _error2 === void 0 ? void 0 : _error2.message)) {
var _error2$message;
next = _objectSpread2(_objectSpread2({}, next), {}, {
[key]: (_error2$message = _error2 === null || _error2 === void 0 ? void 0 : _error2.message) !== null && _error2$message !== void 0 ? _error2$message : ''
});
}
}
return next;
});
}, [config === null || config === void 0 ? void 0 : config.name, config === null || config === void 0 ? void 0 : config.initialError]);
}, [ref]);
/**

@@ -322,3 +422,3 @@ * This allows us constructing the field at runtime as we have no information

get(_target, key) {
var _constraint, _config$defaultValue, _config$initialError$, _config$initialError3, _config$initialError4, _config$initialError5, _config$initialError6, _error$key;
var _fieldsetConfig$const, _error$key;

@@ -329,9 +429,10 @@ if (typeof key !== 'string') {

var constraint = config === null || config === void 0 ? void 0 : (_constraint = config.constraint) === null || _constraint === void 0 ? void 0 : _constraint[key];
var fieldsetConfig = config !== null && config !== void 0 ? config : {};
var constraint = (_fieldsetConfig$const = fieldsetConfig.constraint) === null || _fieldsetConfig$const === void 0 ? void 0 : _fieldsetConfig$const[key];
var field = {
config: _objectSpread2({
name: config !== null && config !== void 0 && config.name ? "".concat(config.name, ".").concat(key) : key,
form: config === null || config === void 0 ? void 0 : config.form,
defaultValue: config === null || config === void 0 ? void 0 : (_config$defaultValue = config.defaultValue) === null || _config$defaultValue === void 0 ? void 0 : _config$defaultValue[key],
initialError: (_config$initialError$ = config === null || config === void 0 ? void 0 : (_config$initialError3 = config.initialError) === null || _config$initialError3 === void 0 ? void 0 : (_config$initialError4 = _config$initialError3[key]) === null || _config$initialError4 === void 0 ? void 0 : _config$initialError4.details) !== null && _config$initialError$ !== void 0 ? _config$initialError$ : config === null || config === void 0 ? void 0 : (_config$initialError5 = config.initialError) === null || _config$initialError5 === void 0 ? void 0 : (_config$initialError6 = _config$initialError5[key]) === null || _config$initialError6 === void 0 ? void 0 : _config$initialError6.message
name: fieldsetConfig.name ? "".concat(fieldsetConfig.name, ".").concat(key) : key,
form: fieldsetConfig.form,
defaultValue: uncontrolledState.defaultValue[key],
initialError: uncontrolledState.initialError[key]
}, constraint),

@@ -350,21 +451,51 @@ error: (_error$key = error === null || error === void 0 ? void 0 : error[key]) !== null && _error$key !== void 0 ? _error$key : ''

*
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usefieldlist
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usefieldlist
*/
function useFieldList(ref, config) {
var [entries, setEntries] = useState(() => {
var configRef = useRef(config);
var [uncontrolledState, setUncontrolledState] = useState(() => {
var _config$defaultValue2;
return Object.entries((_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : [undefined]);
var initialError = [];
for (var [name, message] of (_config$initialError2 = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError2 !== void 0 ? _config$initialError2 : []) {
var _config$initialError2;
var [index, ...paths] = getPaths(name);
if (typeof index === 'number') {
var _initialError$index;
var scopedName = getName(paths);
var _entries = (_initialError$index = initialError[index]) !== null && _initialError$index !== void 0 ? _initialError$index : [];
if (scopedName === '' && _entries.length > 0 && _entries[0][0] !== '') {
initialError[index] = [[scopedName, message], ..._entries];
} else {
initialError[index] = [..._entries, [scopedName, message]];
}
}
}
return {
defaultValue: (_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : [],
initialError
};
});
var list = entries.map((_ref, index) => {
var _config$defaultValue3, _config$initialError7, _config$initialError8;
var [entries, setEntries] = useState(() => {
var _config$defaultValue3;
var [key, defaultValue] = _ref;
return Object.entries((_config$defaultValue3 = config.defaultValue) !== null && _config$defaultValue3 !== void 0 ? _config$defaultValue3 : [undefined]);
});
var list = entries.map((_ref3, index) => {
var [key, defaultValue] = _ref3;
return {
key,
config: _objectSpread2(_objectSpread2({}, config), {}, {
config: {
name: "".concat(config.name, "[").concat(index, "]"),
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : (_config$defaultValue3 = config.defaultValue) === null || _config$defaultValue3 === void 0 ? void 0 : _config$defaultValue3[index],
initialError: (_config$initialError7 = config.initialError) === null || _config$initialError7 === void 0 ? void 0 : (_config$initialError8 = _config$initialError7[index]) === null || _config$initialError8 === void 0 ? void 0 : _config$initialError8.details
})
form: config.form,
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : uncontrolledState.defaultValue[index],
initialError: uncontrolledState.initialError[index]
}
};

@@ -382,5 +513,6 @@ });

return {
name: listCommandKey,
value: serializeListCommand(config.name, {
name: 'conform/list',
value: JSON.stringify({
type,
scope: config.name,
payload

@@ -396,34 +528,15 @@ }),

useEffect(() => {
setEntries(prevEntries => {
var _config$defaultValue4;
var nextEntries = Object.entries((_config$defaultValue4 = config.defaultValue) !== null && _config$defaultValue4 !== void 0 ? _config$defaultValue4 : [undefined]);
if (prevEntries.length !== nextEntries.length) {
return nextEntries;
}
for (var i = 0; i < prevEntries.length; i++) {
var [prevKey, prevValue] = prevEntries[i];
var [nextKey, nextValue] = nextEntries[i];
if (prevKey !== nextKey || prevValue !== nextValue) {
return nextEntries;
}
} // No need to rerender in this case
return prevEntries;
});
configRef.current = config;
});
useEffect(() => {
var submitHandler = event => {
var form = getFormElement(ref.current);
if (!form || event.target !== form || !(event.submitter instanceof HTMLButtonElement) || event.submitter.name !== listCommandKey) {
if (!form || event.target !== form || !(event.submitter instanceof HTMLButtonElement) || event.submitter.name !== 'conform/list') {
return;
}
var [name, command] = parseListCommand(event.submitter.value);
var command = parseListCommand(event.submitter.value);
if (name !== config.name) {
if (command.scope !== configRef.current.name) {
// Ensure the scope of the listener are limited to specific field name

@@ -433,11 +546,19 @@ return;

switch (command.type) {
case 'append':
case 'prepend':
case 'replace':
command.payload.defaultValue = ["".concat(Date.now()), command.payload.defaultValue];
break;
}
setEntries(entries => {
switch (command.type) {
case 'append':
case 'prepend':
case 'replace':
return updateList([...(entries !== null && entries !== void 0 ? entries : [])], _objectSpread2(_objectSpread2({}, command), {}, {
payload: _objectSpread2(_objectSpread2({}, command.payload), {}, {
defaultValue: ["".concat(Date.now()), command.payload.defaultValue]
})
}));
setEntries(entries => updateList([...(entries !== null && entries !== void 0 ? entries : [])], command));
default:
{
return updateList([...(entries !== null && entries !== void 0 ? entries : [])], command);
}
}
});
event.preventDefault();

@@ -447,3 +568,3 @@ };

var resetHandler = event => {
var _config$defaultValue5;
var _fieldConfig$defaultV, _fieldConfig$defaultV2;

@@ -456,3 +577,8 @@ var form = getFormElement(ref.current);

setEntries(Object.entries((_config$defaultValue5 = config.defaultValue) !== null && _config$defaultValue5 !== void 0 ? _config$defaultValue5 : []));
var fieldConfig = configRef.current;
setUncontrolledState({
defaultValue: (_fieldConfig$defaultV = fieldConfig.defaultValue) !== null && _fieldConfig$defaultV !== void 0 ? _fieldConfig$defaultV : [],
initialError: []
});
setEntries(Object.entries((_fieldConfig$defaultV2 = fieldConfig.defaultValue) !== null && _fieldConfig$defaultV2 !== void 0 ? _fieldConfig$defaultV2 : [undefined]));
};

@@ -466,3 +592,3 @@

};
}, [ref, config.name, config.defaultValue]);
}, [ref]);
return [list, control];

@@ -476,10 +602,15 @@ }

*
* @see https://github.com/edmundhung/conform/tree/v0.3.1/packages/conform-react/README.md#usecontrolledinput
* @see https://github.com/edmundhung/conform/tree/v0.4.0-pre.0/packages/conform-react/README.md#usecontrolledinput
*/
function useControlledInput(field) {
var _field$defaultValue;
function useControlledInput(config) {
var _config$defaultValue4;
var ref = useRef(null);
var inputRef = useRef(null);
var [value, setValue] = useState("".concat((_field$defaultValue = field.defaultValue) !== null && _field$defaultValue !== void 0 ? _field$defaultValue : ''));
var configRef = useRef(config);
var [uncontrolledState, setUncontrolledState] = useState({
defaultValue: config.defaultValue,
initialError: config.initialError
});
var [value, setValue] = useState("".concat((_config$defaultValue4 = config.defaultValue) !== null && _config$defaultValue4 !== void 0 ? _config$defaultValue4 : ''));

@@ -511,2 +642,27 @@ var handleChange = eventOrValue => {

useEffect(() => {
configRef.current = config;
});
useEffect(() => {
var resetHandler = event => {
var _configRef$current$de;
var form = getFormElement(ref.current);
if (!form || event.target !== form) {
return;
}
setUncontrolledState({
defaultValue: configRef.current.defaultValue,
initialError: configRef.current.initialError
});
setValue("".concat((_configRef$current$de = configRef.current.defaultValue) !== null && _configRef$current$de !== void 0 ? _configRef$current$de : ''));
};
document.addEventListener('reset', resetHandler);
return () => {
document.removeEventListener('reset', resetHandler);
};
}, []);
return [_objectSpread2({

@@ -532,3 +688,3 @@ ref,

}, input(field, {
}, input(_objectSpread2(_objectSpread2({}, config), uncontrolledState), {
type: 'text'

@@ -535,0 +691,0 @@ })), {

@@ -1,4 +0,4 @@

export { createSubmission, createValidate } from '@conform-to/dom';
export { hasError, isFieldElement, parse, reportValidity } from '@conform-to/dom';
export { useControlledInput, useFieldList, useFieldset, useForm } from './hooks.js';
import * as helpers from './helpers.js';
export { helpers as conform };

@@ -5,3 +5,3 @@ {

"license": "MIT",
"version": "0.3.1",
"version": "0.4.0-pre.0",
"main": "index.js",

@@ -23,3 +23,3 @@ "module": "module/index.js",

"dependencies": {
"@conform-to/dom": "0.3.1"
"@conform-to/dom": "0.4.0-pre.0"
},

@@ -26,0 +26,0 @@ "peerDependencies": {

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc