Socket
Socket
Sign inDemoInstall

@conform-to/react

Package Overview
Dependencies
Maintainers
1
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@conform-to/react - npm Package Compare versions

Comparing version 0.5.1 to 0.6.0-pre.0

17

_virtual/_rollupPluginBabelHelpers.js

@@ -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;

7

helpers.d.ts

@@ -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: {

@@ -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';

@@ -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": {

@@ -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'));
```
SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc