@conform-to/react
Advanced tools
Comparing version 0.6.0 to 0.6.1
@@ -37,21 +37,19 @@ import { type FieldConfig, type Primitive, VALIDATION_UNDEFINED, VALIDATION_SKIPPED, INTENT } from '@conform-to/dom'; | ||
} | ||
type InputOptions = { | ||
type BaseOptions = { | ||
description?: boolean; | ||
hidden?: boolean; | ||
}; | ||
type InputOptions = BaseOptions & ({ | ||
type: 'checkbox' | 'radio'; | ||
hidden?: boolean; | ||
value?: string; | ||
} | { | ||
type?: Exclude<HTMLInputTypeAttribute, 'button' | 'submit' | 'hidden'>; | ||
hidden?: boolean; | ||
value?: never; | ||
}; | ||
export declare function input<Schema extends File | File[]>(config: FieldConfig<Schema>, options: { | ||
}); | ||
export declare function input<Schema extends File | File[]>(config: FieldConfig<Schema>, options: InputOptions & { | ||
type: 'file'; | ||
}): InputProps<Schema>; | ||
export declare function input<Schema extends Primitive>(config: FieldConfig<Schema>, options?: InputOptions): InputProps<Schema>; | ||
export declare function select(config: FieldConfig<Primitive | Primitive[]>, options?: { | ||
hidden?: boolean; | ||
}): SelectProps; | ||
export declare function textarea(config: FieldConfig<Primitive>, options?: { | ||
hidden?: boolean; | ||
}): TextareaProps; | ||
export declare function select(config: FieldConfig<Primitive | Primitive[]>, options?: BaseOptions): SelectProps; | ||
export declare function textarea(config: FieldConfig<Primitive>, options?: BaseOptions): TextareaProps; | ||
export { INTENT, VALIDATION_UNDEFINED, VALIDATION_SKIPPED }; |
@@ -33,6 +33,9 @@ 'use strict'; | ||
props.id = config.id; | ||
props['aria-describedby'] = config.errorId; | ||
} | ||
if (config.descriptionId && options !== null && options !== void 0 && options.description) { | ||
props['aria-describedby'] = config.descriptionId; | ||
} | ||
if (config.errorId && (_config$error = config.error) !== null && _config$error !== void 0 && _config$error.length) { | ||
props['aria-invalid'] = true; | ||
props['aria-describedby'] = config.descriptionId && options !== null && options !== void 0 && options.description ? "".concat(config.errorId, " ").concat(config.descriptionId) : config.errorId; | ||
} | ||
@@ -39,0 +42,0 @@ if (config.initialError && Object.entries(config.initialError).length > 0) { |
@@ -10,3 +10,11 @@ import { type FieldConfig, type FieldElement, type FieldValue, type FieldsetConstraint, type FormMethod, type FormEncType, type Submission } from '@conform-to/dom'; | ||
/** | ||
* Define when the error should be reported initially. | ||
* A form ref object. Conform will fallback to its own ref object if it is not provided. | ||
*/ | ||
ref?: RefObject<HTMLFormElement>; | ||
/** | ||
* @deprecated Use `shouldValidate` and `shouldRevalidate` instead. | ||
*/ | ||
initialReport?: 'onSubmit' | 'onChange' | 'onBlur'; | ||
/** | ||
* Define when conform should start validation. | ||
* Support "onSubmit", "onChange", "onBlur". | ||
@@ -16,4 +24,11 @@ * | ||
*/ | ||
initialReport?: 'onSubmit' | 'onChange' | 'onBlur'; | ||
shouldValidate?: 'onSubmit' | 'onBlur' | 'onInput'; | ||
/** | ||
* Define when conform should revalidate again. | ||
* Support "onSubmit", "onChange", "onBlur". | ||
* | ||
* Default to `onInput`. | ||
*/ | ||
shouldRevalidate?: 'onSubmit' | 'onBlur' | 'onInput'; | ||
/** | ||
* An object representing the initial value of the form. | ||
@@ -20,0 +35,0 @@ */ |
196
hooks.js
@@ -16,6 +16,6 @@ 'use strict'; | ||
function useForm() { | ||
var _config$lastSubmissio; | ||
var _config$lastSubmissio, _config$ref, _ref2, _config$lastSubmissio2; | ||
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
var configRef = react.useRef(config); | ||
var ref = react.useRef(null); | ||
var formRef = react.useRef(null); | ||
var [lastSubmission, setLastSubmission] = react.useState((_config$lastSubmissio = config.lastSubmission) !== null && _config$lastSubmissio !== void 0 ? _config$lastSubmissio : null); | ||
@@ -28,28 +28,25 @@ var [errors, setErrors] = react.useState(() => { | ||
}); | ||
var [uncontrolledState, setUncontrolledState] = react.useState(() => { | ||
var initialError = react.useMemo(() => { | ||
var submission = config.lastSubmission; | ||
if (!submission) { | ||
return { | ||
defaultValue: config.defaultValue | ||
}; | ||
return {}; | ||
} | ||
var scope = dom.getScope(submission.intent); | ||
return { | ||
defaultValue: submission.payload, | ||
initialError: Object.entries(submission.error).reduce((result, _ref) => { | ||
var [name, message] = _ref; | ||
if (name !== '' && (scope === null || scope === name)) { | ||
result[name] = message; | ||
} | ||
return result; | ||
}, {}) | ||
}; | ||
}); | ||
var fieldsetConfig = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, uncontrolledState), {}, { | ||
return Object.entries(submission.error).reduce((result, _ref) => { | ||
var [name, message] = _ref; | ||
if (name !== '' && (scope === null || scope === name)) { | ||
result[name] = message; | ||
} | ||
return result; | ||
}, {}); | ||
}, [config.lastSubmission]); | ||
var ref = (_config$ref = config.ref) !== null && _config$ref !== void 0 ? _config$ref : formRef; | ||
var fieldset = useFieldset(ref, { | ||
defaultValue: (_ref2 = (_config$lastSubmissio2 = config.lastSubmission) === null || _config$lastSubmissio2 === void 0 ? void 0 : _config$lastSubmissio2.payload) !== null && _ref2 !== void 0 ? _ref2 : config.defaultValue, | ||
initialError, | ||
constraint: config.constraint, | ||
form: config.id | ||
}); | ||
var fieldset = useFieldset(ref, fieldsetConfig); | ||
var [noValidate, setNoValidate] = react.useState(config.noValidate || !config.fallbackNative); | ||
react.useEffect(() => { | ||
useSafeLayoutEffect(() => { | ||
configRef.current = config; | ||
@@ -73,3 +70,3 @@ }); | ||
setLastSubmission(submission); | ||
}, [config.lastSubmission]); | ||
}, [ref, config.lastSubmission]); | ||
react.useEffect(() => { | ||
@@ -80,4 +77,4 @@ var form = ref.current; | ||
} | ||
dom.reportSubmission(ref.current, lastSubmission); | ||
}, [lastSubmission]); | ||
dom.reportSubmission(form, lastSubmission); | ||
}, [ref, lastSubmission]); | ||
react.useEffect(() => { | ||
@@ -89,6 +86,11 @@ // Revalidate the form when input value is changed | ||
var formConfig = configRef.current; | ||
var { | ||
initialReport = 'onSubmit', | ||
shouldValidate = initialReport === 'onChange' ? 'onInput' : initialReport, | ||
shouldRevalidate = 'onInput' | ||
} = formConfig; | ||
if (!form || !dom.isFieldElement(field) || field.form !== form) { | ||
return; | ||
} | ||
if (field.dataset.conformTouched || formConfig.initialReport === 'onChange') { | ||
if (field.dataset.conformTouched ? shouldRevalidate === 'onInput' : shouldValidate === 'onInput') { | ||
dom.requestIntent(form, dom.validate(field.name)); | ||
@@ -101,6 +103,11 @@ } | ||
var formConfig = configRef.current; | ||
var { | ||
initialReport = 'onSubmit', | ||
shouldValidate = initialReport === 'onChange' ? 'onInput' : initialReport, | ||
shouldRevalidate = 'onInput' | ||
} = formConfig; | ||
if (!form || !dom.isFieldElement(field) || field.form !== form) { | ||
return; | ||
} | ||
if (formConfig.initialReport === 'onBlur' && !field.dataset.conformTouched) { | ||
if (field.dataset.conformTouched ? shouldRevalidate === 'onBlur' : shouldValidate === 'onBlur') { | ||
dom.requestIntent(form, dom.validate(field.name)); | ||
@@ -110,3 +117,3 @@ } | ||
var handleInvalid = event => { | ||
var form = dom.getFormElement(ref.current); | ||
var form = ref.current; | ||
var field = event.target; | ||
@@ -123,3 +130,2 @@ if (!form || !dom.isFieldElement(field) || field.form !== form || field.name !== dom.FORM_ERROR_ELEMENT_NAME) { | ||
var form = ref.current; | ||
var formConfig = configRef.current; | ||
if (!form || event.target !== form) { | ||
@@ -137,13 +143,3 @@ return; | ||
setErrors([]); | ||
setUncontrolledState({ | ||
defaultValue: formConfig.defaultValue | ||
}); | ||
}; | ||
/** | ||
* The input event handler will be triggered in capturing phase in order to | ||
* allow follow-up action in the bubble phase based on the latest validity | ||
* E.g. `useFieldset` reset the error of valid field after checking the | ||
* validity in the bubble phase. | ||
*/ | ||
document.addEventListener('input', handleInput, true); | ||
@@ -159,3 +155,3 @@ document.addEventListener('blur', handleBlur, true); | ||
}; | ||
}, []); | ||
}, [ref]); | ||
var form = { | ||
@@ -183,7 +179,7 @@ ref, | ||
}); | ||
if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && Object.entries(submission.error).some(_ref2 => { | ||
var [, message] = _ref2; | ||
if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && Object.entries(submission.error).some(_ref3 => { | ||
var [, message] = _ref3; | ||
return message !== '' && ![].concat(message).includes(dom.VALIDATION_UNDEFINED); | ||
}) || typeof config.onValidate !== 'undefined' && (submission.intent.startsWith('validate') || submission.intent.startsWith('list')) && Object.entries(submission.error).every(_ref3 => { | ||
var [, message] = _ref3; | ||
}) || typeof config.onValidate !== 'undefined' && (submission.intent.startsWith('validate') || submission.intent.startsWith('list')) && Object.entries(submission.error).every(_ref4 => { | ||
var [, message] = _ref4; | ||
return ![].concat(message).includes(dom.VALIDATION_UNDEFINED); | ||
@@ -216,6 +212,6 @@ })) { | ||
form.props.id = form.id; | ||
form.props['aria-describedby'] = form.errorId; | ||
} | ||
if (form.errorId && form.errors.length > 0) { | ||
form.props['aria-invalid'] = 'true'; | ||
form.props['aria-describedby'] = form.errorId; | ||
} | ||
@@ -231,31 +227,17 @@ return [form, fieldset]; | ||
var configRef = react.useRef(config); | ||
var [uncontrolledState, setUncontrolledState] = react.useState( | ||
// @ts-expect-error | ||
() => { | ||
var _config$defaultValue; | ||
var initialError = {}; | ||
for (var [name, message] of Object.entries((_config$initialError = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError !== void 0 ? _config$initialError : {})) { | ||
var _config$initialError; | ||
var [error, setError] = react.useState(() => { | ||
var initialError = config === null || config === void 0 ? void 0 : config.initialError; | ||
if (!initialError) { | ||
return {}; | ||
} | ||
var result = {}; | ||
for (var [name, message] of Object.entries(initialError)) { | ||
var [key, ...paths] = dom.getPaths(name); | ||
if (typeof key === 'string') { | ||
var scopedName = dom.getName(paths); | ||
initialError[key] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, initialError[key]), {}, { | ||
[scopedName]: message | ||
}); | ||
if (typeof key === 'string' && paths.length === 0) { | ||
result[key] = [].concat(message !== null && message !== void 0 ? 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(uncontrolledState.initialError)) { | ||
var _error$; | ||
result[key] = [].concat((_error$ = _error === null || _error === void 0 ? void 0 : _error['']) !== null && _error$ !== void 0 ? _error$ : []); | ||
} | ||
return result; | ||
}); | ||
react.useEffect(() => { | ||
useSafeLayoutEffect(() => { | ||
configRef.current = config; | ||
@@ -291,3 +273,2 @@ }); | ||
var resetHandler = event => { | ||
var _fieldsetConfig$defau; | ||
var form = dom.getFormElement(ref.current); | ||
@@ -297,8 +278,2 @@ if (!form || event.target !== form) { | ||
} | ||
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({}); | ||
@@ -323,13 +298,21 @@ }; | ||
get(_target, key) { | ||
var _fieldsetConfig$const; | ||
var _fieldsetConfig$const, _fieldsetConfig$initi, _fieldsetConfig$defau; | ||
if (typeof key !== 'string') { | ||
return; | ||
} | ||
var fieldsetConfig = config !== null && config !== void 0 ? config : {}; | ||
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, _ref5) => { | ||
var [name, message] = _ref5; | ||
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, | ||
defaultValue: uncontrolledState.defaultValue[key], | ||
initialError: uncontrolledState.initialError[key], | ||
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], | ||
@@ -342,2 +325,3 @@ errors | ||
field.errorId = "".concat(field.id, "-error"); | ||
field.descriptionId = "".concat(field.id, "-description"); | ||
} | ||
@@ -357,29 +341,18 @@ return field; | ||
var configRef = react.useRef(config); | ||
var [uncontrolledState, setUncontrolledState] = react.useState(() => { | ||
var _config$defaultValue2; | ||
var [error, setError] = react.useState(() => { | ||
var initialError = []; | ||
for (var [name, message] of Object.entries((_config$initialError2 = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError2 !== void 0 ? _config$initialError2 : {})) { | ||
var _config$initialError2; | ||
for (var [name, message] of Object.entries((_config$initialError = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError !== void 0 ? _config$initialError : {})) { | ||
var _config$initialError; | ||
var [index, ...paths] = dom.getPaths(name); | ||
if (typeof index === 'number') { | ||
var scopedName = dom.getName(paths); | ||
initialError[index] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, initialError[index]), {}, { | ||
[scopedName]: message | ||
}); | ||
if (typeof index === 'number' && paths.length === 0) { | ||
initialError[index] = [].concat(message !== null && message !== void 0 ? message : []); | ||
} | ||
} | ||
return { | ||
defaultValue: (_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : [], | ||
initialError | ||
}; | ||
return initialError; | ||
}); | ||
var [error, setError] = react.useState(() => uncontrolledState.initialError.map(error => { | ||
var _error$2; | ||
return [].concat((_error$2 = error === null || error === void 0 ? void 0 : error['']) !== null && _error$2 !== void 0 ? _error$2 : []); | ||
})); | ||
var [entries, setEntries] = react.useState(() => { | ||
var _config$defaultValue3; | ||
return Object.entries((_config$defaultValue3 = config.defaultValue) !== null && _config$defaultValue3 !== void 0 ? _config$defaultValue3 : [undefined]); | ||
var _config$defaultValue; | ||
return Object.entries((_config$defaultValue = config.defaultValue) !== null && _config$defaultValue !== void 0 ? _config$defaultValue : [undefined]); | ||
}); | ||
react.useEffect(() => { | ||
useSafeLayoutEffect(() => { | ||
configRef.current = config; | ||
@@ -458,3 +431,3 @@ }); | ||
var resetHandler = event => { | ||
var _fieldConfig$defaultV, _fieldConfig$defaultV2; | ||
var _configRef$current$de; | ||
var form = dom.getFormElement(ref.current); | ||
@@ -464,8 +437,3 @@ if (!form || event.target !== form) { | ||
} | ||
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])); | ||
setEntries(Object.entries((_configRef$current$de = configRef.current.defaultValue) !== null && _configRef$current$de !== void 0 ? _configRef$current$de : [undefined])); | ||
setError([]); | ||
@@ -485,9 +453,18 @@ }; | ||
}, [ref]); | ||
return entries.map((_ref4, index) => { | ||
var [key, defaultValue] = _ref4; | ||
return entries.map((_ref6, index) => { | ||
var _config$initialError2, _config$defaultValue2; | ||
var [key, defaultValue] = _ref6; | ||
var errors = error[index]; | ||
var initialError = Object.entries((_config$initialError2 = config.initialError) !== null && _config$initialError2 !== void 0 ? _config$initialError2 : {}).reduce((result, _ref7) => { | ||
var [name, message] = _ref7; | ||
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: defaultValue !== null && defaultValue !== void 0 ? defaultValue : uncontrolledState.defaultValue[index], | ||
initialError: uncontrolledState.initialError[index], | ||
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : (_config$defaultValue2 = config.defaultValue) === null || _config$defaultValue2 === void 0 ? void 0 : _config$defaultValue2[index], | ||
initialError, | ||
error: errors === null || errors === void 0 ? void 0 : errors[0], | ||
@@ -500,2 +477,3 @@ errors | ||
fieldConfig.errorId = "".concat(fieldConfig.id, "-error"); | ||
fieldConfig.descriptionId = "".concat(fieldConfig.id, "-description"); | ||
} | ||
@@ -502,0 +480,0 @@ return _rollupPluginBabelHelpers.objectSpread2({ |
@@ -29,6 +29,9 @@ import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js'; | ||
props.id = config.id; | ||
props['aria-describedby'] = config.errorId; | ||
} | ||
if (config.descriptionId && options !== null && options !== void 0 && options.description) { | ||
props['aria-describedby'] = config.descriptionId; | ||
} | ||
if (config.errorId && (_config$error = config.error) !== null && _config$error !== void 0 && _config$error.length) { | ||
props['aria-invalid'] = true; | ||
props['aria-describedby'] = config.descriptionId && options !== null && options !== void 0 && options.description ? "".concat(config.errorId, " ").concat(config.descriptionId) : config.errorId; | ||
} | ||
@@ -35,0 +38,0 @@ if (config.initialError && Object.entries(config.initialError).length > 0) { |
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js'; | ||
import { getScope, parseListCommand, reportSubmission, getFormData, parse, VALIDATION_UNDEFINED, getFormAttributes, getPaths, getName, isFieldElement, requestIntent, validate, getFormElement, FORM_ERROR_ELEMENT_NAME, getErrors, getValidationMessage, updateList } from '@conform-to/dom'; | ||
import { useRef, useState, useEffect, useMemo, useLayoutEffect } from 'react'; | ||
import { getScope, parseListCommand, reportSubmission, getFormData, parse, VALIDATION_UNDEFINED, getFormAttributes, getPaths, getName, isFieldElement, requestIntent, validate, FORM_ERROR_ELEMENT_NAME, getErrors, getFormElement, getValidationMessage, updateList } from '@conform-to/dom'; | ||
import { useRef, useState, useMemo, useEffect, useLayoutEffect } from 'react'; | ||
@@ -12,6 +12,6 @@ /** | ||
function useForm() { | ||
var _config$lastSubmissio; | ||
var _config$lastSubmissio, _config$ref, _ref2, _config$lastSubmissio2; | ||
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
var configRef = useRef(config); | ||
var ref = useRef(null); | ||
var formRef = useRef(null); | ||
var [lastSubmission, setLastSubmission] = useState((_config$lastSubmissio = config.lastSubmission) !== null && _config$lastSubmissio !== void 0 ? _config$lastSubmissio : null); | ||
@@ -24,28 +24,25 @@ var [errors, setErrors] = useState(() => { | ||
}); | ||
var [uncontrolledState, setUncontrolledState] = useState(() => { | ||
var initialError = useMemo(() => { | ||
var submission = config.lastSubmission; | ||
if (!submission) { | ||
return { | ||
defaultValue: config.defaultValue | ||
}; | ||
return {}; | ||
} | ||
var scope = getScope(submission.intent); | ||
return { | ||
defaultValue: submission.payload, | ||
initialError: Object.entries(submission.error).reduce((result, _ref) => { | ||
var [name, message] = _ref; | ||
if (name !== '' && (scope === null || scope === name)) { | ||
result[name] = message; | ||
} | ||
return result; | ||
}, {}) | ||
}; | ||
}); | ||
var fieldsetConfig = _objectSpread2(_objectSpread2({}, uncontrolledState), {}, { | ||
return Object.entries(submission.error).reduce((result, _ref) => { | ||
var [name, message] = _ref; | ||
if (name !== '' && (scope === null || scope === name)) { | ||
result[name] = message; | ||
} | ||
return result; | ||
}, {}); | ||
}, [config.lastSubmission]); | ||
var ref = (_config$ref = config.ref) !== null && _config$ref !== void 0 ? _config$ref : formRef; | ||
var fieldset = useFieldset(ref, { | ||
defaultValue: (_ref2 = (_config$lastSubmissio2 = config.lastSubmission) === null || _config$lastSubmissio2 === void 0 ? void 0 : _config$lastSubmissio2.payload) !== null && _ref2 !== void 0 ? _ref2 : config.defaultValue, | ||
initialError, | ||
constraint: config.constraint, | ||
form: config.id | ||
}); | ||
var fieldset = useFieldset(ref, fieldsetConfig); | ||
var [noValidate, setNoValidate] = useState(config.noValidate || !config.fallbackNative); | ||
useEffect(() => { | ||
useSafeLayoutEffect(() => { | ||
configRef.current = config; | ||
@@ -69,3 +66,3 @@ }); | ||
setLastSubmission(submission); | ||
}, [config.lastSubmission]); | ||
}, [ref, config.lastSubmission]); | ||
useEffect(() => { | ||
@@ -76,4 +73,4 @@ var form = ref.current; | ||
} | ||
reportSubmission(ref.current, lastSubmission); | ||
}, [lastSubmission]); | ||
reportSubmission(form, lastSubmission); | ||
}, [ref, lastSubmission]); | ||
useEffect(() => { | ||
@@ -85,6 +82,11 @@ // Revalidate the form when input value is changed | ||
var formConfig = configRef.current; | ||
var { | ||
initialReport = 'onSubmit', | ||
shouldValidate = initialReport === 'onChange' ? 'onInput' : initialReport, | ||
shouldRevalidate = 'onInput' | ||
} = formConfig; | ||
if (!form || !isFieldElement(field) || field.form !== form) { | ||
return; | ||
} | ||
if (field.dataset.conformTouched || formConfig.initialReport === 'onChange') { | ||
if (field.dataset.conformTouched ? shouldRevalidate === 'onInput' : shouldValidate === 'onInput') { | ||
requestIntent(form, validate(field.name)); | ||
@@ -97,6 +99,11 @@ } | ||
var formConfig = configRef.current; | ||
var { | ||
initialReport = 'onSubmit', | ||
shouldValidate = initialReport === 'onChange' ? 'onInput' : initialReport, | ||
shouldRevalidate = 'onInput' | ||
} = formConfig; | ||
if (!form || !isFieldElement(field) || field.form !== form) { | ||
return; | ||
} | ||
if (formConfig.initialReport === 'onBlur' && !field.dataset.conformTouched) { | ||
if (field.dataset.conformTouched ? shouldRevalidate === 'onBlur' : shouldValidate === 'onBlur') { | ||
requestIntent(form, validate(field.name)); | ||
@@ -106,3 +113,3 @@ } | ||
var handleInvalid = event => { | ||
var form = getFormElement(ref.current); | ||
var form = ref.current; | ||
var field = event.target; | ||
@@ -119,3 +126,2 @@ if (!form || !isFieldElement(field) || field.form !== form || field.name !== FORM_ERROR_ELEMENT_NAME) { | ||
var form = ref.current; | ||
var formConfig = configRef.current; | ||
if (!form || event.target !== form) { | ||
@@ -133,13 +139,3 @@ return; | ||
setErrors([]); | ||
setUncontrolledState({ | ||
defaultValue: formConfig.defaultValue | ||
}); | ||
}; | ||
/** | ||
* The input event handler will be triggered in capturing phase in order to | ||
* allow follow-up action in the bubble phase based on the latest validity | ||
* E.g. `useFieldset` reset the error of valid field after checking the | ||
* validity in the bubble phase. | ||
*/ | ||
document.addEventListener('input', handleInput, true); | ||
@@ -155,3 +151,3 @@ document.addEventListener('blur', handleBlur, true); | ||
}; | ||
}, []); | ||
}, [ref]); | ||
var form = { | ||
@@ -179,7 +175,7 @@ ref, | ||
}); | ||
if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && Object.entries(submission.error).some(_ref2 => { | ||
var [, message] = _ref2; | ||
if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && Object.entries(submission.error).some(_ref3 => { | ||
var [, message] = _ref3; | ||
return message !== '' && ![].concat(message).includes(VALIDATION_UNDEFINED); | ||
}) || typeof config.onValidate !== 'undefined' && (submission.intent.startsWith('validate') || submission.intent.startsWith('list')) && Object.entries(submission.error).every(_ref3 => { | ||
var [, message] = _ref3; | ||
}) || typeof config.onValidate !== 'undefined' && (submission.intent.startsWith('validate') || submission.intent.startsWith('list')) && Object.entries(submission.error).every(_ref4 => { | ||
var [, message] = _ref4; | ||
return ![].concat(message).includes(VALIDATION_UNDEFINED); | ||
@@ -212,6 +208,6 @@ })) { | ||
form.props.id = form.id; | ||
form.props['aria-describedby'] = form.errorId; | ||
} | ||
if (form.errorId && form.errors.length > 0) { | ||
form.props['aria-invalid'] = 'true'; | ||
form.props['aria-describedby'] = form.errorId; | ||
} | ||
@@ -227,31 +223,17 @@ return [form, fieldset]; | ||
var configRef = useRef(config); | ||
var [uncontrolledState, setUncontrolledState] = useState( | ||
// @ts-expect-error | ||
() => { | ||
var _config$defaultValue; | ||
var initialError = {}; | ||
for (var [name, message] of Object.entries((_config$initialError = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError !== void 0 ? _config$initialError : {})) { | ||
var _config$initialError; | ||
var [error, setError] = useState(() => { | ||
var initialError = config === null || config === void 0 ? void 0 : config.initialError; | ||
if (!initialError) { | ||
return {}; | ||
} | ||
var result = {}; | ||
for (var [name, message] of Object.entries(initialError)) { | ||
var [key, ...paths] = getPaths(name); | ||
if (typeof key === 'string') { | ||
var scopedName = getName(paths); | ||
initialError[key] = _objectSpread2(_objectSpread2({}, initialError[key]), {}, { | ||
[scopedName]: message | ||
}); | ||
if (typeof key === 'string' && paths.length === 0) { | ||
result[key] = [].concat(message !== null && message !== void 0 ? 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(uncontrolledState.initialError)) { | ||
var _error$; | ||
result[key] = [].concat((_error$ = _error === null || _error === void 0 ? void 0 : _error['']) !== null && _error$ !== void 0 ? _error$ : []); | ||
} | ||
return result; | ||
}); | ||
useEffect(() => { | ||
useSafeLayoutEffect(() => { | ||
configRef.current = config; | ||
@@ -287,3 +269,2 @@ }); | ||
var resetHandler = event => { | ||
var _fieldsetConfig$defau; | ||
var form = getFormElement(ref.current); | ||
@@ -293,8 +274,2 @@ if (!form || event.target !== form) { | ||
} | ||
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({}); | ||
@@ -319,13 +294,21 @@ }; | ||
get(_target, key) { | ||
var _fieldsetConfig$const; | ||
var _fieldsetConfig$const, _fieldsetConfig$initi, _fieldsetConfig$defau; | ||
if (typeof key !== 'string') { | ||
return; | ||
} | ||
var fieldsetConfig = config !== null && config !== void 0 ? config : {}; | ||
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, _ref5) => { | ||
var [name, message] = _ref5; | ||
var [field, ...paths] = getPaths(name); | ||
if (field === key) { | ||
result[getName(paths)] = message; | ||
} | ||
return result; | ||
}, {}); | ||
var field = _objectSpread2(_objectSpread2({}, constraint), {}, { | ||
name: fieldsetConfig.name ? "".concat(fieldsetConfig.name, ".").concat(key) : key, | ||
defaultValue: uncontrolledState.defaultValue[key], | ||
initialError: uncontrolledState.initialError[key], | ||
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], | ||
@@ -338,2 +321,3 @@ errors | ||
field.errorId = "".concat(field.id, "-error"); | ||
field.descriptionId = "".concat(field.id, "-description"); | ||
} | ||
@@ -353,29 +337,18 @@ return field; | ||
var configRef = useRef(config); | ||
var [uncontrolledState, setUncontrolledState] = useState(() => { | ||
var _config$defaultValue2; | ||
var [error, setError] = useState(() => { | ||
var initialError = []; | ||
for (var [name, message] of Object.entries((_config$initialError2 = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError2 !== void 0 ? _config$initialError2 : {})) { | ||
var _config$initialError2; | ||
for (var [name, message] of Object.entries((_config$initialError = config === null || config === void 0 ? void 0 : config.initialError) !== null && _config$initialError !== void 0 ? _config$initialError : {})) { | ||
var _config$initialError; | ||
var [index, ...paths] = getPaths(name); | ||
if (typeof index === 'number') { | ||
var scopedName = getName(paths); | ||
initialError[index] = _objectSpread2(_objectSpread2({}, initialError[index]), {}, { | ||
[scopedName]: message | ||
}); | ||
if (typeof index === 'number' && paths.length === 0) { | ||
initialError[index] = [].concat(message !== null && message !== void 0 ? message : []); | ||
} | ||
} | ||
return { | ||
defaultValue: (_config$defaultValue2 = config.defaultValue) !== null && _config$defaultValue2 !== void 0 ? _config$defaultValue2 : [], | ||
initialError | ||
}; | ||
return initialError; | ||
}); | ||
var [error, setError] = useState(() => uncontrolledState.initialError.map(error => { | ||
var _error$2; | ||
return [].concat((_error$2 = error === null || error === void 0 ? void 0 : error['']) !== null && _error$2 !== void 0 ? _error$2 : []); | ||
})); | ||
var [entries, setEntries] = useState(() => { | ||
var _config$defaultValue3; | ||
return Object.entries((_config$defaultValue3 = config.defaultValue) !== null && _config$defaultValue3 !== void 0 ? _config$defaultValue3 : [undefined]); | ||
var _config$defaultValue; | ||
return Object.entries((_config$defaultValue = config.defaultValue) !== null && _config$defaultValue !== void 0 ? _config$defaultValue : [undefined]); | ||
}); | ||
useEffect(() => { | ||
useSafeLayoutEffect(() => { | ||
configRef.current = config; | ||
@@ -454,3 +427,3 @@ }); | ||
var resetHandler = event => { | ||
var _fieldConfig$defaultV, _fieldConfig$defaultV2; | ||
var _configRef$current$de; | ||
var form = getFormElement(ref.current); | ||
@@ -460,8 +433,3 @@ if (!form || event.target !== form) { | ||
} | ||
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])); | ||
setEntries(Object.entries((_configRef$current$de = configRef.current.defaultValue) !== null && _configRef$current$de !== void 0 ? _configRef$current$de : [undefined])); | ||
setError([]); | ||
@@ -481,9 +449,18 @@ }; | ||
}, [ref]); | ||
return entries.map((_ref4, index) => { | ||
var [key, defaultValue] = _ref4; | ||
return entries.map((_ref6, index) => { | ||
var _config$initialError2, _config$defaultValue2; | ||
var [key, defaultValue] = _ref6; | ||
var errors = error[index]; | ||
var initialError = Object.entries((_config$initialError2 = config.initialError) !== null && _config$initialError2 !== void 0 ? _config$initialError2 : {}).reduce((result, _ref7) => { | ||
var [name, message] = _ref7; | ||
var [field, ...paths] = getPaths(name); | ||
if (field === index) { | ||
result[getName(paths)] = message; | ||
} | ||
return result; | ||
}, {}); | ||
var fieldConfig = { | ||
name: "".concat(config.name, "[").concat(index, "]"), | ||
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : uncontrolledState.defaultValue[index], | ||
initialError: uncontrolledState.initialError[index], | ||
defaultValue: defaultValue !== null && defaultValue !== void 0 ? defaultValue : (_config$defaultValue2 = config.defaultValue) === null || _config$defaultValue2 === void 0 ? void 0 : _config$defaultValue2[index], | ||
initialError, | ||
error: errors === null || errors === void 0 ? void 0 : errors[0], | ||
@@ -496,2 +473,3 @@ errors | ||
fieldConfig.errorId = "".concat(fieldConfig.id, "-error"); | ||
fieldConfig.descriptionId = "".concat(fieldConfig.id, "-description"); | ||
} | ||
@@ -498,0 +476,0 @@ return _objectSpread2({ |
{ | ||
"name": "@conform-to/react", | ||
"description": "Conform view adapter for react", | ||
"homepage": "https://conform.guide", | ||
"license": "MIT", | ||
"version": "0.6.0", | ||
"version": "0.6.1", | ||
"main": "index.js", | ||
@@ -22,3 +23,3 @@ "module": "module/index.js", | ||
"dependencies": { | ||
"@conform-to/dom": "0.6.0" | ||
"@conform-to/dom": "0.6.1" | ||
}, | ||
@@ -32,6 +33,9 @@ "peerDependencies": { | ||
"form-validation", | ||
"html", | ||
"progressive-enhancement", | ||
"validation", | ||
"react" | ||
"react", | ||
"remix" | ||
], | ||
"sideEffects": false | ||
} |
@@ -45,3 +45,3 @@ # @conform-to/react | ||
/** | ||
* Define when the error should be reported initially. | ||
* Define when conform should start validation. | ||
* Support "onSubmit", "onChange", "onBlur". | ||
@@ -51,5 +51,13 @@ * | ||
*/ | ||
initialReport: 'onBlur', | ||
shouldValidate: 'onSubmit', | ||
/** | ||
* Define when conform should revalidate again. | ||
* Support "onSubmit", "onChange", "onBlur". | ||
* | ||
* Default to `onInput`. | ||
*/ | ||
shouldRevalidate: 'onInput', | ||
/** | ||
* An object representing the initial value of the form. | ||
@@ -56,0 +64,0 @@ */ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
1
620
88607
1793
+ Added@conform-to/dom@0.6.1(transitive)
- Removed@conform-to/dom@0.6.0(transitive)
Updated@conform-to/dom@0.6.1