@conform-to/react 0.9.0 → 1.0.0-pre.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/context.d.ts +56 -0
- package/context.js +154 -0
- package/context.mjs +143 -0
- package/helpers.d.ts +41 -29
- package/helpers.js +78 -67
- package/helpers.mjs +78 -56
- package/hooks.d.ts +45 -199
- package/hooks.js +125 -701
- package/hooks.mjs +124 -698
- package/index.d.ts +6 -3
- package/index.js +9 -14
- package/index.mjs +6 -2
- package/integrations.d.ts +23 -0
- package/integrations.js +145 -0
- package/integrations.mjs +141 -0
- package/intent.d.ts +38 -0
- package/intent.js +37 -0
- package/intent.mjs +32 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -350,7 +350,7 @@ function Example() {
|
|
|
350
350
|
form={title.form}
|
|
351
351
|
defaultValue={title.defaultValue}
|
|
352
352
|
autoFocus={title.initialError ? true : undefined}
|
|
353
|
-
|
|
353
|
+
required={title.required}
|
|
354
354
|
minLength={title.minLength}
|
|
355
355
|
maxLength={title.maxLength}
|
|
356
356
|
min={title.min}
|
package/context.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type Constraint, type FieldName, type Form, type FormValue, type FormContext, type SubscriptionSubject } from '@conform-to/dom';
|
|
2
|
+
import { type ReactElement, type ReactNode, type MutableRefObject } from 'react';
|
|
3
|
+
export type Pretty<T> = {
|
|
4
|
+
[K in keyof T]: T[K];
|
|
5
|
+
} & {};
|
|
6
|
+
export type BaseMetadata<Schema> = {
|
|
7
|
+
key?: string;
|
|
8
|
+
id: string;
|
|
9
|
+
errorId: string;
|
|
10
|
+
descriptionId: string;
|
|
11
|
+
initialValue: FormValue<Schema>;
|
|
12
|
+
value: FormValue<Schema>;
|
|
13
|
+
errors: string[] | undefined;
|
|
14
|
+
allErrors: Record<string, string[]>;
|
|
15
|
+
allValid: boolean;
|
|
16
|
+
valid: boolean;
|
|
17
|
+
dirty: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type Field<Schema> = {
|
|
20
|
+
name: FieldName<Schema>;
|
|
21
|
+
formId: string;
|
|
22
|
+
};
|
|
23
|
+
export type FormMetadata<Schema extends Record<string, any>> = BaseMetadata<Schema> & {
|
|
24
|
+
onSubmit: (event: React.FormEvent<HTMLFormElement>) => ReturnType<Form<Schema>['submit']>;
|
|
25
|
+
onReset: (event: React.FormEvent<HTMLFormElement>) => void;
|
|
26
|
+
noValidate: boolean;
|
|
27
|
+
};
|
|
28
|
+
export type FieldMetadata<Schema> = BaseMetadata<Schema> & {
|
|
29
|
+
formId: string;
|
|
30
|
+
name: FieldName<Schema>;
|
|
31
|
+
constraint?: Constraint;
|
|
32
|
+
};
|
|
33
|
+
export declare const Registry: import("react").Context<Record<string, Form>>;
|
|
34
|
+
export declare function useFormStore(formId: string, context?: Form): Form;
|
|
35
|
+
export declare function useFormContext(form: Form, subjectRef?: MutableRefObject<SubscriptionSubject>): FormContext;
|
|
36
|
+
export declare function FormProvider(props: {
|
|
37
|
+
context: Form;
|
|
38
|
+
children: ReactNode;
|
|
39
|
+
}): ReactElement;
|
|
40
|
+
export declare function FormStateInput(props: {
|
|
41
|
+
formId: string;
|
|
42
|
+
context?: undefined;
|
|
43
|
+
} | {
|
|
44
|
+
formId?: undefined;
|
|
45
|
+
context: Form;
|
|
46
|
+
}): React.ReactElement;
|
|
47
|
+
export declare function useSubjectRef(initialSubject?: SubscriptionSubject): MutableRefObject<SubscriptionSubject>;
|
|
48
|
+
export declare function getBaseMetadata<Schema>(formId: string, context: FormContext, options: {
|
|
49
|
+
name?: string;
|
|
50
|
+
subjectRef: MutableRefObject<SubscriptionSubject>;
|
|
51
|
+
}): BaseMetadata<Schema>;
|
|
52
|
+
export declare function getFieldMetadata<Schema>(formId: string, context: FormContext, options: {
|
|
53
|
+
name?: string;
|
|
54
|
+
key?: string | number;
|
|
55
|
+
subjectRef: MutableRefObject<SubscriptionSubject>;
|
|
56
|
+
}): FieldMetadata<Schema>;
|
package/context.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
|
|
6
|
+
var dom = require('@conform-to/dom');
|
|
7
|
+
var react = require('react');
|
|
8
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
+
|
|
10
|
+
var Registry = /*#__PURE__*/react.createContext({});
|
|
11
|
+
function useFormStore(formId, context) {
|
|
12
|
+
var registry = react.useContext(Registry);
|
|
13
|
+
var form = context !== null && context !== void 0 ? context : registry[formId];
|
|
14
|
+
if (!form) {
|
|
15
|
+
throw new Error('Form context is not available');
|
|
16
|
+
}
|
|
17
|
+
return form;
|
|
18
|
+
}
|
|
19
|
+
function useFormContext(form, subjectRef) {
|
|
20
|
+
var subscribe = react.useCallback(callback => form.subscribe(callback, () => subjectRef === null || subjectRef === void 0 ? void 0 : subjectRef.current), [form, subjectRef]);
|
|
21
|
+
var result = react.useSyncExternalStore(subscribe, form.getContext, form.getContext);
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
function FormProvider(props) {
|
|
25
|
+
var registry = react.useContext(Registry);
|
|
26
|
+
var value = react.useMemo(() => _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, registry), {}, {
|
|
27
|
+
[props.context.id]: props.context
|
|
28
|
+
}), [registry, props.context]);
|
|
29
|
+
return /*#__PURE__*/jsxRuntime.jsx(Registry.Provider, {
|
|
30
|
+
value: value,
|
|
31
|
+
children: props.children
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function FormStateInput(props) {
|
|
35
|
+
var _props$formId;
|
|
36
|
+
var form = useFormStore((_props$formId = props.formId) !== null && _props$formId !== void 0 ? _props$formId : props.context.id, props.context);
|
|
37
|
+
return /*#__PURE__*/jsxRuntime.jsx("input", {
|
|
38
|
+
type: "hidden",
|
|
39
|
+
name: dom.STATE,
|
|
40
|
+
value: form.getSerializedState(),
|
|
41
|
+
form: props.formId
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function useSubjectRef() {
|
|
45
|
+
var initialSubject = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
46
|
+
var subjectRef = react.useRef(initialSubject);
|
|
47
|
+
|
|
48
|
+
// Reset the subject everytime the component is rerendered
|
|
49
|
+
// This let us subscribe to data used in the last render only
|
|
50
|
+
subjectRef.current = initialSubject;
|
|
51
|
+
return subjectRef;
|
|
52
|
+
}
|
|
53
|
+
function getBaseMetadata(formId, context, options) {
|
|
54
|
+
var _options$name;
|
|
55
|
+
var name = (_options$name = options.name) !== null && _options$name !== void 0 ? _options$name : '';
|
|
56
|
+
var id = name ? "".concat(formId, "-").concat(name) : formId;
|
|
57
|
+
var updateSubject = (subject, scope) => {
|
|
58
|
+
var _options$subjectRef$c, _options$subjectRef$c2;
|
|
59
|
+
options.subjectRef.current[subject] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options.subjectRef.current[subject]), {}, {
|
|
60
|
+
[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)
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
return new Proxy({
|
|
64
|
+
id,
|
|
65
|
+
errorId: "".concat(id, "-error"),
|
|
66
|
+
descriptionId: "".concat(id, "-description"),
|
|
67
|
+
initialValue: context.initialValue[name],
|
|
68
|
+
value: context.value[name],
|
|
69
|
+
errors: context.error[name],
|
|
70
|
+
get key() {
|
|
71
|
+
return context.state.key[name];
|
|
72
|
+
},
|
|
73
|
+
get valid() {
|
|
74
|
+
return context.state.valid[name];
|
|
75
|
+
},
|
|
76
|
+
get dirty() {
|
|
77
|
+
return context.state.dirty[name];
|
|
78
|
+
},
|
|
79
|
+
get allValid() {
|
|
80
|
+
var keys = Object.keys(context.error);
|
|
81
|
+
if (name === '') {
|
|
82
|
+
return keys.length === 0;
|
|
83
|
+
}
|
|
84
|
+
for (var key of Object.keys(context.error)) {
|
|
85
|
+
if (dom.isPrefix(key, name) && !context.state.valid[key]) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
},
|
|
91
|
+
get allErrors() {
|
|
92
|
+
if (name === '') {
|
|
93
|
+
return context.error;
|
|
94
|
+
}
|
|
95
|
+
var result = {};
|
|
96
|
+
for (var [key, errors] of Object.entries(context.error)) {
|
|
97
|
+
if (dom.isPrefix(key, name)) {
|
|
98
|
+
result[key] = errors;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
}, {
|
|
104
|
+
get(target, key, receiver) {
|
|
105
|
+
switch (key) {
|
|
106
|
+
case 'key':
|
|
107
|
+
case 'errors':
|
|
108
|
+
case 'initialValue':
|
|
109
|
+
case 'value':
|
|
110
|
+
case 'valid':
|
|
111
|
+
case 'dirty':
|
|
112
|
+
updateSubject(key === 'errors' ? 'error' : key, 'name');
|
|
113
|
+
break;
|
|
114
|
+
case 'allErrors':
|
|
115
|
+
updateSubject('error', 'prefix');
|
|
116
|
+
break;
|
|
117
|
+
case 'allValid':
|
|
118
|
+
updateSubject('valid', 'prefix');
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
return Reflect.get(target, key, receiver);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function getFieldMetadata(formId, context, options) {
|
|
126
|
+
var _options$name2, _options$name3;
|
|
127
|
+
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 : '';
|
|
128
|
+
var metadata = getBaseMetadata(formId, context, {
|
|
129
|
+
subjectRef: options.subjectRef,
|
|
130
|
+
name
|
|
131
|
+
});
|
|
132
|
+
return new Proxy(metadata, {
|
|
133
|
+
get(target, key, receiver) {
|
|
134
|
+
switch (key) {
|
|
135
|
+
case 'formId':
|
|
136
|
+
return formId;
|
|
137
|
+
case 'name':
|
|
138
|
+
return name;
|
|
139
|
+
case 'constraint':
|
|
140
|
+
return context.constraint[name];
|
|
141
|
+
}
|
|
142
|
+
return Reflect.get(target, key, receiver);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
exports.FormProvider = FormProvider;
|
|
148
|
+
exports.FormStateInput = FormStateInput;
|
|
149
|
+
exports.Registry = Registry;
|
|
150
|
+
exports.getBaseMetadata = getBaseMetadata;
|
|
151
|
+
exports.getFieldMetadata = getFieldMetadata;
|
|
152
|
+
exports.useFormContext = useFormContext;
|
|
153
|
+
exports.useFormStore = useFormStore;
|
|
154
|
+
exports.useSubjectRef = useSubjectRef;
|
package/context.mjs
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
|
|
2
|
+
import { STATE, isPrefix, formatPaths, getPaths } from '@conform-to/dom';
|
|
3
|
+
import { useContext, useMemo, createContext, useCallback, useSyncExternalStore, useRef } from 'react';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var Registry = /*#__PURE__*/createContext({});
|
|
7
|
+
function useFormStore(formId, context) {
|
|
8
|
+
var registry = useContext(Registry);
|
|
9
|
+
var form = context !== null && context !== void 0 ? context : registry[formId];
|
|
10
|
+
if (!form) {
|
|
11
|
+
throw new Error('Form context is not available');
|
|
12
|
+
}
|
|
13
|
+
return form;
|
|
14
|
+
}
|
|
15
|
+
function useFormContext(form, subjectRef) {
|
|
16
|
+
var subscribe = useCallback(callback => form.subscribe(callback, () => subjectRef === null || subjectRef === void 0 ? void 0 : subjectRef.current), [form, subjectRef]);
|
|
17
|
+
var result = useSyncExternalStore(subscribe, form.getContext, form.getContext);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
function FormProvider(props) {
|
|
21
|
+
var registry = useContext(Registry);
|
|
22
|
+
var value = useMemo(() => _objectSpread2(_objectSpread2({}, registry), {}, {
|
|
23
|
+
[props.context.id]: props.context
|
|
24
|
+
}), [registry, props.context]);
|
|
25
|
+
return /*#__PURE__*/jsx(Registry.Provider, {
|
|
26
|
+
value: value,
|
|
27
|
+
children: props.children
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function FormStateInput(props) {
|
|
31
|
+
var _props$formId;
|
|
32
|
+
var form = useFormStore((_props$formId = props.formId) !== null && _props$formId !== void 0 ? _props$formId : props.context.id, props.context);
|
|
33
|
+
return /*#__PURE__*/jsx("input", {
|
|
34
|
+
type: "hidden",
|
|
35
|
+
name: STATE,
|
|
36
|
+
value: form.getSerializedState(),
|
|
37
|
+
form: props.formId
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function useSubjectRef() {
|
|
41
|
+
var initialSubject = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
42
|
+
var subjectRef = useRef(initialSubject);
|
|
43
|
+
|
|
44
|
+
// Reset the subject everytime the component is rerendered
|
|
45
|
+
// This let us subscribe to data used in the last render only
|
|
46
|
+
subjectRef.current = initialSubject;
|
|
47
|
+
return subjectRef;
|
|
48
|
+
}
|
|
49
|
+
function getBaseMetadata(formId, context, options) {
|
|
50
|
+
var _options$name;
|
|
51
|
+
var name = (_options$name = options.name) !== null && _options$name !== void 0 ? _options$name : '';
|
|
52
|
+
var id = name ? "".concat(formId, "-").concat(name) : formId;
|
|
53
|
+
var updateSubject = (subject, scope) => {
|
|
54
|
+
var _options$subjectRef$c, _options$subjectRef$c2;
|
|
55
|
+
options.subjectRef.current[subject] = _objectSpread2(_objectSpread2({}, options.subjectRef.current[subject]), {}, {
|
|
56
|
+
[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)
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
return new Proxy({
|
|
60
|
+
id,
|
|
61
|
+
errorId: "".concat(id, "-error"),
|
|
62
|
+
descriptionId: "".concat(id, "-description"),
|
|
63
|
+
initialValue: context.initialValue[name],
|
|
64
|
+
value: context.value[name],
|
|
65
|
+
errors: context.error[name],
|
|
66
|
+
get key() {
|
|
67
|
+
return context.state.key[name];
|
|
68
|
+
},
|
|
69
|
+
get valid() {
|
|
70
|
+
return context.state.valid[name];
|
|
71
|
+
},
|
|
72
|
+
get dirty() {
|
|
73
|
+
return context.state.dirty[name];
|
|
74
|
+
},
|
|
75
|
+
get allValid() {
|
|
76
|
+
var keys = Object.keys(context.error);
|
|
77
|
+
if (name === '') {
|
|
78
|
+
return keys.length === 0;
|
|
79
|
+
}
|
|
80
|
+
for (var key of Object.keys(context.error)) {
|
|
81
|
+
if (isPrefix(key, name) && !context.state.valid[key]) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
},
|
|
87
|
+
get allErrors() {
|
|
88
|
+
if (name === '') {
|
|
89
|
+
return context.error;
|
|
90
|
+
}
|
|
91
|
+
var result = {};
|
|
92
|
+
for (var [key, errors] of Object.entries(context.error)) {
|
|
93
|
+
if (isPrefix(key, name)) {
|
|
94
|
+
result[key] = errors;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
}, {
|
|
100
|
+
get(target, key, receiver) {
|
|
101
|
+
switch (key) {
|
|
102
|
+
case 'key':
|
|
103
|
+
case 'errors':
|
|
104
|
+
case 'initialValue':
|
|
105
|
+
case 'value':
|
|
106
|
+
case 'valid':
|
|
107
|
+
case 'dirty':
|
|
108
|
+
updateSubject(key === 'errors' ? 'error' : key, 'name');
|
|
109
|
+
break;
|
|
110
|
+
case 'allErrors':
|
|
111
|
+
updateSubject('error', 'prefix');
|
|
112
|
+
break;
|
|
113
|
+
case 'allValid':
|
|
114
|
+
updateSubject('valid', 'prefix');
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
return Reflect.get(target, key, receiver);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function getFieldMetadata(formId, context, options) {
|
|
122
|
+
var _options$name2, _options$name3;
|
|
123
|
+
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 : '';
|
|
124
|
+
var metadata = getBaseMetadata(formId, context, {
|
|
125
|
+
subjectRef: options.subjectRef,
|
|
126
|
+
name
|
|
127
|
+
});
|
|
128
|
+
return new Proxy(metadata, {
|
|
129
|
+
get(target, key, receiver) {
|
|
130
|
+
switch (key) {
|
|
131
|
+
case 'formId':
|
|
132
|
+
return formId;
|
|
133
|
+
case 'name':
|
|
134
|
+
return name;
|
|
135
|
+
case 'constraint':
|
|
136
|
+
return context.constraint[name];
|
|
137
|
+
}
|
|
138
|
+
return Reflect.get(target, key, receiver);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export { FormProvider, FormStateInput, Registry, getBaseMetadata, getFieldMetadata, useFormContext, useFormStore, useSubjectRef };
|
package/helpers.d.ts
CHANGED
|
@@ -1,42 +1,40 @@
|
|
|
1
|
-
import { INTENT, VALIDATION_UNDEFINED, VALIDATION_SKIPPED } from '@conform-to/dom';
|
|
2
|
-
import type { FieldConfig, Primitive } from './hooks.js';
|
|
3
1
|
import type { CSSProperties, HTMLInputTypeAttribute } from 'react';
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import type { FormMetadata, FieldMetadata, Pretty } from './context';
|
|
3
|
+
type FormControlProps = {
|
|
4
|
+
id: string;
|
|
6
5
|
name: string;
|
|
7
|
-
form
|
|
8
|
-
'aria-describedby'?: string;
|
|
9
|
-
'aria-invalid'?: boolean;
|
|
10
|
-
}
|
|
11
|
-
interface FormControlProps extends FormElementProps {
|
|
6
|
+
form: string;
|
|
12
7
|
required?: boolean;
|
|
13
8
|
autoFocus?: boolean;
|
|
14
9
|
tabIndex?: number;
|
|
15
10
|
style?: CSSProperties;
|
|
11
|
+
'aria-describedby'?: string;
|
|
12
|
+
'aria-invalid'?: boolean;
|
|
16
13
|
'aria-hidden'?: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
type?: HTMLInputTypeAttribute
|
|
14
|
+
};
|
|
15
|
+
type InputProps = Pretty<FormControlProps & {
|
|
16
|
+
type?: Exclude<HTMLInputTypeAttribute, 'submit' | 'reset' | 'button'>;
|
|
20
17
|
minLength?: number;
|
|
21
18
|
maxLength?: number;
|
|
22
|
-
min?:
|
|
23
|
-
max?:
|
|
24
|
-
step?:
|
|
19
|
+
min?: string | number;
|
|
20
|
+
max?: string | number;
|
|
21
|
+
step?: string | number;
|
|
25
22
|
pattern?: string;
|
|
26
23
|
multiple?: boolean;
|
|
27
24
|
value?: string;
|
|
28
25
|
defaultChecked?: boolean;
|
|
29
26
|
defaultValue?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
27
|
+
}>;
|
|
28
|
+
type SelectProps = Pretty<FormControlProps & {
|
|
32
29
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
33
30
|
multiple?: boolean;
|
|
34
|
-
}
|
|
35
|
-
|
|
31
|
+
}>;
|
|
32
|
+
type TextareaProps = Pretty<FormControlProps & {
|
|
36
33
|
minLength?: number;
|
|
37
34
|
maxLength?: number;
|
|
38
35
|
defaultValue?: string;
|
|
39
|
-
}
|
|
36
|
+
}>;
|
|
37
|
+
type Primitive = string | number | boolean | Date | null | undefined;
|
|
40
38
|
type BaseOptions = {
|
|
41
39
|
ariaAttributes?: true;
|
|
42
40
|
description?: boolean;
|
|
@@ -46,6 +44,10 @@ type BaseOptions = {
|
|
|
46
44
|
type ControlOptions = BaseOptions & {
|
|
47
45
|
hidden?: boolean;
|
|
48
46
|
};
|
|
47
|
+
type FormOptions<Schema extends Record<string, any>> = BaseOptions & {
|
|
48
|
+
onSubmit?: (event: React.FormEvent<HTMLFormElement>, context: ReturnType<FormMetadata<Schema>['onSubmit']>) => void;
|
|
49
|
+
onReset?: (event: React.FormEvent<HTMLFormElement>) => void;
|
|
50
|
+
};
|
|
49
51
|
type InputOptions = ControlOptions & ({
|
|
50
52
|
type: 'checkbox' | 'radio';
|
|
51
53
|
value?: string;
|
|
@@ -58,15 +60,25 @@ export declare const hiddenProps: {
|
|
|
58
60
|
tabIndex: number;
|
|
59
61
|
'aria-hidden': boolean;
|
|
60
62
|
};
|
|
61
|
-
export declare function input<Schema extends Primitive | unknown>(
|
|
62
|
-
export declare function input<Schema extends File | File[]>(
|
|
63
|
+
export declare function input<Schema extends Primitive | unknown>(field: FieldMetadata<Schema>, options?: InputOptions): InputProps;
|
|
64
|
+
export declare function input<Schema extends File | File[]>(field: FieldMetadata<Schema>, options: InputOptions & {
|
|
63
65
|
type: 'file';
|
|
64
|
-
}): InputProps
|
|
65
|
-
export declare function select<Schema extends Primitive | Primitive[] | undefined | unknown>(
|
|
66
|
-
export declare function textarea<Schema extends Primitive | undefined | unknown>(
|
|
67
|
-
export declare function
|
|
68
|
-
|
|
66
|
+
}): InputProps;
|
|
67
|
+
export declare function select<Schema extends Primitive | Primitive[] | undefined | unknown>(metadata: FieldMetadata<Schema>, options?: ControlOptions): SelectProps;
|
|
68
|
+
export declare function textarea<Schema extends Primitive | undefined | unknown>(metadata: FieldMetadata<Schema>, options?: ControlOptions): TextareaProps;
|
|
69
|
+
export declare function form<Schema extends Record<string, any>>(metadata: FormMetadata<Schema>, options?: FormOptions<Schema>): {
|
|
70
|
+
id: string;
|
|
71
|
+
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
|
|
72
|
+
onReset: (event: import("react").FormEvent<HTMLFormElement>) => void;
|
|
73
|
+
noValidate: boolean;
|
|
74
|
+
};
|
|
75
|
+
export declare function fieldset<Schema extends Record<string, any> | undefined | unknown>(metadata: FieldMetadata<Schema>, options?: BaseOptions): {
|
|
76
|
+
id: string;
|
|
77
|
+
name: import("@conform-to/dom").FieldName<Schema>;
|
|
78
|
+
form: string;
|
|
79
|
+
};
|
|
80
|
+
export declare function collection<Schema extends Array<string | boolean> | string | boolean | undefined | unknown>(metadata: FieldMetadata<Schema>, options: BaseOptions & {
|
|
69
81
|
type: 'checkbox' | 'radio';
|
|
70
82
|
options: string[];
|
|
71
|
-
}): Array<InputProps
|
|
72
|
-
export {
|
|
83
|
+
}): Array<InputProps & Pick<Required<InputProps>, 'type' | 'value'>>;
|
|
84
|
+
export {};
|
package/helpers.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
|
|
6
|
-
var dom = require('@conform-to/dom');
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* Cleanup `undefined` from the dervied props
|
|
@@ -17,31 +16,25 @@ function cleanup(props) {
|
|
|
17
16
|
}
|
|
18
17
|
return props;
|
|
19
18
|
}
|
|
20
|
-
function
|
|
21
|
-
var _options$ariaAttribut, _config$error, _config$error2;
|
|
19
|
+
function getAriaAttributes(metadata) {
|
|
22
20
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
23
|
-
|
|
21
|
+
if (typeof options.ariaAttributes !== 'undefined' && !options.ariaAttributes) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
24
|
return cleanup({
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
form: config.form,
|
|
28
|
-
'aria-invalid': hasAriaAttributes && config.errorId && (_config$error = config.error) !== null && _config$error !== void 0 && _config$error.length ? true : undefined,
|
|
29
|
-
'aria-describedby': hasAriaAttributes ? [config.errorId && (_config$error2 = config.error) !== null && _config$error2 !== void 0 && _config$error2.length ? config.errorId : undefined, config.descriptionId && options.ariaAttributes !== false && options.description ? config.descriptionId : undefined].reduce((result, id) => {
|
|
30
|
-
if (!result) {
|
|
31
|
-
return id;
|
|
32
|
-
}
|
|
33
|
-
if (!id) {
|
|
34
|
-
return result;
|
|
35
|
-
}
|
|
36
|
-
return "".concat(result, " ").concat(id);
|
|
37
|
-
}) : undefined
|
|
25
|
+
'aria-invalid': !metadata.valid || undefined,
|
|
26
|
+
'aria-describedby': metadata.valid ? options.description ? metadata.descriptionId : undefined : "".concat(metadata.errorId, " ").concat(options.description ? metadata.descriptionId : '').trim()
|
|
38
27
|
});
|
|
39
28
|
}
|
|
40
|
-
function getFormControlProps(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
29
|
+
function getFormControlProps(metadata, options) {
|
|
30
|
+
var _metadata$constraint;
|
|
31
|
+
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({
|
|
32
|
+
id: metadata.id,
|
|
33
|
+
name: metadata.name,
|
|
34
|
+
form: metadata.formId,
|
|
35
|
+
required: ((_metadata$constraint = metadata.constraint) === null || _metadata$constraint === void 0 ? void 0 : _metadata$constraint.required) || undefined,
|
|
36
|
+
autoFocus: !metadata.valid || undefined
|
|
37
|
+
}, options !== null && options !== void 0 && options.hidden ? hiddenProps : undefined), getAriaAttributes(metadata, options)));
|
|
45
38
|
}
|
|
46
39
|
var hiddenProps = {
|
|
47
40
|
/**
|
|
@@ -62,70 +55,88 @@ var hiddenProps = {
|
|
|
62
55
|
tabIndex: -1,
|
|
63
56
|
'aria-hidden': true
|
|
64
57
|
};
|
|
65
|
-
function input(
|
|
58
|
+
function input(field) {
|
|
59
|
+
var _field$constraint, _field$constraint2, _field$constraint3, _field$constraint4, _field$constraint5, _field$constraint6, _field$constraint7;
|
|
66
60
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
67
|
-
var props = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(
|
|
61
|
+
var props = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(field, options)), {}, {
|
|
68
62
|
type: options.type,
|
|
69
|
-
minLength:
|
|
70
|
-
maxLength:
|
|
71
|
-
min:
|
|
72
|
-
max:
|
|
73
|
-
step:
|
|
74
|
-
pattern:
|
|
75
|
-
multiple:
|
|
63
|
+
minLength: (_field$constraint = field.constraint) === null || _field$constraint === void 0 ? void 0 : _field$constraint.minLength,
|
|
64
|
+
maxLength: (_field$constraint2 = field.constraint) === null || _field$constraint2 === void 0 ? void 0 : _field$constraint2.maxLength,
|
|
65
|
+
min: (_field$constraint3 = field.constraint) === null || _field$constraint3 === void 0 ? void 0 : _field$constraint3.min,
|
|
66
|
+
max: (_field$constraint4 = field.constraint) === null || _field$constraint4 === void 0 ? void 0 : _field$constraint4.max,
|
|
67
|
+
step: (_field$constraint5 = field.constraint) === null || _field$constraint5 === void 0 ? void 0 : _field$constraint5.step,
|
|
68
|
+
pattern: (_field$constraint6 = field.constraint) === null || _field$constraint6 === void 0 ? void 0 : _field$constraint6.pattern,
|
|
69
|
+
multiple: (_field$constraint7 = field.constraint) === null || _field$constraint7 === void 0 ? void 0 : _field$constraint7.multiple
|
|
76
70
|
});
|
|
77
71
|
if (options.type === 'checkbox' || options.type === 'radio') {
|
|
78
72
|
var _options$value;
|
|
79
73
|
props.value = (_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : 'on';
|
|
80
|
-
props.defaultChecked =
|
|
74
|
+
props.defaultChecked = typeof field.initialValue === 'boolean' ? field.initialValue : field.initialValue === props.value;
|
|
81
75
|
} else if (options.type !== 'file') {
|
|
82
|
-
|
|
76
|
+
var _field$initialValue;
|
|
77
|
+
props.defaultValue = (_field$initialValue = field.initialValue) === null || _field$initialValue === void 0 ? void 0 : _field$initialValue.toString();
|
|
83
78
|
}
|
|
84
79
|
return cleanup(props);
|
|
85
80
|
}
|
|
86
|
-
function select(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
81
|
+
function select(metadata, options) {
|
|
82
|
+
var _metadata$initialValu, _metadata$constraint2;
|
|
83
|
+
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, {
|
|
84
|
+
defaultValue: (_metadata$initialValu = metadata.initialValue) === null || _metadata$initialValu === void 0 ? void 0 : _metadata$initialValu.toString(),
|
|
85
|
+
multiple: (_metadata$constraint2 = metadata.constraint) === null || _metadata$constraint2 === void 0 ? void 0 : _metadata$constraint2.multiple
|
|
90
86
|
}));
|
|
91
87
|
}
|
|
92
|
-
function textarea(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
function textarea(metadata, options) {
|
|
89
|
+
var _metadata$initialValu2, _metadata$constraint3, _metadata$constraint4;
|
|
90
|
+
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, {
|
|
91
|
+
defaultValue: (_metadata$initialValu2 = metadata.initialValue) === null || _metadata$initialValu2 === void 0 ? void 0 : _metadata$initialValu2.toString(),
|
|
92
|
+
minLength: (_metadata$constraint3 = metadata.constraint) === null || _metadata$constraint3 === void 0 ? void 0 : _metadata$constraint3.minLength,
|
|
93
|
+
maxLength: (_metadata$constraint4 = metadata.constraint) === null || _metadata$constraint4 === void 0 ? void 0 : _metadata$constraint4.maxLength
|
|
97
94
|
}));
|
|
98
95
|
}
|
|
99
|
-
function
|
|
100
|
-
|
|
96
|
+
function form(metadata, options) {
|
|
97
|
+
var onSubmit = options === null || options === void 0 ? void 0 : options.onSubmit;
|
|
98
|
+
var onReset = options === null || options === void 0 ? void 0 : options.onReset;
|
|
99
|
+
return cleanup(_rollupPluginBabelHelpers.objectSpread2({
|
|
100
|
+
id: metadata.id,
|
|
101
|
+
onSubmit: typeof onSubmit !== 'function' ? metadata.onSubmit : event => {
|
|
102
|
+
var context = metadata.onSubmit(event);
|
|
103
|
+
if (!event.defaultPrevented) {
|
|
104
|
+
onSubmit(event, context);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
onReset: typeof onReset !== 'function' ? metadata.onReset : event => {
|
|
108
|
+
metadata.onReset(event);
|
|
109
|
+
onReset(event);
|
|
110
|
+
},
|
|
111
|
+
noValidate: metadata.noValidate
|
|
112
|
+
}, getAriaAttributes(metadata, options)));
|
|
101
113
|
}
|
|
102
|
-
function
|
|
103
|
-
return
|
|
104
|
-
id:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
function fieldset(metadata, options) {
|
|
115
|
+
return cleanup(_rollupPluginBabelHelpers.objectSpread2({
|
|
116
|
+
id: metadata.id,
|
|
117
|
+
name: metadata.name,
|
|
118
|
+
form: metadata.formId
|
|
119
|
+
}, getAriaAttributes(metadata, options)));
|
|
120
|
+
}
|
|
121
|
+
function collection(metadata, options) {
|
|
122
|
+
return options.options.map(value => {
|
|
123
|
+
var _metadata$constraint5;
|
|
124
|
+
return cleanup(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, getFormControlProps(metadata, options)), {}, {
|
|
125
|
+
id: "".concat(metadata.id, "-").concat(value),
|
|
126
|
+
type: options.type,
|
|
127
|
+
value,
|
|
128
|
+
defaultChecked: options.type === 'checkbox' && Array.isArray(metadata.initialValue) ? metadata.initialValue.includes(value) : metadata.initialValue === value,
|
|
129
|
+
// The required attribute doesn't make sense for checkbox group
|
|
130
|
+
// As it would require all checkboxes to be checked instead of at least one
|
|
131
|
+
// It is overriden with `undefiend` so it could be cleaned upW properly
|
|
132
|
+
required: options.type === 'checkbox' ? undefined : (_metadata$constraint5 = metadata.constraint) === null || _metadata$constraint5 === void 0 ? void 0 : _metadata$constraint5.required
|
|
133
|
+
}));
|
|
134
|
+
});
|
|
113
135
|
}
|
|
114
136
|
|
|
115
|
-
Object.defineProperty(exports, 'INTENT', {
|
|
116
|
-
enumerable: true,
|
|
117
|
-
get: function () { return dom.INTENT; }
|
|
118
|
-
});
|
|
119
|
-
Object.defineProperty(exports, 'VALIDATION_SKIPPED', {
|
|
120
|
-
enumerable: true,
|
|
121
|
-
get: function () { return dom.VALIDATION_SKIPPED; }
|
|
122
|
-
});
|
|
123
|
-
Object.defineProperty(exports, 'VALIDATION_UNDEFINED', {
|
|
124
|
-
enumerable: true,
|
|
125
|
-
get: function () { return dom.VALIDATION_UNDEFINED; }
|
|
126
|
-
});
|
|
127
137
|
exports.collection = collection;
|
|
128
138
|
exports.fieldset = fieldset;
|
|
139
|
+
exports.form = form;
|
|
129
140
|
exports.hiddenProps = hiddenProps;
|
|
130
141
|
exports.input = input;
|
|
131
142
|
exports.select = select;
|