@uniform-ts/core 0.0.6 → 0.0.8

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.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,7 +738,7 @@ function getDefaultValue(field) {
720
738
  return void 0;
721
739
  }
722
740
  }
723
- function getRowSummary(row, itemConfig, index) {
741
+ function getRowSummary(row, itemConfig, index, itemSummary) {
724
742
  if (itemConfig.type === "object") {
725
743
  for (const child of itemConfig.children) {
726
744
  const key = child.name.split(".").pop() ?? child.name;
@@ -730,7 +748,7 @@ function getRowSummary(row, itemConfig, index) {
730
748
  }
731
749
  }
732
750
  }
733
- return `Item ${index + 1}`;
751
+ return itemSummary?.(index) ?? `Item ${index + 1}`;
734
752
  }
735
753
  function ArrayField({ field, control, effectiveName }) {
736
754
  const { classNames, layout, labels } = useAutoFormContext();
@@ -781,13 +799,13 @@ function ArrayField({ field, control, effectiveName }) {
781
799
  const RowLayout = layout.arrayRowLayout;
782
800
  const renderedRows = rows.map((row, index) => {
783
801
  const isCollapsed = showCollapse && collapsed.has(index);
784
- const collapseButton = showCollapse ? /* @__PURE__ */ jsxRuntime.jsxs(
802
+ const collapseButton = showCollapse && CollapseBtn ? /* @__PURE__ */ jsxRuntime.jsxs(
785
803
  CollapseBtn,
786
804
  {
787
805
  type: "button",
788
806
  className: classNames.arrayCollapse,
789
807
  onClick: () => toggleCollapse(index),
790
- "aria-label": isCollapsed ? `Expand item ${index + 1}` : `Collapse item ${index + 1}`,
808
+ "aria-label": isCollapsed ? labels.arrayAriaExpand?.(index) ?? `Expand item ${index + 1}` : labels.arrayAriaCollapse?.(index) ?? `Collapse item ${index + 1}`,
791
809
  isCollapsed,
792
810
  children: [
793
811
  isCollapsed ? labels.arrayExpand ?? "\u25BC" : labels.arrayCollapse ?? "\u25B6",
@@ -805,29 +823,29 @@ function ArrayField({ field, control, effectiveName }) {
805
823
  ]
806
824
  }
807
825
  ) : null;
808
- const moveUpButton = showMove && rows.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
826
+ const moveUpButton = showMove && rows.length > 1 && MoveUpBtn ? /* @__PURE__ */ jsxRuntime.jsx(
809
827
  MoveUpBtn,
810
828
  {
811
829
  type: "button",
812
830
  className: classNames.arrayMove,
813
831
  onClick: () => move(index, index - 1),
814
832
  disabled: index === 0,
815
- "aria-label": `Move item ${index + 1} up`,
833
+ "aria-label": labels.arrayAriaMoveUp?.(index) ?? `Move item ${index + 1} up`,
816
834
  children: labels.arrayMoveUp ?? "\u2191"
817
835
  }
818
836
  ) : null;
819
- const moveDownButton = showMove && rows.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
837
+ const moveDownButton = showMove && rows.length > 1 && MoveDownBtn ? /* @__PURE__ */ jsxRuntime.jsx(
820
838
  MoveDownBtn,
821
839
  {
822
840
  type: "button",
823
841
  className: classNames.arrayMove,
824
842
  onClick: () => move(index, index + 1),
825
843
  disabled: index === rows.length - 1,
826
- "aria-label": `Move item ${index + 1} down`,
844
+ "aria-label": labels.arrayAriaMoveDown?.(index) ?? `Move item ${index + 1} down`,
827
845
  children: labels.arrayMoveDown ?? "\u2193"
828
846
  }
829
847
  ) : null;
830
- const duplicateButton = showDuplicate && !atMax ? /* @__PURE__ */ jsxRuntime.jsx(
848
+ const duplicateButton = showDuplicate && !atMax && DuplicateBtn ? /* @__PURE__ */ jsxRuntime.jsx(
831
849
  DuplicateBtn,
832
850
  {
833
851
  type: "button",
@@ -838,21 +856,21 @@ function ArrayField({ field, control, effectiveName }) {
838
856
  );
839
857
  insert(index + 1, values);
840
858
  },
841
- "aria-label": `Duplicate item ${index + 1}`,
859
+ "aria-label": labels.arrayAriaDuplicate?.(index) ?? `Duplicate item ${index + 1}`,
842
860
  children: labels.arrayDuplicate ?? "Duplicate"
843
861
  }
844
862
  ) : null;
845
- const removeButton = /* @__PURE__ */ jsxRuntime.jsx(
863
+ const removeButton = RemoveBtn ? /* @__PURE__ */ jsxRuntime.jsx(
846
864
  RemoveBtn,
847
865
  {
848
866
  type: "button",
849
867
  className: classNames.arrayRemove,
850
868
  onClick: () => remove(index),
851
869
  disabled: atMin,
852
- "aria-label": `Remove item ${index + 1}`,
870
+ "aria-label": labels.arrayAriaRemove?.(index) ?? `Remove item ${index + 1}`,
853
871
  children: labels.arrayRemove ?? "Remove"
854
872
  }
855
- );
873
+ ) : null;
856
874
  const fieldContent = !isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(
857
875
  FieldRenderer,
858
876
  {
@@ -878,7 +896,7 @@ function ArrayField({ field, control, effectiveName }) {
878
896
  row.id
879
897
  );
880
898
  });
881
- const addButton = /* @__PURE__ */ jsxRuntime.jsx(
899
+ const addButton = AddBtn ? /* @__PURE__ */ jsxRuntime.jsx(
882
900
  AddBtn,
883
901
  {
884
902
  type: "button",
@@ -887,7 +905,7 @@ function ArrayField({ field, control, effectiveName }) {
887
905
  onClick: () => append(getDefaultValue(itemConfig)),
888
906
  children: labels.arrayAdd ?? "Add"
889
907
  }
890
- );
908
+ ) : null;
891
909
  const content = /* @__PURE__ */ jsxRuntime.jsx(
892
910
  ArrayFieldLayout,
893
911
  {
@@ -918,13 +936,22 @@ function CollapseSummary({
918
936
  itemConfig,
919
937
  isCollapsed
920
938
  }) {
939
+ const { labels } = useAutoFormContext();
940
+ const fallback = labels.arrayItemSummary?.(index) ?? `Item ${index + 1}`;
921
941
  const rowValues = reactHookForm.useWatch({ control, name: `${effectiveName}.${index}` });
922
942
  const summary = React3.useMemo(() => {
923
- if (!isCollapsed) return `Item ${index + 1}`;
924
- if (!rowValues) return `Item ${index + 1}`;
925
- return getRowSummary(rowValues, itemConfig, index);
926
- }, [isCollapsed, rowValues, itemConfig, index]);
927
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: isCollapsed ? summary : `Item ${index + 1}` });
943
+ if (!isCollapsed) return fallback;
944
+ if (!rowValues) return fallback;
945
+ return getRowSummary(rowValues, itemConfig, index, labels.arrayItemSummary);
946
+ }, [
947
+ isCollapsed,
948
+ rowValues,
949
+ itemConfig,
950
+ index,
951
+ fallback,
952
+ labels.arrayItemSummary
953
+ ]);
954
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: isCollapsed ? summary : fallback });
928
955
  }
929
956
  function getEffectiveName(field, namePrefix) {
930
957
  if (!namePrefix) return field.name;
@@ -1040,22 +1067,6 @@ function FieldRenderer({
1040
1067
  }
1041
1068
  );
1042
1069
  }
1043
- function useConditionalFields(fields, control) {
1044
- const values = reactHookForm.useWatch({ control });
1045
- return React3.useMemo(() => {
1046
- return fields.filter((field) => {
1047
- if (field.meta.hidden) return false;
1048
- if (typeof field.meta.condition === "function") {
1049
- return field.meta.condition(values);
1050
- }
1051
- return true;
1052
- }).sort((a, b) => {
1053
- const orderA = typeof a.meta.order === "number" ? a.meta.order : Infinity;
1054
- const orderB = typeof b.meta.order === "number" ? b.meta.order : Infinity;
1055
- return orderA - orderB;
1056
- });
1057
- }, [fields, values]);
1058
- }
1059
1070
  function useSectionGrouping(fields) {
1060
1071
  return React3.useMemo(() => {
1061
1072
  const ungrouped = [];
@@ -1294,6 +1305,12 @@ function buildDefaults(fields) {
1294
1305
  }
1295
1306
  return result;
1296
1307
  }
1308
+
1309
+ // src/utils/resolveNullableSlot.ts
1310
+ function resolveNullableSlot(slot, fallback) {
1311
+ if (slot === null) return null;
1312
+ return slot ?? fallback;
1313
+ }
1297
1314
  function AutoForm(props) {
1298
1315
  const {
1299
1316
  form: uniForm,
@@ -1518,24 +1535,33 @@ function AutoForm(props) {
1518
1535
  const visibleFields = useConditionalFields(fieldsWithDynamic, control);
1519
1536
  const sections = useSectionGrouping(visibleFields);
1520
1537
  const resolvedLayout = React3__namespace.useMemo(() => {
1521
- const base = layout?.arrayButtons?.base ?? DefaultArrayButton;
1538
+ const base = resolveNullableSlot(
1539
+ layout?.arrayButtons?.base,
1540
+ DefaultArrayButton
1541
+ );
1522
1542
  const slots = layout?.arrayButtons;
1523
1543
  return {
1524
1544
  formWrapper: layout?.formWrapper ?? DefaultFormWrapper,
1525
1545
  sectionWrapper: layout?.sectionWrapper ?? DefaultSectionWrapper,
1526
- submitButton: layout?.submitButton ?? DefaultSubmitButton,
1546
+ submitButton: resolveNullableSlot(
1547
+ layout?.submitButton,
1548
+ DefaultSubmitButton
1549
+ ),
1527
1550
  arrayRowLayout: layout?.arrayRowLayout ?? DefaultArrayRowLayout,
1528
1551
  arrayFieldLayout: layout?.arrayFieldLayout ?? DefaultArrayFieldLayout,
1529
1552
  objectWrapper: layout?.objectWrapper ?? DefaultObjectWrapper,
1530
1553
  arrayWrapper: layout?.arrayWrapper ?? DefaultArrayWrapper,
1531
1554
  arrayButtons: {
1532
1555
  base,
1533
- add: slots?.add ?? base,
1534
- remove: slots?.remove ?? base,
1535
- moveUp: slots?.moveUp ?? base,
1536
- moveDown: slots?.moveDown ?? base,
1537
- duplicate: slots?.duplicate ?? base,
1538
- collapse: slots?.collapse ?? DefaultArrayCollapseButton
1556
+ add: resolveNullableSlot(slots?.add, base),
1557
+ remove: resolveNullableSlot(slots?.remove, base),
1558
+ moveUp: resolveNullableSlot(slots?.moveUp, base),
1559
+ moveDown: resolveNullableSlot(slots?.moveDown, base),
1560
+ duplicate: resolveNullableSlot(slots?.duplicate, base),
1561
+ collapse: resolveNullableSlot(
1562
+ slots?.collapse,
1563
+ DefaultArrayCollapseButton
1564
+ )
1539
1565
  },
1540
1566
  loadingFallback: layout?.loadingFallback ?? /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading\u2026" })
1541
1567
  };
@@ -1557,6 +1583,7 @@ function AutoForm(props) {
1557
1583
  const contextValue = React3__namespace.useMemo(
1558
1584
  () => ({
1559
1585
  registry,
1586
+ fieldConfigs: mergedFields,
1560
1587
  fieldOverrides: fieldOverridesProp,
1561
1588
  fieldWrapper: resolvedFieldWrapper,
1562
1589
  layout: resolvedLayout,
@@ -1565,10 +1592,12 @@ function AutoForm(props) {
1565
1592
  coercions,
1566
1593
  messages,
1567
1594
  labels,
1568
- formMethods
1595
+ formMethods,
1596
+ control
1569
1597
  }),
1570
1598
  [
1571
1599
  registry,
1600
+ mergedFields,
1572
1601
  fieldOverridesProp,
1573
1602
  resolvedFieldWrapper,
1574
1603
  resolvedLayout,
@@ -1577,7 +1606,8 @@ function AutoForm(props) {
1577
1606
  coercions,
1578
1607
  messages,
1579
1608
  labels,
1580
- formMethods
1609
+ formMethods,
1610
+ control
1581
1611
  ]
1582
1612
  );
1583
1613
  if (isLoadingDefaults) {
@@ -1621,13 +1651,13 @@ function AutoForm(props) {
1621
1651
  section.title
1622
1652
  );
1623
1653
  }),
1624
- /* @__PURE__ */ jsxRuntime.jsx(
1654
+ SubmitButton ? /* @__PURE__ */ jsxRuntime.jsx(
1625
1655
  SubmitButton,
1626
1656
  {
1627
1657
  isSubmitting: formState.isSubmitting,
1628
1658
  label: labels.submit ?? "Submit"
1629
1659
  }
1630
- )
1660
+ ) : null
1631
1661
  ] })
1632
1662
  }
1633
1663
  ) });
@@ -1726,6 +1756,34 @@ var UniForm = class {
1726
1756
  function createForm(schema) {
1727
1757
  return new UniForm(schema);
1728
1758
  }
1759
+ function findArrayConfig(fields, name) {
1760
+ for (const field of fields) {
1761
+ if (field.name === name) {
1762
+ return field.type === "array" ? field : void 0;
1763
+ }
1764
+ if (field.type === "object") {
1765
+ const found = findArrayConfig(field.children, name);
1766
+ if (found) return found;
1767
+ }
1768
+ }
1769
+ return void 0;
1770
+ }
1771
+ function useArrayField(fieldName) {
1772
+ const { control, fieldConfigs } = useAutoFormContext();
1773
+ const result = reactHookForm.useFieldArray({ control, name: fieldName });
1774
+ const rowCount = result.fields.length;
1775
+ const config = findArrayConfig(fieldConfigs, fieldName);
1776
+ const minItems = config?.minItems;
1777
+ const maxItems = config?.maxItems;
1778
+ const canAdd = maxItems == null || rowCount < maxItems;
1779
+ const atMin = minItems != null && rowCount <= minItems;
1780
+ return {
1781
+ ...result,
1782
+ rowCount,
1783
+ canAdd,
1784
+ atMin
1785
+ };
1786
+ }
1729
1787
 
1730
1788
  exports.AutoForm = AutoForm;
1731
1789
  exports.DefaultArrayButton = DefaultArrayButton;
@@ -1749,6 +1807,7 @@ exports.defaultRegistry = defaultRegistry;
1749
1807
  exports.introspectObjectSchema = introspectObjectSchema;
1750
1808
  exports.introspectSchema = introspectSchema;
1751
1809
  exports.mergeRegistries = mergeRegistries;
1810
+ exports.useArrayField = useArrayField;
1752
1811
  exports.useAutoFormContext = useAutoFormContext;
1753
1812
  exports.useConditionalFields = useConditionalFields;
1754
1813
  exports.useFormPersistence = useFormPersistence;