@formality-ui/react 0.3.0 → 0.4.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 +2 -2
- package/dist/index.cjs +53 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +54 -51
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -133,6 +133,15 @@ interface ReactInputConfig<TValue = unknown> extends Omit<InputConfig<TValue>, "
|
|
|
133
133
|
*
|
|
134
134
|
* The generic `V` defaults to `FieldValues`; pass your form's values type for
|
|
135
135
|
* slightly tighter checking on path-based rules.
|
|
136
|
+
*
|
|
137
|
+
* The §6.4 field-level override fields (`defaultValue`, `debounce`,
|
|
138
|
+
* `parser`, `formatter`, `valueField`, `getSubmitField`) are inherited
|
|
139
|
+
* from core `FieldConfig` unchanged. They override their `InputConfig`
|
|
140
|
+
* counterparts when `!== undefined`, using the single
|
|
141
|
+
* `resolveFieldOverType` rule (§6.4.0). The field-level
|
|
142
|
+
* `parser`/`formatter` stay `string | ((value: unknown) => unknown)` —
|
|
143
|
+
* NOT generified over `TValue` (per-field `TValue` is a future
|
|
144
|
+
* enhancement, §3.2.1).
|
|
136
145
|
*/
|
|
137
146
|
interface ReactFieldConfig<V extends FieldValues = FieldValues> extends Omit<FieldConfig, "rules"> {
|
|
138
147
|
/** react-hook-form register options forwarded to the field's Controller. */
|
package/dist/index.d.ts
CHANGED
|
@@ -133,6 +133,15 @@ interface ReactInputConfig<TValue = unknown> extends Omit<InputConfig<TValue>, "
|
|
|
133
133
|
*
|
|
134
134
|
* The generic `V` defaults to `FieldValues`; pass your form's values type for
|
|
135
135
|
* slightly tighter checking on path-based rules.
|
|
136
|
+
*
|
|
137
|
+
* The §6.4 field-level override fields (`defaultValue`, `debounce`,
|
|
138
|
+
* `parser`, `formatter`, `valueField`, `getSubmitField`) are inherited
|
|
139
|
+
* from core `FieldConfig` unchanged. They override their `InputConfig`
|
|
140
|
+
* counterparts when `!== undefined`, using the single
|
|
141
|
+
* `resolveFieldOverType` rule (§6.4.0). The field-level
|
|
142
|
+
* `parser`/`formatter` stay `string | ((value: unknown) => unknown)` —
|
|
143
|
+
* NOT generified over `TValue` (per-field `TValue` is a future
|
|
144
|
+
* enhancement, §3.2.1).
|
|
136
145
|
*/
|
|
137
146
|
interface ReactFieldConfig<V extends FieldValues = FieldValues> extends Omit<FieldConfig, "rules"> {
|
|
138
147
|
/** react-hook-form register options forwarded to the field's Controller. */
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createContext, useContext, useMemo, useRef, useState, useCallback, useE
|
|
|
2
2
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { useForm, FormProvider, useWatch, Controller, useFormContext as useFormContext$1 } from 'react-hook-form';
|
|
4
4
|
import { debounce } from 'lodash-es';
|
|
5
|
-
import { resolveAllInitialValues, buildFormContext, evaluateDescriptor, resolveFormTitle, transformFieldName, extractValueField, inferFieldsFromDescriptor, inferFieldsFromConditions, evaluateConditions, buildFieldContext, resolveInputConfig, resolveLabel, runValidator, resolveErrorMessage, parse, format, mergeFieldProps, sortFieldsByOrder } from '@formality-ui/core';
|
|
5
|
+
import { resolveAllInitialValues, resolveFieldOverType, buildFormContext, evaluateDescriptor, resolveFormTitle, transformFieldName, extractValueField, inferFieldsFromDescriptor, inferFieldsFromConditions, evaluateConditions, buildFieldContext, resolveInputConfig, resolveLabel, runValidator, resolveErrorMessage, parse, format, mergeFieldProps, sortFieldsByOrder } from '@formality-ui/core';
|
|
6
6
|
|
|
7
7
|
// src/context/ConfigContext.ts
|
|
8
8
|
var defaultConfigContext = {
|
|
@@ -162,8 +162,15 @@ function Form({
|
|
|
162
162
|
return result;
|
|
163
163
|
}, [providerConfig.inputs, formConfig.inputs]);
|
|
164
164
|
const defaultValues = useMemo(() => {
|
|
165
|
-
const resolved = resolveAllInitialValues(
|
|
166
|
-
|
|
165
|
+
const resolved = resolveAllInitialValues(
|
|
166
|
+
config,
|
|
167
|
+
mergedInputs,
|
|
168
|
+
record ?? {}
|
|
169
|
+
);
|
|
170
|
+
const baseline = {
|
|
171
|
+
...record ?? {},
|
|
172
|
+
...resolved
|
|
173
|
+
};
|
|
167
174
|
for (const fieldName of Object.keys(config)) {
|
|
168
175
|
if (!(fieldName in baseline)) baseline[fieldName] = void 0;
|
|
169
176
|
}
|
|
@@ -201,11 +208,6 @@ function Form({
|
|
|
201
208
|
invertedSubscriptions.current.set(target, /* @__PURE__ */ new Set());
|
|
202
209
|
}
|
|
203
210
|
invertedSubscriptions.current.get(target).add(subscriber);
|
|
204
|
-
if (process.env.NODE_ENV !== "production") {
|
|
205
|
-
console.warn(
|
|
206
|
-
`[Formality Subscription] "${subscriber}" added to watch "${target}"`
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
211
|
const setter = watcherSetters.current.get(target);
|
|
210
212
|
if (setter) {
|
|
211
213
|
setter((prev) => ({ ...prev, [subscriber]: true }));
|
|
@@ -218,20 +220,7 @@ function Form({
|
|
|
218
220
|
}, []);
|
|
219
221
|
const removeSubscription = useCallback(
|
|
220
222
|
(target, subscriber) => {
|
|
221
|
-
const subscribers = invertedSubscriptions.current.get(target);
|
|
222
|
-
const subscriptionExists = subscribers?.has(subscriber) ?? false;
|
|
223
223
|
invertedSubscriptions.current.get(target)?.delete(subscriber);
|
|
224
|
-
if (process.env.NODE_ENV !== "production") {
|
|
225
|
-
if (subscriptionExists) {
|
|
226
|
-
console.warn(
|
|
227
|
-
`[Formality Subscription] "${subscriber}" removed from watching "${target}"`
|
|
228
|
-
);
|
|
229
|
-
} else {
|
|
230
|
-
console.warn(
|
|
231
|
-
`[Formality Subscription] WARNING: Double-cleanup attempt - "${subscriber}" was not watching "${target}"`
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
224
|
const setter = watcherSetters.current.get(target);
|
|
236
225
|
if (setter) {
|
|
237
226
|
setter((prev) => {
|
|
@@ -288,7 +277,11 @@ function Form({
|
|
|
288
277
|
for (const field of affected) {
|
|
289
278
|
pendingAffectedFields.current.add(field);
|
|
290
279
|
}
|
|
291
|
-
const
|
|
280
|
+
const fieldConfig = config[name];
|
|
281
|
+
const fieldDebounce = resolveFieldOverType(
|
|
282
|
+
fieldConfig?.debounce,
|
|
283
|
+
inputConfig?.debounce
|
|
284
|
+
);
|
|
292
285
|
if (fieldDebounce === false) {
|
|
293
286
|
executeAutoSaveRef.current?.();
|
|
294
287
|
} else if (typeof fieldDebounce === "number") {
|
|
@@ -298,7 +291,7 @@ function Form({
|
|
|
298
291
|
}
|
|
299
292
|
}
|
|
300
293
|
},
|
|
301
|
-
[autoSave, getAffectedFields]
|
|
294
|
+
[autoSave, getAffectedFields, config]
|
|
302
295
|
);
|
|
303
296
|
const setFieldValidating = useCallback(
|
|
304
297
|
(name, isValidating) => {
|
|
@@ -602,13 +595,17 @@ function transformValuesForSubmit(values, config, inputs) {
|
|
|
602
595
|
const fieldConfig = config[name];
|
|
603
596
|
const type = fieldConfig?.type ?? "textField";
|
|
604
597
|
const inputConfig = inputs[type];
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
598
|
+
const effectiveGetSubmitField = resolveFieldOverType(
|
|
599
|
+
fieldConfig?.getSubmitField,
|
|
600
|
+
inputConfig?.getSubmitField
|
|
601
|
+
);
|
|
602
|
+
const effectiveValueField = resolveFieldOverType(
|
|
603
|
+
fieldConfig?.valueField,
|
|
604
|
+
inputConfig?.valueField
|
|
605
|
+
);
|
|
606
|
+
const submitName = transformFieldName(name, effectiveGetSubmitField);
|
|
607
|
+
const submitValue = extractValueField(value, effectiveValueField);
|
|
608
|
+
result[submitName] = submitValue;
|
|
612
609
|
}
|
|
613
610
|
return result;
|
|
614
611
|
}
|
|
@@ -918,20 +915,10 @@ function useSubscriptions(fieldName, subscriptions) {
|
|
|
918
915
|
runSubscriptionsRef.current.set(currentRunId, [...subscriptions]);
|
|
919
916
|
subscriptions.forEach((target) => {
|
|
920
917
|
addSubscription(target, fieldName);
|
|
921
|
-
if (process.env.NODE_ENV !== "production") {
|
|
922
|
-
console.warn(
|
|
923
|
-
`[Formality Subscription] Run ${currentRunId}: "${fieldName}" subscribing to "${target}"`
|
|
924
|
-
);
|
|
925
|
-
}
|
|
926
918
|
});
|
|
927
919
|
return () => {
|
|
928
920
|
const thisRunSubscriptions = runSubscriptionsRef.current.get(currentRunId);
|
|
929
921
|
if (thisRunSubscriptions) {
|
|
930
|
-
if (process.env.NODE_ENV !== "production") {
|
|
931
|
-
console.warn(
|
|
932
|
-
`[Formality Subscription] Run ${currentRunId}: "${fieldName}" cleaning up [${thisRunSubscriptions.join(", ")}]`
|
|
933
|
-
);
|
|
934
|
-
}
|
|
935
922
|
[...thisRunSubscriptions].reverse().forEach((target) => {
|
|
936
923
|
removeSubscription(target, fieldName);
|
|
937
924
|
});
|
|
@@ -1095,8 +1082,22 @@ function useField({
|
|
|
1095
1082
|
groupContext.state.isVisible
|
|
1096
1083
|
]);
|
|
1097
1084
|
const label = useMemo(() => {
|
|
1098
|
-
return resolveLabel(
|
|
1099
|
-
|
|
1085
|
+
return resolveLabel(
|
|
1086
|
+
name,
|
|
1087
|
+
fieldConfig,
|
|
1088
|
+
fieldSelectProps,
|
|
1089
|
+
restProps,
|
|
1090
|
+
providerSelectProps,
|
|
1091
|
+
formSelectProps
|
|
1092
|
+
);
|
|
1093
|
+
}, [
|
|
1094
|
+
name,
|
|
1095
|
+
fieldConfig,
|
|
1096
|
+
fieldSelectProps,
|
|
1097
|
+
restProps,
|
|
1098
|
+
providerSelectProps,
|
|
1099
|
+
formSelectProps
|
|
1100
|
+
]);
|
|
1100
1101
|
const passSubscriptionsEnabled = fieldConfig.passSubscriptions === true;
|
|
1101
1102
|
const provideStateEnabled = fieldConfig.provideState === true;
|
|
1102
1103
|
const subscribedWatchNames = useMemo(
|
|
@@ -1175,23 +1176,25 @@ function useField({
|
|
|
1175
1176
|
name,
|
|
1176
1177
|
setFieldValidating
|
|
1177
1178
|
]);
|
|
1179
|
+
const effectiveParser = useMemo(
|
|
1180
|
+
() => resolveFieldOverType(fieldConfig.parser, inputConfig.parser),
|
|
1181
|
+
[fieldConfig.parser, inputConfig.parser]
|
|
1182
|
+
);
|
|
1183
|
+
const effectiveFormatter = useMemo(
|
|
1184
|
+
() => resolveFieldOverType(fieldConfig.formatter, inputConfig.formatter),
|
|
1185
|
+
[fieldConfig.formatter, inputConfig.formatter]
|
|
1186
|
+
);
|
|
1178
1187
|
const handleChange = useCallback(
|
|
1179
1188
|
(onChange) => (newValue) => {
|
|
1180
1189
|
const parsedValue = parse(
|
|
1181
1190
|
newValue,
|
|
1182
|
-
|
|
1191
|
+
effectiveParser,
|
|
1183
1192
|
providerConfig.parsers
|
|
1184
1193
|
);
|
|
1185
1194
|
onChange(parsedValue);
|
|
1186
1195
|
changeField(name, parsedValue, inputConfig);
|
|
1187
1196
|
},
|
|
1188
|
-
[
|
|
1189
|
-
inputConfig.parser,
|
|
1190
|
-
providerConfig.parsers,
|
|
1191
|
-
changeField,
|
|
1192
|
-
name,
|
|
1193
|
-
inputConfig
|
|
1194
|
-
]
|
|
1197
|
+
[effectiveParser, providerConfig.parsers, changeField, name, inputConfig]
|
|
1195
1198
|
);
|
|
1196
1199
|
const fieldStateRef = useRef(
|
|
1197
1200
|
{}
|
|
@@ -1209,7 +1212,7 @@ function useField({
|
|
|
1209
1212
|
render: ({ field, fieldState, formState }) => {
|
|
1210
1213
|
const formattedValue = format(
|
|
1211
1214
|
field.value,
|
|
1212
|
-
|
|
1215
|
+
effectiveFormatter,
|
|
1213
1216
|
providerConfig.formatters
|
|
1214
1217
|
);
|
|
1215
1218
|
const stateInjection = {};
|