@conform-to/react
Advanced tools
Comparing version 0.5.1 to 0.6.0-pre.0
@@ -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; |
@@ -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 }; |
@@ -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; |
@@ -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: { |
263
hooks.js
@@ -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,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'; |
17
index.js
@@ -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 }; |
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 }; |
@@ -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 }; |
@@ -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": { |
100
README.md
@@ -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')); | ||
``` |
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
96630
2091
566
+ Added@conform-to/dom@0.6.0-pre.0(transitive)
- Removed@conform-to/dom@0.5.1(transitive)
Updated@conform-to/dom@0.6.0-pre.0