@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.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as z from 'zod/v4/core';
2
2
  import * as React3 from 'react';
3
3
  import { useMemo, useRef, useEffect, useCallback, useState } from 'react';
4
- import { useFormState, useWatch, useForm, useFieldArray, Controller } from 'react-hook-form';
4
+ import { useWatch, useFormState, useForm, useFieldArray, Controller } from 'react-hook-form';
5
5
  import { zodResolver } from '@hookform/resolvers/zod';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
 
@@ -635,6 +635,24 @@ function SelectField({
635
635
  }
636
636
  );
637
637
  }
638
+ function useConditionalFields(fields, control, scopeName) {
639
+ const allValues = useWatch({ control });
640
+ const scopedValues = useWatch({ control, name: scopeName });
641
+ const values = scopeName ? scopedValues : allValues;
642
+ return useMemo(() => {
643
+ return fields.filter((field) => {
644
+ if (field.meta.hidden) return false;
645
+ if (typeof field.meta.condition === "function") {
646
+ return field.meta.condition(values);
647
+ }
648
+ return true;
649
+ }).sort((a, b) => {
650
+ const orderA = typeof a.meta.order === "number" ? a.meta.order : Infinity;
651
+ const orderB = typeof b.meta.order === "number" ? b.meta.order : Infinity;
652
+ return orderA - orderB;
653
+ });
654
+ }, [fields, values]);
655
+ }
638
656
  function ObjectField({
639
657
  field,
640
658
  control,
@@ -643,7 +661,7 @@ function ObjectField({
643
661
  shouldUnregister
644
662
  }) {
645
663
  const { classNames, layout } = useAutoFormContext();
646
- const children = field.children;
664
+ const children = useConditionalFields(field.children, control, namePrefix);
647
665
  const content = children.map((child, idx) => /* @__PURE__ */ jsx(
648
666
  FieldRenderer,
649
667
  {
@@ -698,7 +716,7 @@ function getDefaultValue(field) {
698
716
  return void 0;
699
717
  }
700
718
  }
701
- function getRowSummary(row, itemConfig, index) {
719
+ function getRowSummary(row, itemConfig, index, itemSummary) {
702
720
  if (itemConfig.type === "object") {
703
721
  for (const child of itemConfig.children) {
704
722
  const key = child.name.split(".").pop() ?? child.name;
@@ -708,7 +726,7 @@ function getRowSummary(row, itemConfig, index) {
708
726
  }
709
727
  }
710
728
  }
711
- return `Item ${index + 1}`;
729
+ return itemSummary?.(index) ?? `Item ${index + 1}`;
712
730
  }
713
731
  function ArrayField({ field, control, effectiveName }) {
714
732
  const { classNames, layout, labels } = useAutoFormContext();
@@ -759,13 +777,13 @@ function ArrayField({ field, control, effectiveName }) {
759
777
  const RowLayout = layout.arrayRowLayout;
760
778
  const renderedRows = rows.map((row, index) => {
761
779
  const isCollapsed = showCollapse && collapsed.has(index);
762
- const collapseButton = showCollapse ? /* @__PURE__ */ jsxs(
780
+ const collapseButton = showCollapse && CollapseBtn ? /* @__PURE__ */ jsxs(
763
781
  CollapseBtn,
764
782
  {
765
783
  type: "button",
766
784
  className: classNames.arrayCollapse,
767
785
  onClick: () => toggleCollapse(index),
768
- "aria-label": isCollapsed ? `Expand item ${index + 1}` : `Collapse item ${index + 1}`,
786
+ "aria-label": isCollapsed ? labels.arrayAriaExpand?.(index) ?? `Expand item ${index + 1}` : labels.arrayAriaCollapse?.(index) ?? `Collapse item ${index + 1}`,
769
787
  isCollapsed,
770
788
  children: [
771
789
  isCollapsed ? labels.arrayExpand ?? "\u25BC" : labels.arrayCollapse ?? "\u25B6",
@@ -783,29 +801,29 @@ function ArrayField({ field, control, effectiveName }) {
783
801
  ]
784
802
  }
785
803
  ) : null;
786
- const moveUpButton = showMove && rows.length > 1 ? /* @__PURE__ */ jsx(
804
+ const moveUpButton = showMove && rows.length > 1 && MoveUpBtn ? /* @__PURE__ */ jsx(
787
805
  MoveUpBtn,
788
806
  {
789
807
  type: "button",
790
808
  className: classNames.arrayMove,
791
809
  onClick: () => move(index, index - 1),
792
810
  disabled: index === 0,
793
- "aria-label": `Move item ${index + 1} up`,
811
+ "aria-label": labels.arrayAriaMoveUp?.(index) ?? `Move item ${index + 1} up`,
794
812
  children: labels.arrayMoveUp ?? "\u2191"
795
813
  }
796
814
  ) : null;
797
- const moveDownButton = showMove && rows.length > 1 ? /* @__PURE__ */ jsx(
815
+ const moveDownButton = showMove && rows.length > 1 && MoveDownBtn ? /* @__PURE__ */ jsx(
798
816
  MoveDownBtn,
799
817
  {
800
818
  type: "button",
801
819
  className: classNames.arrayMove,
802
820
  onClick: () => move(index, index + 1),
803
821
  disabled: index === rows.length - 1,
804
- "aria-label": `Move item ${index + 1} down`,
822
+ "aria-label": labels.arrayAriaMoveDown?.(index) ?? `Move item ${index + 1} down`,
805
823
  children: labels.arrayMoveDown ?? "\u2193"
806
824
  }
807
825
  ) : null;
808
- const duplicateButton = showDuplicate && !atMax ? /* @__PURE__ */ jsx(
826
+ const duplicateButton = showDuplicate && !atMax && DuplicateBtn ? /* @__PURE__ */ jsx(
809
827
  DuplicateBtn,
810
828
  {
811
829
  type: "button",
@@ -816,21 +834,21 @@ function ArrayField({ field, control, effectiveName }) {
816
834
  );
817
835
  insert(index + 1, values);
818
836
  },
819
- "aria-label": `Duplicate item ${index + 1}`,
837
+ "aria-label": labels.arrayAriaDuplicate?.(index) ?? `Duplicate item ${index + 1}`,
820
838
  children: labels.arrayDuplicate ?? "Duplicate"
821
839
  }
822
840
  ) : null;
823
- const removeButton = /* @__PURE__ */ jsx(
841
+ const removeButton = RemoveBtn ? /* @__PURE__ */ jsx(
824
842
  RemoveBtn,
825
843
  {
826
844
  type: "button",
827
845
  className: classNames.arrayRemove,
828
846
  onClick: () => remove(index),
829
847
  disabled: atMin,
830
- "aria-label": `Remove item ${index + 1}`,
848
+ "aria-label": labels.arrayAriaRemove?.(index) ?? `Remove item ${index + 1}`,
831
849
  children: labels.arrayRemove ?? "Remove"
832
850
  }
833
- );
851
+ ) : null;
834
852
  const fieldContent = !isCollapsed ? /* @__PURE__ */ jsx(
835
853
  FieldRenderer,
836
854
  {
@@ -856,7 +874,7 @@ function ArrayField({ field, control, effectiveName }) {
856
874
  row.id
857
875
  );
858
876
  });
859
- const addButton = /* @__PURE__ */ jsx(
877
+ const addButton = AddBtn ? /* @__PURE__ */ jsx(
860
878
  AddBtn,
861
879
  {
862
880
  type: "button",
@@ -865,7 +883,7 @@ function ArrayField({ field, control, effectiveName }) {
865
883
  onClick: () => append(getDefaultValue(itemConfig)),
866
884
  children: labels.arrayAdd ?? "Add"
867
885
  }
868
- );
886
+ ) : null;
869
887
  const content = /* @__PURE__ */ jsx(
870
888
  ArrayFieldLayout,
871
889
  {
@@ -896,13 +914,22 @@ function CollapseSummary({
896
914
  itemConfig,
897
915
  isCollapsed
898
916
  }) {
917
+ const { labels } = useAutoFormContext();
918
+ const fallback = labels.arrayItemSummary?.(index) ?? `Item ${index + 1}`;
899
919
  const rowValues = useWatch({ control, name: `${effectiveName}.${index}` });
900
920
  const summary = useMemo(() => {
901
- if (!isCollapsed) return `Item ${index + 1}`;
902
- if (!rowValues) return `Item ${index + 1}`;
903
- return getRowSummary(rowValues, itemConfig, index);
904
- }, [isCollapsed, rowValues, itemConfig, index]);
905
- return /* @__PURE__ */ jsx(Fragment, { children: isCollapsed ? summary : `Item ${index + 1}` });
921
+ if (!isCollapsed) return fallback;
922
+ if (!rowValues) return fallback;
923
+ return getRowSummary(rowValues, itemConfig, index, labels.arrayItemSummary);
924
+ }, [
925
+ isCollapsed,
926
+ rowValues,
927
+ itemConfig,
928
+ index,
929
+ fallback,
930
+ labels.arrayItemSummary
931
+ ]);
932
+ return /* @__PURE__ */ jsx(Fragment, { children: isCollapsed ? summary : fallback });
906
933
  }
907
934
  function getEffectiveName(field, namePrefix) {
908
935
  if (!namePrefix) return field.name;
@@ -1018,22 +1045,6 @@ function FieldRenderer({
1018
1045
  }
1019
1046
  );
1020
1047
  }
1021
- function useConditionalFields(fields, control) {
1022
- const values = useWatch({ control });
1023
- return useMemo(() => {
1024
- return fields.filter((field) => {
1025
- if (field.meta.hidden) return false;
1026
- if (typeof field.meta.condition === "function") {
1027
- return field.meta.condition(values);
1028
- }
1029
- return true;
1030
- }).sort((a, b) => {
1031
- const orderA = typeof a.meta.order === "number" ? a.meta.order : Infinity;
1032
- const orderB = typeof b.meta.order === "number" ? b.meta.order : Infinity;
1033
- return orderA - orderB;
1034
- });
1035
- }, [fields, values]);
1036
- }
1037
1048
  function useSectionGrouping(fields) {
1038
1049
  return useMemo(() => {
1039
1050
  const ungrouped = [];
@@ -1272,6 +1283,12 @@ function buildDefaults(fields) {
1272
1283
  }
1273
1284
  return result;
1274
1285
  }
1286
+
1287
+ // src/utils/resolveNullableSlot.ts
1288
+ function resolveNullableSlot(slot, fallback) {
1289
+ if (slot === null) return null;
1290
+ return slot ?? fallback;
1291
+ }
1275
1292
  function AutoForm(props) {
1276
1293
  const {
1277
1294
  form: uniForm,
@@ -1496,24 +1513,33 @@ function AutoForm(props) {
1496
1513
  const visibleFields = useConditionalFields(fieldsWithDynamic, control);
1497
1514
  const sections = useSectionGrouping(visibleFields);
1498
1515
  const resolvedLayout = React3.useMemo(() => {
1499
- const base = layout?.arrayButtons?.base ?? DefaultArrayButton;
1516
+ const base = resolveNullableSlot(
1517
+ layout?.arrayButtons?.base,
1518
+ DefaultArrayButton
1519
+ );
1500
1520
  const slots = layout?.arrayButtons;
1501
1521
  return {
1502
1522
  formWrapper: layout?.formWrapper ?? DefaultFormWrapper,
1503
1523
  sectionWrapper: layout?.sectionWrapper ?? DefaultSectionWrapper,
1504
- submitButton: layout?.submitButton ?? DefaultSubmitButton,
1524
+ submitButton: resolveNullableSlot(
1525
+ layout?.submitButton,
1526
+ DefaultSubmitButton
1527
+ ),
1505
1528
  arrayRowLayout: layout?.arrayRowLayout ?? DefaultArrayRowLayout,
1506
1529
  arrayFieldLayout: layout?.arrayFieldLayout ?? DefaultArrayFieldLayout,
1507
1530
  objectWrapper: layout?.objectWrapper ?? DefaultObjectWrapper,
1508
1531
  arrayWrapper: layout?.arrayWrapper ?? DefaultArrayWrapper,
1509
1532
  arrayButtons: {
1510
1533
  base,
1511
- add: slots?.add ?? base,
1512
- remove: slots?.remove ?? base,
1513
- moveUp: slots?.moveUp ?? base,
1514
- moveDown: slots?.moveDown ?? base,
1515
- duplicate: slots?.duplicate ?? base,
1516
- collapse: slots?.collapse ?? DefaultArrayCollapseButton
1534
+ add: resolveNullableSlot(slots?.add, base),
1535
+ remove: resolveNullableSlot(slots?.remove, base),
1536
+ moveUp: resolveNullableSlot(slots?.moveUp, base),
1537
+ moveDown: resolveNullableSlot(slots?.moveDown, base),
1538
+ duplicate: resolveNullableSlot(slots?.duplicate, base),
1539
+ collapse: resolveNullableSlot(
1540
+ slots?.collapse,
1541
+ DefaultArrayCollapseButton
1542
+ )
1517
1543
  },
1518
1544
  loadingFallback: layout?.loadingFallback ?? /* @__PURE__ */ jsx("p", { children: "Loading\u2026" })
1519
1545
  };
@@ -1535,6 +1561,7 @@ function AutoForm(props) {
1535
1561
  const contextValue = React3.useMemo(
1536
1562
  () => ({
1537
1563
  registry,
1564
+ fieldConfigs: mergedFields,
1538
1565
  fieldOverrides: fieldOverridesProp,
1539
1566
  fieldWrapper: resolvedFieldWrapper,
1540
1567
  layout: resolvedLayout,
@@ -1543,10 +1570,12 @@ function AutoForm(props) {
1543
1570
  coercions,
1544
1571
  messages,
1545
1572
  labels,
1546
- formMethods
1573
+ formMethods,
1574
+ control
1547
1575
  }),
1548
1576
  [
1549
1577
  registry,
1578
+ mergedFields,
1550
1579
  fieldOverridesProp,
1551
1580
  resolvedFieldWrapper,
1552
1581
  resolvedLayout,
@@ -1555,7 +1584,8 @@ function AutoForm(props) {
1555
1584
  coercions,
1556
1585
  messages,
1557
1586
  labels,
1558
- formMethods
1587
+ formMethods,
1588
+ control
1559
1589
  ]
1560
1590
  );
1561
1591
  if (isLoadingDefaults) {
@@ -1599,13 +1629,13 @@ function AutoForm(props) {
1599
1629
  section.title
1600
1630
  );
1601
1631
  }),
1602
- /* @__PURE__ */ jsx(
1632
+ SubmitButton ? /* @__PURE__ */ jsx(
1603
1633
  SubmitButton,
1604
1634
  {
1605
1635
  isSubmitting: formState.isSubmitting,
1606
1636
  label: labels.submit ?? "Submit"
1607
1637
  }
1608
- )
1638
+ ) : null
1609
1639
  ] })
1610
1640
  }
1611
1641
  ) });
@@ -1704,7 +1734,35 @@ var UniForm = class {
1704
1734
  function createForm(schema) {
1705
1735
  return new UniForm(schema);
1706
1736
  }
1737
+ function findArrayConfig(fields, name) {
1738
+ for (const field of fields) {
1739
+ if (field.name === name) {
1740
+ return field.type === "array" ? field : void 0;
1741
+ }
1742
+ if (field.type === "object") {
1743
+ const found = findArrayConfig(field.children, name);
1744
+ if (found) return found;
1745
+ }
1746
+ }
1747
+ return void 0;
1748
+ }
1749
+ function useArrayField(fieldName) {
1750
+ const { control, fieldConfigs } = useAutoFormContext();
1751
+ const result = useFieldArray({ control, name: fieldName });
1752
+ const rowCount = result.fields.length;
1753
+ const config = findArrayConfig(fieldConfigs, fieldName);
1754
+ const minItems = config?.minItems;
1755
+ const maxItems = config?.maxItems;
1756
+ const canAdd = maxItems == null || rowCount < maxItems;
1757
+ const atMin = minItems != null && rowCount <= minItems;
1758
+ return {
1759
+ ...result,
1760
+ rowCount,
1761
+ canAdd,
1762
+ atMin
1763
+ };
1764
+ }
1707
1765
 
1708
- export { AutoForm, DefaultArrayButton, DefaultArrayCollapseButton, DefaultArrayFieldLayout, DefaultArrayRowLayout, DefaultArrayWrapper, DefaultCheckbox, DefaultFieldWrapper, DefaultInput, DefaultObjectWrapper, DefaultSelect, DefaultSubmitButton, FieldRenderer, UniForm, coerceValue, createAutoForm, createForm, defaultCoercionMap, defaultRegistry, introspectObjectSchema, introspectSchema, mergeRegistries, useAutoFormContext, useConditionalFields, useFormPersistence, useSectionGrouping };
1766
+ export { AutoForm, DefaultArrayButton, DefaultArrayCollapseButton, DefaultArrayFieldLayout, DefaultArrayRowLayout, DefaultArrayWrapper, DefaultCheckbox, DefaultFieldWrapper, DefaultInput, DefaultObjectWrapper, DefaultSelect, DefaultSubmitButton, FieldRenderer, UniForm, coerceValue, createAutoForm, createForm, defaultCoercionMap, defaultRegistry, introspectObjectSchema, introspectSchema, mergeRegistries, useArrayField, useAutoFormContext, useConditionalFields, useFormPersistence, useSectionGrouping };
1709
1767
  //# sourceMappingURL=index.mjs.map
1710
1768
  //# sourceMappingURL=index.mjs.map