@uniform-ts/core 0.0.7 → 0.0.9
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 +19 -16
- package/dist/{field-DPgaGkOL.d.mts → field-Cogi7eQc.d.mts} +62 -30
- package/dist/{field-DPgaGkOL.d.ts → field-Cogi7eQc.d.ts} +62 -30
- package/dist/index.d.mts +54 -8
- package/dist/index.d.ts +54 -8
- package/dist/index.js +418 -53
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +419 -55
- package/dist/index.mjs.map +1 -1
- package/dist/locales/en.d.mts +1 -1
- package/dist/locales/en.d.ts +1 -1
- package/dist/locales/es.d.mts +1 -1
- package/dist/locales/es.d.ts +1 -1
- package/dist/locales/he.d.mts +1 -1
- package/dist/locales/he.d.ts +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -657,6 +657,24 @@ function SelectField({
|
|
|
657
657
|
}
|
|
658
658
|
);
|
|
659
659
|
}
|
|
660
|
+
function useConditionalFields(fields, control, scopeName) {
|
|
661
|
+
const allValues = reactHookForm.useWatch({ control });
|
|
662
|
+
const scopedValues = reactHookForm.useWatch({ control, name: scopeName });
|
|
663
|
+
const values = scopeName ? scopedValues : allValues;
|
|
664
|
+
return React3.useMemo(() => {
|
|
665
|
+
return fields.filter((field) => {
|
|
666
|
+
if (field.meta.hidden) return false;
|
|
667
|
+
if (typeof field.meta.condition === "function") {
|
|
668
|
+
return field.meta.condition(values);
|
|
669
|
+
}
|
|
670
|
+
return true;
|
|
671
|
+
}).sort((a, b) => {
|
|
672
|
+
const orderA = typeof a.meta.order === "number" ? a.meta.order : Infinity;
|
|
673
|
+
const orderB = typeof b.meta.order === "number" ? b.meta.order : Infinity;
|
|
674
|
+
return orderA - orderB;
|
|
675
|
+
});
|
|
676
|
+
}, [fields, values]);
|
|
677
|
+
}
|
|
660
678
|
function ObjectField({
|
|
661
679
|
field,
|
|
662
680
|
control,
|
|
@@ -665,7 +683,7 @@ function ObjectField({
|
|
|
665
683
|
shouldUnregister
|
|
666
684
|
}) {
|
|
667
685
|
const { classNames, layout } = useAutoFormContext();
|
|
668
|
-
const children = field.children;
|
|
686
|
+
const children = useConditionalFields(field.children, control, namePrefix);
|
|
669
687
|
const content = children.map((child, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
670
688
|
FieldRenderer,
|
|
671
689
|
{
|
|
@@ -720,6 +738,124 @@ function getDefaultValue(field) {
|
|
|
720
738
|
return void 0;
|
|
721
739
|
}
|
|
722
740
|
}
|
|
741
|
+
|
|
742
|
+
// src/utils/reindexDynamicMeta.ts
|
|
743
|
+
function buildKeyPattern(arrayName) {
|
|
744
|
+
return new RegExp(`^${escapeRegExp(arrayName)}\\.(\\d+)\\.(.+)$`);
|
|
745
|
+
}
|
|
746
|
+
function escapeRegExp(str) {
|
|
747
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
748
|
+
}
|
|
749
|
+
function reindexDynamicMeta(dynamicMeta, arrayName, mutation) {
|
|
750
|
+
const pattern = buildKeyPattern(arrayName);
|
|
751
|
+
const matched = [];
|
|
752
|
+
const result = {};
|
|
753
|
+
for (const [key, value] of Object.entries(dynamicMeta)) {
|
|
754
|
+
const match = pattern.exec(key);
|
|
755
|
+
if (match) {
|
|
756
|
+
matched.push({
|
|
757
|
+
key,
|
|
758
|
+
index: parseInt(match[1], 10),
|
|
759
|
+
childField: match[2],
|
|
760
|
+
value
|
|
761
|
+
});
|
|
762
|
+
} else {
|
|
763
|
+
result[key] = value;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
if (!isValidMutation(mutation)) {
|
|
767
|
+
return dynamicMeta;
|
|
768
|
+
}
|
|
769
|
+
switch (mutation.type) {
|
|
770
|
+
case "remove":
|
|
771
|
+
applyRemove(matched, mutation.index, arrayName, result);
|
|
772
|
+
break;
|
|
773
|
+
case "move":
|
|
774
|
+
applyMove(matched, mutation.from, mutation.to, arrayName, result);
|
|
775
|
+
break;
|
|
776
|
+
case "duplicate":
|
|
777
|
+
applyDuplicate(matched, mutation.index, arrayName, result);
|
|
778
|
+
break;
|
|
779
|
+
case "add":
|
|
780
|
+
applyAdd(matched, mutation.index, arrayName, result);
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
783
|
+
return result;
|
|
784
|
+
}
|
|
785
|
+
function isValidMutation(mutation, _entries) {
|
|
786
|
+
switch (mutation.type) {
|
|
787
|
+
case "remove":
|
|
788
|
+
return mutation.index >= 0;
|
|
789
|
+
case "move":
|
|
790
|
+
return mutation.from >= 0 && mutation.to >= 0;
|
|
791
|
+
case "duplicate":
|
|
792
|
+
return mutation.index >= 0;
|
|
793
|
+
case "add":
|
|
794
|
+
return mutation.index >= 0;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
function buildKey(arrayName, index, childField) {
|
|
798
|
+
return `${arrayName}.${index}.${childField}`;
|
|
799
|
+
}
|
|
800
|
+
function applyRemove(entries, removedIndex, arrayName, result) {
|
|
801
|
+
for (const entry of entries) {
|
|
802
|
+
if (entry.index === removedIndex) {
|
|
803
|
+
continue;
|
|
804
|
+
} else if (entry.index > removedIndex) {
|
|
805
|
+
result[buildKey(arrayName, entry.index - 1, entry.childField)] = entry.value;
|
|
806
|
+
} else {
|
|
807
|
+
result[buildKey(arrayName, entry.index, entry.childField)] = entry.value;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
function applyMove(entries, from, to, arrayName, result) {
|
|
812
|
+
if (from === to) {
|
|
813
|
+
for (const entry of entries) {
|
|
814
|
+
result[buildKey(arrayName, entry.index, entry.childField)] = entry.value;
|
|
815
|
+
}
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
for (const entry of entries) {
|
|
819
|
+
let newIndex;
|
|
820
|
+
if (entry.index === from) {
|
|
821
|
+
newIndex = to;
|
|
822
|
+
} else if (from < to) {
|
|
823
|
+
if (entry.index > from && entry.index <= to) {
|
|
824
|
+
newIndex = entry.index - 1;
|
|
825
|
+
} else {
|
|
826
|
+
newIndex = entry.index;
|
|
827
|
+
}
|
|
828
|
+
} else {
|
|
829
|
+
if (entry.index >= to && entry.index < from) {
|
|
830
|
+
newIndex = entry.index + 1;
|
|
831
|
+
} else {
|
|
832
|
+
newIndex = entry.index;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
result[buildKey(arrayName, newIndex, entry.childField)] = entry.value;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
function applyDuplicate(entries, sourceIndex, arrayName, result) {
|
|
839
|
+
for (const entry of entries) {
|
|
840
|
+
if (entry.index === sourceIndex) {
|
|
841
|
+
result[buildKey(arrayName, entry.index, entry.childField)] = entry.value;
|
|
842
|
+
result[buildKey(arrayName, sourceIndex + 1, entry.childField)] = entry.value;
|
|
843
|
+
} else if (entry.index > sourceIndex) {
|
|
844
|
+
result[buildKey(arrayName, entry.index + 1, entry.childField)] = entry.value;
|
|
845
|
+
} else {
|
|
846
|
+
result[buildKey(arrayName, entry.index, entry.childField)] = entry.value;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
function applyAdd(entries, newIndex, arrayName, result) {
|
|
851
|
+
for (const entry of entries) {
|
|
852
|
+
if (entry.index >= newIndex) {
|
|
853
|
+
result[buildKey(arrayName, entry.index + 1, entry.childField)] = entry.value;
|
|
854
|
+
} else {
|
|
855
|
+
result[buildKey(arrayName, entry.index, entry.childField)] = entry.value;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
723
859
|
function getRowSummary(row, itemConfig, index, itemSummary) {
|
|
724
860
|
if (itemConfig.type === "object") {
|
|
725
861
|
for (const child of itemConfig.children) {
|
|
@@ -732,8 +868,43 @@ function getRowSummary(row, itemConfig, index, itemSummary) {
|
|
|
732
868
|
}
|
|
733
869
|
return itemSummary?.(index) ?? `Item ${index + 1}`;
|
|
734
870
|
}
|
|
871
|
+
function bindRowIndexToItemConfig(itemConfig, rowIndex) {
|
|
872
|
+
if (itemConfig.type !== "object") return itemConfig;
|
|
873
|
+
const children = itemConfig.children.map((child) => {
|
|
874
|
+
if (!child.meta.onChange) return child;
|
|
875
|
+
const originalOnChange = child.meta.onChange;
|
|
876
|
+
return {
|
|
877
|
+
...child,
|
|
878
|
+
meta: {
|
|
879
|
+
...child.meta,
|
|
880
|
+
onChange: (value, formMethods) => {
|
|
881
|
+
void originalOnChange(value, formMethods, rowIndex);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
});
|
|
886
|
+
return { ...itemConfig, children };
|
|
887
|
+
}
|
|
888
|
+
function applyRowDynamicMeta(itemConfig, rowOverrides) {
|
|
889
|
+
if (itemConfig.type !== "object") return itemConfig;
|
|
890
|
+
const children = itemConfig.children.map((child) => {
|
|
891
|
+
const override = rowOverrides[child.name];
|
|
892
|
+
if (!override) return child;
|
|
893
|
+
const { options, label, ...metaOverrides } = override;
|
|
894
|
+
let updated = {
|
|
895
|
+
...child,
|
|
896
|
+
...label !== void 0 ? { label } : {},
|
|
897
|
+
meta: { ...child.meta, ...metaOverrides }
|
|
898
|
+
};
|
|
899
|
+
if (options !== void 0 && updated.type === "select") {
|
|
900
|
+
updated = { ...updated, options };
|
|
901
|
+
}
|
|
902
|
+
return updated;
|
|
903
|
+
});
|
|
904
|
+
return { ...itemConfig, children };
|
|
905
|
+
}
|
|
735
906
|
function ArrayField({ field, control, effectiveName }) {
|
|
736
|
-
const { classNames, layout, labels } = useAutoFormContext();
|
|
907
|
+
const { classNames, layout, labels, setDynamicMeta } = useAutoFormContext();
|
|
737
908
|
const {
|
|
738
909
|
fields: rows,
|
|
739
910
|
append,
|
|
@@ -779,9 +950,10 @@ function ArrayField({ field, control, effectiveName }) {
|
|
|
779
950
|
} = layout.arrayButtons;
|
|
780
951
|
const ArrayFieldLayout = layout.arrayFieldLayout;
|
|
781
952
|
const RowLayout = layout.arrayRowLayout;
|
|
953
|
+
const rowDynamicMeta = field._rowDynamicMeta;
|
|
782
954
|
const renderedRows = rows.map((row, index) => {
|
|
783
955
|
const isCollapsed = showCollapse && collapsed.has(index);
|
|
784
|
-
const collapseButton = showCollapse ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
956
|
+
const collapseButton = showCollapse && CollapseBtn ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
785
957
|
CollapseBtn,
|
|
786
958
|
{
|
|
787
959
|
type: "button",
|
|
@@ -805,29 +977,47 @@ function ArrayField({ field, control, effectiveName }) {
|
|
|
805
977
|
]
|
|
806
978
|
}
|
|
807
979
|
) : null;
|
|
808
|
-
const moveUpButton = showMove && rows.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
980
|
+
const moveUpButton = showMove && rows.length > 1 && MoveUpBtn ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
809
981
|
MoveUpBtn,
|
|
810
982
|
{
|
|
811
983
|
type: "button",
|
|
812
984
|
className: classNames.arrayMove,
|
|
813
|
-
onClick: () =>
|
|
985
|
+
onClick: () => {
|
|
986
|
+
move(index, index - 1);
|
|
987
|
+
setDynamicMeta(
|
|
988
|
+
(prev) => reindexDynamicMeta(prev, effectiveName, {
|
|
989
|
+
type: "move",
|
|
990
|
+
from: index,
|
|
991
|
+
to: index - 1
|
|
992
|
+
})
|
|
993
|
+
);
|
|
994
|
+
},
|
|
814
995
|
disabled: index === 0,
|
|
815
996
|
"aria-label": labels.arrayAriaMoveUp?.(index) ?? `Move item ${index + 1} up`,
|
|
816
997
|
children: labels.arrayMoveUp ?? "\u2191"
|
|
817
998
|
}
|
|
818
999
|
) : null;
|
|
819
|
-
const moveDownButton = showMove && rows.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1000
|
+
const moveDownButton = showMove && rows.length > 1 && MoveDownBtn ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
820
1001
|
MoveDownBtn,
|
|
821
1002
|
{
|
|
822
1003
|
type: "button",
|
|
823
1004
|
className: classNames.arrayMove,
|
|
824
|
-
onClick: () =>
|
|
1005
|
+
onClick: () => {
|
|
1006
|
+
move(index, index + 1);
|
|
1007
|
+
setDynamicMeta(
|
|
1008
|
+
(prev) => reindexDynamicMeta(prev, effectiveName, {
|
|
1009
|
+
type: "move",
|
|
1010
|
+
from: index,
|
|
1011
|
+
to: index + 1
|
|
1012
|
+
})
|
|
1013
|
+
);
|
|
1014
|
+
},
|
|
825
1015
|
disabled: index === rows.length - 1,
|
|
826
1016
|
"aria-label": labels.arrayAriaMoveDown?.(index) ?? `Move item ${index + 1} down`,
|
|
827
1017
|
children: labels.arrayMoveDown ?? "\u2193"
|
|
828
1018
|
}
|
|
829
1019
|
) : null;
|
|
830
|
-
const duplicateButton = showDuplicate && !atMax ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1020
|
+
const duplicateButton = showDuplicate && !atMax && DuplicateBtn ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
831
1021
|
DuplicateBtn,
|
|
832
1022
|
{
|
|
833
1023
|
type: "button",
|
|
@@ -837,26 +1027,43 @@ function ArrayField({ field, control, effectiveName }) {
|
|
|
837
1027
|
Object.entries(row).filter(([k]) => k !== "id")
|
|
838
1028
|
);
|
|
839
1029
|
insert(index + 1, values);
|
|
1030
|
+
setDynamicMeta(
|
|
1031
|
+
(prev) => reindexDynamicMeta(prev, effectiveName, {
|
|
1032
|
+
type: "duplicate",
|
|
1033
|
+
index
|
|
1034
|
+
})
|
|
1035
|
+
);
|
|
840
1036
|
},
|
|
841
1037
|
"aria-label": labels.arrayAriaDuplicate?.(index) ?? `Duplicate item ${index + 1}`,
|
|
842
1038
|
children: labels.arrayDuplicate ?? "Duplicate"
|
|
843
1039
|
}
|
|
844
1040
|
) : null;
|
|
845
|
-
const removeButton = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1041
|
+
const removeButton = RemoveBtn ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
846
1042
|
RemoveBtn,
|
|
847
1043
|
{
|
|
848
1044
|
type: "button",
|
|
849
1045
|
className: classNames.arrayRemove,
|
|
850
|
-
onClick: () =>
|
|
1046
|
+
onClick: () => {
|
|
1047
|
+
remove(index);
|
|
1048
|
+
setDynamicMeta(
|
|
1049
|
+
(prev) => reindexDynamicMeta(prev, effectiveName, {
|
|
1050
|
+
type: "remove",
|
|
1051
|
+
index
|
|
1052
|
+
})
|
|
1053
|
+
);
|
|
1054
|
+
},
|
|
851
1055
|
disabled: atMin,
|
|
852
1056
|
"aria-label": labels.arrayAriaRemove?.(index) ?? `Remove item ${index + 1}`,
|
|
853
1057
|
children: labels.arrayRemove ?? "Remove"
|
|
854
1058
|
}
|
|
855
|
-
);
|
|
1059
|
+
) : null;
|
|
856
1060
|
const fieldContent = !isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
857
1061
|
FieldRenderer,
|
|
858
1062
|
{
|
|
859
|
-
field:
|
|
1063
|
+
field: bindRowIndexToItemConfig(
|
|
1064
|
+
rowDynamicMeta?.[index] ? applyRowDynamicMeta(effectiveItemConfig, rowDynamicMeta[index]) : effectiveItemConfig,
|
|
1065
|
+
index
|
|
1066
|
+
),
|
|
860
1067
|
control,
|
|
861
1068
|
namePrefix: `${effectiveName}.${index}`
|
|
862
1069
|
}
|
|
@@ -878,16 +1085,25 @@ function ArrayField({ field, control, effectiveName }) {
|
|
|
878
1085
|
row.id
|
|
879
1086
|
);
|
|
880
1087
|
});
|
|
881
|
-
const addButton = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1088
|
+
const addButton = AddBtn ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
882
1089
|
AddBtn,
|
|
883
1090
|
{
|
|
884
1091
|
type: "button",
|
|
885
1092
|
className: classNames.arrayAdd,
|
|
886
1093
|
disabled: atMax,
|
|
887
|
-
onClick: () =>
|
|
1094
|
+
onClick: () => {
|
|
1095
|
+
const newIndex = rows.length;
|
|
1096
|
+
append(getDefaultValue(itemConfig));
|
|
1097
|
+
setDynamicMeta(
|
|
1098
|
+
(prev) => reindexDynamicMeta(prev, effectiveName, {
|
|
1099
|
+
type: "add",
|
|
1100
|
+
index: newIndex
|
|
1101
|
+
})
|
|
1102
|
+
);
|
|
1103
|
+
},
|
|
888
1104
|
children: labels.arrayAdd ?? "Add"
|
|
889
1105
|
}
|
|
890
|
-
);
|
|
1106
|
+
) : null;
|
|
891
1107
|
const content = /* @__PURE__ */ jsxRuntime.jsx(
|
|
892
1108
|
ArrayFieldLayout,
|
|
893
1109
|
{
|
|
@@ -1049,22 +1265,6 @@ function FieldRenderer({
|
|
|
1049
1265
|
}
|
|
1050
1266
|
);
|
|
1051
1267
|
}
|
|
1052
|
-
function useConditionalFields(fields, control) {
|
|
1053
|
-
const values = reactHookForm.useWatch({ control });
|
|
1054
|
-
return React3.useMemo(() => {
|
|
1055
|
-
return fields.filter((field) => {
|
|
1056
|
-
if (field.meta.hidden) return false;
|
|
1057
|
-
if (typeof field.meta.condition === "function") {
|
|
1058
|
-
return field.meta.condition(values);
|
|
1059
|
-
}
|
|
1060
|
-
return true;
|
|
1061
|
-
}).sort((a, b) => {
|
|
1062
|
-
const orderA = typeof a.meta.order === "number" ? a.meta.order : Infinity;
|
|
1063
|
-
const orderB = typeof b.meta.order === "number" ? b.meta.order : Infinity;
|
|
1064
|
-
return orderA - orderB;
|
|
1065
|
-
});
|
|
1066
|
-
}, [fields, values]);
|
|
1067
|
-
}
|
|
1068
1268
|
function useSectionGrouping(fields) {
|
|
1069
1269
|
return React3.useMemo(() => {
|
|
1070
1270
|
const ungrouped = [];
|
|
@@ -1153,6 +1353,28 @@ function useLatestRef(value) {
|
|
|
1153
1353
|
return ref;
|
|
1154
1354
|
}
|
|
1155
1355
|
|
|
1356
|
+
// src/utils/createRowScopedContext.ts
|
|
1357
|
+
function createRowScopedContext(baseCtx, arrayName, rowIndex, itemFieldNames, getValues) {
|
|
1358
|
+
return {
|
|
1359
|
+
...baseCtx,
|
|
1360
|
+
getValues,
|
|
1361
|
+
setFieldMeta: (field, meta) => {
|
|
1362
|
+
const fieldStr = field;
|
|
1363
|
+
const prefix = arrayName + ".";
|
|
1364
|
+
const childName = fieldStr.startsWith(prefix) ? fieldStr.slice(prefix.length) : fieldStr;
|
|
1365
|
+
if (itemFieldNames.has(childName)) {
|
|
1366
|
+
const qualifiedKey = `${arrayName}.${rowIndex}.${childName}`;
|
|
1367
|
+
baseCtx.setFieldMeta(
|
|
1368
|
+
qualifiedKey,
|
|
1369
|
+
meta
|
|
1370
|
+
);
|
|
1371
|
+
} else {
|
|
1372
|
+
baseCtx.setFieldMeta(field, meta);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1156
1378
|
// src/utils/fieldPipeline.ts
|
|
1157
1379
|
function applyFieldOverrides(fields, overrides) {
|
|
1158
1380
|
return fields.map((field) => {
|
|
@@ -1213,10 +1435,74 @@ function injectOnChangeHandlers(fields, uniForm, ctx, handlerKeys = new Set(uniF
|
|
|
1213
1435
|
} else if (updated.type === "array") {
|
|
1214
1436
|
const prefix = field.name + ".";
|
|
1215
1437
|
const itemKeys = /* @__PURE__ */ new Set();
|
|
1438
|
+
const indexedKeys = /* @__PURE__ */ new Set();
|
|
1216
1439
|
for (const key of handlerKeys) {
|
|
1217
|
-
if (key.startsWith(prefix))
|
|
1440
|
+
if (key.startsWith(prefix)) {
|
|
1441
|
+
const remainder = key.slice(prefix.length);
|
|
1442
|
+
const indexMatch = remainder.match(/^(\d+)\.(.+)$/);
|
|
1443
|
+
if (indexMatch) {
|
|
1444
|
+
indexedKeys.add(remainder);
|
|
1445
|
+
itemKeys.add(indexMatch[2]);
|
|
1446
|
+
} else {
|
|
1447
|
+
itemKeys.add(remainder);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1218
1450
|
}
|
|
1219
|
-
if (itemKeys.size) {
|
|
1451
|
+
if (itemKeys.size && updated.itemConfig.type === "object") {
|
|
1452
|
+
const itemFieldNames = new Set(
|
|
1453
|
+
updated.itemConfig.children.map((c) => c.name)
|
|
1454
|
+
);
|
|
1455
|
+
const arrayName = field.name;
|
|
1456
|
+
const newChildren = updated.itemConfig.children.map((child) => {
|
|
1457
|
+
if (!itemKeys.has(child.name)) return child;
|
|
1458
|
+
const existingOnChange = child.meta.onChange;
|
|
1459
|
+
const rowAwareHandler = (value, formMethods, rowIndex) => {
|
|
1460
|
+
void existingOnChange?.(value, formMethods);
|
|
1461
|
+
const rowCtx = createRowScopedContext(
|
|
1462
|
+
ctx,
|
|
1463
|
+
arrayName,
|
|
1464
|
+
rowIndex,
|
|
1465
|
+
itemFieldNames,
|
|
1466
|
+
() => {
|
|
1467
|
+
const allValues = ctx.getValues();
|
|
1468
|
+
const arrayValues = allValues?.[arrayName];
|
|
1469
|
+
if (Array.isArray(arrayValues)) {
|
|
1470
|
+
return arrayValues[rowIndex] ?? {};
|
|
1471
|
+
}
|
|
1472
|
+
return {};
|
|
1473
|
+
}
|
|
1474
|
+
);
|
|
1475
|
+
void uniForm._fireHandler(
|
|
1476
|
+
`${arrayName}.${child.name}`,
|
|
1477
|
+
value,
|
|
1478
|
+
rowCtx
|
|
1479
|
+
);
|
|
1480
|
+
const indexedKey = `${rowIndex}.${child.name}`;
|
|
1481
|
+
if (indexedKeys.has(indexedKey)) {
|
|
1482
|
+
void uniForm._fireHandler(
|
|
1483
|
+
`${arrayName}.${indexedKey}`,
|
|
1484
|
+
value,
|
|
1485
|
+
rowCtx
|
|
1486
|
+
);
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
return {
|
|
1490
|
+
...child,
|
|
1491
|
+
meta: {
|
|
1492
|
+
...child.meta,
|
|
1493
|
+
// Cast to FieldMeta onChange type — ArrayField's bindRowIndexToItemConfig
|
|
1494
|
+
// will call this with the rowIndex third argument at render time.
|
|
1495
|
+
onChange: rowAwareHandler
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1498
|
+
});
|
|
1499
|
+
const newItemConfig = {
|
|
1500
|
+
...updated.itemConfig,
|
|
1501
|
+
children: newChildren
|
|
1502
|
+
};
|
|
1503
|
+
if (newItemConfig !== updated.itemConfig)
|
|
1504
|
+
updated = { ...updated, itemConfig: newItemConfig };
|
|
1505
|
+
} else if (itemKeys.size) {
|
|
1220
1506
|
const remappedUniForm = {
|
|
1221
1507
|
_getWatchedFields: () => Array.from(itemKeys),
|
|
1222
1508
|
_fireHandlers: (name, value, c) => uniForm._fireHandler(`${field.name}.${name}`, value, c)
|
|
@@ -1262,18 +1548,43 @@ function injectConditions(fields, conditions) {
|
|
|
1262
1548
|
return updated;
|
|
1263
1549
|
});
|
|
1264
1550
|
}
|
|
1551
|
+
var ROW_KEY_PATTERN = /^(.+?)\.(\d+)\.(.+)$/;
|
|
1265
1552
|
function applyDynamicMeta(fields, overrides) {
|
|
1266
1553
|
if (!Object.keys(overrides).length) return fields;
|
|
1267
1554
|
return fields.map((field) => {
|
|
1268
1555
|
const override = overrides[field.name];
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1556
|
+
let updated = field;
|
|
1557
|
+
if (override) {
|
|
1558
|
+
const { options, label, ...metaOverrides } = override;
|
|
1559
|
+
updated = {
|
|
1560
|
+
...field,
|
|
1561
|
+
...label !== void 0 ? { label } : {},
|
|
1562
|
+
...options !== void 0 ? { options } : {},
|
|
1563
|
+
meta: { ...field.meta, ...metaOverrides }
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
if (updated.type === "array") {
|
|
1567
|
+
const prefix = `${updated.name}.`;
|
|
1568
|
+
let rowDynamicMeta;
|
|
1569
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
1570
|
+
if (!key.startsWith(prefix)) continue;
|
|
1571
|
+
const match = ROW_KEY_PATTERN.exec(key);
|
|
1572
|
+
if (!match) continue;
|
|
1573
|
+
const [, matchedArrayName, indexStr, childField] = match;
|
|
1574
|
+
if (matchedArrayName !== updated.name) continue;
|
|
1575
|
+
const rowIndex = Number(indexStr);
|
|
1576
|
+
if (!rowDynamicMeta) rowDynamicMeta = {};
|
|
1577
|
+
if (!rowDynamicMeta[rowIndex]) rowDynamicMeta[rowIndex] = {};
|
|
1578
|
+
rowDynamicMeta[rowIndex][childField] = value;
|
|
1579
|
+
}
|
|
1580
|
+
if (rowDynamicMeta) {
|
|
1581
|
+
updated = {
|
|
1582
|
+
...updated,
|
|
1583
|
+
_rowDynamicMeta: rowDynamicMeta
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
return updated;
|
|
1277
1588
|
});
|
|
1278
1589
|
}
|
|
1279
1590
|
function buildDefaults(fields) {
|
|
@@ -1303,6 +1614,12 @@ function buildDefaults(fields) {
|
|
|
1303
1614
|
}
|
|
1304
1615
|
return result;
|
|
1305
1616
|
}
|
|
1617
|
+
|
|
1618
|
+
// src/utils/resolveNullableSlot.ts
|
|
1619
|
+
function resolveNullableSlot(slot, fallback) {
|
|
1620
|
+
if (slot === null) return null;
|
|
1621
|
+
return slot ?? fallback;
|
|
1622
|
+
}
|
|
1306
1623
|
function AutoForm(props) {
|
|
1307
1624
|
const {
|
|
1308
1625
|
form: uniForm,
|
|
@@ -1527,24 +1844,33 @@ function AutoForm(props) {
|
|
|
1527
1844
|
const visibleFields = useConditionalFields(fieldsWithDynamic, control);
|
|
1528
1845
|
const sections = useSectionGrouping(visibleFields);
|
|
1529
1846
|
const resolvedLayout = React3__namespace.useMemo(() => {
|
|
1530
|
-
const base =
|
|
1847
|
+
const base = resolveNullableSlot(
|
|
1848
|
+
layout?.arrayButtons?.base,
|
|
1849
|
+
DefaultArrayButton
|
|
1850
|
+
);
|
|
1531
1851
|
const slots = layout?.arrayButtons;
|
|
1532
1852
|
return {
|
|
1533
1853
|
formWrapper: layout?.formWrapper ?? DefaultFormWrapper,
|
|
1534
1854
|
sectionWrapper: layout?.sectionWrapper ?? DefaultSectionWrapper,
|
|
1535
|
-
submitButton:
|
|
1855
|
+
submitButton: resolveNullableSlot(
|
|
1856
|
+
layout?.submitButton,
|
|
1857
|
+
DefaultSubmitButton
|
|
1858
|
+
),
|
|
1536
1859
|
arrayRowLayout: layout?.arrayRowLayout ?? DefaultArrayRowLayout,
|
|
1537
1860
|
arrayFieldLayout: layout?.arrayFieldLayout ?? DefaultArrayFieldLayout,
|
|
1538
1861
|
objectWrapper: layout?.objectWrapper ?? DefaultObjectWrapper,
|
|
1539
1862
|
arrayWrapper: layout?.arrayWrapper ?? DefaultArrayWrapper,
|
|
1540
1863
|
arrayButtons: {
|
|
1541
1864
|
base,
|
|
1542
|
-
add: slots?.add
|
|
1543
|
-
remove: slots?.remove
|
|
1544
|
-
moveUp: slots?.moveUp
|
|
1545
|
-
moveDown: slots?.moveDown
|
|
1546
|
-
duplicate: slots?.duplicate
|
|
1547
|
-
collapse:
|
|
1865
|
+
add: resolveNullableSlot(slots?.add, base),
|
|
1866
|
+
remove: resolveNullableSlot(slots?.remove, base),
|
|
1867
|
+
moveUp: resolveNullableSlot(slots?.moveUp, base),
|
|
1868
|
+
moveDown: resolveNullableSlot(slots?.moveDown, base),
|
|
1869
|
+
duplicate: resolveNullableSlot(slots?.duplicate, base),
|
|
1870
|
+
collapse: resolveNullableSlot(
|
|
1871
|
+
slots?.collapse,
|
|
1872
|
+
DefaultArrayCollapseButton
|
|
1873
|
+
)
|
|
1548
1874
|
},
|
|
1549
1875
|
loadingFallback: layout?.loadingFallback ?? /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading\u2026" })
|
|
1550
1876
|
};
|
|
@@ -1566,6 +1892,7 @@ function AutoForm(props) {
|
|
|
1566
1892
|
const contextValue = React3__namespace.useMemo(
|
|
1567
1893
|
() => ({
|
|
1568
1894
|
registry,
|
|
1895
|
+
fieldConfigs: mergedFields,
|
|
1569
1896
|
fieldOverrides: fieldOverridesProp,
|
|
1570
1897
|
fieldWrapper: resolvedFieldWrapper,
|
|
1571
1898
|
layout: resolvedLayout,
|
|
@@ -1574,10 +1901,13 @@ function AutoForm(props) {
|
|
|
1574
1901
|
coercions,
|
|
1575
1902
|
messages,
|
|
1576
1903
|
labels,
|
|
1577
|
-
formMethods
|
|
1904
|
+
formMethods,
|
|
1905
|
+
control,
|
|
1906
|
+
setDynamicMeta
|
|
1578
1907
|
}),
|
|
1579
1908
|
[
|
|
1580
1909
|
registry,
|
|
1910
|
+
mergedFields,
|
|
1581
1911
|
fieldOverridesProp,
|
|
1582
1912
|
resolvedFieldWrapper,
|
|
1583
1913
|
resolvedLayout,
|
|
@@ -1586,7 +1916,9 @@ function AutoForm(props) {
|
|
|
1586
1916
|
coercions,
|
|
1587
1917
|
messages,
|
|
1588
1918
|
labels,
|
|
1589
|
-
formMethods
|
|
1919
|
+
formMethods,
|
|
1920
|
+
control,
|
|
1921
|
+
setDynamicMeta
|
|
1590
1922
|
]
|
|
1591
1923
|
);
|
|
1592
1924
|
if (isLoadingDefaults) {
|
|
@@ -1630,13 +1962,13 @@ function AutoForm(props) {
|
|
|
1630
1962
|
section.title
|
|
1631
1963
|
);
|
|
1632
1964
|
}),
|
|
1633
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1965
|
+
SubmitButton ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1634
1966
|
SubmitButton,
|
|
1635
1967
|
{
|
|
1636
1968
|
isSubmitting: formState.isSubmitting,
|
|
1637
1969
|
label: labels.submit ?? "Submit"
|
|
1638
1970
|
}
|
|
1639
|
-
)
|
|
1971
|
+
) : null
|
|
1640
1972
|
] })
|
|
1641
1973
|
}
|
|
1642
1974
|
) });
|
|
@@ -1703,6 +2035,10 @@ var UniForm = class {
|
|
|
1703
2035
|
* Replaces any previously registered handler for that field — only one
|
|
1704
2036
|
* handler per field is kept. This prevents accidental handler accumulation
|
|
1705
2037
|
* when called inside a React render cycle.
|
|
2038
|
+
*
|
|
2039
|
+
* Supports both generic array paths (`"tasks.priority"` — fires for all rows)
|
|
2040
|
+
* and indexed paths (`"tasks.0.priority"` — fires only for row 0).
|
|
2041
|
+
*
|
|
1706
2042
|
* Returns `this` for fluent chaining.
|
|
1707
2043
|
*/
|
|
1708
2044
|
setOnChange(field, handler) {
|
|
@@ -1735,6 +2071,34 @@ var UniForm = class {
|
|
|
1735
2071
|
function createForm(schema) {
|
|
1736
2072
|
return new UniForm(schema);
|
|
1737
2073
|
}
|
|
2074
|
+
function findArrayConfig(fields, name) {
|
|
2075
|
+
for (const field of fields) {
|
|
2076
|
+
if (field.name === name) {
|
|
2077
|
+
return field.type === "array" ? field : void 0;
|
|
2078
|
+
}
|
|
2079
|
+
if (field.type === "object") {
|
|
2080
|
+
const found = findArrayConfig(field.children, name);
|
|
2081
|
+
if (found) return found;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
return void 0;
|
|
2085
|
+
}
|
|
2086
|
+
function useArrayField(fieldName) {
|
|
2087
|
+
const { control, fieldConfigs } = useAutoFormContext();
|
|
2088
|
+
const result = reactHookForm.useFieldArray({ control, name: fieldName });
|
|
2089
|
+
const rowCount = result.fields.length;
|
|
2090
|
+
const config = findArrayConfig(fieldConfigs, fieldName);
|
|
2091
|
+
const minItems = config?.minItems;
|
|
2092
|
+
const maxItems = config?.maxItems;
|
|
2093
|
+
const canAdd = maxItems == null || rowCount < maxItems;
|
|
2094
|
+
const atMin = minItems != null && rowCount <= minItems;
|
|
2095
|
+
return {
|
|
2096
|
+
...result,
|
|
2097
|
+
rowCount,
|
|
2098
|
+
canAdd,
|
|
2099
|
+
atMin
|
|
2100
|
+
};
|
|
2101
|
+
}
|
|
1738
2102
|
|
|
1739
2103
|
exports.AutoForm = AutoForm;
|
|
1740
2104
|
exports.DefaultArrayButton = DefaultArrayButton;
|
|
@@ -1758,6 +2122,7 @@ exports.defaultRegistry = defaultRegistry;
|
|
|
1758
2122
|
exports.introspectObjectSchema = introspectObjectSchema;
|
|
1759
2123
|
exports.introspectSchema = introspectSchema;
|
|
1760
2124
|
exports.mergeRegistries = mergeRegistries;
|
|
2125
|
+
exports.useArrayField = useArrayField;
|
|
1761
2126
|
exports.useAutoFormContext = useAutoFormContext;
|
|
1762
2127
|
exports.useConditionalFields = useConditionalFields;
|
|
1763
2128
|
exports.useFormPersistence = useFormPersistence;
|