@conform-to/react
Advanced tools
| import { type Submission } from '@conform-to/dom'; | ||
| /** | ||
| * Validate the form with the Constraint Validation API | ||
| * @see https://conform.guide/api/react#validateconstraint | ||
| */ | ||
| export declare function validateConstraint(options: { | ||
| form: HTMLFormElement; | ||
| formData?: FormData; | ||
| }): Submission<Record<string, any>, { | ||
| validity: ValidityState; | ||
| validationMessage: string; | ||
| }>; |
| 'use strict'; | ||
| Object.defineProperty(exports, '__esModule', { value: true }); | ||
| var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js'); | ||
| var dom = require('@conform-to/dom'); | ||
| /** | ||
| * Validate the form with the Constraint Validation API | ||
| * @see https://conform.guide/api/react#validateconstraint | ||
| */ | ||
| function validateConstraint(options) { | ||
| var _options$formData; | ||
| var formData = (_options$formData = options === null || options === void 0 ? void 0 : options.formData) !== null && _options$formData !== void 0 ? _options$formData : new FormData(options.form); | ||
| return dom.parse(formData, { | ||
| resolve(value) { | ||
| var error = {}; | ||
| for (var element of options.form.elements) { | ||
| if (dom.isFieldElement(element) && element.name !== '' && !element.validity.valid) { | ||
| error[element.name] = { | ||
| validity: _rollupPluginBabelHelpers.objectSpread2({}, element.validity), | ||
| validationMessage: element.validationMessage | ||
| }; | ||
| } | ||
| } | ||
| if (Object.entries(error).length > 0) { | ||
| return { | ||
| error | ||
| }; | ||
| } | ||
| return { | ||
| value | ||
| }; | ||
| } | ||
| }); | ||
| } | ||
| exports.validateConstraint = validateConstraint; |
| import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs'; | ||
| import { parse, isFieldElement } from '@conform-to/dom'; | ||
| /** | ||
| * Validate the form with the Constraint Validation API | ||
| * @see https://conform.guide/api/react#validateconstraint | ||
| */ | ||
| function validateConstraint(options) { | ||
| var _options$formData; | ||
| var formData = (_options$formData = options === null || options === void 0 ? void 0 : options.formData) !== null && _options$formData !== void 0 ? _options$formData : new FormData(options.form); | ||
| return parse(formData, { | ||
| resolve(value) { | ||
| var error = {}; | ||
| for (var element of options.form.elements) { | ||
| if (isFieldElement(element) && element.name !== '' && !element.validity.valid) { | ||
| error[element.name] = { | ||
| validity: _objectSpread2({}, element.validity), | ||
| validationMessage: element.validationMessage | ||
| }; | ||
| } | ||
| } | ||
| if (Object.entries(error).length > 0) { | ||
| return { | ||
| error | ||
| }; | ||
| } | ||
| return { | ||
| value | ||
| }; | ||
| } | ||
| }); | ||
| } | ||
| export { validateConstraint }; |
+31
-23
@@ -1,2 +0,2 @@ | ||
| import { type Constraint, type FieldName, type Form, type FormValue, type FormContext, type SubscriptionSubject } from '@conform-to/dom'; | ||
| import { type Constraint, type FormId, type FieldName, type Form, type FormValue, type FormState, type SubscriptionScope, type SubscriptionSubject, type UnionKeyof, type UnionKeyType } from '@conform-to/dom'; | ||
| import { type ReactElement, type ReactNode, type MutableRefObject } from 'react'; | ||
@@ -6,3 +6,11 @@ export type Pretty<T> = { | ||
| } & {}; | ||
| export type BaseMetadata<Schema> = { | ||
| export type Primitive = string | number | boolean | Date | File | null | undefined; | ||
| export type FieldProps<FieldSchema, Error = unknown, FormSchema extends Record<string, unknown> = Record<string, unknown>> = { | ||
| formId: FormId<FormSchema, Error>; | ||
| name: FieldName<FieldSchema>; | ||
| } | { | ||
| formId: FieldSchema extends Record<string, unknown> ? FormId<FieldSchema, Error> : never; | ||
| name?: undefined; | ||
| }; | ||
| export type Metadata<Schema, Error> = { | ||
| key?: string; | ||
@@ -14,4 +22,4 @@ id: string; | ||
| value: FormValue<Schema>; | ||
| errors: string[] | undefined; | ||
| allErrors: Record<string, string[]>; | ||
| error: Error | undefined; | ||
| allError: Record<string, Error>; | ||
| allValid: boolean; | ||
@@ -21,7 +29,8 @@ valid: boolean; | ||
| }; | ||
| export type Field<Schema> = { | ||
| name: FieldName<Schema>; | ||
| formId: string; | ||
| }; | ||
| export type FormMetadata<Schema extends Record<string, any>> = BaseMetadata<Schema> & { | ||
| export type FormMetadata<Schema extends Record<string, unknown> = Record<string, unknown>, Error = unknown> = Omit<Metadata<Schema, Error>, 'id'> & { | ||
| id: FormId<Schema, Error>; | ||
| context: Form<Schema, Error>; | ||
| getFieldset: () => { | ||
| [Key in UnionKeyof<Schema>]: FieldMetadata<UnionKeyType<Schema, Key>, Error, Schema>; | ||
| }; | ||
| onSubmit: (event: React.FormEvent<HTMLFormElement>) => ReturnType<Form<Schema>['submit']>; | ||
@@ -31,12 +40,16 @@ onReset: (event: React.FormEvent<HTMLFormElement>) => void; | ||
| }; | ||
| export type FieldMetadata<Schema> = BaseMetadata<Schema> & { | ||
| formId: string; | ||
| export type FieldMetadata<Schema = unknown, Error = unknown, FormSchema extends Record<string, any> = Record<string, unknown>> = Metadata<Schema, Error> & { | ||
| formId: FormId<FormSchema, Error>; | ||
| name: FieldName<Schema>; | ||
| constraint?: Constraint; | ||
| getFieldset: unknown extends Schema ? () => unknown : Schema extends Primitive | Array<any> ? never : () => { | ||
| [Key in UnionKeyof<Schema>]: FieldMetadata<UnionKeyType<Schema, Key>, Error>; | ||
| }; | ||
| getFieldList: unknown extends Schema ? () => unknown : Schema extends Array<infer Item> ? () => Array<FieldMetadata<Item, Error>> : never; | ||
| }; | ||
| export declare const Registry: import("react").Context<Record<string, Form>>; | ||
| export declare function useFormStore(formId: string, context?: Form): Form; | ||
| export declare function useFormContext(form: Form, subjectRef?: MutableRefObject<SubscriptionSubject>): FormContext; | ||
| export declare function useRegistry<Schema extends Record<string, any>, Error, Value = Schema>(formId: FormId<Schema, Error>, context?: Form<Schema, Error, Value>): Form<Schema, Error, Value>; | ||
| export declare function useFormState<Error>(form: Form<any, Error>, subjectRef?: MutableRefObject<SubscriptionSubject>): FormState<Error>; | ||
| export declare function FormProvider(props: { | ||
| context: Form; | ||
| context: Form<any, any, any>; | ||
| children: ReactNode; | ||
@@ -52,10 +65,5 @@ }): ReactElement; | ||
| export declare function useSubjectRef(initialSubject?: SubscriptionSubject): MutableRefObject<SubscriptionSubject>; | ||
| export declare function getBaseMetadata<Schema>(formId: string, context: FormContext, options: { | ||
| name?: string; | ||
| subjectRef: MutableRefObject<SubscriptionSubject>; | ||
| }): BaseMetadata<Schema>; | ||
| export declare function getFieldMetadata<Schema>(formId: string, context: FormContext, options: { | ||
| name?: string; | ||
| key?: string | number; | ||
| subjectRef: MutableRefObject<SubscriptionSubject>; | ||
| }): FieldMetadata<Schema>; | ||
| export declare function updateSubjectRef(ref: MutableRefObject<SubscriptionSubject>, name: string, subject: keyof SubscriptionSubject, scope: keyof SubscriptionScope): void; | ||
| export declare function getMetadata<Schema, Error, FormSchema extends Record<string, any>>(formId: FormId<FormSchema, Error>, state: FormState<Error>, subjectRef: MutableRefObject<SubscriptionSubject>, name?: FieldName<Schema>): Metadata<Schema, Error>; | ||
| export declare function getFieldMetadata<Schema, Error, FormSchema extends Record<string, any>>(formId: FormId<FormSchema, Error>, state: FormState<Error>, subjectRef: MutableRefObject<SubscriptionSubject>, prefix?: string, key?: string | number): FieldMetadata<Schema, Error, FormSchema>; | ||
| export declare function getFormMetadata<Schema extends Record<string, any>, Error>(formId: FormId<Schema, Error>, state: FormState<Error>, subjectRef: MutableRefObject<SubscriptionSubject>, form: Form<Schema, Error, any>, noValidate: boolean): FormMetadata<Schema, Error>; |
+85
-43
@@ -11,3 +11,3 @@ 'use strict'; | ||
| var Registry = /*#__PURE__*/react.createContext({}); | ||
| function useFormStore(formId, context) { | ||
| function useRegistry(formId, context) { | ||
| var registry = react.useContext(Registry); | ||
@@ -20,6 +20,5 @@ var form = context !== null && context !== void 0 ? context : registry[formId]; | ||
| } | ||
| function useFormContext(form, subjectRef) { | ||
| function useFormState(form, subjectRef) { | ||
| var subscribe = react.useCallback(callback => form.subscribe(callback, () => subjectRef === null || subjectRef === void 0 ? void 0 : subjectRef.current), [form, subjectRef]); | ||
| var result = react.useSyncExternalStore(subscribe, form.getContext, form.getContext); | ||
| return result; | ||
| return react.useSyncExternalStore(subscribe, form.getState, form.getState); | ||
| } | ||
@@ -38,3 +37,3 @@ function FormProvider(props) { | ||
| var _props$formId; | ||
| var form = useFormStore((_props$formId = props.formId) !== null && _props$formId !== void 0 ? _props$formId : props.context.id, props.context); | ||
| var form = useRegistry((_props$formId = props.formId) !== null && _props$formId !== void 0 ? _props$formId : props.context.id, props.context); | ||
| return /*#__PURE__*/jsxRuntime.jsx("input", { | ||
@@ -56,12 +55,11 @@ type: "hidden", | ||
| } | ||
| function getBaseMetadata(formId, context, options) { | ||
| var _options$name; | ||
| var name = (_options$name = options.name) !== null && _options$name !== void 0 ? _options$name : ''; | ||
| function updateSubjectRef(ref, name, subject, scope) { | ||
| var _ref$current$subject$, _ref$current$subject; | ||
| ref.current[subject] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, ref.current[subject]), {}, { | ||
| [scope]: ((_ref$current$subject$ = (_ref$current$subject = ref.current[subject]) === null || _ref$current$subject === void 0 ? void 0 : _ref$current$subject[scope]) !== null && _ref$current$subject$ !== void 0 ? _ref$current$subject$ : []).concat(name) | ||
| }); | ||
| } | ||
| function getMetadata(formId, state, subjectRef) { | ||
| var name = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ''; | ||
| var id = name ? "".concat(formId, "-").concat(name) : formId; | ||
| var updateSubject = (subject, scope) => { | ||
| var _options$subjectRef$c, _options$subjectRef$c2; | ||
| options.subjectRef.current[subject] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options.subjectRef.current[subject]), {}, { | ||
| [scope]: ((_options$subjectRef$c = (_options$subjectRef$c2 = options.subjectRef.current[subject]) === null || _options$subjectRef$c2 === void 0 ? void 0 : _options$subjectRef$c2[scope]) !== null && _options$subjectRef$c !== void 0 ? _options$subjectRef$c : []).concat(name) | ||
| }); | ||
| }; | ||
| return new Proxy({ | ||
@@ -71,21 +69,21 @@ id, | ||
| descriptionId: "".concat(id, "-description"), | ||
| initialValue: context.initialValue[name], | ||
| value: context.value[name], | ||
| errors: context.error[name], | ||
| initialValue: state.initialValue[name], | ||
| value: state.value[name], | ||
| error: state.error[name], | ||
| get key() { | ||
| return context.state.key[name]; | ||
| return state.key[name]; | ||
| }, | ||
| get valid() { | ||
| return context.state.valid[name]; | ||
| return state.valid[name]; | ||
| }, | ||
| get dirty() { | ||
| return context.state.dirty[name]; | ||
| return state.dirty[name]; | ||
| }, | ||
| get allValid() { | ||
| var keys = Object.keys(context.error); | ||
| var keys = Object.keys(state.error); | ||
| if (name === '') { | ||
| return keys.length === 0; | ||
| } | ||
| for (var key of Object.keys(context.error)) { | ||
| if (dom.isPrefix(key, name) && !context.state.valid[key]) { | ||
| for (var key of Object.keys(state.error)) { | ||
| if (dom.isPrefix(key, name) && !state.valid[key]) { | ||
| return false; | ||
@@ -96,13 +94,23 @@ } | ||
| }, | ||
| get allErrors() { | ||
| get allError() { | ||
| if (name === '') { | ||
| return context.error; | ||
| return state.error; | ||
| } | ||
| var result = {}; | ||
| for (var [key, errors] of Object.entries(context.error)) { | ||
| for (var [key, error] of Object.entries(state.error)) { | ||
| if (dom.isPrefix(key, name)) { | ||
| result[key] = errors; | ||
| result[key] = error; | ||
| } | ||
| } | ||
| return result; | ||
| }, | ||
| get getFieldset() { | ||
| return () => new Proxy({}, { | ||
| get(target, key, receiver) { | ||
| if (typeof key === 'string') { | ||
| return getFieldMetadata(formId, state, subjectRef, name, key); | ||
| } | ||
| return Reflect.get(target, key, receiver); | ||
| } | ||
| }); | ||
| } | ||
@@ -113,3 +121,3 @@ }, { | ||
| case 'key': | ||
| case 'errors': | ||
| case 'error': | ||
| case 'initialValue': | ||
@@ -119,9 +127,9 @@ case 'value': | ||
| case 'dirty': | ||
| updateSubject(key === 'errors' ? 'error' : key, 'name'); | ||
| updateSubjectRef(subjectRef, name, key, 'name'); | ||
| break; | ||
| case 'allErrors': | ||
| updateSubject('error', 'prefix'); | ||
| case 'allError': | ||
| updateSubjectRef(subjectRef, name, 'error', 'prefix'); | ||
| break; | ||
| case 'allValid': | ||
| updateSubject('valid', 'prefix'); | ||
| updateSubjectRef(subjectRef, name, 'valid', 'prefix'); | ||
| break; | ||
@@ -133,9 +141,7 @@ } | ||
| } | ||
| function getFieldMetadata(formId, context, options) { | ||
| var _options$name2, _options$name3; | ||
| var name = typeof options.key !== 'undefined' ? dom.formatPaths([...dom.getPaths((_options$name2 = options.name) !== null && _options$name2 !== void 0 ? _options$name2 : ''), options.key]) : (_options$name3 = options.name) !== null && _options$name3 !== void 0 ? _options$name3 : ''; | ||
| var metadata = getBaseMetadata(formId, context, { | ||
| subjectRef: options.subjectRef, | ||
| name | ||
| }); | ||
| function getFieldMetadata(formId, state, subjectRef) { | ||
| var prefix = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ''; | ||
| var key = arguments.length > 4 ? arguments[4] : undefined; | ||
| var name = typeof key === 'undefined' ? prefix : dom.formatPaths([...dom.getPaths(prefix), key]); | ||
| var metadata = getMetadata(formId, state, subjectRef, name); | ||
| return new Proxy(metadata, { | ||
@@ -149,3 +155,15 @@ get(target, key, receiver) { | ||
| case 'constraint': | ||
| return context.constraint[name]; | ||
| return state.constraint[name]; | ||
| case 'getFieldList': | ||
| { | ||
| return () => { | ||
| var _state$initialValue$n; | ||
| var initialValue = (_state$initialValue$n = state.initialValue[name]) !== null && _state$initialValue$n !== void 0 ? _state$initialValue$n : []; | ||
| updateSubjectRef(subjectRef, name, 'initialValue', 'name'); | ||
| if (!Array.isArray(initialValue)) { | ||
| throw new Error('The initial value at the given name is not a list'); | ||
| } | ||
| return Array(initialValue.length).fill(0).map((_, index) => getFieldMetadata(formId, state, subjectRef, name, index)); | ||
| }; | ||
| } | ||
| } | ||
@@ -156,2 +174,24 @@ return Reflect.get(target, key, receiver); | ||
| } | ||
| function getFormMetadata(formId, state, subjectRef, form, noValidate) { | ||
| var metadata = getMetadata(formId, state, subjectRef); | ||
| return new Proxy(metadata, { | ||
| get(target, key, receiver) { | ||
| switch (key) { | ||
| case 'context': | ||
| return form; | ||
| case 'onSubmit': | ||
| return event => { | ||
| var submitEvent = event.nativeEvent; | ||
| form.submit(submitEvent); | ||
| if (submitEvent.defaultPrevented) { | ||
| event.preventDefault(); | ||
| } | ||
| }; | ||
| case 'noValidate': | ||
| return noValidate; | ||
| } | ||
| return Reflect.get(target, key, receiver); | ||
| } | ||
| }); | ||
| } | ||
@@ -161,6 +201,8 @@ exports.FormProvider = FormProvider; | ||
| exports.Registry = Registry; | ||
| exports.getBaseMetadata = getBaseMetadata; | ||
| exports.getFieldMetadata = getFieldMetadata; | ||
| exports.useFormContext = useFormContext; | ||
| exports.useFormStore = useFormStore; | ||
| exports.getFormMetadata = getFormMetadata; | ||
| exports.getMetadata = getMetadata; | ||
| exports.updateSubjectRef = updateSubjectRef; | ||
| exports.useFormState = useFormState; | ||
| exports.useRegistry = useRegistry; | ||
| exports.useSubjectRef = useSubjectRef; |
+82
-42
| import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs'; | ||
| import { STATE, isPrefix, formatPaths, getPaths } from '@conform-to/dom'; | ||
| import { STATE, formatPaths, getPaths, isPrefix } from '@conform-to/dom'; | ||
| import { useContext, useMemo, createContext, useCallback, useSyncExternalStore, useRef } from 'react'; | ||
@@ -7,3 +7,3 @@ import { jsx } from 'react/jsx-runtime'; | ||
| var Registry = /*#__PURE__*/createContext({}); | ||
| function useFormStore(formId, context) { | ||
| function useRegistry(formId, context) { | ||
| var registry = useContext(Registry); | ||
@@ -16,6 +16,5 @@ var form = context !== null && context !== void 0 ? context : registry[formId]; | ||
| } | ||
| function useFormContext(form, subjectRef) { | ||
| function useFormState(form, subjectRef) { | ||
| var subscribe = useCallback(callback => form.subscribe(callback, () => subjectRef === null || subjectRef === void 0 ? void 0 : subjectRef.current), [form, subjectRef]); | ||
| var result = useSyncExternalStore(subscribe, form.getContext, form.getContext); | ||
| return result; | ||
| return useSyncExternalStore(subscribe, form.getState, form.getState); | ||
| } | ||
@@ -34,3 +33,3 @@ function FormProvider(props) { | ||
| var _props$formId; | ||
| var form = useFormStore((_props$formId = props.formId) !== null && _props$formId !== void 0 ? _props$formId : props.context.id, props.context); | ||
| var form = useRegistry((_props$formId = props.formId) !== null && _props$formId !== void 0 ? _props$formId : props.context.id, props.context); | ||
| return /*#__PURE__*/jsx("input", { | ||
@@ -52,12 +51,11 @@ type: "hidden", | ||
| } | ||
| function getBaseMetadata(formId, context, options) { | ||
| var _options$name; | ||
| var name = (_options$name = options.name) !== null && _options$name !== void 0 ? _options$name : ''; | ||
| function updateSubjectRef(ref, name, subject, scope) { | ||
| var _ref$current$subject$, _ref$current$subject; | ||
| ref.current[subject] = _objectSpread2(_objectSpread2({}, ref.current[subject]), {}, { | ||
| [scope]: ((_ref$current$subject$ = (_ref$current$subject = ref.current[subject]) === null || _ref$current$subject === void 0 ? void 0 : _ref$current$subject[scope]) !== null && _ref$current$subject$ !== void 0 ? _ref$current$subject$ : []).concat(name) | ||
| }); | ||
| } | ||
| function getMetadata(formId, state, subjectRef) { | ||
| var name = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ''; | ||
| var id = name ? "".concat(formId, "-").concat(name) : formId; | ||
| var updateSubject = (subject, scope) => { | ||
| var _options$subjectRef$c, _options$subjectRef$c2; | ||
| options.subjectRef.current[subject] = _objectSpread2(_objectSpread2({}, options.subjectRef.current[subject]), {}, { | ||
| [scope]: ((_options$subjectRef$c = (_options$subjectRef$c2 = options.subjectRef.current[subject]) === null || _options$subjectRef$c2 === void 0 ? void 0 : _options$subjectRef$c2[scope]) !== null && _options$subjectRef$c !== void 0 ? _options$subjectRef$c : []).concat(name) | ||
| }); | ||
| }; | ||
| return new Proxy({ | ||
@@ -67,21 +65,21 @@ id, | ||
| descriptionId: "".concat(id, "-description"), | ||
| initialValue: context.initialValue[name], | ||
| value: context.value[name], | ||
| errors: context.error[name], | ||
| initialValue: state.initialValue[name], | ||
| value: state.value[name], | ||
| error: state.error[name], | ||
| get key() { | ||
| return context.state.key[name]; | ||
| return state.key[name]; | ||
| }, | ||
| get valid() { | ||
| return context.state.valid[name]; | ||
| return state.valid[name]; | ||
| }, | ||
| get dirty() { | ||
| return context.state.dirty[name]; | ||
| return state.dirty[name]; | ||
| }, | ||
| get allValid() { | ||
| var keys = Object.keys(context.error); | ||
| var keys = Object.keys(state.error); | ||
| if (name === '') { | ||
| return keys.length === 0; | ||
| } | ||
| for (var key of Object.keys(context.error)) { | ||
| if (isPrefix(key, name) && !context.state.valid[key]) { | ||
| for (var key of Object.keys(state.error)) { | ||
| if (isPrefix(key, name) && !state.valid[key]) { | ||
| return false; | ||
@@ -92,13 +90,23 @@ } | ||
| }, | ||
| get allErrors() { | ||
| get allError() { | ||
| if (name === '') { | ||
| return context.error; | ||
| return state.error; | ||
| } | ||
| var result = {}; | ||
| for (var [key, errors] of Object.entries(context.error)) { | ||
| for (var [key, error] of Object.entries(state.error)) { | ||
| if (isPrefix(key, name)) { | ||
| result[key] = errors; | ||
| result[key] = error; | ||
| } | ||
| } | ||
| return result; | ||
| }, | ||
| get getFieldset() { | ||
| return () => new Proxy({}, { | ||
| get(target, key, receiver) { | ||
| if (typeof key === 'string') { | ||
| return getFieldMetadata(formId, state, subjectRef, name, key); | ||
| } | ||
| return Reflect.get(target, key, receiver); | ||
| } | ||
| }); | ||
| } | ||
@@ -109,3 +117,3 @@ }, { | ||
| case 'key': | ||
| case 'errors': | ||
| case 'error': | ||
| case 'initialValue': | ||
@@ -115,9 +123,9 @@ case 'value': | ||
| case 'dirty': | ||
| updateSubject(key === 'errors' ? 'error' : key, 'name'); | ||
| updateSubjectRef(subjectRef, name, key, 'name'); | ||
| break; | ||
| case 'allErrors': | ||
| updateSubject('error', 'prefix'); | ||
| case 'allError': | ||
| updateSubjectRef(subjectRef, name, 'error', 'prefix'); | ||
| break; | ||
| case 'allValid': | ||
| updateSubject('valid', 'prefix'); | ||
| updateSubjectRef(subjectRef, name, 'valid', 'prefix'); | ||
| break; | ||
@@ -129,9 +137,7 @@ } | ||
| } | ||
| function getFieldMetadata(formId, context, options) { | ||
| var _options$name2, _options$name3; | ||
| var name = typeof options.key !== 'undefined' ? formatPaths([...getPaths((_options$name2 = options.name) !== null && _options$name2 !== void 0 ? _options$name2 : ''), options.key]) : (_options$name3 = options.name) !== null && _options$name3 !== void 0 ? _options$name3 : ''; | ||
| var metadata = getBaseMetadata(formId, context, { | ||
| subjectRef: options.subjectRef, | ||
| name | ||
| }); | ||
| function getFieldMetadata(formId, state, subjectRef) { | ||
| var prefix = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : ''; | ||
| var key = arguments.length > 4 ? arguments[4] : undefined; | ||
| var name = typeof key === 'undefined' ? prefix : formatPaths([...getPaths(prefix), key]); | ||
| var metadata = getMetadata(formId, state, subjectRef, name); | ||
| return new Proxy(metadata, { | ||
@@ -145,3 +151,15 @@ get(target, key, receiver) { | ||
| case 'constraint': | ||
| return context.constraint[name]; | ||
| return state.constraint[name]; | ||
| case 'getFieldList': | ||
| { | ||
| return () => { | ||
| var _state$initialValue$n; | ||
| var initialValue = (_state$initialValue$n = state.initialValue[name]) !== null && _state$initialValue$n !== void 0 ? _state$initialValue$n : []; | ||
| updateSubjectRef(subjectRef, name, 'initialValue', 'name'); | ||
| if (!Array.isArray(initialValue)) { | ||
| throw new Error('The initial value at the given name is not a list'); | ||
| } | ||
| return Array(initialValue.length).fill(0).map((_, index) => getFieldMetadata(formId, state, subjectRef, name, index)); | ||
| }; | ||
| } | ||
| } | ||
@@ -152,3 +170,25 @@ return Reflect.get(target, key, receiver); | ||
| } | ||
| function getFormMetadata(formId, state, subjectRef, form, noValidate) { | ||
| var metadata = getMetadata(formId, state, subjectRef); | ||
| return new Proxy(metadata, { | ||
| get(target, key, receiver) { | ||
| switch (key) { | ||
| case 'context': | ||
| return form; | ||
| case 'onSubmit': | ||
| return event => { | ||
| var submitEvent = event.nativeEvent; | ||
| form.submit(submitEvent); | ||
| if (submitEvent.defaultPrevented) { | ||
| event.preventDefault(); | ||
| } | ||
| }; | ||
| case 'noValidate': | ||
| return noValidate; | ||
| } | ||
| return Reflect.get(target, key, receiver); | ||
| } | ||
| }); | ||
| } | ||
| export { FormProvider, FormStateInput, Registry, getBaseMetadata, getFieldMetadata, useFormContext, useFormStore, useSubjectRef }; | ||
| export { FormProvider, FormStateInput, Registry, getFieldMetadata, getFormMetadata, getMetadata, updateSubjectRef, useFormState, useRegistry, useSubjectRef }; |
+187
-43
@@ -1,3 +0,4 @@ | ||
| import type { CSSProperties, HTMLInputTypeAttribute } from 'react'; | ||
| import type { FormMetadata, FieldMetadata, Pretty } from './context'; | ||
| /// <reference types="react" /> | ||
| import { type Intent } from '@conform-to/dom'; | ||
| import type { FormMetadata, FieldMetadata, Metadata, Pretty, Primitive } from './context'; | ||
| type FormControlProps = { | ||
@@ -10,9 +11,24 @@ id: string; | ||
| tabIndex?: number; | ||
| style?: CSSProperties; | ||
| 'aria-describedby'?: string; | ||
| 'aria-invalid'?: boolean; | ||
| 'aria-hidden'?: boolean; | ||
| }; | ||
| type FormControlOptions = { | ||
| /** | ||
| * Decide whether to include `aria-invalid` and `aria-describedby` in the result. | ||
| */ | ||
| ariaAttributes?: true; | ||
| /** | ||
| * Decide whether the aria attributes should be based on `field.valid` or `field.allValid`. | ||
| * @default 'field' | ||
| */ | ||
| ariaInvalid?: 'all' | 'field'; | ||
| /** | ||
| * Assign additional `id` to the `aria-describedby` attribute. If `true`, it will use the `descriptionId` from the metadata. | ||
| */ | ||
| ariaDescribedBy?: boolean | string; | ||
| } | { | ||
| ariaAttributes: false; | ||
| }; | ||
| type InputProps = Pretty<FormControlProps & { | ||
| type?: Exclude<HTMLInputTypeAttribute, 'submit' | 'reset' | 'button'>; | ||
| type?: 'checkbox' | 'color' | 'date' | 'datetime-local' | 'email' | 'file' | 'image' | 'month' | 'number' | 'password' | 'radio' | 'range' | 'search' | 'tel' | 'text' | 'time' | 'url' | 'week'; | ||
| minLength?: number; | ||
@@ -29,2 +45,16 @@ maxLength?: number; | ||
| }>; | ||
| type InputOptions = Pretty<FormControlOptions & ({ | ||
| type: 'checkbox' | 'radio'; | ||
| /** | ||
| * The value of the checkbox or radio button. Pass `false` if you want to mange the checked state yourself. | ||
| * @default 'on' | ||
| */ | ||
| value?: string | boolean; | ||
| } | { | ||
| type?: Exclude<InputProps['type'], 'checkbox' | 'radio'>; | ||
| /** | ||
| * Decide whether defaultValue should be returned. Pass `false` if you want to mange the value yourself. | ||
| */ | ||
| value?: boolean; | ||
| })>; | ||
| type SelectProps = Pretty<FormControlProps & { | ||
@@ -34,2 +64,8 @@ defaultValue?: string | number | readonly string[] | undefined; | ||
| }>; | ||
| type SelectOptions = Pretty<FormControlOptions & { | ||
| /** | ||
| * Decide whether defaultValue should be returned. Pass `false` if you want to mange the value yourself. | ||
| */ | ||
| value?: boolean; | ||
| }>; | ||
| type TextareaProps = Pretty<FormControlProps & { | ||
@@ -40,49 +76,157 @@ minLength?: number; | ||
| }>; | ||
| type Primitive = string | number | boolean | Date | null | undefined; | ||
| type BaseOptions = { | ||
| ariaAttributes?: true; | ||
| description?: boolean; | ||
| } | { | ||
| ariaAttributes: false; | ||
| type TextareaOptions = Pretty<FormControlOptions & { | ||
| /** | ||
| * Decide whether defaultValue should be returned. Pass `false` if you want to mange the value yourself. | ||
| */ | ||
| value?: true; | ||
| }>; | ||
| /** | ||
| * Derives aria attributes of a form control based on the field metadata. | ||
| */ | ||
| export declare function getAriaAttributes<Schema, Error>(metadata: Metadata<Schema, Error>, options?: FormControlOptions): { | ||
| 'aria-invalid'?: boolean; | ||
| 'aria-describedby'?: string; | ||
| }; | ||
| type ControlOptions = BaseOptions & { | ||
| hidden?: boolean; | ||
| /** | ||
| * Derives the properties of a form element based on the form metadata, | ||
| * including `id`, `onSubmit`, `noValidate`, `aria-invalid` and `aria-describedby`. | ||
| * | ||
| * @example | ||
| * ```tsx | ||
| * <form {...getFormProps(metadata)} /> | ||
| * ``` | ||
| */ | ||
| export declare function getFormProps<Schema extends Record<string, any>, Error>(metadata: FormMetadata<Schema, Error>, options?: FormControlOptions): { | ||
| 'aria-invalid'?: boolean | undefined; | ||
| 'aria-describedby'?: string | undefined; | ||
| id: import("@conform-to/dom").FormId<Schema, Error>; | ||
| onSubmit: (event: import("react").FormEvent<HTMLFormElement>) => void; | ||
| noValidate: boolean; | ||
| }; | ||
| type FormOptions<Schema extends Record<string, any>> = BaseOptions & { | ||
| onSubmit?: (event: React.FormEvent<HTMLFormElement>, context: ReturnType<FormMetadata<Schema>['onSubmit']>) => void; | ||
| onReset?: (event: React.FormEvent<HTMLFormElement>) => void; | ||
| }; | ||
| type InputOptions = ControlOptions & ({ | ||
| type: 'checkbox' | 'radio'; | ||
| value?: string; | ||
| } | { | ||
| type?: Exclude<HTMLInputTypeAttribute, 'button' | 'submit' | 'hidden'>; | ||
| value?: never; | ||
| }); | ||
| export declare const hiddenProps: { | ||
| style: CSSProperties; | ||
| tabIndex: number; | ||
| 'aria-hidden': boolean; | ||
| }; | ||
| export declare function input<Schema extends Primitive | unknown>(field: FieldMetadata<Schema>, options?: InputOptions): InputProps; | ||
| export declare function input<Schema extends File | File[]>(field: FieldMetadata<Schema>, options: InputOptions & { | ||
| type: 'file'; | ||
| }): InputProps; | ||
| export declare function select<Schema extends Primitive | Primitive[] | undefined | unknown>(metadata: FieldMetadata<Schema>, options?: ControlOptions): SelectProps; | ||
| export declare function textarea<Schema extends Primitive | undefined | unknown>(metadata: FieldMetadata<Schema>, options?: ControlOptions): TextareaProps; | ||
| export declare function form<Schema extends Record<string, any>>(metadata: FormMetadata<Schema>, options?: FormOptions<Schema>): { | ||
| /** | ||
| * Derives the properties of a fieldset element based on the field metadata, | ||
| * including `id`, `name`, `form`, `aria-invalid` and `aria-describedby`. | ||
| * | ||
| * @example | ||
| * ```tsx | ||
| * <fieldset {...getFieldsetProps(metadata)} /> | ||
| * ``` | ||
| */ | ||
| export declare function getFieldsetProps<Schema extends Record<string, any> | undefined | unknown, Error>(metadata: FieldMetadata<Schema, Error, any>, options?: FormControlOptions): { | ||
| 'aria-invalid'?: boolean | undefined; | ||
| 'aria-describedby'?: string | undefined; | ||
| id: string; | ||
| onSubmit: (event: React.FormEvent<HTMLFormElement>) => void; | ||
| onReset: (event: import("react").FormEvent<HTMLFormElement>) => void; | ||
| noValidate: boolean; | ||
| name: import("@conform-to/dom").FieldName<Schema>; | ||
| form: import("@conform-to/dom").FormId<any, Error>; | ||
| }; | ||
| export declare function fieldset<Schema extends Record<string, any> | undefined | unknown>(metadata: FieldMetadata<Schema>, options?: BaseOptions): { | ||
| /** | ||
| * Derives common properties of a form control based on the field metadata, | ||
| * including `key`, `id`, `name`, `form`, `required`, `autoFocus`, `aria-invalid` and `aria-describedby`. | ||
| */ | ||
| export declare function getFormControlProps<Schema, Error>(metadata: FieldMetadata<Schema, Error, any>, options?: FormControlOptions): { | ||
| 'aria-invalid'?: boolean | undefined; | ||
| 'aria-describedby'?: string | undefined; | ||
| id: string; | ||
| name: import("@conform-to/dom").FieldName<Schema>; | ||
| form: string; | ||
| form: import("@conform-to/dom").FormId<any, Error>; | ||
| key: string | undefined; | ||
| required: true | undefined; | ||
| autoFocus: true | undefined; | ||
| }; | ||
| export declare function collection<Schema extends Array<string | boolean> | string | boolean | undefined | unknown>(metadata: FieldMetadata<Schema>, options: BaseOptions & { | ||
| /** | ||
| * Derives the properties of an input element based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` | ||
| * and constraint attributes such as `type`, `required`, `minLength`, `maxLength`, `min`, `max`, `step`, `pattern`, `multiple`. | ||
| * Depends on the provided options, it will also set `defaultChecked` / `checked` if it is a checkbox or radio button, | ||
| * or otherwise `defaultValue` / `value`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-input-props | ||
| * @example | ||
| * ```tsx | ||
| * // To setup an uncontrolled input | ||
| * <input {...getInputProps(metadata)} /> | ||
| * // To setup an uncontrolled checkbox | ||
| * <input {...getInputProps(metadata, { type: 'checkbox' })} /> | ||
| * // To setup an input without defaultValue | ||
| * <input {...getInputProps(metadata, { value: false })} /> | ||
| * // To setup a radio button without defaultChecked state | ||
| * <input {...getInputProps(metadata, { type: 'radio', value: false })} /> | ||
| * ``` | ||
| */ | ||
| export declare function getInputProps<Schema extends Exclude<Primitive, File>>(metadata: FieldMetadata<Schema, any, any>, options?: InputOptions): InputProps; | ||
| export declare function getInputProps<Schema extends File | File[]>(metadata: FieldMetadata<Schema, any, any>, options: InputOptions & { | ||
| type: 'file'; | ||
| }): InputProps; | ||
| /** | ||
| * Derives the properties of a select element based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` | ||
| * and constraint attributes such as `required` or `multiple`. | ||
| * Depends on the provided options, it will also set `defaultValue` / `value`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-select-props | ||
| * @example | ||
| * ```tsx | ||
| * // To setup an uncontrolled select | ||
| * <select {...getSelectProps(metadata)} /> | ||
| * // To setup a select without defaultValue | ||
| * <select {...getSelectProps(metadata, { value: false })} /> | ||
| * ``` | ||
| */ | ||
| export declare function getSelectProps<Schema extends Exclude<Primitive, File> | Array<Exclude<Primitive, File>> | undefined>(metadata: FieldMetadata<Schema, any, any>, options?: SelectOptions): SelectProps; | ||
| /** | ||
| * Derives the properties of a textarea element based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` | ||
| * and constraint attributes such as `required`, `minLength` or `maxLength`. | ||
| * Depends on the provided options, it will also set `defaultValue` / `value`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-textarea-props | ||
| * @example | ||
| * ```tsx | ||
| * // To setup an uncontrolled textarea | ||
| * <textarea {...getTextareaProps(metadata)} /> | ||
| * // To setup a textarea without defaultValue | ||
| * <textarea {...getTextareaProps(metadata, { value: false })} /> | ||
| * ``` | ||
| */ | ||
| export declare function getTextareaProps<Schema extends Exclude<Primitive, File> | undefined>(metadata: FieldMetadata<Schema, any, any>, options?: TextareaOptions): TextareaProps; | ||
| /** | ||
| * Derives the properties of a collection of checkboxes or radio buttons based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` and `required`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-textarea-props | ||
| * @example | ||
| * ```tsx | ||
| * <fieldset> | ||
| * {getCollectionProps(metadata, { | ||
| * type: 'checkbox', | ||
| * options: ['a', 'b', 'c'] | ||
| * }).map((props) => ( | ||
| * <div key={props.key}> | ||
| * <label htmlFor={props.id}>{props.value}</label> | ||
| * <input {...props} /> | ||
| * </div> | ||
| * ))} | ||
| * </fieldset> | ||
| * ``` | ||
| */ | ||
| export declare function getCollectionProps<Schema extends Array<string | boolean> | string | boolean | undefined | unknown>(metadata: FieldMetadata<Schema, any, any>, options: Pretty<FormControlOptions & { | ||
| /** | ||
| * The input type. Use `checkbox` for multiple selection or `radio` for single selection. | ||
| */ | ||
| type: 'checkbox' | 'radio'; | ||
| /** | ||
| * The `value` assigned to each input element. | ||
| */ | ||
| options: string[]; | ||
| }): Array<InputProps & Pick<Required<InputProps>, 'type' | 'value'>>; | ||
| /** | ||
| * Decide whether defaultValue should be returned. Pass `false` if you want to mange the value yourself. | ||
| */ | ||
| value?: boolean; | ||
| }>): Array<InputProps & Pick<Required<InputProps>, 'type' | 'value'>>; | ||
| export declare function getControlButtonProps(formId: string, intents: Array<Intent>): { | ||
| name: string; | ||
| value: string; | ||
| form: string; | ||
| formNoValidate: boolean; | ||
| }; | ||
| export {}; |
+192
-98
@@ -6,8 +6,9 @@ 'use strict'; | ||
| var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js'); | ||
| var dom = require('@conform-to/dom'); | ||
| /** | ||
| * Cleanup `undefined` from the dervied props | ||
| * Cleanup `undefined` from the result. | ||
| * To minimize conflicts when merging with user defined props | ||
| */ | ||
| function cleanup(props) { | ||
| function simplify(props) { | ||
| for (var key in props) { | ||
@@ -20,2 +21,6 @@ if (props[key] === undefined) { | ||
| } | ||
| /** | ||
| * Derives aria attributes of a form control based on the field metadata. | ||
| */ | ||
| function getAriaAttributes(metadata) { | ||
@@ -26,121 +31,210 @@ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
| } | ||
| return cleanup({ | ||
| 'aria-invalid': !metadata.valid || undefined, | ||
| 'aria-describedby': metadata.valid ? options.description ? metadata.descriptionId : undefined : "".concat(metadata.errorId, " ").concat(options.description ? metadata.descriptionId : '').trim() | ||
| var invalid = options.ariaInvalid === 'all' ? !metadata.allValid : !metadata.valid; | ||
| var ariaDescribedBy = typeof options.ariaDescribedBy === 'string' ? options.ariaDescribedBy : options.ariaDescribedBy ? metadata.descriptionId : undefined; | ||
| return simplify({ | ||
| 'aria-invalid': invalid || undefined, | ||
| 'aria-describedby': invalid ? "".concat(metadata.errorId, " ").concat(ariaDescribedBy !== null && ariaDescribedBy !== void 0 ? ariaDescribedBy : '').trim() : ariaDescribedBy | ||
| }); | ||
| } | ||
| /** | ||
| * Derives the properties of a form element based on the form metadata, | ||
| * including `id`, `onSubmit`, `noValidate`, `aria-invalid` and `aria-describedby`. | ||
| * | ||
| * @example | ||
| * ```tsx | ||
| * <form {...getFormProps(metadata)} /> | ||
| * ``` | ||
| */ | ||
| function getFormProps(metadata, options) { | ||
| return simplify(_rollupPluginBabelHelpers.objectSpread2({ | ||
| id: metadata.id, | ||
| onSubmit: metadata.onSubmit, | ||
| noValidate: metadata.noValidate | ||
| }, getAriaAttributes(metadata, options))); | ||
| } | ||
| /** | ||
| * Derives the properties of a fieldset element based on the field metadata, | ||
| * including `id`, `name`, `form`, `aria-invalid` and `aria-describedby`. | ||
| * | ||
| * @example | ||
| * ```tsx | ||
| * <fieldset {...getFieldsetProps(metadata)} /> | ||
| * ``` | ||
| */ | ||
| function getFieldsetProps(metadata, options) { | ||
| return simplify(_rollupPluginBabelHelpers.objectSpread2({ | ||
| id: metadata.id, | ||
| name: metadata.name, | ||
| form: metadata.formId | ||
| }, getAriaAttributes(metadata, options))); | ||
| } | ||
| /** | ||
| * Derives common properties of a form control based on the field metadata, | ||
| * including `key`, `id`, `name`, `form`, `required`, `autoFocus`, `aria-invalid` and `aria-describedby`. | ||
| */ | ||
| function getFormControlProps(metadata, options) { | ||
| var _metadata$constraint; | ||
| return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({ | ||
| id: metadata.id, | ||
| name: metadata.name, | ||
| form: metadata.formId, | ||
| return simplify(_rollupPluginBabelHelpers.objectSpread2({ | ||
| key: metadata.key, | ||
| required: ((_metadata$constraint = metadata.constraint) === null || _metadata$constraint === void 0 ? void 0 : _metadata$constraint.required) || undefined, | ||
| autoFocus: !metadata.valid || undefined | ||
| }, options !== null && options !== void 0 && options.hidden ? hiddenProps : undefined), getAriaAttributes(metadata, options))); | ||
| }, getFieldsetProps(metadata, options))); | ||
| } | ||
| var hiddenProps = { | ||
| /** | ||
| * Style to make the input element visually hidden | ||
| * Based on the `sr-only` class from tailwindcss | ||
| */ | ||
| style: { | ||
| position: 'absolute', | ||
| width: '1px', | ||
| height: '1px', | ||
| padding: 0, | ||
| margin: '-1px', | ||
| overflow: 'hidden', | ||
| clip: 'rect(0,0,0,0)', | ||
| whiteSpace: 'nowrap', | ||
| border: 0 | ||
| }, | ||
| tabIndex: -1, | ||
| 'aria-hidden': true | ||
| }; | ||
| function input(field) { | ||
| var _field$constraint, _field$constraint2, _field$constraint3, _field$constraint4, _field$constraint5, _field$constraint6, _field$constraint7; | ||
| /** | ||
| * Derives the properties of an input element based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` | ||
| * and constraint attributes such as `type`, `required`, `minLength`, `maxLength`, `min`, `max`, `step`, `pattern`, `multiple`. | ||
| * Depends on the provided options, it will also set `defaultChecked` / `checked` if it is a checkbox or radio button, | ||
| * or otherwise `defaultValue` / `value`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-input-props | ||
| * @example | ||
| * ```tsx | ||
| * // To setup an uncontrolled input | ||
| * <input {...getInputProps(metadata)} /> | ||
| * // To setup an uncontrolled checkbox | ||
| * <input {...getInputProps(metadata, { type: 'checkbox' })} /> | ||
| * // To setup an input without defaultValue | ||
| * <input {...getInputProps(metadata, { value: false })} /> | ||
| * // To setup a radio button without defaultChecked state | ||
| * <input {...getInputProps(metadata, { type: 'radio', value: false })} /> | ||
| * ``` | ||
| */ | ||
| function getInputProps(metadata) { | ||
| var _metadata$constraint2, _metadata$constraint3, _metadata$constraint4, _metadata$constraint5, _metadata$constraint6, _metadata$constraint7, _metadata$constraint8; | ||
| var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
| var props = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(field, options)), {}, { | ||
| var props = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| type: options.type, | ||
| minLength: (_field$constraint = field.constraint) === null || _field$constraint === void 0 ? void 0 : _field$constraint.minLength, | ||
| maxLength: (_field$constraint2 = field.constraint) === null || _field$constraint2 === void 0 ? void 0 : _field$constraint2.maxLength, | ||
| min: (_field$constraint3 = field.constraint) === null || _field$constraint3 === void 0 ? void 0 : _field$constraint3.min, | ||
| max: (_field$constraint4 = field.constraint) === null || _field$constraint4 === void 0 ? void 0 : _field$constraint4.max, | ||
| step: (_field$constraint5 = field.constraint) === null || _field$constraint5 === void 0 ? void 0 : _field$constraint5.step, | ||
| pattern: (_field$constraint6 = field.constraint) === null || _field$constraint6 === void 0 ? void 0 : _field$constraint6.pattern, | ||
| multiple: (_field$constraint7 = field.constraint) === null || _field$constraint7 === void 0 ? void 0 : _field$constraint7.multiple | ||
| minLength: (_metadata$constraint2 = metadata.constraint) === null || _metadata$constraint2 === void 0 ? void 0 : _metadata$constraint2.minLength, | ||
| maxLength: (_metadata$constraint3 = metadata.constraint) === null || _metadata$constraint3 === void 0 ? void 0 : _metadata$constraint3.maxLength, | ||
| min: (_metadata$constraint4 = metadata.constraint) === null || _metadata$constraint4 === void 0 ? void 0 : _metadata$constraint4.min, | ||
| max: (_metadata$constraint5 = metadata.constraint) === null || _metadata$constraint5 === void 0 ? void 0 : _metadata$constraint5.max, | ||
| step: (_metadata$constraint6 = metadata.constraint) === null || _metadata$constraint6 === void 0 ? void 0 : _metadata$constraint6.step, | ||
| pattern: (_metadata$constraint7 = metadata.constraint) === null || _metadata$constraint7 === void 0 ? void 0 : _metadata$constraint7.pattern, | ||
| multiple: (_metadata$constraint8 = metadata.constraint) === null || _metadata$constraint8 === void 0 ? void 0 : _metadata$constraint8.multiple | ||
| }); | ||
| if (options.type === 'checkbox' || options.type === 'radio') { | ||
| var _options$value; | ||
| props.value = (_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : 'on'; | ||
| props.defaultChecked = typeof field.initialValue === 'boolean' ? field.initialValue : field.initialValue === props.value; | ||
| } else if (options.type !== 'file') { | ||
| var _field$initialValue; | ||
| props.defaultValue = (_field$initialValue = field.initialValue) === null || _field$initialValue === void 0 ? void 0 : _field$initialValue.toString(); | ||
| if (typeof options.value === 'undefined' || options.value) { | ||
| if (options.type === 'checkbox' || options.type === 'radio') { | ||
| props.value = typeof options.value === 'string' ? options.value : 'on'; | ||
| props.defaultChecked = typeof metadata.initialValue === 'boolean' ? metadata.initialValue : metadata.initialValue === props.value; | ||
| } else if (typeof metadata.initialValue === 'string') { | ||
| props.defaultValue = metadata.initialValue; | ||
| } | ||
| } | ||
| return cleanup(props); | ||
| return simplify(props); | ||
| } | ||
| function select(metadata, options) { | ||
| var _metadata$initialValu, _metadata$constraint2; | ||
| return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| defaultValue: (_metadata$initialValu = metadata.initialValue) === null || _metadata$initialValu === void 0 ? void 0 : _metadata$initialValu.toString(), | ||
| multiple: (_metadata$constraint2 = metadata.constraint) === null || _metadata$constraint2 === void 0 ? void 0 : _metadata$constraint2.multiple | ||
| })); | ||
| /** | ||
| * Derives the properties of a select element based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` | ||
| * and constraint attributes such as `required` or `multiple`. | ||
| * Depends on the provided options, it will also set `defaultValue` / `value`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-select-props | ||
| * @example | ||
| * ```tsx | ||
| * // To setup an uncontrolled select | ||
| * <select {...getSelectProps(metadata)} /> | ||
| * // To setup a select without defaultValue | ||
| * <select {...getSelectProps(metadata, { value: false })} /> | ||
| * ``` | ||
| */ | ||
| function getSelectProps(metadata) { | ||
| var _metadata$constraint9; | ||
| var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
| var props = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| multiple: (_metadata$constraint9 = metadata.constraint) === null || _metadata$constraint9 === void 0 ? void 0 : _metadata$constraint9.multiple | ||
| }); | ||
| if (typeof options.value === 'undefined' || options.value) { | ||
| props.defaultValue = Array.isArray(metadata.initialValue) ? metadata.initialValue.map(item => "".concat(item !== null && item !== void 0 ? item : '')) : metadata.initialValue; | ||
| } | ||
| return simplify(props); | ||
| } | ||
| function textarea(metadata, options) { | ||
| var _metadata$initialValu2, _metadata$constraint3, _metadata$constraint4; | ||
| return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| defaultValue: (_metadata$initialValu2 = metadata.initialValue) === null || _metadata$initialValu2 === void 0 ? void 0 : _metadata$initialValu2.toString(), | ||
| minLength: (_metadata$constraint3 = metadata.constraint) === null || _metadata$constraint3 === void 0 ? void 0 : _metadata$constraint3.minLength, | ||
| maxLength: (_metadata$constraint4 = metadata.constraint) === null || _metadata$constraint4 === void 0 ? void 0 : _metadata$constraint4.maxLength | ||
| })); | ||
| /** | ||
| * Derives the properties of a textarea element based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` | ||
| * and constraint attributes such as `required`, `minLength` or `maxLength`. | ||
| * Depends on the provided options, it will also set `defaultValue` / `value`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-textarea-props | ||
| * @example | ||
| * ```tsx | ||
| * // To setup an uncontrolled textarea | ||
| * <textarea {...getTextareaProps(metadata)} /> | ||
| * // To setup a textarea without defaultValue | ||
| * <textarea {...getTextareaProps(metadata, { value: false })} /> | ||
| * ``` | ||
| */ | ||
| function getTextareaProps(metadata) { | ||
| var _metadata$constraint10, _metadata$constraint11; | ||
| var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
| var props = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| minLength: (_metadata$constraint10 = metadata.constraint) === null || _metadata$constraint10 === void 0 ? void 0 : _metadata$constraint10.minLength, | ||
| maxLength: (_metadata$constraint11 = metadata.constraint) === null || _metadata$constraint11 === void 0 ? void 0 : _metadata$constraint11.maxLength | ||
| }); | ||
| if (typeof options.value === 'undefined' || options.value) { | ||
| props.defaultValue = metadata.initialValue; | ||
| } | ||
| return simplify(props); | ||
| } | ||
| function form(metadata, options) { | ||
| var onSubmit = options === null || options === void 0 ? void 0 : options.onSubmit; | ||
| var onReset = options === null || options === void 0 ? void 0 : options.onReset; | ||
| return cleanup(_rollupPluginBabelHelpers.objectSpread2({ | ||
| id: metadata.id, | ||
| onSubmit: typeof onSubmit !== 'function' ? metadata.onSubmit : event => { | ||
| var context = metadata.onSubmit(event); | ||
| if (!event.defaultPrevented) { | ||
| onSubmit(event, context); | ||
| } | ||
| }, | ||
| onReset: typeof onReset !== 'function' ? metadata.onReset : event => { | ||
| metadata.onReset(event); | ||
| onReset(event); | ||
| }, | ||
| noValidate: metadata.noValidate | ||
| }, getAriaAttributes(metadata, options))); | ||
| } | ||
| function fieldset(metadata, options) { | ||
| return cleanup(_rollupPluginBabelHelpers.objectSpread2({ | ||
| id: metadata.id, | ||
| name: metadata.name, | ||
| form: metadata.formId | ||
| }, getAriaAttributes(metadata, options))); | ||
| } | ||
| function collection(metadata, options) { | ||
| /** | ||
| * Derives the properties of a collection of checkboxes or radio buttons based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` and `required`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-textarea-props | ||
| * @example | ||
| * ```tsx | ||
| * <fieldset> | ||
| * {getCollectionProps(metadata, { | ||
| * type: 'checkbox', | ||
| * options: ['a', 'b', 'c'] | ||
| * }).map((props) => ( | ||
| * <div key={props.key}> | ||
| * <label htmlFor={props.id}>{props.value}</label> | ||
| * <input {...props} /> | ||
| * </div> | ||
| * ))} | ||
| * </fieldset> | ||
| * ``` | ||
| */ | ||
| function getCollectionProps(metadata, options) { | ||
| return options.options.map(value => { | ||
| var _metadata$constraint5; | ||
| return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| var _metadata$key, _metadata$constraint12; | ||
| return simplify(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| key: "".concat((_metadata$key = metadata.key) !== null && _metadata$key !== void 0 ? _metadata$key : '').concat(value), | ||
| id: "".concat(metadata.id, "-").concat(value), | ||
| type: options.type, | ||
| value, | ||
| defaultChecked: options.type === 'checkbox' && Array.isArray(metadata.initialValue) ? metadata.initialValue.includes(value) : metadata.initialValue === value, | ||
| defaultChecked: typeof options.value === 'undefined' || options.value ? options.type === 'checkbox' && Array.isArray(metadata.initialValue) ? metadata.initialValue.includes(value) : metadata.initialValue === value : undefined, | ||
| // The required attribute doesn't make sense for checkbox group | ||
| // As it would require all checkboxes to be checked instead of at least one | ||
| // It is overriden with `undefiend` so it could be cleaned upW properly | ||
| required: options.type === 'checkbox' ? undefined : (_metadata$constraint5 = metadata.constraint) === null || _metadata$constraint5 === void 0 ? void 0 : _metadata$constraint5.required | ||
| // It is overriden with `undefiend` so it could be cleaned up properly | ||
| required: options.type === 'checkbox' ? undefined : (_metadata$constraint12 = metadata.constraint) === null || _metadata$constraint12 === void 0 ? void 0 : _metadata$constraint12.required | ||
| })); | ||
| }); | ||
| } | ||
| function getControlButtonProps(formId, intents) { | ||
| return { | ||
| name: dom.INTENT, | ||
| value: dom.serializeIntents(intents), | ||
| form: formId, | ||
| formNoValidate: true | ||
| }; | ||
| } | ||
| exports.collection = collection; | ||
| exports.fieldset = fieldset; | ||
| exports.form = form; | ||
| exports.hiddenProps = hiddenProps; | ||
| exports.input = input; | ||
| exports.select = select; | ||
| exports.textarea = textarea; | ||
| exports.getAriaAttributes = getAriaAttributes; | ||
| exports.getCollectionProps = getCollectionProps; | ||
| exports.getControlButtonProps = getControlButtonProps; | ||
| exports.getFieldsetProps = getFieldsetProps; | ||
| exports.getFormControlProps = getFormControlProps; | ||
| exports.getFormProps = getFormProps; | ||
| exports.getInputProps = getInputProps; | ||
| exports.getSelectProps = getSelectProps; | ||
| exports.getTextareaProps = getTextareaProps; |
+184
-92
| import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs'; | ||
| import { INTENT, serializeIntents } from '@conform-to/dom'; | ||
| /** | ||
| * Cleanup `undefined` from the dervied props | ||
| * Cleanup `undefined` from the result. | ||
| * To minimize conflicts when merging with user defined props | ||
| */ | ||
| function cleanup(props) { | ||
| function simplify(props) { | ||
| for (var key in props) { | ||
@@ -15,2 +16,6 @@ if (props[key] === undefined) { | ||
| } | ||
| /** | ||
| * Derives aria attributes of a form control based on the field metadata. | ||
| */ | ||
| function getAriaAttributes(metadata) { | ||
@@ -21,115 +26,202 @@ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
| } | ||
| return cleanup({ | ||
| 'aria-invalid': !metadata.valid || undefined, | ||
| 'aria-describedby': metadata.valid ? options.description ? metadata.descriptionId : undefined : "".concat(metadata.errorId, " ").concat(options.description ? metadata.descriptionId : '').trim() | ||
| var invalid = options.ariaInvalid === 'all' ? !metadata.allValid : !metadata.valid; | ||
| var ariaDescribedBy = typeof options.ariaDescribedBy === 'string' ? options.ariaDescribedBy : options.ariaDescribedBy ? metadata.descriptionId : undefined; | ||
| return simplify({ | ||
| 'aria-invalid': invalid || undefined, | ||
| 'aria-describedby': invalid ? "".concat(metadata.errorId, " ").concat(ariaDescribedBy !== null && ariaDescribedBy !== void 0 ? ariaDescribedBy : '').trim() : ariaDescribedBy | ||
| }); | ||
| } | ||
| /** | ||
| * Derives the properties of a form element based on the form metadata, | ||
| * including `id`, `onSubmit`, `noValidate`, `aria-invalid` and `aria-describedby`. | ||
| * | ||
| * @example | ||
| * ```tsx | ||
| * <form {...getFormProps(metadata)} /> | ||
| * ``` | ||
| */ | ||
| function getFormProps(metadata, options) { | ||
| return simplify(_objectSpread2({ | ||
| id: metadata.id, | ||
| onSubmit: metadata.onSubmit, | ||
| noValidate: metadata.noValidate | ||
| }, getAriaAttributes(metadata, options))); | ||
| } | ||
| /** | ||
| * Derives the properties of a fieldset element based on the field metadata, | ||
| * including `id`, `name`, `form`, `aria-invalid` and `aria-describedby`. | ||
| * | ||
| * @example | ||
| * ```tsx | ||
| * <fieldset {...getFieldsetProps(metadata)} /> | ||
| * ``` | ||
| */ | ||
| function getFieldsetProps(metadata, options) { | ||
| return simplify(_objectSpread2({ | ||
| id: metadata.id, | ||
| name: metadata.name, | ||
| form: metadata.formId | ||
| }, getAriaAttributes(metadata, options))); | ||
| } | ||
| /** | ||
| * Derives common properties of a form control based on the field metadata, | ||
| * including `key`, `id`, `name`, `form`, `required`, `autoFocus`, `aria-invalid` and `aria-describedby`. | ||
| */ | ||
| function getFormControlProps(metadata, options) { | ||
| var _metadata$constraint; | ||
| return cleanup(_objectSpread2(_objectSpread2({ | ||
| id: metadata.id, | ||
| name: metadata.name, | ||
| form: metadata.formId, | ||
| return simplify(_objectSpread2({ | ||
| key: metadata.key, | ||
| required: ((_metadata$constraint = metadata.constraint) === null || _metadata$constraint === void 0 ? void 0 : _metadata$constraint.required) || undefined, | ||
| autoFocus: !metadata.valid || undefined | ||
| }, options !== null && options !== void 0 && options.hidden ? hiddenProps : undefined), getAriaAttributes(metadata, options))); | ||
| }, getFieldsetProps(metadata, options))); | ||
| } | ||
| var hiddenProps = { | ||
| /** | ||
| * Style to make the input element visually hidden | ||
| * Based on the `sr-only` class from tailwindcss | ||
| */ | ||
| style: { | ||
| position: 'absolute', | ||
| width: '1px', | ||
| height: '1px', | ||
| padding: 0, | ||
| margin: '-1px', | ||
| overflow: 'hidden', | ||
| clip: 'rect(0,0,0,0)', | ||
| whiteSpace: 'nowrap', | ||
| border: 0 | ||
| }, | ||
| tabIndex: -1, | ||
| 'aria-hidden': true | ||
| }; | ||
| function input(field) { | ||
| var _field$constraint, _field$constraint2, _field$constraint3, _field$constraint4, _field$constraint5, _field$constraint6, _field$constraint7; | ||
| /** | ||
| * Derives the properties of an input element based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` | ||
| * and constraint attributes such as `type`, `required`, `minLength`, `maxLength`, `min`, `max`, `step`, `pattern`, `multiple`. | ||
| * Depends on the provided options, it will also set `defaultChecked` / `checked` if it is a checkbox or radio button, | ||
| * or otherwise `defaultValue` / `value`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-input-props | ||
| * @example | ||
| * ```tsx | ||
| * // To setup an uncontrolled input | ||
| * <input {...getInputProps(metadata)} /> | ||
| * // To setup an uncontrolled checkbox | ||
| * <input {...getInputProps(metadata, { type: 'checkbox' })} /> | ||
| * // To setup an input without defaultValue | ||
| * <input {...getInputProps(metadata, { value: false })} /> | ||
| * // To setup a radio button without defaultChecked state | ||
| * <input {...getInputProps(metadata, { type: 'radio', value: false })} /> | ||
| * ``` | ||
| */ | ||
| function getInputProps(metadata) { | ||
| var _metadata$constraint2, _metadata$constraint3, _metadata$constraint4, _metadata$constraint5, _metadata$constraint6, _metadata$constraint7, _metadata$constraint8; | ||
| var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
| var props = _objectSpread2(_objectSpread2({}, getFormControlProps(field, options)), {}, { | ||
| var props = _objectSpread2(_objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| type: options.type, | ||
| minLength: (_field$constraint = field.constraint) === null || _field$constraint === void 0 ? void 0 : _field$constraint.minLength, | ||
| maxLength: (_field$constraint2 = field.constraint) === null || _field$constraint2 === void 0 ? void 0 : _field$constraint2.maxLength, | ||
| min: (_field$constraint3 = field.constraint) === null || _field$constraint3 === void 0 ? void 0 : _field$constraint3.min, | ||
| max: (_field$constraint4 = field.constraint) === null || _field$constraint4 === void 0 ? void 0 : _field$constraint4.max, | ||
| step: (_field$constraint5 = field.constraint) === null || _field$constraint5 === void 0 ? void 0 : _field$constraint5.step, | ||
| pattern: (_field$constraint6 = field.constraint) === null || _field$constraint6 === void 0 ? void 0 : _field$constraint6.pattern, | ||
| multiple: (_field$constraint7 = field.constraint) === null || _field$constraint7 === void 0 ? void 0 : _field$constraint7.multiple | ||
| minLength: (_metadata$constraint2 = metadata.constraint) === null || _metadata$constraint2 === void 0 ? void 0 : _metadata$constraint2.minLength, | ||
| maxLength: (_metadata$constraint3 = metadata.constraint) === null || _metadata$constraint3 === void 0 ? void 0 : _metadata$constraint3.maxLength, | ||
| min: (_metadata$constraint4 = metadata.constraint) === null || _metadata$constraint4 === void 0 ? void 0 : _metadata$constraint4.min, | ||
| max: (_metadata$constraint5 = metadata.constraint) === null || _metadata$constraint5 === void 0 ? void 0 : _metadata$constraint5.max, | ||
| step: (_metadata$constraint6 = metadata.constraint) === null || _metadata$constraint6 === void 0 ? void 0 : _metadata$constraint6.step, | ||
| pattern: (_metadata$constraint7 = metadata.constraint) === null || _metadata$constraint7 === void 0 ? void 0 : _metadata$constraint7.pattern, | ||
| multiple: (_metadata$constraint8 = metadata.constraint) === null || _metadata$constraint8 === void 0 ? void 0 : _metadata$constraint8.multiple | ||
| }); | ||
| if (options.type === 'checkbox' || options.type === 'radio') { | ||
| var _options$value; | ||
| props.value = (_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : 'on'; | ||
| props.defaultChecked = typeof field.initialValue === 'boolean' ? field.initialValue : field.initialValue === props.value; | ||
| } else if (options.type !== 'file') { | ||
| var _field$initialValue; | ||
| props.defaultValue = (_field$initialValue = field.initialValue) === null || _field$initialValue === void 0 ? void 0 : _field$initialValue.toString(); | ||
| if (typeof options.value === 'undefined' || options.value) { | ||
| if (options.type === 'checkbox' || options.type === 'radio') { | ||
| props.value = typeof options.value === 'string' ? options.value : 'on'; | ||
| props.defaultChecked = typeof metadata.initialValue === 'boolean' ? metadata.initialValue : metadata.initialValue === props.value; | ||
| } else if (typeof metadata.initialValue === 'string') { | ||
| props.defaultValue = metadata.initialValue; | ||
| } | ||
| } | ||
| return cleanup(props); | ||
| return simplify(props); | ||
| } | ||
| function select(metadata, options) { | ||
| var _metadata$initialValu, _metadata$constraint2; | ||
| return cleanup(_objectSpread2(_objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| defaultValue: (_metadata$initialValu = metadata.initialValue) === null || _metadata$initialValu === void 0 ? void 0 : _metadata$initialValu.toString(), | ||
| multiple: (_metadata$constraint2 = metadata.constraint) === null || _metadata$constraint2 === void 0 ? void 0 : _metadata$constraint2.multiple | ||
| })); | ||
| /** | ||
| * Derives the properties of a select element based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` | ||
| * and constraint attributes such as `required` or `multiple`. | ||
| * Depends on the provided options, it will also set `defaultValue` / `value`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-select-props | ||
| * @example | ||
| * ```tsx | ||
| * // To setup an uncontrolled select | ||
| * <select {...getSelectProps(metadata)} /> | ||
| * // To setup a select without defaultValue | ||
| * <select {...getSelectProps(metadata, { value: false })} /> | ||
| * ``` | ||
| */ | ||
| function getSelectProps(metadata) { | ||
| var _metadata$constraint9; | ||
| var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
| var props = _objectSpread2(_objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| multiple: (_metadata$constraint9 = metadata.constraint) === null || _metadata$constraint9 === void 0 ? void 0 : _metadata$constraint9.multiple | ||
| }); | ||
| if (typeof options.value === 'undefined' || options.value) { | ||
| props.defaultValue = Array.isArray(metadata.initialValue) ? metadata.initialValue.map(item => "".concat(item !== null && item !== void 0 ? item : '')) : metadata.initialValue; | ||
| } | ||
| return simplify(props); | ||
| } | ||
| function textarea(metadata, options) { | ||
| var _metadata$initialValu2, _metadata$constraint3, _metadata$constraint4; | ||
| return cleanup(_objectSpread2(_objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| defaultValue: (_metadata$initialValu2 = metadata.initialValue) === null || _metadata$initialValu2 === void 0 ? void 0 : _metadata$initialValu2.toString(), | ||
| minLength: (_metadata$constraint3 = metadata.constraint) === null || _metadata$constraint3 === void 0 ? void 0 : _metadata$constraint3.minLength, | ||
| maxLength: (_metadata$constraint4 = metadata.constraint) === null || _metadata$constraint4 === void 0 ? void 0 : _metadata$constraint4.maxLength | ||
| })); | ||
| /** | ||
| * Derives the properties of a textarea element based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` | ||
| * and constraint attributes such as `required`, `minLength` or `maxLength`. | ||
| * Depends on the provided options, it will also set `defaultValue` / `value`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-textarea-props | ||
| * @example | ||
| * ```tsx | ||
| * // To setup an uncontrolled textarea | ||
| * <textarea {...getTextareaProps(metadata)} /> | ||
| * // To setup a textarea without defaultValue | ||
| * <textarea {...getTextareaProps(metadata, { value: false })} /> | ||
| * ``` | ||
| */ | ||
| function getTextareaProps(metadata) { | ||
| var _metadata$constraint10, _metadata$constraint11; | ||
| var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
| var props = _objectSpread2(_objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| minLength: (_metadata$constraint10 = metadata.constraint) === null || _metadata$constraint10 === void 0 ? void 0 : _metadata$constraint10.minLength, | ||
| maxLength: (_metadata$constraint11 = metadata.constraint) === null || _metadata$constraint11 === void 0 ? void 0 : _metadata$constraint11.maxLength | ||
| }); | ||
| if (typeof options.value === 'undefined' || options.value) { | ||
| props.defaultValue = metadata.initialValue; | ||
| } | ||
| return simplify(props); | ||
| } | ||
| function form(metadata, options) { | ||
| var onSubmit = options === null || options === void 0 ? void 0 : options.onSubmit; | ||
| var onReset = options === null || options === void 0 ? void 0 : options.onReset; | ||
| return cleanup(_objectSpread2({ | ||
| id: metadata.id, | ||
| onSubmit: typeof onSubmit !== 'function' ? metadata.onSubmit : event => { | ||
| var context = metadata.onSubmit(event); | ||
| if (!event.defaultPrevented) { | ||
| onSubmit(event, context); | ||
| } | ||
| }, | ||
| onReset: typeof onReset !== 'function' ? metadata.onReset : event => { | ||
| metadata.onReset(event); | ||
| onReset(event); | ||
| }, | ||
| noValidate: metadata.noValidate | ||
| }, getAriaAttributes(metadata, options))); | ||
| } | ||
| function fieldset(metadata, options) { | ||
| return cleanup(_objectSpread2({ | ||
| id: metadata.id, | ||
| name: metadata.name, | ||
| form: metadata.formId | ||
| }, getAriaAttributes(metadata, options))); | ||
| } | ||
| function collection(metadata, options) { | ||
| /** | ||
| * Derives the properties of a collection of checkboxes or radio buttons based on the field metadata, | ||
| * including common form control attributes like `key`, `id`, `name`, `form`, `autoFocus`, `aria-invalid`, `aria-describedby` and `required`. | ||
| * | ||
| * @see https://conform.guide/api/react/get-textarea-props | ||
| * @example | ||
| * ```tsx | ||
| * <fieldset> | ||
| * {getCollectionProps(metadata, { | ||
| * type: 'checkbox', | ||
| * options: ['a', 'b', 'c'] | ||
| * }).map((props) => ( | ||
| * <div key={props.key}> | ||
| * <label htmlFor={props.id}>{props.value}</label> | ||
| * <input {...props} /> | ||
| * </div> | ||
| * ))} | ||
| * </fieldset> | ||
| * ``` | ||
| */ | ||
| function getCollectionProps(metadata, options) { | ||
| return options.options.map(value => { | ||
| var _metadata$constraint5; | ||
| return cleanup(_objectSpread2(_objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| var _metadata$key, _metadata$constraint12; | ||
| return simplify(_objectSpread2(_objectSpread2({}, getFormControlProps(metadata, options)), {}, { | ||
| key: "".concat((_metadata$key = metadata.key) !== null && _metadata$key !== void 0 ? _metadata$key : '').concat(value), | ||
| id: "".concat(metadata.id, "-").concat(value), | ||
| type: options.type, | ||
| value, | ||
| defaultChecked: options.type === 'checkbox' && Array.isArray(metadata.initialValue) ? metadata.initialValue.includes(value) : metadata.initialValue === value, | ||
| defaultChecked: typeof options.value === 'undefined' || options.value ? options.type === 'checkbox' && Array.isArray(metadata.initialValue) ? metadata.initialValue.includes(value) : metadata.initialValue === value : undefined, | ||
| // The required attribute doesn't make sense for checkbox group | ||
| // As it would require all checkboxes to be checked instead of at least one | ||
| // It is overriden with `undefiend` so it could be cleaned upW properly | ||
| required: options.type === 'checkbox' ? undefined : (_metadata$constraint5 = metadata.constraint) === null || _metadata$constraint5 === void 0 ? void 0 : _metadata$constraint5.required | ||
| // It is overriden with `undefiend` so it could be cleaned up properly | ||
| required: options.type === 'checkbox' ? undefined : (_metadata$constraint12 = metadata.constraint) === null || _metadata$constraint12 === void 0 ? void 0 : _metadata$constraint12.required | ||
| })); | ||
| }); | ||
| } | ||
| function getControlButtonProps(formId, intents) { | ||
| return { | ||
| name: INTENT, | ||
| value: serializeIntents(intents), | ||
| form: formId, | ||
| formNoValidate: true | ||
| }; | ||
| } | ||
| export { collection, fieldset, form, hiddenProps, input, select, textarea }; | ||
| export { getAriaAttributes, getCollectionProps, getControlButtonProps, getFieldsetProps, getFormControlProps, getFormProps, getInputProps, getSelectProps, getTextareaProps }; |
+21
-33
@@ -1,2 +0,2 @@ | ||
| import { type UnionKeyof, type UnionKeyType, type FieldName, type Form, type FormOptions } from '@conform-to/dom'; | ||
| import { type FormId, type FieldName, type FormOptions } from '@conform-to/dom'; | ||
| import { useEffect } from 'react'; | ||
@@ -9,4 +9,5 @@ import { type FormMetadata, type FieldMetadata, type Pretty } from './context'; | ||
| export declare const useSafeLayoutEffect: typeof useEffect; | ||
| export declare function useFormId(preferredId?: string): string; | ||
| export declare function useForm<Schema extends Record<string, any>>(options: Pretty<FormOptions<Schema> & { | ||
| export declare function useFormId<Schema extends Record<string, unknown>, Error>(preferredId?: string): FormId<Schema, Error>; | ||
| export declare function useNoValidate(defaultNoValidate?: boolean): boolean; | ||
| export declare function useForm<Schema extends Record<string, any>, Error = string[], Value = Schema>(options: Pretty<FormOptions<Schema, Error, Value> & { | ||
| /** | ||
@@ -24,33 +25,20 @@ * If the form id is provided, Id for label, | ||
| }>): { | ||
| form: FormMetadata<Schema>; | ||
| context: Form<Schema>; | ||
| fields: Pretty<FieldsetMetadata<Schema>>; | ||
| meta: FormMetadata<Schema, Error>; | ||
| fields: ReturnType<FormMetadata<Schema, Error>['getFieldset']>; | ||
| }; | ||
| export declare function useFormMetadata<Schema extends Record<string, any>>(options: { | ||
| formId: string; | ||
| context?: Form<Schema>; | ||
| export declare function useFormMetadata<Schema extends Record<string, any>, Error>(options: { | ||
| formId: FormId<Schema, Error>; | ||
| defaultNoValidate?: boolean; | ||
| }): FormMetadata<Schema>; | ||
| export type FieldsetMetadata<Schema> = Schema extends Array<any> ? { | ||
| [Key in keyof Schema]: FieldMetadata<Schema[Key]>; | ||
| } : Schema extends { | ||
| [key in string]?: any; | ||
| } ? { | ||
| [Key in UnionKeyof<Schema>]: FieldMetadata<UnionKeyType<Schema, Key>>; | ||
| } : Record<string | number, FieldMetadata<any>>; | ||
| export declare function useFieldset<Schema>(options: { | ||
| formId: string; | ||
| name?: FieldName<Schema>; | ||
| context?: Form; | ||
| }): Pretty<FieldsetMetadata<Schema>>; | ||
| export type Item<List> = List extends Array<infer Item> ? Item : any; | ||
| export declare function useFieldList<Schema>(options: { | ||
| formId: string; | ||
| name: FieldName<Schema>; | ||
| context?: Form; | ||
| }): Array<FieldMetadata<Item<Schema>>>; | ||
| export declare function useField<Schema>(options: { | ||
| formId: string; | ||
| name: FieldName<Schema>; | ||
| context?: Form; | ||
| }): FieldMetadata<Schema>; | ||
| }): FormMetadata<Schema, Error>; | ||
| export declare function useField<FormSchema extends Record<string, unknown>, FieldSchema = FormSchema, Error = unknown>(options: { | ||
| formId: FormId<FormSchema, Error>; | ||
| name: FieldName<FieldSchema>; | ||
| } | { | ||
| formId: FormId<FormSchema, Error>; | ||
| name?: undefined; | ||
| }): { | ||
| meta: FieldMetadata<FieldSchema, Error, FormSchema>; | ||
| fields: FieldMetadata<FieldSchema, Error, FormSchema>['getFieldset'] extends Function ? ReturnType<FieldMetadata<FieldSchema, Error, FormSchema>['getFieldset']> : never; | ||
| list: FieldMetadata<FieldSchema, Error, FormSchema>['getFieldList'] extends Function ? ReturnType<FieldMetadata<FieldSchema, Error, FormSchema>['getFieldList']> : never; | ||
| form: FormMetadata<FormSchema, Error>; | ||
| }; |
+53
-109
@@ -18,23 +18,36 @@ 'use strict'; | ||
| } | ||
| function useNoValidate() { | ||
| var defaultNoValidate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; | ||
| var [noValidate, setNoValidate] = react.useState(defaultNoValidate); | ||
| useSafeLayoutEffect(() => { | ||
| // This is necessary to fix an issue in strict mode with related to our proxy setup | ||
| // It avoids the component from being rerendered without re-rendering the child | ||
| // Which reset the proxy but failed to capture its usage within child component | ||
| if (!noValidate) { | ||
| setNoValidate(true); | ||
| } | ||
| }, [noValidate]); | ||
| return noValidate; | ||
| } | ||
| function useForm(options) { | ||
| var formId = useFormId(options.id); | ||
| var initializeForm = () => dom.createForm(formId, options); | ||
| var [form, setForm] = react.useState(initializeForm); | ||
| var initializeContext = () => dom.createForm(formId, options); | ||
| var [form, setForm] = react.useState(initializeContext); | ||
| // If id changes, reinitialize the form immediately | ||
| if (formId !== form.id) { | ||
| setForm(initializeForm); | ||
| setForm(initializeContext); | ||
| } | ||
| var optionsRef = react.useRef(options); | ||
| var metadata = useFormMetadata({ | ||
| formId, | ||
| context: form, | ||
| defaultNoValidate: options.defaultNoValidate | ||
| }); | ||
| var fields = useFieldset({ | ||
| formId, | ||
| context: form | ||
| }); | ||
| useSafeLayoutEffect(() => form.initialize(), [form]); | ||
| useSafeLayoutEffect(() => { | ||
| document.addEventListener('input', form.input); | ||
| document.addEventListener('focusout', form.blur); | ||
| document.addEventListener('reset', form.reset); | ||
| return () => { | ||
| document.removeEventListener('input', form.input); | ||
| document.removeEventListener('focusout', form.blur); | ||
| document.removeEventListener('reset', form.reset); | ||
| }; | ||
| }, [form]); | ||
| useSafeLayoutEffect(() => { | ||
| if (options.lastResult === optionsRef.current.lastResult) { | ||
@@ -55,112 +68,43 @@ // If there is no change, do nothing | ||
| }); | ||
| var subjectRef = context.useSubjectRef(); | ||
| var state = context.useFormState(form, subjectRef); | ||
| var noValidate = useNoValidate(options.defaultNoValidate); | ||
| var meta = context.getFormMetadata(formId, state, subjectRef, form, noValidate); | ||
| return { | ||
| context: form, | ||
| fields, | ||
| form: metadata | ||
| meta, | ||
| fields: meta.getFieldset() | ||
| }; | ||
| } | ||
| function useFormMetadata(options) { | ||
| var _options$defaultNoVal; | ||
| var subjectRef = context.useSubjectRef(); | ||
| var form = context.useFormStore(options.formId, options.context); | ||
| var context$1 = context.useFormContext(form, subjectRef); | ||
| var metadata = context.getBaseMetadata(options.formId, context$1, { | ||
| subjectRef | ||
| }); | ||
| var [noValidate, setNoValidate] = react.useState((_options$defaultNoVal = options.defaultNoValidate) !== null && _options$defaultNoVal !== void 0 ? _options$defaultNoVal : true); | ||
| useSafeLayoutEffect(() => { | ||
| // This is necessary to fix an issue in strict mode with related to our proxy setup | ||
| // It avoids the component from being rerendered without re-rendering the child | ||
| // Which reset the proxy but failed to capture its usage within child component | ||
| if (!noValidate) { | ||
| setNoValidate(true); | ||
| } | ||
| }, [noValidate]); | ||
| return new Proxy(metadata, { | ||
| get(target, key, receiver) { | ||
| switch (key) { | ||
| case 'onSubmit': | ||
| return event => { | ||
| var submitEvent = event.nativeEvent; | ||
| var result = form.submit(submitEvent); | ||
| if (submitEvent.defaultPrevented) { | ||
| event.preventDefault(); | ||
| } | ||
| return result; | ||
| }; | ||
| case 'onReset': | ||
| return event => form.reset(event.nativeEvent); | ||
| case 'noValidate': | ||
| return noValidate; | ||
| } | ||
| return Reflect.get(target, key, receiver); | ||
| } | ||
| }); | ||
| var form = context.useRegistry(options.formId); | ||
| var state = context.useFormState(form, subjectRef); | ||
| var noValidate = useNoValidate(options.defaultNoValidate); | ||
| return context.getFormMetadata(options.formId, state, subjectRef, form, noValidate); | ||
| } | ||
| function useFieldset(options) { | ||
| var subjectRef = context.useSubjectRef(); | ||
| var form = context.useFormStore(options.formId, options.context); | ||
| var context$1 = context.useFormContext(form, subjectRef); | ||
| return new Proxy({}, { | ||
| get(target, prop, receiver) { | ||
| var getMetadata = key => context.getFieldMetadata(options.formId, context$1, { | ||
| name: options.name, | ||
| key: key, | ||
| subjectRef | ||
| }); | ||
| // To support array destructuring | ||
| if (prop === Symbol.iterator) { | ||
| var _index = 0; | ||
| return () => ({ | ||
| next: () => ({ | ||
| value: getMetadata(_index++), | ||
| done: false | ||
| }) | ||
| }); | ||
| } | ||
| var index = Number(prop); | ||
| if (typeof prop === 'string') { | ||
| return getMetadata(Number.isNaN(index) ? prop : index); | ||
| } | ||
| return Reflect.get(target, prop, receiver); | ||
| } | ||
| }); | ||
| } | ||
| function useFieldList(options) { | ||
| var _context$initialValue; | ||
| var subjectRef = context.useSubjectRef({ | ||
| initialValue: { | ||
| name: [options.name] | ||
| } | ||
| }); | ||
| var form = context.useFormStore(options.formId, options.context); | ||
| var context$1 = context.useFormContext(form, subjectRef); | ||
| var initialValue = (_context$initialValue = context$1.initialValue[options.name]) !== null && _context$initialValue !== void 0 ? _context$initialValue : []; | ||
| if (!Array.isArray(initialValue)) { | ||
| throw new Error('The initial value at the given name is not a list'); | ||
| } | ||
| return Array(initialValue.length).fill(0).map((_, index) => context.getFieldMetadata(options.formId, context$1, { | ||
| name: options.name, | ||
| key: index, | ||
| subjectRef | ||
| })); | ||
| } | ||
| function useField(options) { | ||
| var subjectRef = context.useSubjectRef(); | ||
| var form = context.useFormStore(options.formId, options.context); | ||
| var context$1 = context.useFormContext(form, subjectRef); | ||
| var metadata = context.getFieldMetadata(options.formId, context$1, { | ||
| name: options.name, | ||
| subjectRef | ||
| }); | ||
| return metadata; | ||
| var context$1 = context.useRegistry(options.formId); | ||
| var state = context.useFormState(context$1, subjectRef); | ||
| var meta = context.getFieldMetadata(options.formId, state, subjectRef, options.name); | ||
| var form = context.getFormMetadata(options.formId, state, subjectRef, context$1, false); | ||
| return { | ||
| meta, | ||
| // @ts-expect-error The types is used as a hint only | ||
| get fields() { | ||
| return meta.getFieldset(); | ||
| }, | ||
| // @ts-expect-error The types is used as a hint only | ||
| get list() { | ||
| return meta.getFieldList(); | ||
| }, | ||
| form | ||
| }; | ||
| } | ||
| exports.useField = useField; | ||
| exports.useFieldList = useFieldList; | ||
| exports.useFieldset = useFieldset; | ||
| exports.useForm = useForm; | ||
| exports.useFormId = useFormId; | ||
| exports.useFormMetadata = useFormMetadata; | ||
| exports.useNoValidate = useNoValidate; | ||
| exports.useSafeLayoutEffect = useSafeLayoutEffect; |
+54
-109
| import { createForm } from '@conform-to/dom'; | ||
| import { useState, useRef, useEffect, useLayoutEffect, useId } from 'react'; | ||
| import { useSubjectRef, useFormStore, useFormContext, getBaseMetadata, getFieldMetadata } from './context.mjs'; | ||
| import { useSubjectRef, useFormState, getFormMetadata, useRegistry, getFieldMetadata } from './context.mjs'; | ||
@@ -14,23 +14,36 @@ /** | ||
| } | ||
| function useNoValidate() { | ||
| var defaultNoValidate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; | ||
| var [noValidate, setNoValidate] = useState(defaultNoValidate); | ||
| useSafeLayoutEffect(() => { | ||
| // This is necessary to fix an issue in strict mode with related to our proxy setup | ||
| // It avoids the component from being rerendered without re-rendering the child | ||
| // Which reset the proxy but failed to capture its usage within child component | ||
| if (!noValidate) { | ||
| setNoValidate(true); | ||
| } | ||
| }, [noValidate]); | ||
| return noValidate; | ||
| } | ||
| function useForm(options) { | ||
| var formId = useFormId(options.id); | ||
| var initializeForm = () => createForm(formId, options); | ||
| var [form, setForm] = useState(initializeForm); | ||
| var initializeContext = () => createForm(formId, options); | ||
| var [form, setForm] = useState(initializeContext); | ||
| // If id changes, reinitialize the form immediately | ||
| if (formId !== form.id) { | ||
| setForm(initializeForm); | ||
| setForm(initializeContext); | ||
| } | ||
| var optionsRef = useRef(options); | ||
| var metadata = useFormMetadata({ | ||
| formId, | ||
| context: form, | ||
| defaultNoValidate: options.defaultNoValidate | ||
| }); | ||
| var fields = useFieldset({ | ||
| formId, | ||
| context: form | ||
| }); | ||
| useSafeLayoutEffect(() => form.initialize(), [form]); | ||
| useSafeLayoutEffect(() => { | ||
| document.addEventListener('input', form.input); | ||
| document.addEventListener('focusout', form.blur); | ||
| document.addEventListener('reset', form.reset); | ||
| return () => { | ||
| document.removeEventListener('input', form.input); | ||
| document.removeEventListener('focusout', form.blur); | ||
| document.removeEventListener('reset', form.reset); | ||
| }; | ||
| }, [form]); | ||
| useSafeLayoutEffect(() => { | ||
| if (options.lastResult === optionsRef.current.lastResult) { | ||
@@ -51,106 +64,38 @@ // If there is no change, do nothing | ||
| }); | ||
| var subjectRef = useSubjectRef(); | ||
| var state = useFormState(form, subjectRef); | ||
| var noValidate = useNoValidate(options.defaultNoValidate); | ||
| var meta = getFormMetadata(formId, state, subjectRef, form, noValidate); | ||
| return { | ||
| context: form, | ||
| fields, | ||
| form: metadata | ||
| meta, | ||
| fields: meta.getFieldset() | ||
| }; | ||
| } | ||
| function useFormMetadata(options) { | ||
| var _options$defaultNoVal; | ||
| var subjectRef = useSubjectRef(); | ||
| var form = useFormStore(options.formId, options.context); | ||
| var context = useFormContext(form, subjectRef); | ||
| var metadata = getBaseMetadata(options.formId, context, { | ||
| subjectRef | ||
| }); | ||
| var [noValidate, setNoValidate] = useState((_options$defaultNoVal = options.defaultNoValidate) !== null && _options$defaultNoVal !== void 0 ? _options$defaultNoVal : true); | ||
| useSafeLayoutEffect(() => { | ||
| // This is necessary to fix an issue in strict mode with related to our proxy setup | ||
| // It avoids the component from being rerendered without re-rendering the child | ||
| // Which reset the proxy but failed to capture its usage within child component | ||
| if (!noValidate) { | ||
| setNoValidate(true); | ||
| } | ||
| }, [noValidate]); | ||
| return new Proxy(metadata, { | ||
| get(target, key, receiver) { | ||
| switch (key) { | ||
| case 'onSubmit': | ||
| return event => { | ||
| var submitEvent = event.nativeEvent; | ||
| var result = form.submit(submitEvent); | ||
| if (submitEvent.defaultPrevented) { | ||
| event.preventDefault(); | ||
| } | ||
| return result; | ||
| }; | ||
| case 'onReset': | ||
| return event => form.reset(event.nativeEvent); | ||
| case 'noValidate': | ||
| return noValidate; | ||
| } | ||
| return Reflect.get(target, key, receiver); | ||
| } | ||
| }); | ||
| var form = useRegistry(options.formId); | ||
| var state = useFormState(form, subjectRef); | ||
| var noValidate = useNoValidate(options.defaultNoValidate); | ||
| return getFormMetadata(options.formId, state, subjectRef, form, noValidate); | ||
| } | ||
| function useFieldset(options) { | ||
| var subjectRef = useSubjectRef(); | ||
| var form = useFormStore(options.formId, options.context); | ||
| var context = useFormContext(form, subjectRef); | ||
| return new Proxy({}, { | ||
| get(target, prop, receiver) { | ||
| var getMetadata = key => getFieldMetadata(options.formId, context, { | ||
| name: options.name, | ||
| key: key, | ||
| subjectRef | ||
| }); | ||
| // To support array destructuring | ||
| if (prop === Symbol.iterator) { | ||
| var _index = 0; | ||
| return () => ({ | ||
| next: () => ({ | ||
| value: getMetadata(_index++), | ||
| done: false | ||
| }) | ||
| }); | ||
| } | ||
| var index = Number(prop); | ||
| if (typeof prop === 'string') { | ||
| return getMetadata(Number.isNaN(index) ? prop : index); | ||
| } | ||
| return Reflect.get(target, prop, receiver); | ||
| } | ||
| }); | ||
| } | ||
| function useFieldList(options) { | ||
| var _context$initialValue; | ||
| var subjectRef = useSubjectRef({ | ||
| initialValue: { | ||
| name: [options.name] | ||
| } | ||
| }); | ||
| var form = useFormStore(options.formId, options.context); | ||
| var context = useFormContext(form, subjectRef); | ||
| var initialValue = (_context$initialValue = context.initialValue[options.name]) !== null && _context$initialValue !== void 0 ? _context$initialValue : []; | ||
| if (!Array.isArray(initialValue)) { | ||
| throw new Error('The initial value at the given name is not a list'); | ||
| } | ||
| return Array(initialValue.length).fill(0).map((_, index) => getFieldMetadata(options.formId, context, { | ||
| name: options.name, | ||
| key: index, | ||
| subjectRef | ||
| })); | ||
| } | ||
| function useField(options) { | ||
| var subjectRef = useSubjectRef(); | ||
| var form = useFormStore(options.formId, options.context); | ||
| var context = useFormContext(form, subjectRef); | ||
| var metadata = getFieldMetadata(options.formId, context, { | ||
| name: options.name, | ||
| subjectRef | ||
| }); | ||
| return metadata; | ||
| var context = useRegistry(options.formId); | ||
| var state = useFormState(context, subjectRef); | ||
| var meta = getFieldMetadata(options.formId, state, subjectRef, options.name); | ||
| var form = getFormMetadata(options.formId, state, subjectRef, context, false); | ||
| return { | ||
| meta, | ||
| // @ts-expect-error The types is used as a hint only | ||
| get fields() { | ||
| return meta.getFieldset(); | ||
| }, | ||
| // @ts-expect-error The types is used as a hint only | ||
| get list() { | ||
| return meta.getFieldList(); | ||
| }, | ||
| form | ||
| }; | ||
| } | ||
| export { useField, useFieldList, useFieldset, useForm, useFormId, useFormMetadata, useSafeLayoutEffect }; | ||
| export { useField, useForm, useFormId, useFormMetadata, useNoValidate, useSafeLayoutEffect }; |
+6
-6
@@ -1,6 +0,6 @@ | ||
| export { type Submission, type FieldName, requestIntent, isFieldElement, } from '@conform-to/dom'; | ||
| export { type Field, type FieldMetadata as FieldConfig, FormProvider, FormStateInput, } from './context'; | ||
| export { useForm, useFormMetadata, useFieldset, useFieldList, useField, } from './hooks'; | ||
| export { useInputEvent } from './integrations'; | ||
| export * as conform from './helpers'; | ||
| export * as intent from './intent'; | ||
| export { type Submission, type SubmissionResult, type Intent, type FormId, type FieldName, requestIntent, requestSubmit, isFieldElement, intent, } from '@conform-to/dom'; | ||
| export { type FieldProps, type FieldMetadata, type FormMetadata, FormProvider, FormStateInput, } from './context'; | ||
| export { useForm, useFormMetadata, useField } from './hooks'; | ||
| export { useInputControl } from './integrations'; | ||
| export { validateConstraint } from './validitystate'; | ||
| export { getFormProps, getFieldsetProps, getInputProps, getSelectProps, getTextareaProps, getCollectionProps, getControlButtonProps, } from './helpers'; |
+18
-6
@@ -9,7 +9,11 @@ 'use strict'; | ||
| var integrations = require('./integrations.js'); | ||
| var validitystate = require('./validitystate.js'); | ||
| var helpers = require('./helpers.js'); | ||
| var intent = require('./intent.js'); | ||
| Object.defineProperty(exports, 'intent', { | ||
| enumerable: true, | ||
| get: function () { return dom.intent; } | ||
| }); | ||
| Object.defineProperty(exports, 'isFieldElement', { | ||
@@ -23,11 +27,19 @@ enumerable: true, | ||
| }); | ||
| Object.defineProperty(exports, 'requestSubmit', { | ||
| enumerable: true, | ||
| get: function () { return dom.requestSubmit; } | ||
| }); | ||
| exports.FormProvider = context.FormProvider; | ||
| exports.FormStateInput = context.FormStateInput; | ||
| exports.useField = hooks.useField; | ||
| exports.useFieldList = hooks.useFieldList; | ||
| exports.useFieldset = hooks.useFieldset; | ||
| exports.useForm = hooks.useForm; | ||
| exports.useFormMetadata = hooks.useFormMetadata; | ||
| exports.useInputEvent = integrations.useInputEvent; | ||
| exports.conform = helpers; | ||
| exports.intent = intent; | ||
| exports.useInputControl = integrations.useInputControl; | ||
| exports.validateConstraint = validitystate.validateConstraint; | ||
| exports.getCollectionProps = helpers.getCollectionProps; | ||
| exports.getControlButtonProps = helpers.getControlButtonProps; | ||
| exports.getFieldsetProps = helpers.getFieldsetProps; | ||
| exports.getFormProps = helpers.getFormProps; | ||
| exports.getInputProps = helpers.getInputProps; | ||
| exports.getSelectProps = helpers.getSelectProps; | ||
| exports.getTextareaProps = helpers.getTextareaProps; |
+5
-7
@@ -1,8 +0,6 @@ | ||
| export { isFieldElement, requestIntent } from '@conform-to/dom'; | ||
| export { intent, isFieldElement, requestIntent, requestSubmit } from '@conform-to/dom'; | ||
| export { FormProvider, FormStateInput } from './context.mjs'; | ||
| export { useField, useFieldList, useFieldset, useForm, useFormMetadata } from './hooks.mjs'; | ||
| export { useInputEvent } from './integrations.mjs'; | ||
| import * as helpers from './helpers.mjs'; | ||
| export { helpers as conform }; | ||
| import * as intent from './intent.mjs'; | ||
| export { intent }; | ||
| export { useField, useForm, useFormMetadata } from './hooks.mjs'; | ||
| export { useInputControl } from './integrations.mjs'; | ||
| export { validateConstraint } from './validitystate.mjs'; | ||
| export { getCollectionProps, getControlButtonProps, getFieldsetProps, getFormProps, getInputProps, getSelectProps, getTextareaProps } from './helpers.mjs'; |
+15
-20
@@ -1,23 +0,18 @@ | ||
| import { type FieldElement } from '@conform-to/dom'; | ||
| import { type RefObject } from 'react'; | ||
| export type InputControl = { | ||
| change: (eventOrValue: { | ||
| target: { | ||
| value: string; | ||
| }; | ||
| } | string | boolean) => void; | ||
| import { type FieldElement, type FormValue } from '@conform-to/dom'; | ||
| import { type FieldMetadata } from './context'; | ||
| export type InputControl<Value> = { | ||
| value: Value; | ||
| change: (value: Value) => void; | ||
| focus: () => void; | ||
| blur: () => void; | ||
| }; | ||
| /** | ||
| * Returns a ref object and a set of helpers that dispatch corresponding dom event. | ||
| * | ||
| * @see https://conform.guide/api/react#useinputevent | ||
| */ | ||
| export declare function useInputEvent(options: { | ||
| ref: RefObject<FieldElement> | (() => Element | RadioNodeList | FieldElement | null | undefined); | ||
| onInput?: (event: Event) => void; | ||
| onFocus?: (event: FocusEvent) => void; | ||
| onBlur?: (event: FocusEvent) => void; | ||
| onReset?: (event: Event) => void; | ||
| }): InputControl; | ||
| export declare function getFieldElement(formId: string, name: string, match?: (element: FieldElement) => boolean): FieldElement | null; | ||
| export declare function getEventTarget(formId: string, name: string): FieldElement; | ||
| export declare function useInputControl<Schema>(metadata: FieldMetadata<Schema, any, any>, options?: { | ||
| onFocus?: (event: Event) => void; | ||
| }): InputControl<string | undefined>; | ||
| export declare function useInputControl<Schema, Value>(metadata: FieldMetadata<Schema, any, any>, options: { | ||
| initialize: (value: FormValue<Schema> | undefined) => Value; | ||
| serialize?: (value: Value) => string; | ||
| onFocus?: (event: Event) => void; | ||
| }): InputControl<Value>; |
+105
-89
@@ -5,86 +5,90 @@ 'use strict'; | ||
| var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js'); | ||
| var dom = require('@conform-to/dom'); | ||
| var react = require('react'); | ||
| var hooks = require('./hooks.js'); | ||
| /** | ||
| * Returns a ref object and a set of helpers that dispatch corresponding dom event. | ||
| * | ||
| * @see https://conform.guide/api/react#useinputevent | ||
| */ | ||
| function useInputEvent(options) { | ||
| var optionsRef = react.useRef(options); | ||
| function getFieldElement(formId, name) { | ||
| var _document$forms$named; | ||
| var match = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : () => true; | ||
| var element = (_document$forms$named = document.forms.namedItem(formId)) === null || _document$forms$named === void 0 ? void 0 : _document$forms$named.elements.namedItem(name); | ||
| if (element) { | ||
| var items = element instanceof Element ? [element] : Array.from(element.values()); | ||
| for (var item of items) { | ||
| if (dom.isFieldElement(item) && match(item)) { | ||
| return item; | ||
| } | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| function getEventTarget(formId, name) { | ||
| var element = getFieldElement(formId, name); | ||
| if (element) { | ||
| return element; | ||
| } | ||
| var form = document.forms.namedItem(formId); | ||
| var input = document.createElement('input'); | ||
| input.type = 'hidden'; | ||
| input.name = name; | ||
| form === null || form === void 0 ? void 0 : form.appendChild(input); | ||
| return input; | ||
| } | ||
| function useInputControl(metadata, options) { | ||
| var _options$initialize; | ||
| var eventDispatched = react.useRef({ | ||
| onInput: false, | ||
| onFocus: false, | ||
| onBlur: false | ||
| change: false, | ||
| focus: false, | ||
| blur: false | ||
| }); | ||
| hooks.useSafeLayoutEffect(() => { | ||
| var [key, setKey] = react.useState(metadata.key); | ||
| var optionsRef = react.useRef(options); | ||
| var initialize = (_options$initialize = options === null || options === void 0 ? void 0 : options.initialize) !== null && _options$initialize !== void 0 ? _options$initialize : value => value === null || value === void 0 ? void 0 : value.toString(); | ||
| var [value, setValue] = react.useState(() => initialize(metadata.initialValue)); | ||
| if (key !== metadata.key) { | ||
| setValue(initialize(metadata.initialValue)); | ||
| setKey(metadata.key); | ||
| } | ||
| react.useEffect(() => { | ||
| optionsRef.current = options; | ||
| }); | ||
| hooks.useSafeLayoutEffect(() => { | ||
| react.useEffect(() => { | ||
| var createEventListener = listener => { | ||
| return event => { | ||
| var _optionsRef$current, _optionsRef$current2, _optionsRef$current3; | ||
| var element = typeof ((_optionsRef$current = optionsRef.current) === null || _optionsRef$current === void 0 ? void 0 : _optionsRef$current.ref) === 'function' ? (_optionsRef$current2 = optionsRef.current) === null || _optionsRef$current2 === void 0 ? void 0 : _optionsRef$current2.ref() : (_optionsRef$current3 = optionsRef.current) === null || _optionsRef$current3 === void 0 ? void 0 : _optionsRef$current3.ref.current; | ||
| if (dom.isFieldElement(element) && (listener === 'onReset' ? event.target === element.form : event.target === element)) { | ||
| var _optionsRef$current4, _optionsRef$current4$; | ||
| if (listener !== 'onReset') { | ||
| eventDispatched.current[listener] = true; | ||
| var element = getFieldElement(metadata.formId, metadata.name, element => element === event.target); | ||
| if (element) { | ||
| if (listener === 'focus') { | ||
| var _optionsRef$current, _optionsRef$current$o; | ||
| (_optionsRef$current = optionsRef.current) === null || _optionsRef$current === void 0 || (_optionsRef$current$o = _optionsRef$current.onFocus) === null || _optionsRef$current$o === void 0 ? void 0 : _optionsRef$current$o.call(_optionsRef$current, event); | ||
| } | ||
| (_optionsRef$current4 = optionsRef.current) === null || _optionsRef$current4 === void 0 || (_optionsRef$current4$ = _optionsRef$current4[listener]) === null || _optionsRef$current4$ === void 0 ? void 0 : _optionsRef$current4$.call(_optionsRef$current4, event); | ||
| eventDispatched.current[listener] = true; | ||
| } | ||
| }; | ||
| }; | ||
| var inputHandler = createEventListener('onInput'); | ||
| var focusHandler = createEventListener('onFocus'); | ||
| var blurHandler = createEventListener('onBlur'); | ||
| var resetHandler = createEventListener('onReset'); | ||
| // focus/blur event does not bubble | ||
| var inputHandler = createEventListener('change'); | ||
| var focusHandler = createEventListener('focus'); | ||
| var blurHandler = createEventListener('blur'); | ||
| document.addEventListener('input', inputHandler, true); | ||
| document.addEventListener('focus', focusHandler, true); | ||
| document.addEventListener('blur', blurHandler, true); | ||
| document.addEventListener('reset', resetHandler); | ||
| document.addEventListener('focusin', focusHandler, true); | ||
| document.addEventListener('focusout', blurHandler, true); | ||
| return () => { | ||
| document.removeEventListener('input', inputHandler, true); | ||
| document.removeEventListener('focus', focusHandler, true); | ||
| document.removeEventListener('blur', blurHandler, true); | ||
| document.removeEventListener('reset', resetHandler); | ||
| document.removeEventListener('focusin', focusHandler, true); | ||
| document.removeEventListener('focusout', blurHandler, true); | ||
| }; | ||
| }, []); | ||
| var control = react.useMemo(() => { | ||
| var dispatch = (listener, fn) => { | ||
| if (!eventDispatched.current[listener]) { | ||
| var _optionsRef$current5, _optionsRef$current6, _optionsRef$current7; | ||
| var _element = typeof ((_optionsRef$current5 = optionsRef.current) === null || _optionsRef$current5 === void 0 ? void 0 : _optionsRef$current5.ref) === 'function' ? (_optionsRef$current6 = optionsRef.current) === null || _optionsRef$current6 === void 0 ? void 0 : _optionsRef$current6.ref() : (_optionsRef$current7 = optionsRef.current) === null || _optionsRef$current7 === void 0 ? void 0 : _optionsRef$current7.ref.current; | ||
| if (!dom.isFieldElement(_element)) { | ||
| // eslint-disable-next-line no-console | ||
| console.warn('Failed to dispatch event; is the input mounted?'); | ||
| return; | ||
| } | ||
| // To avoid recursion | ||
| eventDispatched.current[listener] = true; | ||
| fn(_element); | ||
| } | ||
| eventDispatched.current[listener] = false; | ||
| }; | ||
| }, [metadata.formId, metadata.name]); | ||
| var handlers = react.useMemo(() => { | ||
| return { | ||
| change(eventOrValue) { | ||
| dispatch('onInput', element => { | ||
| if (element instanceof HTMLInputElement && (element.type === 'checkbox' || element.type === 'radio')) { | ||
| if (typeof eventOrValue !== 'boolean') { | ||
| throw new Error('You should pass a boolean when changing a checkbox or radio input'); | ||
| change(value) { | ||
| if (!eventDispatched.current.change) { | ||
| var _ref, _optionsRef$current$s, _optionsRef$current2, _optionsRef$current2$; | ||
| var _element = getEventTarget(metadata.formId, metadata.name); | ||
| var serializedValue = (_ref = (_optionsRef$current$s = (_optionsRef$current2 = optionsRef.current) === null || _optionsRef$current2 === void 0 || (_optionsRef$current2$ = _optionsRef$current2.serialize) === null || _optionsRef$current2$ === void 0 ? void 0 : _optionsRef$current2$.call(_optionsRef$current2, value)) !== null && _optionsRef$current$s !== void 0 ? _optionsRef$current$s : value === null || value === void 0 ? void 0 : value.toString()) !== null && _ref !== void 0 ? _ref : ''; | ||
| eventDispatched.current.change = true; | ||
| if (_element instanceof HTMLInputElement && (_element.type === 'checkbox' || _element.type === 'radio')) { | ||
| if (_element.checked ? _element.value !== serializedValue : _element.value === serializedValue) { | ||
| _element.click(); | ||
| } | ||
| element.checked = eventOrValue; | ||
| } else { | ||
| if (typeof eventOrValue === 'boolean') { | ||
| throw new Error('You can pass a boolean only when changing a checkbox or radio input'); | ||
| } | ||
| var value = typeof eventOrValue === 'string' ? eventOrValue : eventOrValue.target.value; | ||
| // No change event will triggered on React if `element.value` is updated | ||
| // before dispatching the event | ||
| if (element.value !== value) { | ||
| // No change event will be triggered on React if `element.value` is already updated | ||
| if (_element.value !== serializedValue) { | ||
| /** | ||
@@ -98,4 +102,4 @@ * Triggering react custom change event | ||
| set: valueSetter | ||
| } = Object.getOwnPropertyDescriptor(element, 'value') || {}; | ||
| var prototype = Object.getPrototypeOf(element); | ||
| } = Object.getOwnPropertyDescriptor(_element, 'value') || {}; | ||
| var prototype = Object.getPrototypeOf(_element); | ||
| var { | ||
@@ -105,6 +109,6 @@ set: prototypeValueSetter | ||
| if (prototypeValueSetter && valueSetter !== prototypeValueSetter) { | ||
| prototypeValueSetter.call(element, value); | ||
| prototypeValueSetter.call(_element, value); | ||
| } else { | ||
| if (valueSetter) { | ||
| valueSetter.call(element, value); | ||
| valueSetter.call(_element, value); | ||
| } else { | ||
@@ -115,35 +119,47 @@ throw new Error('The given element does not have a value setter'); | ||
| } | ||
| // Dispatch input event with the updated input value | ||
| _element.dispatchEvent(new InputEvent('input', { | ||
| bubbles: true | ||
| })); | ||
| // Dispatch change event (necessary for select to update the selected option) | ||
| _element.dispatchEvent(new Event('change', { | ||
| bubbles: true | ||
| })); | ||
| } | ||
| // Dispatch input event with the updated input value | ||
| element.dispatchEvent(new InputEvent('input', { | ||
| bubbles: true | ||
| })); | ||
| // Dispatch change event (necessary for select to update the selected option) | ||
| element.dispatchEvent(new Event('change', { | ||
| bubbles: true | ||
| })); | ||
| }); | ||
| } | ||
| setValue(value); | ||
| eventDispatched.current.change = false; | ||
| }, | ||
| focus() { | ||
| dispatch('onFocus', element => { | ||
| element.dispatchEvent(new FocusEvent('focusin', { | ||
| if (!eventDispatched.current.focus) { | ||
| var _element2 = getEventTarget(metadata.formId, metadata.name); | ||
| eventDispatched.current.focus = true; | ||
| _element2.dispatchEvent(new FocusEvent('focusin', { | ||
| bubbles: true | ||
| })); | ||
| element.dispatchEvent(new FocusEvent('focus')); | ||
| }); | ||
| _element2.dispatchEvent(new FocusEvent('focus')); | ||
| } | ||
| eventDispatched.current.focus = false; | ||
| }, | ||
| blur() { | ||
| dispatch('onBlur', element => { | ||
| element.dispatchEvent(new FocusEvent('focusout', { | ||
| if (!eventDispatched.current.blur) { | ||
| var _element3 = getEventTarget(metadata.formId, metadata.name); | ||
| eventDispatched.current.blur = true; | ||
| _element3.dispatchEvent(new FocusEvent('focusout', { | ||
| bubbles: true | ||
| })); | ||
| element.dispatchEvent(new FocusEvent('blur')); | ||
| }); | ||
| _element3.dispatchEvent(new FocusEvent('blur')); | ||
| } | ||
| eventDispatched.current.blur = false; | ||
| } | ||
| }; | ||
| }, [optionsRef]); | ||
| return control; | ||
| }, [metadata.formId, metadata.name]); | ||
| return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, handlers), {}, { | ||
| value | ||
| }); | ||
| } | ||
| exports.useInputEvent = useInputEvent; | ||
| exports.getEventTarget = getEventTarget; | ||
| exports.getFieldElement = getFieldElement; | ||
| exports.useInputControl = useInputControl; |
+104
-90
@@ -0,85 +1,89 @@ | ||
| import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs'; | ||
| import { isFieldElement } from '@conform-to/dom'; | ||
| import { useRef, useMemo } from 'react'; | ||
| import { useSafeLayoutEffect } from './hooks.mjs'; | ||
| import { useRef, useState, useEffect, useMemo } from 'react'; | ||
| /** | ||
| * Returns a ref object and a set of helpers that dispatch corresponding dom event. | ||
| * | ||
| * @see https://conform.guide/api/react#useinputevent | ||
| */ | ||
| function useInputEvent(options) { | ||
| var optionsRef = useRef(options); | ||
| function getFieldElement(formId, name) { | ||
| var _document$forms$named; | ||
| var match = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : () => true; | ||
| var element = (_document$forms$named = document.forms.namedItem(formId)) === null || _document$forms$named === void 0 ? void 0 : _document$forms$named.elements.namedItem(name); | ||
| if (element) { | ||
| var items = element instanceof Element ? [element] : Array.from(element.values()); | ||
| for (var item of items) { | ||
| if (isFieldElement(item) && match(item)) { | ||
| return item; | ||
| } | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| function getEventTarget(formId, name) { | ||
| var element = getFieldElement(formId, name); | ||
| if (element) { | ||
| return element; | ||
| } | ||
| var form = document.forms.namedItem(formId); | ||
| var input = document.createElement('input'); | ||
| input.type = 'hidden'; | ||
| input.name = name; | ||
| form === null || form === void 0 ? void 0 : form.appendChild(input); | ||
| return input; | ||
| } | ||
| function useInputControl(metadata, options) { | ||
| var _options$initialize; | ||
| var eventDispatched = useRef({ | ||
| onInput: false, | ||
| onFocus: false, | ||
| onBlur: false | ||
| change: false, | ||
| focus: false, | ||
| blur: false | ||
| }); | ||
| useSafeLayoutEffect(() => { | ||
| var [key, setKey] = useState(metadata.key); | ||
| var optionsRef = useRef(options); | ||
| var initialize = (_options$initialize = options === null || options === void 0 ? void 0 : options.initialize) !== null && _options$initialize !== void 0 ? _options$initialize : value => value === null || value === void 0 ? void 0 : value.toString(); | ||
| var [value, setValue] = useState(() => initialize(metadata.initialValue)); | ||
| if (key !== metadata.key) { | ||
| setValue(initialize(metadata.initialValue)); | ||
| setKey(metadata.key); | ||
| } | ||
| useEffect(() => { | ||
| optionsRef.current = options; | ||
| }); | ||
| useSafeLayoutEffect(() => { | ||
| useEffect(() => { | ||
| var createEventListener = listener => { | ||
| return event => { | ||
| var _optionsRef$current, _optionsRef$current2, _optionsRef$current3; | ||
| var element = typeof ((_optionsRef$current = optionsRef.current) === null || _optionsRef$current === void 0 ? void 0 : _optionsRef$current.ref) === 'function' ? (_optionsRef$current2 = optionsRef.current) === null || _optionsRef$current2 === void 0 ? void 0 : _optionsRef$current2.ref() : (_optionsRef$current3 = optionsRef.current) === null || _optionsRef$current3 === void 0 ? void 0 : _optionsRef$current3.ref.current; | ||
| if (isFieldElement(element) && (listener === 'onReset' ? event.target === element.form : event.target === element)) { | ||
| var _optionsRef$current4, _optionsRef$current4$; | ||
| if (listener !== 'onReset') { | ||
| eventDispatched.current[listener] = true; | ||
| var element = getFieldElement(metadata.formId, metadata.name, element => element === event.target); | ||
| if (element) { | ||
| if (listener === 'focus') { | ||
| var _optionsRef$current, _optionsRef$current$o; | ||
| (_optionsRef$current = optionsRef.current) === null || _optionsRef$current === void 0 || (_optionsRef$current$o = _optionsRef$current.onFocus) === null || _optionsRef$current$o === void 0 ? void 0 : _optionsRef$current$o.call(_optionsRef$current, event); | ||
| } | ||
| (_optionsRef$current4 = optionsRef.current) === null || _optionsRef$current4 === void 0 || (_optionsRef$current4$ = _optionsRef$current4[listener]) === null || _optionsRef$current4$ === void 0 ? void 0 : _optionsRef$current4$.call(_optionsRef$current4, event); | ||
| eventDispatched.current[listener] = true; | ||
| } | ||
| }; | ||
| }; | ||
| var inputHandler = createEventListener('onInput'); | ||
| var focusHandler = createEventListener('onFocus'); | ||
| var blurHandler = createEventListener('onBlur'); | ||
| var resetHandler = createEventListener('onReset'); | ||
| // focus/blur event does not bubble | ||
| var inputHandler = createEventListener('change'); | ||
| var focusHandler = createEventListener('focus'); | ||
| var blurHandler = createEventListener('blur'); | ||
| document.addEventListener('input', inputHandler, true); | ||
| document.addEventListener('focus', focusHandler, true); | ||
| document.addEventListener('blur', blurHandler, true); | ||
| document.addEventListener('reset', resetHandler); | ||
| document.addEventListener('focusin', focusHandler, true); | ||
| document.addEventListener('focusout', blurHandler, true); | ||
| return () => { | ||
| document.removeEventListener('input', inputHandler, true); | ||
| document.removeEventListener('focus', focusHandler, true); | ||
| document.removeEventListener('blur', blurHandler, true); | ||
| document.removeEventListener('reset', resetHandler); | ||
| document.removeEventListener('focusin', focusHandler, true); | ||
| document.removeEventListener('focusout', blurHandler, true); | ||
| }; | ||
| }, []); | ||
| var control = useMemo(() => { | ||
| var dispatch = (listener, fn) => { | ||
| if (!eventDispatched.current[listener]) { | ||
| var _optionsRef$current5, _optionsRef$current6, _optionsRef$current7; | ||
| var _element = typeof ((_optionsRef$current5 = optionsRef.current) === null || _optionsRef$current5 === void 0 ? void 0 : _optionsRef$current5.ref) === 'function' ? (_optionsRef$current6 = optionsRef.current) === null || _optionsRef$current6 === void 0 ? void 0 : _optionsRef$current6.ref() : (_optionsRef$current7 = optionsRef.current) === null || _optionsRef$current7 === void 0 ? void 0 : _optionsRef$current7.ref.current; | ||
| if (!isFieldElement(_element)) { | ||
| // eslint-disable-next-line no-console | ||
| console.warn('Failed to dispatch event; is the input mounted?'); | ||
| return; | ||
| } | ||
| // To avoid recursion | ||
| eventDispatched.current[listener] = true; | ||
| fn(_element); | ||
| } | ||
| eventDispatched.current[listener] = false; | ||
| }; | ||
| }, [metadata.formId, metadata.name]); | ||
| var handlers = useMemo(() => { | ||
| return { | ||
| change(eventOrValue) { | ||
| dispatch('onInput', element => { | ||
| if (element instanceof HTMLInputElement && (element.type === 'checkbox' || element.type === 'radio')) { | ||
| if (typeof eventOrValue !== 'boolean') { | ||
| throw new Error('You should pass a boolean when changing a checkbox or radio input'); | ||
| change(value) { | ||
| if (!eventDispatched.current.change) { | ||
| var _ref, _optionsRef$current$s, _optionsRef$current2, _optionsRef$current2$; | ||
| var _element = getEventTarget(metadata.formId, metadata.name); | ||
| var serializedValue = (_ref = (_optionsRef$current$s = (_optionsRef$current2 = optionsRef.current) === null || _optionsRef$current2 === void 0 || (_optionsRef$current2$ = _optionsRef$current2.serialize) === null || _optionsRef$current2$ === void 0 ? void 0 : _optionsRef$current2$.call(_optionsRef$current2, value)) !== null && _optionsRef$current$s !== void 0 ? _optionsRef$current$s : value === null || value === void 0 ? void 0 : value.toString()) !== null && _ref !== void 0 ? _ref : ''; | ||
| eventDispatched.current.change = true; | ||
| if (_element instanceof HTMLInputElement && (_element.type === 'checkbox' || _element.type === 'radio')) { | ||
| if (_element.checked ? _element.value !== serializedValue : _element.value === serializedValue) { | ||
| _element.click(); | ||
| } | ||
| element.checked = eventOrValue; | ||
| } else { | ||
| if (typeof eventOrValue === 'boolean') { | ||
| throw new Error('You can pass a boolean only when changing a checkbox or radio input'); | ||
| } | ||
| var value = typeof eventOrValue === 'string' ? eventOrValue : eventOrValue.target.value; | ||
| // No change event will triggered on React if `element.value` is updated | ||
| // before dispatching the event | ||
| if (element.value !== value) { | ||
| // No change event will be triggered on React if `element.value` is already updated | ||
| if (_element.value !== serializedValue) { | ||
| /** | ||
@@ -93,4 +97,4 @@ * Triggering react custom change event | ||
| set: valueSetter | ||
| } = Object.getOwnPropertyDescriptor(element, 'value') || {}; | ||
| var prototype = Object.getPrototypeOf(element); | ||
| } = Object.getOwnPropertyDescriptor(_element, 'value') || {}; | ||
| var prototype = Object.getPrototypeOf(_element); | ||
| var { | ||
@@ -100,6 +104,6 @@ set: prototypeValueSetter | ||
| if (prototypeValueSetter && valueSetter !== prototypeValueSetter) { | ||
| prototypeValueSetter.call(element, value); | ||
| prototypeValueSetter.call(_element, value); | ||
| } else { | ||
| if (valueSetter) { | ||
| valueSetter.call(element, value); | ||
| valueSetter.call(_element, value); | ||
| } else { | ||
@@ -110,35 +114,45 @@ throw new Error('The given element does not have a value setter'); | ||
| } | ||
| // Dispatch input event with the updated input value | ||
| _element.dispatchEvent(new InputEvent('input', { | ||
| bubbles: true | ||
| })); | ||
| // Dispatch change event (necessary for select to update the selected option) | ||
| _element.dispatchEvent(new Event('change', { | ||
| bubbles: true | ||
| })); | ||
| } | ||
| // Dispatch input event with the updated input value | ||
| element.dispatchEvent(new InputEvent('input', { | ||
| bubbles: true | ||
| })); | ||
| // Dispatch change event (necessary for select to update the selected option) | ||
| element.dispatchEvent(new Event('change', { | ||
| bubbles: true | ||
| })); | ||
| }); | ||
| } | ||
| setValue(value); | ||
| eventDispatched.current.change = false; | ||
| }, | ||
| focus() { | ||
| dispatch('onFocus', element => { | ||
| element.dispatchEvent(new FocusEvent('focusin', { | ||
| if (!eventDispatched.current.focus) { | ||
| var _element2 = getEventTarget(metadata.formId, metadata.name); | ||
| eventDispatched.current.focus = true; | ||
| _element2.dispatchEvent(new FocusEvent('focusin', { | ||
| bubbles: true | ||
| })); | ||
| element.dispatchEvent(new FocusEvent('focus')); | ||
| }); | ||
| _element2.dispatchEvent(new FocusEvent('focus')); | ||
| } | ||
| eventDispatched.current.focus = false; | ||
| }, | ||
| blur() { | ||
| dispatch('onBlur', element => { | ||
| element.dispatchEvent(new FocusEvent('focusout', { | ||
| if (!eventDispatched.current.blur) { | ||
| var _element3 = getEventTarget(metadata.formId, metadata.name); | ||
| eventDispatched.current.blur = true; | ||
| _element3.dispatchEvent(new FocusEvent('focusout', { | ||
| bubbles: true | ||
| })); | ||
| element.dispatchEvent(new FocusEvent('blur')); | ||
| }); | ||
| _element3.dispatchEvent(new FocusEvent('blur')); | ||
| } | ||
| eventDispatched.current.blur = false; | ||
| } | ||
| }; | ||
| }, [optionsRef]); | ||
| return control; | ||
| }, [metadata.formId, metadata.name]); | ||
| return _objectSpread2(_objectSpread2({}, handlers), {}, { | ||
| value | ||
| }); | ||
| } | ||
| export { useInputEvent }; | ||
| export { getEventTarget, getFieldElement, useInputControl }; |
+2
-2
@@ -6,3 +6,3 @@ { | ||
| "license": "MIT", | ||
| "version": "1.0.0-pre.0", | ||
| "version": "1.0.0-pre.1", | ||
| "main": "index.js", | ||
@@ -34,3 +34,3 @@ "module": "index.mjs", | ||
| "dependencies": { | ||
| "@conform-to/dom": "1.0.0-pre.0" | ||
| "@conform-to/dom": "1.0.0-pre.1" | ||
| }, | ||
@@ -37,0 +37,0 @@ "peerDependencies": { |
-38
| import { type ListIntentPayload } from '@conform-to/dom'; | ||
| import type { Field, Pretty } from './context'; | ||
| declare function createIntentButtonProps(value: string, form?: string): { | ||
| name: string; | ||
| value: string; | ||
| form: string | undefined; | ||
| formNoValidate: boolean; | ||
| }; | ||
| export declare function validate(field: Field<unknown>): { | ||
| name: string; | ||
| value: string; | ||
| form: string | undefined; | ||
| formNoValidate: boolean; | ||
| }; | ||
| type ExtractListIntentPayload<Operation, Schema = unknown> = Pretty<Omit<Extract<ListIntentPayload<Schema>, { | ||
| operation: Operation; | ||
| }>, 'name' | 'operation'>>; | ||
| type ListIntent<Operation> = {} extends ExtractListIntentPayload<Operation> ? <Item>(name: Field<Array<Item>>, payload?: ExtractListIntentPayload<Operation, Item>) => ReturnType<typeof createIntentButtonProps> : <Item>(field: Field<Array<Item>>, payload: ExtractListIntentPayload<Operation, Item>) => ReturnType<typeof createIntentButtonProps>; | ||
| /** | ||
| * Helpers to configure an intent button for modifying a list | ||
| * | ||
| * @see https://conform.guide/api/react#list | ||
| */ | ||
| export declare const list: { | ||
| /** | ||
| * @deprecated You can use `insert` without specifying an index instead | ||
| */ | ||
| append: ListIntent<'append'>; | ||
| /** | ||
| * @deprecated You can use `insert` with zero index instead | ||
| */ | ||
| prepend: ListIntent<'prepend'>; | ||
| insert: ListIntent<'insert'>; | ||
| replace: ListIntent<'replace'>; | ||
| remove: ListIntent<'remove'>; | ||
| reorder: ListIntent<'reorder'>; | ||
| }; | ||
| export {}; |
-37
| 'use strict'; | ||
| Object.defineProperty(exports, '__esModule', { value: true }); | ||
| var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js'); | ||
| var dom = require('@conform-to/dom'); | ||
| function createIntentButtonProps(value, form) { | ||
| return { | ||
| name: dom.INTENT, | ||
| value, | ||
| form, | ||
| formNoValidate: true | ||
| }; | ||
| } | ||
| function validate(field) { | ||
| return createIntentButtonProps(dom.validate.serialize(field.name), field.formId); | ||
| } | ||
| /** | ||
| * Helpers to configure an intent button for modifying a list | ||
| * | ||
| * @see https://conform.guide/api/react#list | ||
| */ | ||
| var list = new Proxy({}, { | ||
| get(_target, operation) { | ||
| return function (field) { | ||
| var payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
| return createIntentButtonProps(dom.list.serialize(_rollupPluginBabelHelpers.objectSpread2({ | ||
| name: field.name, | ||
| operation | ||
| }, payload)), field.formId); | ||
| }; | ||
| } | ||
| }); | ||
| exports.list = list; | ||
| exports.validate = validate; |
-32
| import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs'; | ||
| import { validate as validate$1, list as list$1, INTENT } from '@conform-to/dom'; | ||
| function createIntentButtonProps(value, form) { | ||
| return { | ||
| name: INTENT, | ||
| value, | ||
| form, | ||
| formNoValidate: true | ||
| }; | ||
| } | ||
| function validate(field) { | ||
| return createIntentButtonProps(validate$1.serialize(field.name), field.formId); | ||
| } | ||
| /** | ||
| * Helpers to configure an intent button for modifying a list | ||
| * | ||
| * @see https://conform.guide/api/react#list | ||
| */ | ||
| var list = new Proxy({}, { | ||
| get(_target, operation) { | ||
| return function (field) { | ||
| var payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
| return createIntentButtonProps(list$1.serialize(_objectSpread2({ | ||
| name: field.name, | ||
| operation | ||
| }, payload)), field.formId); | ||
| }; | ||
| } | ||
| }); | ||
| export { list, validate }; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
99635
20.22%1904
18.48%+ Added
- Removed
Updated