@conform-to/react
Advanced tools
@@ -27,2 +27,3 @@ 'use strict'; | ||
| function _defineProperty(obj, key, value) { | ||
| key = _toPropertyKey(key); | ||
| if (key in obj) { | ||
@@ -40,4 +41,20 @@ Object.defineProperty(obj, key, { | ||
| } | ||
| function _toPrimitive(input, hint) { | ||
| if (typeof input !== "object" || input === null) return input; | ||
| var prim = input[Symbol.toPrimitive]; | ||
| if (prim !== undefined) { | ||
| var res = prim.call(input, hint || "default"); | ||
| if (typeof res !== "object") return res; | ||
| throw new TypeError("@@toPrimitive must return a primitive value."); | ||
| } | ||
| return (hint === "string" ? String : Number)(input); | ||
| } | ||
| function _toPropertyKey(arg) { | ||
| var key = _toPrimitive(arg, "string"); | ||
| return typeof key === "symbol" ? key : String(key); | ||
| } | ||
| exports.defineProperty = _defineProperty; | ||
| exports.objectSpread2 = _objectSpread2; | ||
| exports.toPrimitive = _toPrimitive; | ||
| exports.toPropertyKey = _toPropertyKey; |
+4
-3
@@ -1,2 +0,2 @@ | ||
| import type { FieldConfig } from '@conform-to/dom'; | ||
| import { type FieldConfig, VALIDATION_SKIPPED, VALIDATION_UNDEFINED } from '@conform-to/dom'; | ||
| import type { CSSProperties, HTMLInputTypeAttribute } from 'react'; | ||
@@ -37,3 +37,3 @@ interface FieldProps { | ||
| } | ||
| declare type InputOptions = { | ||
| type InputOptions = { | ||
| type: 'checkbox' | 'radio'; | ||
@@ -57,2 +57,3 @@ hidden?: boolean; | ||
| }): TextareaProps; | ||
| export {}; | ||
| export declare const intent = "__intent__"; | ||
| export { VALIDATION_UNDEFINED, VALIDATION_SKIPPED }; |
+15
-3
@@ -5,2 +5,4 @@ 'use strict'; | ||
| var dom = require('@conform-to/dom'); | ||
| /** | ||
@@ -45,3 +47,3 @@ * Style to make the input element visually hidden | ||
| } | ||
| if (config.initialError && config.initialError.length > 0) { | ||
| if (config.initialError && Object.entries(config.initialError).length > 0) { | ||
| attributes.autoFocus = true; | ||
@@ -75,3 +77,3 @@ } | ||
| } | ||
| if (config.initialError && config.initialError.length > 0) { | ||
| if (config.initialError && Object.entries(config.initialError).length > 0) { | ||
| attributes.autoFocus = true; | ||
@@ -100,3 +102,3 @@ } | ||
| } | ||
| if (config.initialError && config.initialError.length > 0) { | ||
| if (config.initialError && Object.entries(config.initialError).length > 0) { | ||
| attributes.autoFocus = true; | ||
@@ -106,5 +108,15 @@ } | ||
| } | ||
| var intent = '__intent__'; | ||
| Object.defineProperty(exports, 'VALIDATION_SKIPPED', { | ||
| enumerable: true, | ||
| get: function () { return dom.VALIDATION_SKIPPED; } | ||
| }); | ||
| Object.defineProperty(exports, 'VALIDATION_UNDEFINED', { | ||
| enumerable: true, | ||
| get: function () { return dom.VALIDATION_UNDEFINED; } | ||
| }); | ||
| exports.input = input; | ||
| exports.intent = intent; | ||
| exports.select = select; | ||
| exports.textarea = textarea; |
+15
-41
@@ -1,4 +0,4 @@ | ||
| import { type FieldConfig, type FieldElement, type FieldValue, type FieldsetConstraint, type Primitive, type Submission } from '@conform-to/dom'; | ||
| import { type InputHTMLAttributes, type FormEvent, type RefObject } from 'react'; | ||
| export interface FormConfig<Schema extends Record<string, any>> { | ||
| import { type FieldConfig, type FieldElement, type FieldValue, type FieldsetConstraint, type FormMethod, type FormEncType, type Submission } from '@conform-to/dom'; | ||
| import { type FormEvent, type RefObject } from 'react'; | ||
| export interface FormConfig<Schema extends Record<string, any>, ClientSubmission extends Submission | Submission<Schema> = Submission> { | ||
| /** | ||
@@ -10,6 +10,2 @@ * If the form id is provided, Id for label, | ||
| /** | ||
| * Validation mode. Default to `client-only`. | ||
| */ | ||
| mode?: 'client-only' | 'server-validation'; | ||
| /** | ||
| * Define when the error should be reported initially. | ||
@@ -28,3 +24,3 @@ * Support "onSubmit", "onChange", "onBlur". | ||
| */ | ||
| state?: Submission<Schema>; | ||
| state?: Submission; | ||
| /** | ||
@@ -52,3 +48,3 @@ * An object describing the constraint of each field | ||
| formData: FormData; | ||
| }) => Submission<Schema>; | ||
| }) => ClientSubmission; | ||
| /** | ||
@@ -60,3 +56,6 @@ * The submit event handler of the form. It will be called | ||
| formData: FormData; | ||
| submission: Submission<Schema>; | ||
| submission: ClientSubmission; | ||
| action: string; | ||
| encType: FormEncType; | ||
| method: FormMethod; | ||
| }) => void; | ||
@@ -86,9 +85,10 @@ } | ||
| */ | ||
| export declare function useForm<Schema extends Record<string, any>>(config?: FormConfig<Schema>): [Form<Schema>, Fieldset<Schema>]; | ||
| export declare function useForm<Schema extends Record<string, any>, ClientSubmission extends Submission | Submission<Schema> = Submission>(config?: FormConfig<Schema, ClientSubmission>): [Form<Schema>, Fieldset<Schema>]; | ||
| /** | ||
| * All the information of the field, including state and config. | ||
| */ | ||
| export declare type Field<Schema> = { | ||
| export type Field<Schema> = { | ||
| config: FieldConfig<Schema>; | ||
| error?: string; | ||
| errors?: string[]; | ||
| }; | ||
@@ -98,3 +98,3 @@ /** | ||
| */ | ||
| export declare type Fieldset<Schema extends Record<string, any>> = { | ||
| export type Fieldset<Schema extends Record<string, any>> = { | ||
| [Key in keyof Schema]-?: Field<Schema[Key]>; | ||
@@ -114,3 +114,3 @@ }; | ||
| */ | ||
| initialError?: Array<[string, string]>; | ||
| initialError?: Record<string, string | string[]>; | ||
| /** | ||
@@ -141,31 +141,5 @@ * An object describing the constraint of each field | ||
| error: string | undefined; | ||
| errors: string[] | undefined; | ||
| config: FieldConfig<Payload>; | ||
| }>; | ||
| interface ShadowInputProps extends InputHTMLAttributes<HTMLInputElement> { | ||
| ref: RefObject<HTMLInputElement>; | ||
| } | ||
| interface LegacyInputControl<Element extends { | ||
| focus: () => void; | ||
| }> { | ||
| ref: RefObject<Element>; | ||
| value: string; | ||
| onChange: (eventOrValue: { | ||
| target: { | ||
| value: string; | ||
| }; | ||
| } | string) => void; | ||
| onBlur: () => void; | ||
| onInvalid: (event: FormEvent<FieldElement>) => void; | ||
| } | ||
| /** | ||
| * Returns the properties required to configure a shadow input for validation. | ||
| * This is particular useful when integrating dropdown and datepicker whichs | ||
| * introduces custom input mode. | ||
| * | ||
| * @deprecated Please use the `useInputEvent` hook instead | ||
| * @see https://conform.guide/api/react#usecontrolledinput | ||
| */ | ||
| export declare function useControlledInput<Element extends { | ||
| focus: () => void; | ||
| } = HTMLInputElement, Schema extends Primitive = Primitive>(config: FieldConfig<Schema>): [ShadowInputProps, LegacyInputControl<Element>]; | ||
| interface InputControl { | ||
@@ -172,0 +146,0 @@ change: (eventOrValue: { |
+91
-172
@@ -8,3 +8,2 @@ 'use strict'; | ||
| var react = require('react'); | ||
| var helpers = require('./helpers.js'); | ||
@@ -18,12 +17,13 @@ /** | ||
| function useForm() { | ||
| var _config$state; | ||
| var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
| var configRef = react.useRef(config); | ||
| var ref = react.useRef(null); | ||
| var [lastSubmission, setLastSubmission] = react.useState((_config$state = config.state) !== null && _config$state !== void 0 ? _config$state : 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 : ''; | ||
| if (!config.state) { | ||
| return ''; | ||
| } | ||
| var message = config.state.error['']; | ||
| return dom.getValidationMessage(message); | ||
| }); | ||
@@ -38,7 +38,10 @@ var [uncontrolledState, setUncontrolledState] = react.useState(() => { | ||
| return { | ||
| defaultValue: submission.value, | ||
| initialError: submission.error.filter(_ref2 => { | ||
| var [name] = _ref2; | ||
| return name !== '' && dom.shouldValidate(submission, name); | ||
| }) | ||
| defaultValue: submission.payload, | ||
| initialError: Object.entries(submission.error).reduce((result, _ref) => { | ||
| var [name, message] = _ref; | ||
| if (name !== '' && dom.shouldValidate(submission.intent, name)) { | ||
| result[name] = message; | ||
| } | ||
| return result; | ||
| }, {}) | ||
| }; | ||
@@ -60,8 +63,22 @@ }); | ||
| var form = ref.current; | ||
| if (!form || !config.state) { | ||
| var submission = config.state; | ||
| if (!form || !submission) { | ||
| return; | ||
| } | ||
| dom.reportSubmission(form, config.state); | ||
| var listCommand = dom.parseListCommand(submission.intent); | ||
| if (listCommand) { | ||
| form.dispatchEvent(new CustomEvent('conform/list', { | ||
| detail: submission.intent | ||
| })); | ||
| } | ||
| setLastSubmission(submission); | ||
| }, [config.state]); | ||
| react.useEffect(() => { | ||
| var form = ref.current; | ||
| if (!form || !lastSubmission) { | ||
| return; | ||
| } | ||
| dom.reportSubmission(ref.current, lastSubmission); | ||
| }, [lastSubmission]); | ||
| react.useEffect(() => { | ||
| // Revalidate the form when input value is changed | ||
@@ -76,3 +93,3 @@ var handleInput = event => { | ||
| if (field.dataset.conformTouched || formConfig.initialReport === 'onChange') { | ||
| dom.requestCommand(form, dom.validate(field.name)); | ||
| dom.requestIntent(form, dom.validate(field.name)); | ||
| } | ||
@@ -88,3 +105,3 @@ }; | ||
| if (formConfig.initialReport === 'onBlur' && !field.dataset.conformTouched) { | ||
| dom.requestCommand(form, dom.validate(field.name)); | ||
| dom.requestIntent(form, dom.validate(field.name)); | ||
| } | ||
@@ -120,4 +137,3 @@ }; | ||
| setUncontrolledState({ | ||
| defaultValue: formConfig.defaultValue, | ||
| initialError: [] | ||
| defaultValue: formConfig.defaultValue | ||
| }); | ||
@@ -155,9 +171,2 @@ }; | ||
| var submitter = nativeEvent.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. | ||
| */ | ||
| if (event.defaultPrevented) { | ||
@@ -167,39 +176,31 @@ return; | ||
| try { | ||
| var submission; | ||
| var _config$onValidate; | ||
| var formData = dom.getFormData(form, submitter); | ||
| if (typeof config.onValidate === 'function') { | ||
| submission = config.onValidate({ | ||
| form, | ||
| formData | ||
| }); | ||
| } else { | ||
| submission = dom.parse(formData); | ||
| if (config.mode !== 'server-validation') { | ||
| /** | ||
| * As there is no custom logic defined, | ||
| * removing the custom validity state will allow us | ||
| * finding the latest validation message. | ||
| * | ||
| * This is mainly used to showcase the constraint validation API. | ||
| */ | ||
| for (var element of form.elements) { | ||
| if (dom.isFieldElement(element) && element.willValidate) { | ||
| element.setCustomValidity(''); | ||
| submission.error.push([element.name, element.validationMessage]); | ||
| } | ||
| } | ||
| var getSubmission = (_config$onValidate = config.onValidate) !== null && _config$onValidate !== void 0 ? _config$onValidate : context => dom.parse(context.formData); | ||
| var submission = getSubmission({ | ||
| form, | ||
| formData | ||
| }); | ||
| if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && Object.entries(submission.error).some(_ref2 => { | ||
| var [, message] = _ref2; | ||
| 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; | ||
| return ![].concat(message).includes(dom.VALIDATION_UNDEFINED); | ||
| })) { | ||
| var listCommand = dom.parseListCommand(submission.intent); | ||
| if (listCommand) { | ||
| form.dispatchEvent(new CustomEvent('conform/list', { | ||
| detail: submission.intent | ||
| })); | ||
| } | ||
| } | ||
| if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && dom.hasError(submission.error) || submission.type === 'validate' && config.mode !== 'server-validation') { | ||
| setLastSubmission(submission); | ||
| event.preventDefault(); | ||
| } else { | ||
| 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, _rollupPluginBabelHelpers.objectSpread2({ | ||
| formData, | ||
| submission | ||
| }); | ||
| }, dom.getFormAttributes(form, submitter))); | ||
| } | ||
| if (event.defaultPrevented) { | ||
| dom.reportSubmission(form, submission); | ||
| } | ||
| } catch (e) { | ||
@@ -226,14 +227,10 @@ console.warn(e); | ||
| 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 : []) { | ||
| 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 [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]]; | ||
| } | ||
| initialError[key] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, initialError[key]), {}, { | ||
| [scopedName]: message | ||
| }); | ||
| } | ||
@@ -248,8 +245,4 @@ } | ||
| var result = {}; | ||
| for (var [key, entries] of Object.entries(uncontrolledState.initialError)) { | ||
| var _entries$; | ||
| 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 : ''; | ||
| } | ||
| for (var [key, _error] of Object.entries(uncontrolledState.initialError)) { | ||
| result[key] = dom.getErrors(dom.getValidationMessage(_error === null || _error === void 0 ? void 0 : _error[''])); | ||
| } | ||
@@ -280,4 +273,3 @@ return result; | ||
| 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 = dom.getValidationMessage(prev === null || prev === void 0 ? void 0 : prev[key]); | ||
| if (prevMessage === field.validationMessage) { | ||
@@ -287,3 +279,3 @@ return prev; | ||
| return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, prev), {}, { | ||
| [key]: field.validationMessage | ||
| [key]: dom.getErrors(field.validationMessage) | ||
| }); | ||
@@ -326,3 +318,3 @@ }); | ||
| get(_target, key) { | ||
| var _fieldsetConfig$const, _error$key; | ||
| var _fieldsetConfig$const; | ||
| if (typeof key !== 'string') { | ||
@@ -333,2 +325,3 @@ return; | ||
| 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 field = { | ||
@@ -340,3 +333,4 @@ config: _rollupPluginBabelHelpers.objectSpread2({ | ||
| }, constraint), | ||
| error: (_error$key = error === null || error === void 0 ? void 0 : error[key]) !== null && _error$key !== void 0 ? _error$key : '' | ||
| error: errors === null || errors === void 0 ? void 0 : errors[0], | ||
| errors | ||
| }; | ||
@@ -364,14 +358,10 @@ if (fieldsetConfig.form) { | ||
| 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 : []) { | ||
| 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; | ||
| 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]]; | ||
| } | ||
| initialError[index] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, initialError[index]), {}, { | ||
| [scopedName]: message | ||
| }); | ||
| } | ||
@@ -384,3 +374,3 @@ } | ||
| }); | ||
| var [error, setError] = react.useState(() => uncontrolledState.initialError.map(error => error === null || error === void 0 ? void 0 : error[0][1])); | ||
| var [error, setError] = react.useState(() => uncontrolledState.initialError.map(error => dom.getErrors(dom.getValidationMessage(error === null || error === void 0 ? void 0 : error[''])))); | ||
| var [entries, setEntries] = react.useState(() => { | ||
@@ -408,8 +398,7 @@ var _config$defaultValue3; | ||
| setError(prev => { | ||
| var _prev$index; | ||
| var prevMessage = (_prev$index = prev === null || prev === void 0 ? void 0 : prev[index]) !== null && _prev$index !== void 0 ? _prev$index : ''; | ||
| var prevMessage = dom.getValidationMessage(prev === null || prev === void 0 ? void 0 : prev[index]); | ||
| if (prevMessage === field.validationMessage) { | ||
| return prev; | ||
| } | ||
| return [...prev.slice(0, index), field.validationMessage, ...prev.slice(index + 1)]; | ||
| return [...prev.slice(0, index), dom.getErrors(field.validationMessage), ...prev.slice(index + 1)]; | ||
| }); | ||
@@ -420,9 +409,9 @@ } | ||
| }; | ||
| var submitHandler = event => { | ||
| var listHandler = event => { | ||
| var form = dom.getFormElement(ref.current); | ||
| if (!form || event.target !== form || !(event.submitter instanceof HTMLButtonElement) || event.submitter.name !== 'conform/list') { | ||
| if (!form || event.target !== form) { | ||
| return; | ||
| } | ||
| var command = dom.parseListCommand(event.submitter.value); | ||
| if (command.scope !== configRef.current.name) { | ||
| var command = dom.parseListCommand(event.detail); | ||
| if ((command === null || command === void 0 ? void 0 : command.scope) !== configRef.current.name) { | ||
| // Ensure the scope of the listener are limited to specific field name | ||
@@ -438,3 +427,5 @@ return; | ||
| payload: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, command.payload), {}, { | ||
| defaultValue: ["".concat(Date.now()), command.payload.defaultValue] | ||
| defaultValue: ["".concat(Date.now()), | ||
| // @ts-expect-error unknown type as it is sent through network | ||
| command.payload.defaultValue] | ||
| }) | ||
@@ -464,3 +455,2 @@ })); | ||
| }); | ||
| event.preventDefault(); | ||
| }; | ||
@@ -481,7 +471,10 @@ var resetHandler = event => { | ||
| }; | ||
| document.addEventListener('submit', submitHandler, true); | ||
| // @ts-expect-error Custom event: conform/list | ||
| document.addEventListener('conform/list', listHandler, true); | ||
| document.addEventListener('invalid', invalidHandler, true); | ||
| document.addEventListener('reset', resetHandler); | ||
| return () => { | ||
| document.removeEventListener('submit', submitHandler, true); | ||
| // @ts-expect-error Custom event: conform/list | ||
| document.removeEventListener('conform/list', listHandler, true); | ||
| document.removeEventListener('invalid', invalidHandler, true); | ||
@@ -491,4 +484,5 @@ document.removeEventListener('reset', resetHandler); | ||
| }, [ref]); | ||
| return entries.map((_ref3, index) => { | ||
| var [key, defaultValue] = _ref3; | ||
| return entries.map((_ref4, index) => { | ||
| var [key, defaultValue] = _ref4; | ||
| var errors = error[index]; | ||
| var fieldConfig = { | ||
@@ -506,3 +500,4 @@ name: "".concat(config.name, "[").concat(index, "]"), | ||
| key, | ||
| error: error[index], | ||
| error: errors === null || errors === void 0 ? void 0 : errors[0], | ||
| errors, | ||
| config: fieldConfig | ||
@@ -512,77 +507,2 @@ }; | ||
| } | ||
| /** | ||
| * Returns the properties required to configure a shadow input for validation. | ||
| * This is particular useful when integrating dropdown and datepicker whichs | ||
| * introduces custom input mode. | ||
| * | ||
| * @deprecated Please use the `useInputEvent` hook instead | ||
| * @see https://conform.guide/api/react#usecontrolledinput | ||
| */ | ||
| function useControlledInput(config) { | ||
| var _config$defaultValue4; | ||
| var ref = react.useRef(null); | ||
| var inputRef = react.useRef(null); | ||
| 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 : '')); | ||
| var handleChange = eventOrValue => { | ||
| if (!ref.current) { | ||
| return; | ||
| } | ||
| var newValue = typeof eventOrValue === 'string' ? eventOrValue : eventOrValue.target.value; | ||
| ref.current.value = newValue; | ||
| ref.current.dispatchEvent(new InputEvent('input', { | ||
| bubbles: true | ||
| })); | ||
| setValue(newValue); | ||
| }; | ||
| var handleBlur = () => { | ||
| var _ref$current; | ||
| (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.dispatchEvent(new FocusEvent('blur', { | ||
| bubbles: true | ||
| })); | ||
| }; | ||
| var handleInvalid = event => { | ||
| event.preventDefault(); | ||
| }; | ||
| 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({ | ||
| ref, | ||
| onFocus() { | ||
| var _inputRef$current; | ||
| (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus(); | ||
| } | ||
| }, helpers.input(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, config), uncontrolledState), { | ||
| hidden: true | ||
| })), { | ||
| ref: inputRef, | ||
| value, | ||
| onChange: handleChange, | ||
| onBlur: handleBlur, | ||
| onInvalid: handleInvalid | ||
| }]; | ||
| } | ||
@@ -764,3 +684,2 @@ /** | ||
| exports.useControlledInput = useControlledInput; | ||
| exports.useFieldList = useFieldList; | ||
@@ -767,0 +686,0 @@ exports.useFieldset = useFieldset; |
+1
-1
@@ -1,3 +0,3 @@ | ||
| export { type FieldConfig, type FieldsetConstraint, type Submission, getFormElements, hasError, list, validate, requestCommand, requestSubmit, parse, shouldValidate, } from '@conform-to/dom'; | ||
| export { type FieldConfig, type FieldsetConstraint, type Submission, getFormElements, list, validate, requestIntent, requestSubmit, parse, validateConstraint, } from '@conform-to/dom'; | ||
| export * from './hooks'; | ||
| export * as conform from './helpers'; |
+6
-11
@@ -15,6 +15,2 @@ 'use strict'; | ||
| }); | ||
| Object.defineProperty(exports, 'hasError', { | ||
| enumerable: true, | ||
| get: function () { return dom.hasError; } | ||
| }); | ||
| Object.defineProperty(exports, 'list', { | ||
@@ -28,5 +24,5 @@ enumerable: true, | ||
| }); | ||
| Object.defineProperty(exports, 'requestCommand', { | ||
| Object.defineProperty(exports, 'requestIntent', { | ||
| enumerable: true, | ||
| get: function () { return dom.requestCommand; } | ||
| get: function () { return dom.requestIntent; } | ||
| }); | ||
@@ -37,6 +33,2 @@ Object.defineProperty(exports, 'requestSubmit', { | ||
| }); | ||
| Object.defineProperty(exports, 'shouldValidate', { | ||
| enumerable: true, | ||
| get: function () { return dom.shouldValidate; } | ||
| }); | ||
| Object.defineProperty(exports, 'validate', { | ||
@@ -46,3 +38,6 @@ enumerable: true, | ||
| }); | ||
| exports.useControlledInput = hooks.useControlledInput; | ||
| Object.defineProperty(exports, 'validateConstraint', { | ||
| enumerable: true, | ||
| get: function () { return dom.validateConstraint; } | ||
| }); | ||
| exports.useFieldList = hooks.useFieldList; | ||
@@ -49,0 +44,0 @@ exports.useFieldset = hooks.useFieldset; |
@@ -23,2 +23,3 @@ function ownKeys(object, enumerableOnly) { | ||
| function _defineProperty(obj, key, value) { | ||
| key = _toPropertyKey(key); | ||
| if (key in obj) { | ||
@@ -36,3 +37,17 @@ Object.defineProperty(obj, key, { | ||
| } | ||
| function _toPrimitive(input, hint) { | ||
| if (typeof input !== "object" || input === null) return input; | ||
| var prim = input[Symbol.toPrimitive]; | ||
| if (prim !== undefined) { | ||
| var res = prim.call(input, hint || "default"); | ||
| if (typeof res !== "object") return res; | ||
| throw new TypeError("@@toPrimitive must return a primitive value."); | ||
| } | ||
| return (hint === "string" ? String : Number)(input); | ||
| } | ||
| function _toPropertyKey(arg) { | ||
| var key = _toPrimitive(arg, "string"); | ||
| return typeof key === "symbol" ? key : String(key); | ||
| } | ||
| export { _defineProperty as defineProperty, _objectSpread2 as objectSpread2 }; | ||
| export { _defineProperty as defineProperty, _objectSpread2 as objectSpread2, _toPrimitive as toPrimitive, _toPropertyKey as toPropertyKey }; |
@@ -0,1 +1,3 @@ | ||
| export { VALIDATION_SKIPPED, VALIDATION_UNDEFINED } from '@conform-to/dom'; | ||
| /** | ||
@@ -40,3 +42,3 @@ * Style to make the input element visually hidden | ||
| } | ||
| if (config.initialError && config.initialError.length > 0) { | ||
| if (config.initialError && Object.entries(config.initialError).length > 0) { | ||
| attributes.autoFocus = true; | ||
@@ -70,3 +72,3 @@ } | ||
| } | ||
| if (config.initialError && config.initialError.length > 0) { | ||
| if (config.initialError && Object.entries(config.initialError).length > 0) { | ||
| attributes.autoFocus = true; | ||
@@ -95,3 +97,3 @@ } | ||
| } | ||
| if (config.initialError && config.initialError.length > 0) { | ||
| if (config.initialError && Object.entries(config.initialError).length > 0) { | ||
| attributes.autoFocus = true; | ||
@@ -101,3 +103,4 @@ } | ||
| } | ||
| var intent = '__intent__'; | ||
| export { input, select, textarea }; | ||
| export { input, intent, select, textarea }; |
+93
-173
| import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js'; | ||
| import { shouldValidate, reportSubmission, getFormData, parse, isFieldElement, hasError, getPaths, getName, requestCommand, validate, getFormElement, parseListCommand, updateList } from '@conform-to/dom'; | ||
| import { getValidationMessage, shouldValidate, parseListCommand, reportSubmission, getFormData, parse, VALIDATION_UNDEFINED, getFormAttributes, getPaths, getName, getErrors, isFieldElement, requestIntent, validate, getFormElement, updateList } from '@conform-to/dom'; | ||
| import { useRef, useState, useEffect, useMemo, useLayoutEffect } from 'react'; | ||
| import { input } from './helpers.js'; | ||
@@ -13,12 +12,13 @@ /** | ||
| function useForm() { | ||
| var _config$state; | ||
| var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
| var configRef = useRef(config); | ||
| var ref = useRef(null); | ||
| var [lastSubmission, setLastSubmission] = useState((_config$state = config.state) !== null && _config$state !== void 0 ? _config$state : 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 : ''; | ||
| if (!config.state) { | ||
| return ''; | ||
| } | ||
| var message = config.state.error['']; | ||
| return getValidationMessage(message); | ||
| }); | ||
@@ -33,7 +33,10 @@ var [uncontrolledState, setUncontrolledState] = useState(() => { | ||
| return { | ||
| defaultValue: submission.value, | ||
| initialError: submission.error.filter(_ref2 => { | ||
| var [name] = _ref2; | ||
| return name !== '' && shouldValidate(submission, name); | ||
| }) | ||
| defaultValue: submission.payload, | ||
| initialError: Object.entries(submission.error).reduce((result, _ref) => { | ||
| var [name, message] = _ref; | ||
| if (name !== '' && shouldValidate(submission.intent, name)) { | ||
| result[name] = message; | ||
| } | ||
| return result; | ||
| }, {}) | ||
| }; | ||
@@ -55,8 +58,22 @@ }); | ||
| var form = ref.current; | ||
| if (!form || !config.state) { | ||
| var submission = config.state; | ||
| if (!form || !submission) { | ||
| return; | ||
| } | ||
| reportSubmission(form, config.state); | ||
| var listCommand = parseListCommand(submission.intent); | ||
| if (listCommand) { | ||
| form.dispatchEvent(new CustomEvent('conform/list', { | ||
| detail: submission.intent | ||
| })); | ||
| } | ||
| setLastSubmission(submission); | ||
| }, [config.state]); | ||
| useEffect(() => { | ||
| var form = ref.current; | ||
| if (!form || !lastSubmission) { | ||
| return; | ||
| } | ||
| reportSubmission(ref.current, lastSubmission); | ||
| }, [lastSubmission]); | ||
| useEffect(() => { | ||
| // Revalidate the form when input value is changed | ||
@@ -71,3 +88,3 @@ var handleInput = event => { | ||
| if (field.dataset.conformTouched || formConfig.initialReport === 'onChange') { | ||
| requestCommand(form, validate(field.name)); | ||
| requestIntent(form, validate(field.name)); | ||
| } | ||
@@ -83,3 +100,3 @@ }; | ||
| if (formConfig.initialReport === 'onBlur' && !field.dataset.conformTouched) { | ||
| requestCommand(form, validate(field.name)); | ||
| requestIntent(form, validate(field.name)); | ||
| } | ||
@@ -115,4 +132,3 @@ }; | ||
| setUncontrolledState({ | ||
| defaultValue: formConfig.defaultValue, | ||
| initialError: [] | ||
| defaultValue: formConfig.defaultValue | ||
| }); | ||
@@ -150,9 +166,2 @@ }; | ||
| var submitter = nativeEvent.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. | ||
| */ | ||
| if (event.defaultPrevented) { | ||
@@ -162,39 +171,31 @@ return; | ||
| try { | ||
| var submission; | ||
| var _config$onValidate; | ||
| var formData = getFormData(form, submitter); | ||
| if (typeof config.onValidate === 'function') { | ||
| submission = config.onValidate({ | ||
| form, | ||
| formData | ||
| }); | ||
| } else { | ||
| submission = parse(formData); | ||
| if (config.mode !== 'server-validation') { | ||
| /** | ||
| * As there is no custom logic defined, | ||
| * removing the custom validity state will allow us | ||
| * finding the latest validation message. | ||
| * | ||
| * This is mainly used to showcase the constraint validation API. | ||
| */ | ||
| for (var element of form.elements) { | ||
| if (isFieldElement(element) && element.willValidate) { | ||
| element.setCustomValidity(''); | ||
| submission.error.push([element.name, element.validationMessage]); | ||
| } | ||
| } | ||
| var getSubmission = (_config$onValidate = config.onValidate) !== null && _config$onValidate !== void 0 ? _config$onValidate : context => parse(context.formData); | ||
| var submission = getSubmission({ | ||
| form, | ||
| formData | ||
| }); | ||
| if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && Object.entries(submission.error).some(_ref2 => { | ||
| var [, message] = _ref2; | ||
| 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; | ||
| return ![].concat(message).includes(VALIDATION_UNDEFINED); | ||
| })) { | ||
| var listCommand = parseListCommand(submission.intent); | ||
| if (listCommand) { | ||
| form.dispatchEvent(new CustomEvent('conform/list', { | ||
| detail: submission.intent | ||
| })); | ||
| } | ||
| } | ||
| if (!config.noValidate && !(submitter !== null && submitter !== void 0 && submitter.formNoValidate) && hasError(submission.error) || submission.type === 'validate' && config.mode !== 'server-validation') { | ||
| setLastSubmission(submission); | ||
| event.preventDefault(); | ||
| } else { | ||
| 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, _objectSpread2({ | ||
| formData, | ||
| submission | ||
| }); | ||
| }, getFormAttributes(form, submitter))); | ||
| } | ||
| if (event.defaultPrevented) { | ||
| reportSubmission(form, submission); | ||
| } | ||
| } catch (e) { | ||
@@ -221,14 +222,10 @@ console.warn(e); | ||
| 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 : []) { | ||
| 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 [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]]; | ||
| } | ||
| initialError[key] = _objectSpread2(_objectSpread2({}, initialError[key]), {}, { | ||
| [scopedName]: message | ||
| }); | ||
| } | ||
@@ -243,8 +240,4 @@ } | ||
| var result = {}; | ||
| for (var [key, entries] of Object.entries(uncontrolledState.initialError)) { | ||
| var _entries$; | ||
| 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 : ''; | ||
| } | ||
| for (var [key, _error] of Object.entries(uncontrolledState.initialError)) { | ||
| result[key] = getErrors(getValidationMessage(_error === null || _error === void 0 ? void 0 : _error[''])); | ||
| } | ||
@@ -275,4 +268,3 @@ return result; | ||
| 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 = getValidationMessage(prev === null || prev === void 0 ? void 0 : prev[key]); | ||
| if (prevMessage === field.validationMessage) { | ||
@@ -282,3 +274,3 @@ return prev; | ||
| return _objectSpread2(_objectSpread2({}, prev), {}, { | ||
| [key]: field.validationMessage | ||
| [key]: getErrors(field.validationMessage) | ||
| }); | ||
@@ -321,3 +313,3 @@ }); | ||
| get(_target, key) { | ||
| var _fieldsetConfig$const, _error$key; | ||
| var _fieldsetConfig$const; | ||
| if (typeof key !== 'string') { | ||
@@ -328,2 +320,3 @@ return; | ||
| 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 field = { | ||
@@ -335,3 +328,4 @@ config: _objectSpread2({ | ||
| }, constraint), | ||
| error: (_error$key = error === null || error === void 0 ? void 0 : error[key]) !== null && _error$key !== void 0 ? _error$key : '' | ||
| error: errors === null || errors === void 0 ? void 0 : errors[0], | ||
| errors | ||
| }; | ||
@@ -359,14 +353,10 @@ if (fieldsetConfig.form) { | ||
| 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 : []) { | ||
| 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; | ||
| 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]]; | ||
| } | ||
| initialError[index] = _objectSpread2(_objectSpread2({}, initialError[index]), {}, { | ||
| [scopedName]: message | ||
| }); | ||
| } | ||
@@ -379,3 +369,3 @@ } | ||
| }); | ||
| var [error, setError] = useState(() => uncontrolledState.initialError.map(error => error === null || error === void 0 ? void 0 : error[0][1])); | ||
| var [error, setError] = useState(() => uncontrolledState.initialError.map(error => getErrors(getValidationMessage(error === null || error === void 0 ? void 0 : error[''])))); | ||
| var [entries, setEntries] = useState(() => { | ||
@@ -403,8 +393,7 @@ var _config$defaultValue3; | ||
| setError(prev => { | ||
| var _prev$index; | ||
| var prevMessage = (_prev$index = prev === null || prev === void 0 ? void 0 : prev[index]) !== null && _prev$index !== void 0 ? _prev$index : ''; | ||
| var prevMessage = getValidationMessage(prev === null || prev === void 0 ? void 0 : prev[index]); | ||
| if (prevMessage === field.validationMessage) { | ||
| return prev; | ||
| } | ||
| return [...prev.slice(0, index), field.validationMessage, ...prev.slice(index + 1)]; | ||
| return [...prev.slice(0, index), getErrors(field.validationMessage), ...prev.slice(index + 1)]; | ||
| }); | ||
@@ -415,9 +404,9 @@ } | ||
| }; | ||
| var submitHandler = event => { | ||
| var listHandler = event => { | ||
| var form = getFormElement(ref.current); | ||
| if (!form || event.target !== form || !(event.submitter instanceof HTMLButtonElement) || event.submitter.name !== 'conform/list') { | ||
| if (!form || event.target !== form) { | ||
| return; | ||
| } | ||
| var command = parseListCommand(event.submitter.value); | ||
| if (command.scope !== configRef.current.name) { | ||
| var command = parseListCommand(event.detail); | ||
| if ((command === null || command === void 0 ? void 0 : command.scope) !== configRef.current.name) { | ||
| // Ensure the scope of the listener are limited to specific field name | ||
@@ -433,3 +422,5 @@ return; | ||
| payload: _objectSpread2(_objectSpread2({}, command.payload), {}, { | ||
| defaultValue: ["".concat(Date.now()), command.payload.defaultValue] | ||
| defaultValue: ["".concat(Date.now()), | ||
| // @ts-expect-error unknown type as it is sent through network | ||
| command.payload.defaultValue] | ||
| }) | ||
@@ -459,3 +450,2 @@ })); | ||
| }); | ||
| event.preventDefault(); | ||
| }; | ||
@@ -476,7 +466,10 @@ var resetHandler = event => { | ||
| }; | ||
| document.addEventListener('submit', submitHandler, true); | ||
| // @ts-expect-error Custom event: conform/list | ||
| document.addEventListener('conform/list', listHandler, true); | ||
| document.addEventListener('invalid', invalidHandler, true); | ||
| document.addEventListener('reset', resetHandler); | ||
| return () => { | ||
| document.removeEventListener('submit', submitHandler, true); | ||
| // @ts-expect-error Custom event: conform/list | ||
| document.removeEventListener('conform/list', listHandler, true); | ||
| document.removeEventListener('invalid', invalidHandler, true); | ||
@@ -486,4 +479,5 @@ document.removeEventListener('reset', resetHandler); | ||
| }, [ref]); | ||
| return entries.map((_ref3, index) => { | ||
| var [key, defaultValue] = _ref3; | ||
| return entries.map((_ref4, index) => { | ||
| var [key, defaultValue] = _ref4; | ||
| var errors = error[index]; | ||
| var fieldConfig = { | ||
@@ -501,3 +495,4 @@ name: "".concat(config.name, "[").concat(index, "]"), | ||
| key, | ||
| error: error[index], | ||
| error: errors === null || errors === void 0 ? void 0 : errors[0], | ||
| errors, | ||
| config: fieldConfig | ||
@@ -507,77 +502,2 @@ }; | ||
| } | ||
| /** | ||
| * Returns the properties required to configure a shadow input for validation. | ||
| * This is particular useful when integrating dropdown and datepicker whichs | ||
| * introduces custom input mode. | ||
| * | ||
| * @deprecated Please use the `useInputEvent` hook instead | ||
| * @see https://conform.guide/api/react#usecontrolledinput | ||
| */ | ||
| function useControlledInput(config) { | ||
| var _config$defaultValue4; | ||
| var ref = useRef(null); | ||
| var inputRef = useRef(null); | ||
| 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 : '')); | ||
| var handleChange = eventOrValue => { | ||
| if (!ref.current) { | ||
| return; | ||
| } | ||
| var newValue = typeof eventOrValue === 'string' ? eventOrValue : eventOrValue.target.value; | ||
| ref.current.value = newValue; | ||
| ref.current.dispatchEvent(new InputEvent('input', { | ||
| bubbles: true | ||
| })); | ||
| setValue(newValue); | ||
| }; | ||
| var handleBlur = () => { | ||
| var _ref$current; | ||
| (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.dispatchEvent(new FocusEvent('blur', { | ||
| bubbles: true | ||
| })); | ||
| }; | ||
| var handleInvalid = event => { | ||
| event.preventDefault(); | ||
| }; | ||
| 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({ | ||
| ref, | ||
| onFocus() { | ||
| var _inputRef$current; | ||
| (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus(); | ||
| } | ||
| }, input(_objectSpread2(_objectSpread2({}, config), uncontrolledState), { | ||
| hidden: true | ||
| })), { | ||
| ref: inputRef, | ||
| value, | ||
| onChange: handleChange, | ||
| onBlur: handleBlur, | ||
| onInvalid: handleInvalid | ||
| }]; | ||
| } | ||
@@ -759,2 +679,2 @@ /** | ||
| export { useControlledInput, useFieldList, useFieldset, useForm, useInputEvent }; | ||
| export { useFieldList, useFieldset, useForm, useInputEvent }; |
+2
-2
@@ -1,4 +0,4 @@ | ||
| export { getFormElements, hasError, list, parse, requestCommand, requestSubmit, shouldValidate, validate } from '@conform-to/dom'; | ||
| export { useControlledInput, useFieldList, useFieldset, useForm, useInputEvent } from './hooks.js'; | ||
| export { getFormElements, list, parse, requestIntent, requestSubmit, validate, validateConstraint } from '@conform-to/dom'; | ||
| export { useFieldList, useFieldset, useForm, useInputEvent } from './hooks.js'; | ||
| import * as helpers from './helpers.js'; | ||
| export { helpers as conform }; |
+2
-2
@@ -5,3 +5,3 @@ { | ||
| "license": "MIT", | ||
| "version": "0.5.1", | ||
| "version": "0.6.0-pre.0", | ||
| "main": "index.js", | ||
@@ -23,3 +23,3 @@ "module": "module/index.js", | ||
| "dependencies": { | ||
| "@conform-to/dom": "0.5.1" | ||
| "@conform-to/dom": "0.6.0-pre.0" | ||
| }, | ||
@@ -26,0 +26,0 @@ "peerDependencies": { |
+11
-89
@@ -13,7 +13,6 @@ # @conform-to/react | ||
| - [useInputEvent](#useinputevent) | ||
| - [useControlledInput](#usecontrolledinput) | ||
| - [conform](#conform) | ||
| - [list](#list) | ||
| - [validate](#validate) | ||
| - [requestCommand](#requestcommand) | ||
| - [requestIntent](#requestintent) | ||
| - [getFormElements](#getformelements) | ||
@@ -48,10 +47,2 @@ - [hasError](#haserror) | ||
| /** | ||
| * Validation mode. | ||
| * Support "client-only" or "server-validation". | ||
| * | ||
| * Default to `client-only`. | ||
| */ | ||
| mode: 'client-only', | ||
| /** | ||
| * Define when the error should be reported initially. | ||
@@ -335,45 +326,2 @@ * Support "onSubmit", "onChange", "onBlur". | ||
| ### useControlledInput | ||
| > This API is deprecated and replaced with the [useInputEvent](#useinputevent) hook. | ||
| It returns the properties required to configure a shadow input for validation and helper to integrate it. This is particularly useful when [integrating custom input components](/docs/integrations.md#custom-input-component) like dropdown and datepicker. | ||
| ```tsx | ||
| import { useForm, useControlledInput } from '@conform-to/react'; | ||
| import { Select, MenuItem } from '@mui/material'; | ||
| function MuiForm() { | ||
| const [form, { category }] = useForm(); | ||
| const [inputProps, control] = useControlledInput(category.config); | ||
| return ( | ||
| <form {...form.props}> | ||
| {/* Render a shadow input somewhere */} | ||
| <input {...inputProps} /> | ||
| {/* MUI Select is a controlled component */} | ||
| <TextField | ||
| label="Category" | ||
| inputRef={control.ref} | ||
| value={control.value} | ||
| onChange={control.onChange} | ||
| onBlur={control.onBlur} | ||
| inputProps={{ | ||
| onInvalid: control.onInvalid, | ||
| }} | ||
| select | ||
| > | ||
| <MenuItem value="">Please select</MenuItem> | ||
| <MenuItem value="a">Category A</MenuItem> | ||
| <MenuItem value="b">Category B</MenuItem> | ||
| <MenuItem value="c">Category C</MenuItem> | ||
| </TextField> | ||
| </form> | ||
| ); | ||
| } | ||
| ``` | ||
| --- | ||
| ### conform | ||
@@ -505,5 +453,5 @@ | ||
| ### requestCommand | ||
| ### requestIntent | ||
| It lets you [trigger a command](/docs/commands.md#triggering-a-command) without requiring users to click on a button. It supports both [list](#list) and [validate](#validate) command. | ||
| It lets you [trigger an intent](/docs/commands.md#triggering-an-intent) without requiring users to click on a button. It supports both [list](#list) and [validate](#validate) intent. | ||
@@ -516,3 +464,3 @@ ```tsx | ||
| list, | ||
| requestCommand, | ||
| requestIntent, | ||
| } from '@conform-to/react'; | ||
@@ -526,3 +474,3 @@ import DragAndDrop from 'awesome-dnd-example'; | ||
| const handleDrop = (from, to) => | ||
| requestCommand(form.ref.current, list.reorder({ from, to })); | ||
| requestIntent(form.ref.current, list.reorder({ from, to })); | ||
@@ -589,23 +537,2 @@ return ( | ||
| ### hasError | ||
| This helper checks if there is any message defined in error array with the provided name. | ||
| ```ts | ||
| import { hasError } from '@conform-to/react'; | ||
| /** | ||
| * Assume the error looks like this: | ||
| */ | ||
| const error = [['email', 'Email is required']]; | ||
| // This will log `true` | ||
| console.log(hasError(error, 'email')); | ||
| // This will log `false` | ||
| console.log(hasError(error, 'password')); | ||
| ``` | ||
| --- | ||
| ### parse | ||
@@ -634,18 +561,13 @@ | ||
| /** | ||
| * The submission type and intent give us hint on what should be valdiated. | ||
| * If the type is 'validate', only the field with name matching the metadata must be validated. | ||
| * If the type is 'submit', everything should be validated (Default submission) | ||
| * The submission intent give us hint on what should be valdiated. | ||
| * If the intent is 'validate/:field', only the field with name matching must be validated. | ||
| * If the intent is undefined, everything should be validated (Default submission) | ||
| */ | ||
| const submission = { | ||
| context: 'validate', | ||
| intent: 'email', | ||
| value: {}, | ||
| error: [], | ||
| }; | ||
| const intent = 'validate/email'; | ||
| // This will log 'true' | ||
| console.log(shouldValidate(submission, 'email')); | ||
| console.log(shouldValidate(intent, 'email')); | ||
| // This will log 'false' | ||
| console.log(shouldValidate(submission, 'password')); | ||
| console.log(shouldValidate(intent, 'password')); | ||
| ``` |
96630
-7.13%2091
-6.53%566
-12.11%+ Added
- Removed
Updated