@formality-ui/react 0.0.0 → 0.1.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/dist/index.cjs CHANGED
@@ -25,7 +25,9 @@ function useConfigContext() {
25
25
  var FormContext = react.createContext(null);
26
26
  FormContext.displayName = "FormalityFormContext";
27
27
  function useFormContext() {
28
- const context = react.useContext(FormContext);
28
+ const context = react.useContext(
29
+ FormContext
30
+ );
29
31
  if (!context) {
30
32
  throw new Error(
31
33
  "useFormContext must be used within a Form component. Make sure your component is wrapped in a <Form> component."
@@ -111,7 +113,6 @@ function makeDeepProxyState(source) {
111
113
  const result = {};
112
114
  for (const key in source) {
113
115
  if (Object.prototype.hasOwnProperty.call(source, key)) {
114
- source[key];
115
116
  Object.defineProperty(result, key, {
116
117
  get: () => {
117
118
  const currentValue = source[key];
@@ -193,6 +194,11 @@ function Form({
193
194
  invertedSubscriptions.current.set(target, /* @__PURE__ */ new Set());
194
195
  }
195
196
  invertedSubscriptions.current.get(target).add(subscriber);
197
+ if (process.env.NODE_ENV !== "production") {
198
+ console.warn(
199
+ `[Formality Subscription] "${subscriber}" added to watch "${target}"`
200
+ );
201
+ }
196
202
  const setter = watcherSetters.current.get(target);
197
203
  if (setter) {
198
204
  setter((prev) => ({ ...prev, [subscriber]: true }));
@@ -205,7 +211,20 @@ function Form({
205
211
  }, []);
206
212
  const removeSubscription = react.useCallback(
207
213
  (target, subscriber) => {
214
+ const subscribers = invertedSubscriptions.current.get(target);
215
+ const subscriptionExists = subscribers?.has(subscriber) ?? false;
208
216
  invertedSubscriptions.current.get(target)?.delete(subscriber);
217
+ if (process.env.NODE_ENV !== "production") {
218
+ if (subscriptionExists) {
219
+ console.warn(
220
+ `[Formality Subscription] "${subscriber}" removed from watching "${target}"`
221
+ );
222
+ } else {
223
+ console.warn(
224
+ `[Formality Subscription] WARNING: Double-cleanup attempt - "${subscriber}" was not watching "${target}"`
225
+ );
226
+ }
227
+ }
209
228
  const setter = watcherSetters.current.get(target);
210
229
  if (setter) {
211
230
  setter((prev) => {
@@ -255,14 +274,18 @@ function Form({
255
274
  return affected;
256
275
  }, []);
257
276
  const changeField = react.useCallback(
258
- (name, value) => {
277
+ (name, value, inputConfig) => {
259
278
  if (autoSave) {
260
279
  pendingChangedFields.current.add(name);
261
280
  const affected = getAffectedFields(name);
262
281
  for (const field of affected) {
263
282
  pendingAffectedFields.current.add(field);
264
283
  }
265
- debouncedSubmit();
284
+ if (inputConfig?.debounce === false) {
285
+ executeAutoSaveRef.current?.();
286
+ } else {
287
+ debouncedSubmitRef.current?.();
288
+ }
266
289
  }
267
290
  },
268
291
  [autoSave, getAffectedFields]
@@ -305,7 +328,7 @@ function Form({
305
328
  };
306
329
  }, [methods, config, record, defaultValues]);
307
330
  const handleSubmit = react.useCallback(
308
- async (values) => {
331
+ async (values, overrideOnSubmit) => {
309
332
  for (const [, isValidating] of validatingFields.current) {
310
333
  if (isValidating) return;
311
334
  }
@@ -318,12 +341,26 @@ function Form({
318
341
  return;
319
342
  }
320
343
  }
321
- const submitValues = transformValuesForSubmit(values, config, mergedInputs);
322
- await onSubmit?.(submitValues);
344
+ const submitValues = transformValuesForSubmit(
345
+ values,
346
+ config,
347
+ mergedInputs
348
+ );
349
+ const sink = overrideOnSubmit ?? onSubmit;
350
+ await sink?.(submitValues);
323
351
  },
324
352
  [validate, methods, onSubmit, config, mergedInputs]
325
353
  );
354
+ const handleRenderSubmit = react.useCallback(
355
+ (userOnSubmit) => {
356
+ return methods.handleSubmit(async (values) => {
357
+ await handleSubmit(values, userOnSubmit);
358
+ });
359
+ },
360
+ [methods, handleSubmit]
361
+ );
326
362
  const debouncedSubmitRef = react.useRef();
363
+ const executeAutoSaveRef = react.useRef();
327
364
  const waitForFieldValidation = react.useCallback(
328
365
  async (fields, version) => {
329
366
  const maxWaitMs = 1e4;
@@ -355,29 +392,36 @@ function Form({
355
392
  if (changedFields.size === 0) {
356
393
  return;
357
394
  }
358
- const fieldsToValidate = [...changedFields, ...affectedFields];
395
+ const fieldsToWaitFor = [...changedFields, ...affectedFields];
396
+ const fieldsToTrigger = [...affectedFields];
359
397
  const validationsComplete = await waitForFieldValidation(
360
- fieldsToValidate,
398
+ fieldsToWaitFor,
361
399
  executionVersion
362
400
  );
363
401
  if (!validationsComplete || executionVersionRef.current !== executionVersion) {
364
402
  return;
365
403
  }
366
- if (fieldsToValidate.length > 0) {
367
- const isValid = await methods.trigger(fieldsToValidate);
404
+ for (const fieldName of changedFields) {
405
+ const fieldState = methods.getFieldState(fieldName);
406
+ if (fieldState.error) {
407
+ return;
408
+ }
409
+ }
410
+ if (fieldsToTrigger.length > 0) {
411
+ const isValid = await methods.trigger(fieldsToTrigger);
368
412
  if (executionVersionRef.current !== executionVersion) {
369
413
  return;
370
414
  }
371
415
  if (!isValid) {
372
416
  return;
373
417
  }
374
- }
375
- const postTriggerComplete = await waitForFieldValidation(
376
- fieldsToValidate,
377
- executionVersion
378
- );
379
- if (!postTriggerComplete || executionVersionRef.current !== executionVersion) {
380
- return;
418
+ const postTriggerComplete = await waitForFieldValidation(
419
+ fieldsToTrigger,
420
+ executionVersion
421
+ );
422
+ if (!postTriggerComplete || executionVersionRef.current !== executionVersion) {
423
+ return;
424
+ }
381
425
  }
382
426
  const formState = methods.formState;
383
427
  if (Object.keys(formState.errors).length > 0) {
@@ -386,7 +430,27 @@ function Form({
386
430
  const values = methods.getValues();
387
431
  await handleSubmit(values);
388
432
  }, [methods, handleSubmit, waitForFieldValidation]);
433
+ executeAutoSaveRef.current = executeAutoSave;
389
434
  react.useEffect(() => {
435
+ if (debounceMs === false) {
436
+ const immediateFn = Object.assign(
437
+ () => {
438
+ executeAutoSave();
439
+ },
440
+ {
441
+ cancel: () => {
442
+ },
443
+ // No-op for immediate function
444
+ flush: () => executeAutoSave(),
445
+ // Execute immediately on flush
446
+ pending: () => false
447
+ // Never pending when immediate
448
+ }
449
+ );
450
+ debouncedSubmitRef.current = immediateFn;
451
+ return () => {
452
+ };
453
+ }
390
454
  const debouncedFn = lodashEs.debounce(() => {
391
455
  executeAutoSave();
392
456
  }, debounceMs);
@@ -399,12 +463,13 @@ function Form({
399
463
  debouncedFn.cancel();
400
464
  };
401
465
  }, [executeAutoSave, debounceMs]);
402
- const debouncedSubmit = react.useCallback(() => {
403
- debouncedSubmitRef.current?.();
404
- }, []);
405
466
  const submitImmediate = react.useCallback(() => {
406
- debouncedSubmitRef.current?.flush();
407
- }, []);
467
+ if (debouncedSubmitRef.current?.flush) {
468
+ debouncedSubmitRef.current.flush();
469
+ } else {
470
+ executeAutoSave();
471
+ }
472
+ }, [executeAutoSave]);
408
473
  const unusedFields = react.useMemo(() => {
409
474
  const allFields = Object.keys(config);
410
475
  return allFields.filter((name) => !registeredFields.has(name));
@@ -472,6 +537,7 @@ function Form({
472
537
  unusedFields,
473
538
  formState: methods.formState,
474
539
  methods,
540
+ handleSubmit: handleRenderSubmit,
475
541
  resolvedTitle
476
542
  }) : children }) }) });
477
543
  }
@@ -492,9 +558,21 @@ function transformValuesForSubmit(values, config, inputs) {
492
558
  return result;
493
559
  }
494
560
  function useInferredInputs(options) {
495
- const { selectProps, conditions = [], subscribesTo = [] } = options;
561
+ const {
562
+ selectProps,
563
+ formDefaultFieldProps,
564
+ providerDefaultFieldProps,
565
+ conditions = [],
566
+ subscribesTo = []
567
+ } = options;
496
568
  return react.useMemo(() => {
497
569
  const inferred = [...subscribesTo];
570
+ if (providerDefaultFieldProps) {
571
+ inferred.push(...core.inferFieldsFromDescriptor(providerDefaultFieldProps));
572
+ }
573
+ if (formDefaultFieldProps) {
574
+ inferred.push(...core.inferFieldsFromDescriptor(formDefaultFieldProps));
575
+ }
498
576
  if (selectProps) {
499
577
  inferred.push(...core.inferFieldsFromDescriptor(selectProps));
500
578
  }
@@ -502,12 +580,18 @@ function useInferredInputs(options) {
502
580
  inferred.push(...core.inferFieldsFromConditions(conditions));
503
581
  }
504
582
  return [...new Set(inferred)];
505
- }, [selectProps, conditions, subscribesTo]);
583
+ }, [
584
+ providerDefaultFieldProps,
585
+ formDefaultFieldProps,
586
+ selectProps,
587
+ conditions,
588
+ subscribesTo
589
+ ]);
506
590
  }
507
591
 
508
592
  // src/hooks/useConditions.ts
509
593
  function useConditions(options) {
510
- const { conditions, subscribesTo, props } = options;
594
+ const { conditions, subscribesTo, props, allFieldsConfig } = options;
511
595
  const { record, methods } = useFormContext();
512
596
  const watchFields = useInferredInputs({
513
597
  conditions,
@@ -531,12 +615,14 @@ function useConditions(options) {
531
615
  }
532
616
  return values;
533
617
  }, [watchFields, watchedValues]);
534
- const fieldStates = react.useMemo(() => {
618
+ const baseFieldStates = react.useMemo(() => {
535
619
  const states = {};
536
- if (watchFields.length === 0) {
620
+ const currentFieldName = props?.name;
621
+ const allFieldsForPass1 = currentFieldName ? [.../* @__PURE__ */ new Set([...watchFields, currentFieldName])] : watchFields;
622
+ if (allFieldsForPass1.length === 0) {
537
623
  return states;
538
624
  }
539
- watchFields.forEach((fieldName) => {
625
+ allFieldsForPass1.forEach((fieldName) => {
540
626
  const fieldState = methods.getFieldState(fieldName);
541
627
  states[fieldName] = {
542
628
  value: fieldValues[fieldName],
@@ -546,10 +632,112 @@ function useConditions(options) {
546
632
  invalid: fieldState.invalid,
547
633
  isValidating: false
548
634
  // Not easily available per-field
635
+ // ❌ NO disabled property - this is critical for Pass 1 to prevent circular dependency
549
636
  };
550
637
  });
551
638
  return states;
552
- }, [watchFields, fieldValues, methods]);
639
+ }, [watchFields, fieldValues, methods, props]);
640
+ const disabledStates = react.useMemo(() => {
641
+ const disabled = {};
642
+ const currentFieldName = props?.name;
643
+ const configFields = allFieldsConfig ? Object.keys(allFieldsConfig) : [];
644
+ const allFieldsForPass2 = [.../* @__PURE__ */ new Set([...watchFields, ...configFields])];
645
+ if (currentFieldName && !allFieldsForPass2.includes(currentFieldName)) {
646
+ allFieldsForPass2.push(currentFieldName);
647
+ }
648
+ if (allFieldsForPass2.length === 0) {
649
+ return disabled;
650
+ }
651
+ const allBaseStates = {};
652
+ for (const fieldName of allFieldsForPass2) {
653
+ if (baseFieldStates[fieldName]) {
654
+ allBaseStates[fieldName] = baseFieldStates[fieldName];
655
+ } else {
656
+ const fieldState = methods.getFieldState(fieldName);
657
+ allBaseStates[fieldName] = {
658
+ value: fieldValues[fieldName],
659
+ isTouched: fieldState.isTouched,
660
+ isDirty: fieldState.isDirty,
661
+ error: fieldState.error,
662
+ invalid: fieldState.invalid,
663
+ isValidating: false
664
+ };
665
+ }
666
+ }
667
+ let currentStates = allBaseStates;
668
+ let hasChanged = true;
669
+ let iteration = 0;
670
+ const maxIterations = 10;
671
+ while (hasChanged && iteration < maxIterations) {
672
+ hasChanged = false;
673
+ iteration++;
674
+ const newDisabled = {};
675
+ for (const fieldName of allFieldsForPass2) {
676
+ const fieldConfig = allFieldsConfig?.[fieldName];
677
+ const fieldConditions = fieldConfig?.conditions ?? [];
678
+ const configDisabled = fieldConfig?.disabled;
679
+ const result = core.evaluateConditions({
680
+ conditions: fieldConditions,
681
+ fieldValues,
682
+ fieldStates: currentStates,
683
+ record,
684
+ props: { name: fieldName }
685
+ });
686
+ newDisabled[fieldName] = configDisabled ?? result.disabled ?? false;
687
+ }
688
+ const newStates = {};
689
+ for (const fieldName of allFieldsForPass2) {
690
+ const baseState = allBaseStates[fieldName];
691
+ if (baseState) {
692
+ newStates[fieldName] = {
693
+ ...baseState,
694
+ disabled: newDisabled[fieldName]
695
+ };
696
+ }
697
+ }
698
+ for (const fieldName of allFieldsForPass2) {
699
+ const oldDisabled = disabled[fieldName];
700
+ const newDisabledValue = newDisabled[fieldName];
701
+ if (oldDisabled !== newDisabledValue) {
702
+ hasChanged = true;
703
+ disabled[fieldName] = newDisabledValue;
704
+ }
705
+ }
706
+ currentStates = newStates;
707
+ }
708
+ return disabled;
709
+ }, [
710
+ watchFields,
711
+ allFieldsConfig,
712
+ fieldValues,
713
+ baseFieldStates,
714
+ record,
715
+ props,
716
+ methods
717
+ ]);
718
+ const fieldStates = react.useMemo(() => {
719
+ const states = { ...baseFieldStates };
720
+ Object.entries(disabledStates).forEach(([fieldName, disabled]) => {
721
+ if (states[fieldName]) {
722
+ states[fieldName] = {
723
+ ...states[fieldName],
724
+ disabled
725
+ };
726
+ } else {
727
+ const fieldState = methods.getFieldState(fieldName);
728
+ states[fieldName] = {
729
+ value: fieldValues[fieldName],
730
+ isTouched: fieldState.isTouched,
731
+ isDirty: fieldState.isDirty,
732
+ error: fieldState.error,
733
+ invalid: fieldState.invalid,
734
+ isValidating: false,
735
+ disabled
736
+ };
737
+ }
738
+ });
739
+ return states;
740
+ }, [baseFieldStates, disabledStates, fieldValues, methods]);
553
741
  return react.useMemo(() => {
554
742
  if (conditions.length === 0) {
555
743
  return {
@@ -571,9 +759,17 @@ function useConditions(options) {
571
759
  }, [conditions, fieldValues, fieldStates, record, props]);
572
760
  }
573
761
  function usePropsEvaluation(options) {
574
- const { selectProps, subscribesTo, fieldName } = options;
762
+ const {
763
+ selectProps,
764
+ formDefaultFieldProps,
765
+ providerDefaultFieldProps,
766
+ subscribesTo,
767
+ fieldName
768
+ } = options;
575
769
  const { record, methods } = useFormContext();
576
770
  const watchFields = useInferredInputs({
771
+ providerDefaultFieldProps,
772
+ formDefaultFieldProps,
577
773
  selectProps,
578
774
  subscribesTo
579
775
  });
@@ -584,10 +780,13 @@ function usePropsEvaluation(options) {
584
780
  const formState = react.useMemo(() => {
585
781
  const fields = {};
586
782
  if (watchFields.length > 0) {
587
- const values = watchFields.length === 1 ? { [watchFields[0]]: watchedValues } : watchFields.reduce((acc, field, i) => {
588
- acc[field] = watchedValues[i];
589
- return acc;
590
- }, {});
783
+ const values = Array.isArray(watchedValues) ? watchFields.reduce(
784
+ (acc, field, i) => {
785
+ acc[field] = watchedValues[i];
786
+ return acc;
787
+ },
788
+ {}
789
+ ) : watchedValues;
591
790
  watchFields.forEach((name) => {
592
791
  fields[name] = makeProxyState({
593
792
  value: values[name],
@@ -613,40 +812,75 @@ function usePropsEvaluation(options) {
613
812
  };
614
813
  }, [watchFields, watchedValues, record]);
615
814
  return react.useMemo(() => {
616
- if (!selectProps) {
617
- return {};
815
+ let providerResult = {};
816
+ if (providerDefaultFieldProps) {
817
+ if (typeof providerDefaultFieldProps === "function") {
818
+ providerResult = providerDefaultFieldProps(formState, methods) ?? {};
819
+ } else {
820
+ const context = core.buildFieldContext(formState, fieldName);
821
+ providerResult = core.evaluateDescriptor(providerDefaultFieldProps, context) ?? {};
822
+ }
823
+ }
824
+ let formResult = {};
825
+ if (formDefaultFieldProps) {
826
+ if (typeof formDefaultFieldProps === "function") {
827
+ formResult = formDefaultFieldProps(formState, methods) ?? {};
828
+ } else {
829
+ const context = core.buildFieldContext(formState, fieldName);
830
+ formResult = core.evaluateDescriptor(formDefaultFieldProps, context) ?? {};
831
+ }
618
832
  }
619
- if (typeof selectProps === "function") {
620
- const result2 = selectProps(formState, methods);
621
- return result2 ?? {};
833
+ let fieldResult = {};
834
+ if (selectProps) {
835
+ if (typeof selectProps === "function") {
836
+ fieldResult = selectProps(formState, methods) ?? {};
837
+ } else {
838
+ const context = core.buildFieldContext(formState, fieldName);
839
+ fieldResult = core.evaluateDescriptor(selectProps, context) ?? {};
840
+ }
622
841
  }
623
- const context = core.buildFieldContext(formState, fieldName);
624
- const result = core.evaluateDescriptor(selectProps, context);
625
- return result ?? {};
626
- }, [selectProps, formState, methods, fieldName]);
842
+ return {
843
+ providerSelectProps: providerResult,
844
+ formSelectProps: formResult,
845
+ fieldSelectProps: fieldResult
846
+ };
847
+ }, [
848
+ providerDefaultFieldProps,
849
+ formDefaultFieldProps,
850
+ selectProps,
851
+ formState,
852
+ methods,
853
+ fieldName
854
+ ]);
627
855
  }
628
856
  function useSubscriptions(fieldName, subscriptions) {
629
857
  const { addSubscription, removeSubscription } = useFormContext();
630
- const prevSubscriptionsRef = react.useRef([]);
858
+ const runIdRef = react.useRef(0);
859
+ const runSubscriptionsRef = react.useRef(/* @__PURE__ */ new Map());
631
860
  react.useEffect(() => {
632
- const prevSubscriptions = prevSubscriptionsRef.current;
633
- const toRemove = prevSubscriptions.filter(
634
- (target) => !subscriptions.includes(target)
635
- );
636
- const toAdd = subscriptions.filter(
637
- (target) => !prevSubscriptions.includes(target)
638
- );
639
- toRemove.forEach((target) => {
640
- removeSubscription(target, fieldName);
641
- });
642
- toAdd.forEach((target) => {
861
+ const currentRunId = ++runIdRef.current;
862
+ runSubscriptionsRef.current.set(currentRunId, [...subscriptions]);
863
+ subscriptions.forEach((target) => {
643
864
  addSubscription(target, fieldName);
865
+ if (process.env.NODE_ENV !== "production") {
866
+ console.warn(
867
+ `[Formality Subscription] Run ${currentRunId}: "${fieldName}" subscribing to "${target}"`
868
+ );
869
+ }
644
870
  });
645
- prevSubscriptionsRef.current = subscriptions;
646
871
  return () => {
647
- subscriptions.forEach((target) => {
648
- removeSubscription(target, fieldName);
649
- });
872
+ const thisRunSubscriptions = runSubscriptionsRef.current.get(currentRunId);
873
+ if (thisRunSubscriptions) {
874
+ if (process.env.NODE_ENV !== "production") {
875
+ console.warn(
876
+ `[Formality Subscription] Run ${currentRunId}: "${fieldName}" cleaning up [${thisRunSubscriptions.join(", ")}]`
877
+ );
878
+ }
879
+ [...thisRunSubscriptions].reverse().forEach((target) => {
880
+ removeSubscription(target, fieldName);
881
+ });
882
+ runSubscriptionsRef.current.delete(currentRunId);
883
+ }
650
884
  };
651
885
  }, [fieldName, subscriptions, addSubscription, removeSubscription]);
652
886
  }
@@ -657,6 +891,7 @@ function Field({
657
891
  hidden: hiddenProp,
658
892
  children,
659
893
  shouldRegister = true,
894
+ inputConfig: inputConfigProp,
660
895
  ...restProps
661
896
  }) {
662
897
  const {
@@ -676,14 +911,23 @@ function Field({
676
911
  const type = typeProp ?? fieldConfig.type ?? "textField";
677
912
  const inputConfig = react.useMemo(() => {
678
913
  const formInputs = typeof formConfig.inputs === "function" ? formConfig.inputs(providerConfig.inputs) : formConfig.inputs ?? {};
679
- const mergedInputs = { ...providerConfig.inputs };
914
+ const mergedInputs = {
915
+ ...providerConfig.inputs
916
+ };
680
917
  for (const [key, override] of Object.entries(formInputs)) {
681
918
  if (mergedInputs[key]) {
682
- mergedInputs[key] = { ...mergedInputs[key], ...override };
919
+ mergedInputs[key] = {
920
+ ...mergedInputs[key],
921
+ ...override
922
+ };
683
923
  }
684
924
  }
685
- return core.resolveInputConfig(type, mergedInputs) ?? { component: "input", defaultValue: "" };
686
- }, [type, providerConfig.inputs, formConfig.inputs]);
925
+ const baseInputConfig = core.resolveInputConfig(type, mergedInputs) ?? {
926
+ component: "input",
927
+ defaultValue: ""
928
+ };
929
+ return inputConfigProp ? { ...baseInputConfig, ...inputConfigProp } : baseInputConfig;
930
+ }, [type, providerConfig.inputs, formConfig.inputs, inputConfigProp]);
687
931
  react.useEffect(() => {
688
932
  if (shouldRegister) {
689
933
  registerField(name);
@@ -701,13 +945,17 @@ function Field({
701
945
  subscribesTo: fieldConfig.subscribesTo
702
946
  });
703
947
  const allSubscriptions = react.useMemo(() => {
704
- return [.../* @__PURE__ */ new Set([...inferredSubscriptions, ...groupContext.subscriptions])];
948
+ return [
949
+ .../* @__PURE__ */ new Set([...inferredSubscriptions, ...groupContext.subscriptions])
950
+ ];
705
951
  }, [inferredSubscriptions, groupContext.subscriptions]);
706
952
  useSubscriptions(name, allSubscriptions);
707
953
  const conditionResult = useConditions({
708
954
  conditions: fieldConfig.conditions ?? [],
709
955
  subscribesTo: fieldConfig.subscribesTo,
710
- props: { name }
956
+ props: { name },
957
+ allFieldsConfig: config
958
+ // Pass all field configs for two-pass evaluation of disabled states
711
959
  });
712
960
  const setValueRef = react.useRef(methods.setValue);
713
961
  setValueRef.current = methods.setValue;
@@ -759,15 +1007,22 @@ function Field({
759
1007
  return conditionResult.visible ?? true;
760
1008
  if (!groupContext.state.isVisible) return false;
761
1009
  return true;
762
- }, [hiddenProp, fieldConfig.hidden, conditionResult, groupContext.state.isVisible]);
763
- const evaluatedSelectProps = usePropsEvaluation({
1010
+ }, [
1011
+ hiddenProp,
1012
+ fieldConfig.hidden,
1013
+ conditionResult,
1014
+ groupContext.state.isVisible
1015
+ ]);
1016
+ const { providerSelectProps, formSelectProps, fieldSelectProps } = usePropsEvaluation({
764
1017
  selectProps: fieldConfig.selectProps,
1018
+ formDefaultFieldProps: formConfig.selectDefaultFieldProps,
1019
+ providerDefaultFieldProps: providerConfig.selectDefaultFieldProps,
765
1020
  subscribesTo: fieldConfig.subscribesTo,
766
1021
  fieldName: name
767
1022
  });
768
1023
  const label = react.useMemo(() => {
769
- return core.resolveLabel(name, fieldConfig, evaluatedSelectProps, restProps);
770
- }, [name, fieldConfig, evaluatedSelectProps, restProps]);
1024
+ return core.resolveLabel(name, fieldConfig, fieldSelectProps, restProps);
1025
+ }, [name, fieldConfig, fieldSelectProps, restProps]);
771
1026
  const validationRules = react.useMemo(() => {
772
1027
  return {
773
1028
  ...fieldConfig.rules,
@@ -820,9 +1075,15 @@ function Field({
820
1075
  providerConfig.parsers
821
1076
  );
822
1077
  onChange(parsedValue);
823
- changeField(name, parsedValue);
1078
+ changeField(name, parsedValue, inputConfig);
824
1079
  },
825
- [inputConfig.parser, providerConfig.parsers, changeField, name]
1080
+ [
1081
+ inputConfig.parser,
1082
+ providerConfig.parsers,
1083
+ changeField,
1084
+ name,
1085
+ inputConfig
1086
+ ]
826
1087
  );
827
1088
  if (!isVisible) {
828
1089
  return null;
@@ -841,14 +1102,12 @@ function Field({
841
1102
  );
842
1103
  const finalProps = core.mergeFieldProps({
843
1104
  providerDefaultFieldProps: providerConfig.defaultFieldProps,
844
- providerSelectDefaultFieldProps: {},
845
- // Evaluated at provider level if needed
1105
+ providerSelectDefaultFieldProps: providerSelectProps,
846
1106
  formDefaultFieldProps: formConfig.defaultFieldProps,
847
- formSelectDefaultFieldProps: {},
848
- // Evaluated at form level if needed
1107
+ formSelectDefaultFieldProps: formSelectProps,
849
1108
  inputProps: inputConfig.props,
850
1109
  fieldConfigProps: fieldConfig.props,
851
- selectProps: evaluatedSelectProps,
1110
+ selectProps: fieldSelectProps,
852
1111
  componentProps: restProps,
853
1112
  coreProps: {
854
1113
  name,
@@ -1025,6 +1284,11 @@ function useFormState(options) {
1025
1284
  return result;
1026
1285
  }
1027
1286
 
1287
+ // src/overlays.ts
1288
+ function defineInputs(inputs) {
1289
+ return inputs;
1290
+ }
1291
+
1028
1292
  exports.ConfigContext = ConfigContext;
1029
1293
  exports.Field = Field;
1030
1294
  exports.FieldGroup = FieldGroup;
@@ -1033,6 +1297,7 @@ exports.FormContext = FormContext;
1033
1297
  exports.FormalityProvider = FormalityProvider;
1034
1298
  exports.GroupContext = GroupContext;
1035
1299
  exports.UnusedFields = UnusedFields;
1300
+ exports.defineInputs = defineInputs;
1036
1301
  exports.makeDeepProxyState = makeDeepProxyState;
1037
1302
  exports.makeProxyState = makeProxyState;
1038
1303
  exports.useConditions = useConditions;