@bsol-oss/react-datatable5 12.0.0-beta.73 → 12.0.0-beta.75

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.
Files changed (84) hide show
  1. package/dist/index.d.ts +133 -124
  2. package/dist/index.js +651 -306
  3. package/dist/index.mjs +653 -309
  4. package/dist/types/components/Form/SchemaFormContext.d.ts +5 -2
  5. package/dist/types/components/Form/components/core/FormRoot.d.ts +2 -1
  6. package/dist/types/components/Form/components/fields/BooleanPicker.d.ts +1 -1
  7. package/dist/types/components/Form/components/fields/ColumnRenderer.d.ts +3 -2
  8. package/dist/types/components/Form/components/fields/DateTimePicker.d.ts +1 -1
  9. package/dist/types/components/Form/components/fields/FilePicker.d.ts +1 -1
  10. package/dist/types/components/Form/components/fields/NumberInputField.d.ts +1 -1
  11. package/dist/types/components/Form/components/fields/ObjectInput.d.ts +1 -1
  12. package/dist/types/components/Form/components/fields/RecordInput.d.ts +1 -1
  13. package/dist/types/components/Form/components/fields/StringInputField.d.ts +1 -1
  14. package/dist/types/components/Form/components/fields/TextAreaInput.d.ts +1 -1
  15. package/dist/types/components/Form/components/fields/TimePicker.d.ts +1 -1
  16. package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +4 -0
  17. package/dist/types/components/Form/components/viewers/NumberViewer.d.ts +1 -1
  18. package/dist/types/components/Form/useForm.d.ts +4 -2
  19. package/dist/types/components/Form/utils/ajvResolver.d.ts +13 -0
  20. package/dist/types/components/Form/utils/buildErrorMessages.d.ts +5 -1
  21. package/dist/types/components/Form/utils/getFieldError.d.ts +6 -0
  22. package/dist/types/components/Form/utils/useFormI18n.d.ts +1 -1
  23. package/dist/types/components/Form/utils/validateData.d.ts +2 -2
  24. package/dist/types/components/ui/field.d.ts +3 -3
  25. package/package.json +1 -1
  26. package/dist/types/components/Controls/DensityFeature.d.ts +0 -23
  27. package/dist/types/components/Controls/DensityToggleButton.d.ts +0 -6
  28. package/dist/types/components/Controls/EditFilterButton.d.ts +0 -9
  29. package/dist/types/components/Controls/EditOrderButton.d.ts +0 -7
  30. package/dist/types/components/Controls/EditSortingButton.d.ts +0 -7
  31. package/dist/types/components/Controls/EditViewButton.d.ts +0 -7
  32. package/dist/types/components/Controls/FilterDialog.d.ts +0 -5
  33. package/dist/types/components/Controls/PageSizeControl.d.ts +0 -4
  34. package/dist/types/components/Controls/Pagination.d.ts +0 -1
  35. package/dist/types/components/Controls/ResetFilteringButton.d.ts +0 -4
  36. package/dist/types/components/Controls/ResetSelectionButton.d.ts +0 -4
  37. package/dist/types/components/Controls/ResetSortingButton.d.ts +0 -4
  38. package/dist/types/components/Controls/RowCountText.d.ts +0 -1
  39. package/dist/types/components/Controls/SelectAllRowsToggle.d.ts +0 -8
  40. package/dist/types/components/Controls/TablePagination.d.ts +0 -1
  41. package/dist/types/components/Controls/ViewDialog.d.ts +0 -5
  42. package/dist/types/components/DataTable/CardHeader.d.ts +0 -13
  43. package/dist/types/components/DataTable/DataDisplay.d.ts +0 -6
  44. package/dist/types/components/DataTable/ReloadButton.d.ts +0 -5
  45. package/dist/types/components/DataTable/Table.d.ts +0 -10
  46. package/dist/types/components/DataTable/TableBody.d.ts +0 -21
  47. package/dist/types/components/DataTable/TableCardContainer.d.ts +0 -7
  48. package/dist/types/components/DataTable/TableCards.d.ts +0 -11
  49. package/dist/types/components/DataTable/TableComponent.d.ts +0 -6
  50. package/dist/types/components/DataTable/TableControls.d.ts +0 -21
  51. package/dist/types/components/DataTable/TableFilter.d.ts +0 -1
  52. package/dist/types/components/DataTable/TableFilterTags.d.ts +0 -1
  53. package/dist/types/components/DataTable/TableFilters.d.ts +0 -1
  54. package/dist/types/components/DataTable/TableFooter.d.ts +0 -9
  55. package/dist/types/components/DataTable/TableHeader.d.ts +0 -13
  56. package/dist/types/components/DataTable/TableLoadingComponent.d.ts +0 -5
  57. package/dist/types/components/DataTable/TableOrderer.d.ts +0 -1
  58. package/dist/types/components/DataTable/TableSelector.d.ts +0 -1
  59. package/dist/types/components/DataTable/TableSorter.d.ts +0 -1
  60. package/dist/types/components/DataTable/TableViewer.d.ts +0 -1
  61. package/dist/types/components/DataTable/TextCell.d.ts +0 -10
  62. package/dist/types/components/DataTable/components/EmptyState.d.ts +0 -5
  63. package/dist/types/components/DataTable/components/ErrorAlert.d.ts +0 -4
  64. package/dist/types/components/DataTable/components/RecordDisplay.d.ts +0 -9
  65. package/dist/types/components/DataTable/components/TextCell.d.ts +0 -10
  66. package/dist/types/components/Filter/DateRangeFilter.d.ts +0 -9
  67. package/dist/types/components/Filter/FilterOptions.d.ts +0 -4
  68. package/dist/types/components/Form/Form.d.ts +0 -36
  69. package/dist/types/components/Form/components/ArrayRenderer.d.ts +0 -7
  70. package/dist/types/components/Form/components/BooleanPicker.d.ts +0 -7
  71. package/dist/types/components/Form/components/ColumnRenderer.d.ts +0 -7
  72. package/dist/types/components/Form/components/DatePicker.d.ts +0 -7
  73. package/dist/types/components/Form/components/EnumPicker.d.ts +0 -8
  74. package/dist/types/components/Form/components/FilePicker.d.ts +0 -5
  75. package/dist/types/components/Form/components/IdPicker.d.ts +0 -8
  76. package/dist/types/components/Form/components/IdViewer.d.ts +0 -5
  77. package/dist/types/components/Form/components/NumberInputField.d.ts +0 -7
  78. package/dist/types/components/Form/components/ObjectInput.d.ts +0 -7
  79. package/dist/types/components/Form/components/RecordInput.d.ts +0 -7
  80. package/dist/types/components/Form/components/SchemaRenderer.d.ts +0 -7
  81. package/dist/types/components/Form/components/StringInputField.d.ts +0 -20
  82. package/dist/types/components/Form/components/TagPicker.d.ts +0 -30
  83. package/dist/types/components/Form/utils/translateWrapper.d.ts +0 -6
  84. package/dist/types/components/Form/utils/validation.d.ts +0 -104
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, Image, EmptyState as EmptyState$2, VStack, Alert, Card, Group, InputElement, Tooltip as Tooltip$1, Icon, List, Table as Table$1, Checkbox as Checkbox$1, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Accordion, Field as Field$1, Popover, NumberInput, Show, RadioCard, CheckboxGroup, Center, Heading } from '@chakra-ui/react';
2
+ import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, Image, EmptyState as EmptyState$2, VStack, Alert, Card, Group, InputElement, Tooltip as Tooltip$1, Icon, List, Table as Table$1, Checkbox as Checkbox$1, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Field as Field$1, Popover, NumberInput, Show, RadioCard, CheckboxGroup, Center, Heading } from '@chakra-ui/react';
3
3
  import { AiOutlineColumnWidth } from 'react-icons/ai';
4
4
  import * as React from 'react';
5
5
  import React__default, { createContext, useContext, useState, useEffect, useRef, forwardRef } from 'react';
6
- import { LuX, LuCheck, LuChevronRight, LuChevronDown } from 'react-icons/lu';
6
+ import { LuX, LuCheck, LuChevronRight } from 'react-icons/lu';
7
7
  import { MdOutlineSort, MdFilterAlt, MdSearch, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdClear, MdOutlineChecklist, MdDateRange } from 'react-icons/md';
8
8
  import { FaUpDown, FaGripLinesVertical, FaTrash } from 'react-icons/fa6';
9
9
  import { BiDownArrow, BiUpArrow, BiError } from 'react-icons/bi';
@@ -30,7 +30,6 @@ import axios from 'axios';
30
30
  import { FormProvider, useFormContext, useForm as useForm$1 } from 'react-hook-form';
31
31
  import Ajv from 'ajv';
32
32
  import addFormats from 'ajv-formats';
33
- import addErrors from 'ajv-errors';
34
33
  import dayjs from 'dayjs';
35
34
  import utc from 'dayjs/plugin/utc';
36
35
  import timezone from 'dayjs/plugin/timezone';
@@ -3644,16 +3643,6 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
3644
3643
  })] }));
3645
3644
  };
3646
3645
 
3647
- const AccordionItemTrigger = React.forwardRef(function AccordionItemTrigger(props, ref) {
3648
- const { children, indicatorPlacement = "end", ...rest } = props;
3649
- return (jsxs(Accordion.ItemTrigger, { ...rest, ref: ref, children: [indicatorPlacement === "start" && (jsx(Accordion.ItemIndicator, { rotate: { base: "-90deg", _open: "0deg" }, children: jsx(LuChevronDown, {}) })), jsx(HStack, { gap: "4", flex: "1", textAlign: "start", width: "full", children: children }), indicatorPlacement === "end" && (jsx(Accordion.ItemIndicator, { children: jsx(LuChevronDown, {}) }))] }));
3650
- });
3651
- const AccordionItemContent = React.forwardRef(function AccordionItemContent(props, ref) {
3652
- return (jsx(Accordion.ItemContent, { children: jsx(Accordion.ItemBody, { ...props, ref: ref }) }));
3653
- });
3654
- const AccordionRoot = Accordion.Root;
3655
- const AccordionItem = Accordion.Item;
3656
-
3657
3646
  //@ts-expect-error TODO: find appropriate type
3658
3647
  const SchemaFormContext = createContext({
3659
3648
  schema: {},
@@ -3671,6 +3660,9 @@ const SchemaFormContext = createContext({
3671
3660
  showResetButton: true,
3672
3661
  showTitle: true,
3673
3662
  },
3663
+ requireConfirmation: false,
3664
+ onFormSubmit: async () => { },
3665
+ ajvResolver: async () => ({ values: {}, errors: {} }),
3674
3666
  });
3675
3667
 
3676
3668
  const useSchemaContext = () => {
@@ -3687,7 +3679,6 @@ const validateData = (data, schema) => {
3687
3679
  allErrors: true,
3688
3680
  });
3689
3681
  addFormats(ajv);
3690
- addErrors(ajv);
3691
3682
  const validate = ajv.compile(schema);
3692
3683
  const validationResult = validate(data);
3693
3684
  const errors = validate.errors;
@@ -3699,6 +3690,185 @@ const validateData = (data, schema) => {
3699
3690
  };
3700
3691
  };
3701
3692
 
3693
+ /**
3694
+ * Gets the schema node for a field by following the path from root schema
3695
+ */
3696
+ const getSchemaNodeForField = (schema, fieldPath) => {
3697
+ if (!fieldPath || fieldPath === '') {
3698
+ return schema;
3699
+ }
3700
+ const pathParts = fieldPath.split('.');
3701
+ let currentSchema = schema;
3702
+ for (const part of pathParts) {
3703
+ if (currentSchema &&
3704
+ currentSchema.properties &&
3705
+ currentSchema.properties[part] &&
3706
+ typeof currentSchema.properties[part] === 'object' &&
3707
+ currentSchema.properties[part] !== null) {
3708
+ currentSchema = currentSchema.properties[part];
3709
+ }
3710
+ else {
3711
+ return undefined;
3712
+ }
3713
+ }
3714
+ return currentSchema;
3715
+ };
3716
+ /**
3717
+ * Converts AJV error objects to react-hook-form field errors format
3718
+ */
3719
+ const convertAjvErrorsToFieldErrors = (errors, schema) => {
3720
+ if (!errors || errors.length === 0) {
3721
+ return {};
3722
+ }
3723
+ const fieldErrors = {};
3724
+ errors.forEach((error) => {
3725
+ let fieldName = '';
3726
+ // Special handling for required keyword: map to the specific missing property
3727
+ if (error.keyword === 'required') {
3728
+ const basePath = (error.instancePath || '')
3729
+ .replace(/^\//, '')
3730
+ .replace(/\//g, '.');
3731
+ const missingProperty = (error.params &&
3732
+ error.params.missingProperty);
3733
+ if (missingProperty) {
3734
+ fieldName = basePath
3735
+ ? `${basePath}.${missingProperty}`
3736
+ : missingProperty;
3737
+ }
3738
+ else {
3739
+ // Fallback to schemaPath conversion if missingProperty is unavailable
3740
+ fieldName = (error.schemaPath || '')
3741
+ .replace(/^#\//, '#.')
3742
+ .replace(/\//g, '.');
3743
+ }
3744
+ }
3745
+ else {
3746
+ const fieldPath = error.instancePath || error.schemaPath;
3747
+ if (fieldPath) {
3748
+ fieldName = fieldPath.replace(/^\//, '').replace(/\//g, '.');
3749
+ }
3750
+ }
3751
+ if (fieldName) {
3752
+ // Get the schema node for this field to check for custom error messages
3753
+ const fieldSchema = getSchemaNodeForField(schema, fieldName);
3754
+ const customMessage = fieldSchema?.errorMessages?.[error.keyword];
3755
+ // Provide helpful fallback message if no custom message is provided
3756
+ const fallbackMessage = customMessage ||
3757
+ `Missing error message for ${error.keyword}. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`;
3758
+ if (error.keyword === 'required') {
3759
+ // Required errors override any existing non-required errors for this field
3760
+ fieldErrors[fieldName] = {
3761
+ type: 'required',
3762
+ keyword: error.keyword,
3763
+ params: error.params,
3764
+ message: fallbackMessage,
3765
+ };
3766
+ }
3767
+ else {
3768
+ const existing = fieldErrors[fieldName];
3769
+ if (existing) {
3770
+ // Do not override required errors
3771
+ if (existing.type === 'required') {
3772
+ return;
3773
+ }
3774
+ // Combine messages if multiple errors for same field
3775
+ existing.message = existing.message
3776
+ ? `${existing.message}; ${fallbackMessage}`
3777
+ : fallbackMessage;
3778
+ }
3779
+ else {
3780
+ fieldErrors[fieldName] = {
3781
+ type: error.keyword,
3782
+ keyword: error.keyword,
3783
+ params: error.params,
3784
+ message: fallbackMessage,
3785
+ };
3786
+ }
3787
+ }
3788
+ }
3789
+ });
3790
+ return fieldErrors;
3791
+ };
3792
+ /**
3793
+ * AJV resolver for react-hook-form
3794
+ * Integrates AJV validation with react-hook-form's validation system
3795
+ */
3796
+ /**
3797
+ * Strips null, undefined, and empty string values from an object
3798
+ */
3799
+ const stripEmptyValues = (obj) => {
3800
+ if (obj === null || obj === undefined) {
3801
+ return undefined;
3802
+ }
3803
+ if (typeof obj === 'string' && obj.trim() === '') {
3804
+ return undefined;
3805
+ }
3806
+ if (Array.isArray(obj)) {
3807
+ const filtered = obj
3808
+ .map(stripEmptyValues)
3809
+ .filter((item) => item !== undefined);
3810
+ return filtered.length > 0 ? filtered : undefined;
3811
+ }
3812
+ if (typeof obj === 'object' && obj !== null) {
3813
+ const result = {};
3814
+ let hasValues = false;
3815
+ for (const [key, value] of Object.entries(obj)) {
3816
+ const cleanedValue = stripEmptyValues(value);
3817
+ if (cleanedValue !== undefined) {
3818
+ result[key] = cleanedValue;
3819
+ hasValues = true;
3820
+ }
3821
+ }
3822
+ return hasValues ? result : undefined;
3823
+ }
3824
+ return obj;
3825
+ };
3826
+ const ajvResolver = (schema) => {
3827
+ return async (values) => {
3828
+ try {
3829
+ // Strip empty values before validation
3830
+ const cleanedValues = stripEmptyValues(values);
3831
+ // Use empty object for validation if all values were stripped
3832
+ const valuesToValidate = cleanedValues === undefined ? {} : cleanedValues;
3833
+ const { isValid, errors } = validateData(valuesToValidate, schema);
3834
+ console.debug('AJV Validation Result:', {
3835
+ isValid,
3836
+ errors,
3837
+ cleanedValues,
3838
+ valuesToValidate,
3839
+ });
3840
+ if (isValid) {
3841
+ return {
3842
+ values: (cleanedValues || {}),
3843
+ errors: {},
3844
+ };
3845
+ }
3846
+ const fieldErrors = convertAjvErrorsToFieldErrors(errors, schema);
3847
+ console.debug('AJV Validation Failed:', {
3848
+ errors,
3849
+ fieldErrors,
3850
+ cleanedValues,
3851
+ valuesToValidate,
3852
+ });
3853
+ return {
3854
+ values: {},
3855
+ errors: fieldErrors,
3856
+ };
3857
+ }
3858
+ catch (error) {
3859
+ return {
3860
+ values: {},
3861
+ errors: {
3862
+ root: {
3863
+ type: 'validation',
3864
+ message: error instanceof Error ? error.message : 'Validation failed',
3865
+ },
3866
+ },
3867
+ };
3868
+ }
3869
+ };
3870
+ };
3871
+
3702
3872
  const idPickerSanityCheck = (column, foreign_key) => {
3703
3873
  if (!!foreign_key == false) {
3704
3874
  throw new Error(`The key foreign_key does not exist in properties of column ${column} when using id-picker.`);
@@ -3718,13 +3888,61 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3718
3888
  showSubmitButton: true,
3719
3889
  showResetButton: true,
3720
3890
  showTitle: true,
3721
- }, dateTimePickerLabels, idPickerLabels, enumPickerLabels, }) => {
3891
+ }, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, }) => {
3722
3892
  const [isSuccess, setIsSuccess] = useState(false);
3723
3893
  const [isError, setIsError] = useState(false);
3724
3894
  const [isSubmiting, setIsSubmiting] = useState(false);
3725
3895
  const [isConfirming, setIsConfirming] = useState(false);
3726
3896
  const [validatedData, setValidatedData] = useState();
3727
3897
  const [error, setError] = useState();
3898
+ const onBeforeSubmit = () => {
3899
+ setIsSubmiting(true);
3900
+ };
3901
+ const onAfterSubmit = () => {
3902
+ setIsSubmiting(false);
3903
+ };
3904
+ const onSubmitError = (error) => {
3905
+ setIsError(true);
3906
+ setError(error);
3907
+ };
3908
+ const onSubmitSuccess = () => {
3909
+ setIsSuccess(true);
3910
+ };
3911
+ const defaultOnSubmit = async (promise) => {
3912
+ try {
3913
+ console.log('onBeforeSubmit');
3914
+ onBeforeSubmit();
3915
+ await promise;
3916
+ console.log('onSubmitSuccess');
3917
+ onSubmitSuccess();
3918
+ }
3919
+ catch (error) {
3920
+ console.log('onSubmitError', error);
3921
+ onSubmitError(error);
3922
+ }
3923
+ finally {
3924
+ onAfterSubmit();
3925
+ }
3926
+ };
3927
+ const defaultSubmitPromise = (data) => {
3928
+ const options = {
3929
+ method: 'POST',
3930
+ url: `${serverUrl}`,
3931
+ data: clearEmptyString(data),
3932
+ ...requestOptions,
3933
+ };
3934
+ return axios.request(options);
3935
+ };
3936
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3937
+ const onFormSubmit = async (data) => {
3938
+ // AJV validation is now handled by react-hook-form resolver
3939
+ // This function will only be called if validation passes
3940
+ if (onSubmit === undefined) {
3941
+ await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
3942
+ return;
3943
+ }
3944
+ await defaultOnSubmit(Promise.resolve(onSubmit(data)));
3945
+ };
3728
3946
  return (jsx(SchemaFormContext.Provider, { value: {
3729
3947
  schema,
3730
3948
  serverUrl,
@@ -3754,9 +3972,12 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3754
3972
  customErrorRenderer,
3755
3973
  customSuccessRenderer,
3756
3974
  displayConfig,
3975
+ requireConfirmation,
3976
+ onFormSubmit,
3757
3977
  dateTimePickerLabels,
3758
3978
  idPickerLabels,
3759
3979
  enumPickerLabels,
3980
+ ajvResolver: ajvResolver(schema),
3760
3981
  }, children: jsx(FormProvider, { ...form, children: children }) }));
3761
3982
  };
3762
3983
 
@@ -3802,20 +4023,22 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
3802
4023
 
3803
4024
  const Field = React.forwardRef(function Field(props, ref) {
3804
4025
  const { label, children, helperText, errorText, optionalText, ...rest } = props;
3805
- return (jsxs(Field$1.Root, { ref: ref, ...rest, children: [label && (jsxs(Field$1.Label, { children: [label, jsx(Field$1.RequiredIndicator, { fallback: optionalText })] })), children, helperText && (jsx(Field$1.HelperText, { children: helperText })), errorText && (jsx(Field$1.ErrorText, { children: errorText }))] }));
4026
+ return (jsxs(Field$1.Root, { ref: ref, ...rest, children: [label && (jsxs(Field$1.Label, { children: [label, jsx(Field$1.RequiredIndicator, { color: rest.invalid && rest.required ? 'red.500' : undefined, fallback: optionalText })] })), children, helperText && (jsx(Field$1.HelperText, { children: helperText })), !!errorText && (jsxs(Field$1.ErrorText, { children: [rest.required && rest.invalid && (jsx("span", { style: { color: 'var(--chakra-colors-red-500)' }, children: "* " })), errorText] }))] }));
3806
4027
  });
3807
4028
 
3808
4029
  const BooleanPicker = ({ schema, column, prefix }) => {
3809
4030
  const { watch, formState: { errors }, setValue, } = useFormContext();
3810
4031
  const { translate } = useSchemaContext();
3811
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4032
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
3812
4033
  const isRequired = required?.some((columnId) => columnId === column);
3813
4034
  const colLabel = `${prefix}${column}`;
3814
4035
  const value = watch(colLabel);
3815
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
3816
- gridRow, children: [jsx(CheckboxCard, { checked: value, variant: "surface", onChange: () => {
3817
- setValue(colLabel, !value);
3818
- } }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4036
+ return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4037
+ gridRow, errorText: errors[`${colLabel}`]
4038
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4039
+ : undefined, invalid: !!errors[colLabel], children: jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
4040
+ setValue(colLabel, !value);
4041
+ } }) }));
3819
4042
  };
3820
4043
 
3821
4044
  const CustomInput = ({ column, schema, prefix }) => {
@@ -4048,83 +4271,83 @@ const DatePicker = ({ column, schema, prefix }) => {
4048
4271
  console.error(e);
4049
4272
  }
4050
4273
  }, [selectedDate, dateFormat, colLabel, setValue]);
4051
- return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4052
- gridRow, children: [jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
4053
- setOpen(true);
4054
- }, justifyContent: 'start', children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsx(PopoverContent, { children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
4055
- setValue(colLabel, dayjs(date).format(dateFormat));
4056
- setOpen(false);
4057
- }, labels: {
4058
- monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
4059
- formI18n.translate.t(`common.month_1`, {
4060
- defaultValue: 'January',
4061
- }),
4062
- formI18n.translate.t(`common.month_2`, {
4063
- defaultValue: 'February',
4064
- }),
4065
- formI18n.translate.t(`common.month_3`, {
4066
- defaultValue: 'March',
4067
- }),
4068
- formI18n.translate.t(`common.month_4`, {
4069
- defaultValue: 'April',
4070
- }),
4071
- formI18n.translate.t(`common.month_5`, {
4072
- defaultValue: 'May',
4073
- }),
4074
- formI18n.translate.t(`common.month_6`, {
4075
- defaultValue: 'June',
4076
- }),
4077
- formI18n.translate.t(`common.month_7`, {
4078
- defaultValue: 'July',
4079
- }),
4080
- formI18n.translate.t(`common.month_8`, {
4081
- defaultValue: 'August',
4082
- }),
4083
- formI18n.translate.t(`common.month_9`, {
4084
- defaultValue: 'September',
4085
- }),
4086
- formI18n.translate.t(`common.month_10`, {
4087
- defaultValue: 'October',
4088
- }),
4089
- formI18n.translate.t(`common.month_11`, {
4090
- defaultValue: 'November',
4091
- }),
4092
- formI18n.translate.t(`common.month_12`, {
4093
- defaultValue: 'December',
4094
- }),
4095
- ],
4096
- weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
4097
- formI18n.translate.t(`common.weekday_1`, {
4098
- defaultValue: 'Sun',
4099
- }),
4100
- formI18n.translate.t(`common.weekday_2`, {
4101
- defaultValue: 'Mon',
4102
- }),
4103
- formI18n.translate.t(`common.weekday_3`, {
4104
- defaultValue: 'Tue',
4105
- }),
4106
- formI18n.translate.t(`common.weekday_4`, {
4107
- defaultValue: 'Wed',
4108
- }),
4109
- formI18n.translate.t(`common.weekday_5`, {
4110
- defaultValue: 'Thu',
4111
- }),
4112
- formI18n.translate.t(`common.weekday_6`, {
4113
- defaultValue: 'Fri',
4114
- }),
4115
- formI18n.translate.t(`common.weekday_7`, {
4116
- defaultValue: 'Sat',
4117
- }),
4118
- ],
4119
- backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
4120
- formI18n.translate.t(`common.back_button`, {
4121
- defaultValue: 'Back',
4122
- }),
4123
- forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
4124
- formI18n.translate.t(`common.forward_button`, {
4125
- defaultValue: 'Forward',
4126
- }),
4127
- } })] }) })] }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
4274
+ return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4275
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
4276
+ setOpen(true);
4277
+ }, justifyContent: 'start', children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsx(PopoverContent, { children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
4278
+ setValue(colLabel, dayjs(date).format(dateFormat));
4279
+ setOpen(false);
4280
+ }, labels: {
4281
+ monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
4282
+ formI18n.translate.t(`common.month_1`, {
4283
+ defaultValue: 'January',
4284
+ }),
4285
+ formI18n.translate.t(`common.month_2`, {
4286
+ defaultValue: 'February',
4287
+ }),
4288
+ formI18n.translate.t(`common.month_3`, {
4289
+ defaultValue: 'March',
4290
+ }),
4291
+ formI18n.translate.t(`common.month_4`, {
4292
+ defaultValue: 'April',
4293
+ }),
4294
+ formI18n.translate.t(`common.month_5`, {
4295
+ defaultValue: 'May',
4296
+ }),
4297
+ formI18n.translate.t(`common.month_6`, {
4298
+ defaultValue: 'June',
4299
+ }),
4300
+ formI18n.translate.t(`common.month_7`, {
4301
+ defaultValue: 'July',
4302
+ }),
4303
+ formI18n.translate.t(`common.month_8`, {
4304
+ defaultValue: 'August',
4305
+ }),
4306
+ formI18n.translate.t(`common.month_9`, {
4307
+ defaultValue: 'September',
4308
+ }),
4309
+ formI18n.translate.t(`common.month_10`, {
4310
+ defaultValue: 'October',
4311
+ }),
4312
+ formI18n.translate.t(`common.month_11`, {
4313
+ defaultValue: 'November',
4314
+ }),
4315
+ formI18n.translate.t(`common.month_12`, {
4316
+ defaultValue: 'December',
4317
+ }),
4318
+ ],
4319
+ weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
4320
+ formI18n.translate.t(`common.weekday_1`, {
4321
+ defaultValue: 'Sun',
4322
+ }),
4323
+ formI18n.translate.t(`common.weekday_2`, {
4324
+ defaultValue: 'Mon',
4325
+ }),
4326
+ formI18n.translate.t(`common.weekday_3`, {
4327
+ defaultValue: 'Tue',
4328
+ }),
4329
+ formI18n.translate.t(`common.weekday_4`, {
4330
+ defaultValue: 'Wed',
4331
+ }),
4332
+ formI18n.translate.t(`common.weekday_5`, {
4333
+ defaultValue: 'Thu',
4334
+ }),
4335
+ formI18n.translate.t(`common.weekday_6`, {
4336
+ defaultValue: 'Fri',
4337
+ }),
4338
+ formI18n.translate.t(`common.weekday_7`, {
4339
+ defaultValue: 'Sat',
4340
+ }),
4341
+ ],
4342
+ backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
4343
+ formI18n.translate.t(`common.back_button`, {
4344
+ defaultValue: 'Back',
4345
+ }),
4346
+ forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
4347
+ formI18n.translate.t(`common.forward_button`, {
4348
+ defaultValue: 'Forward',
4349
+ }),
4350
+ } })] }) })] }) }));
4128
4351
  };
4129
4352
 
4130
4353
  function filterArray(array, searchTerm) {
@@ -4159,7 +4382,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4159
4382
  };
4160
4383
  if (variant === 'radio') {
4161
4384
  return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4162
- gridRow, children: jsx(RadioGroup$1.Root, { defaultValue: "1", children: jsx(HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
4385
+ gridRow, errorText: errors[`${colLabel}`]
4386
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4387
+ : undefined, invalid: !!errors[colLabel], children: jsx(RadioGroup$1.Root, { defaultValue: "1", children: jsx(HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
4163
4388
  return (jsxs(RadioGroup$1.Item, { onClick: () => {
4164
4389
  if (!isMultiple) {
4165
4390
  setOpenSearchResult(false);
@@ -4174,7 +4399,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4174
4399
  }) }) }) }));
4175
4400
  }
4176
4401
  return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4177
- gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
4402
+ gridRow, errorText: errors[`${colLabel}`]
4403
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4404
+ : undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
4178
4405
  const item = enumValue;
4179
4406
  if (!!item === false) {
4180
4407
  return jsx(Fragment, {});
@@ -4229,7 +4456,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4229
4456
  ? renderDisplay(item)
4230
4457
  : translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
4231
4458
  }) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Fragment, { children: enumPickerLabels?.emptySearchResult ??
4232
- translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4459
+ translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] })] }));
4233
4460
  };
4234
4461
 
4235
4462
  function isEnteringWindow(_ref) {
@@ -4587,20 +4814,22 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
4587
4814
  const FilePicker = ({ column, schema, prefix }) => {
4588
4815
  const { setValue, formState: { errors }, watch, } = useFormContext();
4589
4816
  const { translate } = useSchemaContext();
4590
- const { required, gridColumn = "span 12", gridRow = "span 1", } = schema;
4817
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', } = schema;
4591
4818
  const isRequired = required?.some((columnId) => columnId === column);
4592
4819
  const currentFiles = (watch(column) ?? []);
4593
4820
  const colLabel = `${prefix}${column}`;
4594
- return (jsxs(Field, { label: `${translate.t(`${colLabel}.field_label`)}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", display: "grid", gridTemplateRows: "auto 1fr auto", alignItems: "stretch", children: [jsx(FileDropzone, { onDrop: ({ files }) => {
4821
+ return (jsxs(Field, { label: `${translate.t(`${colLabel}.field_label`)}`, required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: 'grid', gridTemplateRows: 'auto 1fr auto', alignItems: 'stretch', errorText: errors[`${colLabel}`]
4822
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4823
+ : undefined, invalid: !!errors[colLabel], children: [jsx(FileDropzone, { onDrop: ({ files }) => {
4595
4824
  const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
4596
4825
  setValue(colLabel, [...currentFiles, ...newFiles]);
4597
- }, placeholder: translate.t(removeIndex(`${colLabel}.fileDropzone`)) }), jsx(Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
4598
- return (jsx(Card.Root, { variant: "subtle", children: jsxs(Card.Body, { gap: "2", cursor: "pointer", onClick: () => {
4826
+ }, placeholder: translate.t(removeIndex(`${colLabel}.fileDropzone`)) }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file) => {
4827
+ return (jsx(Card.Root, { variant: 'subtle', children: jsxs(Card.Body, { gap: "2", cursor: 'pointer', onClick: () => {
4599
4828
  setValue(column, currentFiles.filter(({ name }) => {
4600
4829
  return name !== file.name;
4601
4830
  }));
4602
- }, display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [file.type.startsWith("image/") && (jsx(Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsx(Box, { children: file.name }), jsx(TiDeleteOutline, {})] }) }, file.name));
4603
- }) }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4831
+ }, display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', children: [file.type.startsWith('image/') && (jsx(Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsx(Box, { children: file.name }), jsx(TiDeleteOutline, {})] }) }, file.name));
4832
+ }) })] }));
4604
4833
  };
4605
4834
 
4606
4835
  const ToggleTip = React.forwardRef(function ToggleTip(props, ref) {
@@ -4789,7 +5018,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4789
5018
  return record[display_column];
4790
5019
  };
4791
5020
  return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4792
- gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
5021
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
4793
5022
  const item = idMap[id];
4794
5023
  if (item === undefined) {
4795
5024
  return (jsx(Text, { children: idPickerLabels?.undefined ?? formI18n.t('undefined') }, id));
@@ -4840,7 +5069,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4840
5069
  ? idPickerLabels?.emptySearchResult ??
4841
5070
  formI18n.t('empty_search_result')
4842
5071
  : idPickerLabels?.initialResults ??
4843
- formI18n.t('initial_results') })) }), jsx(PaginationRoot, { justifySelf: 'center', count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxs(HStack, { gap: "4", children: [jsx(PaginationPrevTrigger, {}), count > 0 && jsx(PaginationPageText, {}), jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
5072
+ formI18n.t('initial_results') })) }), jsx(PaginationRoot, { justifySelf: 'center', count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxs(HStack, { gap: "4", children: [jsx(PaginationPrevTrigger, {}), count > 0 && jsx(PaginationPageText, {}), jsx(PaginationNextTrigger, {})] }) })] }))] }) })] })] }));
4844
5073
  };
4845
5074
 
4846
5075
  const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
@@ -4851,20 +5080,84 @@ const NumberInputField$1 = NumberInput.Input;
4851
5080
  NumberInput.Scrubber;
4852
5081
  NumberInput.Label;
4853
5082
 
5083
+ /**
5084
+ * Gets the error message for a specific field from react-hook-form errors
5085
+ * Prioritizes required errors (#.required) over field-specific validation errors
5086
+ */
5087
+ const getFieldError = (errors, fieldName) => {
5088
+ // Check for form-level required errors first (highest priority)
5089
+ const requiredError = errors['#.required'];
5090
+ if (requiredError) {
5091
+ const requiredErrorMessage = extractErrorMessage(requiredError);
5092
+ if (requiredErrorMessage) {
5093
+ return requiredErrorMessage;
5094
+ }
5095
+ }
5096
+ // If no required errors, return field-specific error
5097
+ const fieldError = errors[fieldName];
5098
+ if (fieldError) {
5099
+ const fieldErrorMessage = extractErrorMessage(fieldError);
5100
+ if (fieldErrorMessage) {
5101
+ return fieldErrorMessage;
5102
+ }
5103
+ }
5104
+ return undefined;
5105
+ };
5106
+ /**
5107
+ * Helper function to extract error message from various error formats
5108
+ * Only returns message if explicitly provided, no fallback text
5109
+ */
5110
+ const extractErrorMessage = (error) => {
5111
+ if (!error) {
5112
+ return undefined;
5113
+ }
5114
+ // If it's a simple string error
5115
+ if (typeof error === 'string') {
5116
+ return error;
5117
+ }
5118
+ // If it's an error object with a message property
5119
+ if (error && typeof error === 'object' && 'message' in error) {
5120
+ return error.message;
5121
+ }
5122
+ // If it's an array of errors, get the first one
5123
+ if (Array.isArray(error) && error.length > 0) {
5124
+ const firstError = error[0];
5125
+ if (typeof firstError === 'string') {
5126
+ return firstError;
5127
+ }
5128
+ if (firstError &&
5129
+ typeof firstError === 'object' &&
5130
+ 'message' in firstError) {
5131
+ return firstError.message;
5132
+ }
5133
+ }
5134
+ // No fallback - return undefined if no message provided
5135
+ return undefined;
5136
+ };
5137
+
4854
5138
  const NumberInputField = ({ schema, column, prefix, }) => {
4855
5139
  const { setValue, formState: { errors }, watch, } = useFormContext();
4856
5140
  const { translate } = useSchemaContext();
4857
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5141
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', numberStorageType = 'number', } = schema;
4858
5142
  const isRequired = required?.some((columnId) => columnId === column);
4859
5143
  const colLabel = `${prefix}${column}`;
4860
5144
  const value = watch(`${colLabel}`);
4861
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(NumberInputRoot, { children: jsx(NumberInputField$1, { required: isRequired, value: value, onChange: (event) => {
4862
- setValue(`${colLabel}`, Number(event.target.value));
4863
- } }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5145
+ const fieldError = getFieldError(errors, colLabel);
5146
+ return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, errorText: fieldError
5147
+ ? fieldError.includes('required')
5148
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5149
+ : fieldError
5150
+ : undefined, invalid: !!fieldError, children: jsx(NumberInputRoot, { value: value, onValueChange: (details) => {
5151
+ // Store as string or number based on configuration, default to number
5152
+ const value = numberStorageType === 'string'
5153
+ ? details.value
5154
+ : details.valueAsNumber;
5155
+ setValue(`${colLabel}`, value);
5156
+ }, min: schema.minimum, max: schema.maximum, step: schema.multipleOf || 0.01, allowOverflow: false, clampValueOnBlur: false, inputMode: "decimal", formatOptions: schema.formatOptions, children: jsx(NumberInputField$1, { required: isRequired }) }) }));
4864
5157
  };
4865
5158
 
4866
5159
  const ObjectInput = ({ schema, column, prefix }) => {
4867
- const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
5160
+ const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
4868
5161
  const { translate } = useSchemaContext();
4869
5162
  const colLabel = `${prefix}${column}`;
4870
5163
  const isRequired = required?.some((columnId) => columnId === column);
@@ -4872,29 +5165,32 @@ const ObjectInput = ({ schema, column, prefix }) => {
4872
5165
  if (properties === undefined) {
4873
5166
  throw new Error(`properties is undefined when using ObjectInput`);
4874
5167
  }
4875
- return (jsxs(Box, { gridRow, gridColumn, children: [showLabel && (jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] })), jsx(Grid, { bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
4876
- base: "colorPalette.200",
4877
- _dark: "colorPalette.800",
4878
- }, gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: Object.keys(properties ?? {}).map((key) => {
5168
+ return (jsxs(Box, { gridRow, gridColumn, children: [showLabel && (jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] })), jsx(Grid, { bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
5169
+ base: 'colorPalette.200',
5170
+ _dark: 'colorPalette.800',
5171
+ }, gap: "4", padding: '4', gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: Object.keys(properties ?? {}).map((key) => {
4879
5172
  return (
4880
5173
  // @ts-expect-error find suitable types
4881
5174
  jsx(ColumnRenderer, { column: `${key}`,
4882
5175
  prefix: `${prefix}${column}.`,
4883
- properties }, `form-${colLabel}-${key}`));
4884
- }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5176
+ properties,
5177
+ parentRequired: required }, `form-${colLabel}-${key}`));
5178
+ }) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4885
5179
  };
4886
5180
 
4887
5181
  const RecordInput$1 = ({ column, schema, prefix }) => {
4888
5182
  const { formState: { errors }, setValue, getValues, } = useFormContext();
4889
5183
  const { translate } = useSchemaContext();
4890
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5184
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
4891
5185
  const isRequired = required?.some((columnId) => columnId === column);
4892
5186
  const entries = Object.entries(getValues(column) ?? {});
4893
5187
  const [showNewEntries, setShowNewEntries] = useState(false);
4894
5188
  const [newKey, setNewKey] = useState();
4895
5189
  const [newValue, setNewValue] = useState();
4896
- return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
4897
- return (jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
5190
+ return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: 'stretch', gridColumn, gridRow, errorText: errors[`${column}`]
5191
+ ? translate.t(`${column}.field_required`)
5192
+ : undefined, invalid: !!errors[column], children: [entries.map(([key, value]) => {
5193
+ return (jsxs(Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
4898
5194
  const filtered = entries.filter(([target]) => {
4899
5195
  return target !== key;
4900
5196
  });
@@ -4904,17 +5200,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
4904
5200
  ...getValues(column),
4905
5201
  [key]: e.target.value,
4906
5202
  });
4907
- }, autoComplete: "off" }), jsx(IconButton, { variant: "ghost", onClick: () => {
5203
+ }, autoComplete: "off" }), jsx(IconButton, { variant: 'ghost', onClick: () => {
4908
5204
  const filtered = entries.filter(([target]) => {
4909
5205
  return target !== key;
4910
5206
  });
4911
5207
  setValue(column, Object.fromEntries([...filtered]));
4912
5208
  }, children: jsx(CgClose, {}) })] }));
4913
- }), jsx(Show, { when: showNewEntries, children: jsxs(Card.Root, { children: [jsx(Card.Body, { gap: "2", children: jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: newKey, onChange: (e) => {
5209
+ }), jsx(Show, { when: showNewEntries, children: jsxs(Card.Root, { children: [jsx(Card.Body, { gap: "2", children: jsxs(Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsx(Input, { value: newKey, onChange: (e) => {
4914
5210
  setNewKey(e.target.value);
4915
5211
  }, autoComplete: "off" }), jsx(Input, { value: newValue, onChange: (e) => {
4916
5212
  setNewValue(e.target.value);
4917
- }, autoComplete: "off" })] }) }), jsxs(Card.Footer, { justifyContent: "flex-end", children: [jsx(IconButton, { variant: "subtle", onClick: () => {
5213
+ }, autoComplete: "off" })] }) }), jsxs(Card.Footer, { justifyContent: "flex-end", children: [jsx(IconButton, { variant: 'subtle', onClick: () => {
4918
5214
  setShowNewEntries(false);
4919
5215
  setNewKey(undefined);
4920
5216
  setNewValue(undefined);
@@ -4933,16 +5229,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
4933
5229
  setShowNewEntries(true);
4934
5230
  setNewKey(undefined);
4935
5231
  setNewValue(undefined);
4936
- }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
5232
+ }, children: translate.t(`${column}.addNew`) })] }));
4937
5233
  };
4938
5234
 
4939
5235
  const StringInputField = ({ column, schema, prefix, }) => {
4940
5236
  const { register, formState: { errors }, } = useFormContext();
4941
5237
  const { translate } = useSchemaContext();
4942
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5238
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
4943
5239
  const isRequired = required?.some((columnId) => columnId === column);
4944
5240
  const colLabel = `${prefix}${column}`;
4945
- return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsx(Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }), errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
5241
+ const fieldError = getFieldError(errors, colLabel);
5242
+ return (jsx(Fragment, { children: jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, errorText: fieldError, invalid: !!fieldError, children: jsx(Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }) }) }));
4946
5243
  };
4947
5244
 
4948
5245
  const RadioCardItem = React.forwardRef(function RadioCardItem(props, ref) {
@@ -5128,13 +5425,18 @@ Textarea.displayName = "Textarea";
5128
5425
  const TextAreaInput = ({ column, schema, prefix, }) => {
5129
5426
  const { register, formState: { errors }, } = useFormContext();
5130
5427
  const { translate } = useSchemaContext();
5131
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5428
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5132
5429
  const isRequired = required?.some((columnId) => columnId === column);
5133
5430
  const colLabel = `${prefix}${column}`;
5134
5431
  const form = useFormContext();
5135
5432
  const { setValue, watch } = form;
5433
+ const fieldError = getFieldError(errors, colLabel);
5136
5434
  const watchValue = watch(colLabel);
5137
- return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", display: "grid", children: [jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }), errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
5435
+ return (jsx(Fragment, { children: jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
5436
+ ? fieldError.includes('required')
5437
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5438
+ : fieldError
5439
+ : undefined, invalid: !!fieldError, children: jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }) }) }));
5138
5440
  };
5139
5441
 
5140
5442
  function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
@@ -5265,25 +5567,25 @@ dayjs.extend(timezone);
5265
5567
  const TimePicker = ({ column, schema, prefix }) => {
5266
5568
  const { watch, formState: { errors }, setValue, } = useFormContext();
5267
5569
  const { translate, timezone } = useSchemaContext();
5268
- const { required, gridColumn = "span 12", gridRow = "span 1", timeFormat = "HH:mm:ssZ", displayTimeFormat = "hh:mm A", } = schema;
5570
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
5269
5571
  const isRequired = required?.some((columnId) => columnId === column);
5270
5572
  const colLabel = `${prefix}${column}`;
5271
5573
  const [open, setOpen] = useState(false);
5272
5574
  const value = watch(colLabel);
5273
5575
  const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
5274
5576
  ? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
5275
- : "";
5577
+ : '';
5276
5578
  // Parse the initial time parts from the time string (HH:mm:ssZ)
5277
5579
  const parseTime = (time) => {
5278
5580
  if (!time)
5279
- return { hour: 12, minute: 0, meridiem: "am" };
5581
+ return { hour: 12, minute: 0, meridiem: 'am' };
5280
5582
  const parsed = dayjs(`1970-01-01T${time}`).tz(timezone);
5281
5583
  if (!parsed.isValid()) {
5282
- return { hour: 12, minute: 0, meridiem: "am" };
5584
+ return { hour: 12, minute: 0, meridiem: 'am' };
5283
5585
  }
5284
5586
  let hour = parsed.hour();
5285
5587
  const minute = parsed.minute();
5286
- const meridiem = hour >= 12 ? "pm" : "am";
5588
+ const meridiem = hour >= 12 ? 'pm' : 'am';
5287
5589
  if (hour === 0)
5288
5590
  hour = 12;
5289
5591
  else if (hour > 12)
@@ -5304,10 +5606,15 @@ const TimePicker = ({ column, schema, prefix }) => {
5304
5606
  if (hour === null || minute === null || meridiem === null)
5305
5607
  return null;
5306
5608
  let newHour = hour;
5307
- if (meridiem === "pm" && hour !== 12) {
5609
+ if (meridiem === 'pm' && hour !== 12) {
5308
5610
  newHour = hour + 12;
5309
5611
  }
5310
- return dayjs().tz(timezone).hour(newHour).minute(minute).second(0).format(timeFormat);
5612
+ return dayjs()
5613
+ .tz(timezone)
5614
+ .hour(newHour)
5615
+ .minute(minute)
5616
+ .second(0)
5617
+ .format(timeFormat);
5311
5618
  };
5312
5619
  // Handle changes to time parts
5313
5620
  const handleTimeChange = ({ hour: newHour, minute: newMinute, meridiem: newMeridiem, }) => {
@@ -5317,13 +5624,15 @@ const TimePicker = ({ column, schema, prefix }) => {
5317
5624
  const timeString = getTimeString(newHour, newMinute, newMeridiem);
5318
5625
  setValue(colLabel, timeString, { shouldValidate: true, shouldDirty: true });
5319
5626
  };
5320
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
5321
- gridRow, children: [jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
5322
- setOpen(true);
5323
- }, justifyContent: "start", children: [jsx(IoMdClock, {}), !!value ? `${displayedTime}` : ""] }) }), jsx(Popover.Positioner, { children: jsx(Popover.Content, { children: jsx(Popover.Body, { children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
5324
- am: translate.t(`common.am`, { defaultValue: "AM" }),
5325
- pm: translate.t(`common.pm`, { defaultValue: "PM" }),
5326
- } }) }) }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5627
+ return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
5628
+ gridRow, errorText: errors[`${colLabel}`]
5629
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5630
+ : undefined, invalid: !!errors[colLabel], children: jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
5631
+ setOpen(true);
5632
+ }, justifyContent: 'start', children: [jsx(IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), jsx(Popover.Positioner, { children: jsx(Popover.Content, { children: jsx(Popover.Body, { children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
5633
+ am: translate.t(`common.am`, { defaultValue: 'AM' }),
5634
+ pm: translate.t(`common.pm`, { defaultValue: 'PM' }),
5635
+ } }) }) }) })] }) }));
5327
5636
  };
5328
5637
 
5329
5638
  function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
@@ -5529,9 +5838,9 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
5529
5838
  const { watch, formState: { errors }, setValue, } = useFormContext();
5530
5839
  const { timezone, dateTimePickerLabels } = useSchemaContext();
5531
5840
  const formI18n = useFormI18n(column, prefix);
5532
- const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
5841
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
5533
5842
  // with timezone
5534
- dateFormat = "YYYY-MM-DD[T]HH:mm:ssZ", } = schema;
5843
+ dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
5535
5844
  const isRequired = required?.some((columnId) => columnId === column);
5536
5845
  const colLabel = formI18n.colLabel;
5537
5846
  const [open, setOpen] = useState(false);
@@ -5562,44 +5871,82 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
5562
5871
  console.error(e);
5563
5872
  }
5564
5873
  }, [selectedDate, dateFormat, colLabel, setValue]);
5565
- return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
5566
- gridRow, children: [jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
5567
- setOpen(true);
5568
- }, justifyContent: "start", children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsx(PopoverContent, { minW: "450px", children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
5569
- setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
5570
- }, timezone: timezone, labels: {
5571
- monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
5572
- formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
5573
- formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
5574
- formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
5575
- formI18n.translate.t(`common.month_4`, { defaultValue: "April" }),
5576
- formI18n.translate.t(`common.month_5`, { defaultValue: "May" }),
5577
- formI18n.translate.t(`common.month_6`, { defaultValue: "June" }),
5578
- formI18n.translate.t(`common.month_7`, { defaultValue: "July" }),
5579
- formI18n.translate.t(`common.month_8`, { defaultValue: "August" }),
5580
- formI18n.translate.t(`common.month_9`, { defaultValue: "September" }),
5581
- formI18n.translate.t(`common.month_10`, { defaultValue: "October" }),
5582
- formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
5583
- formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
5584
- ],
5585
- weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
5586
- formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
5587
- formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
5588
- formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
5589
- formI18n.translate.t(`common.weekday_4`, {
5590
- defaultValue: "Wed",
5591
- }),
5592
- formI18n.translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
5593
- formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
5594
- formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
5595
- ],
5596
- backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? formI18n.translate.t(`common.back_button`, {
5597
- defaultValue: "Back",
5874
+ return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
5875
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
5876
+ setOpen(true);
5877
+ }, justifyContent: 'start', children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsx(PopoverContent, { minW: '450px', children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
5878
+ setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
5879
+ }, timezone: timezone, labels: {
5880
+ monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
5881
+ formI18n.translate.t(`common.month_1`, {
5882
+ defaultValue: 'January',
5883
+ }),
5884
+ formI18n.translate.t(`common.month_2`, {
5885
+ defaultValue: 'February',
5886
+ }),
5887
+ formI18n.translate.t(`common.month_3`, {
5888
+ defaultValue: 'March',
5889
+ }),
5890
+ formI18n.translate.t(`common.month_4`, {
5891
+ defaultValue: 'April',
5892
+ }),
5893
+ formI18n.translate.t(`common.month_5`, {
5894
+ defaultValue: 'May',
5895
+ }),
5896
+ formI18n.translate.t(`common.month_6`, {
5897
+ defaultValue: 'June',
5898
+ }),
5899
+ formI18n.translate.t(`common.month_7`, {
5900
+ defaultValue: 'July',
5901
+ }),
5902
+ formI18n.translate.t(`common.month_8`, {
5903
+ defaultValue: 'August',
5904
+ }),
5905
+ formI18n.translate.t(`common.month_9`, {
5906
+ defaultValue: 'September',
5598
5907
  }),
5599
- forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? formI18n.translate.t(`common.forward_button`, {
5600
- defaultValue: "Forward",
5908
+ formI18n.translate.t(`common.month_10`, {
5909
+ defaultValue: 'October',
5601
5910
  }),
5602
- } })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
5911
+ formI18n.translate.t(`common.month_11`, {
5912
+ defaultValue: 'November',
5913
+ }),
5914
+ formI18n.translate.t(`common.month_12`, {
5915
+ defaultValue: 'December',
5916
+ }),
5917
+ ],
5918
+ weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
5919
+ formI18n.translate.t(`common.weekday_1`, {
5920
+ defaultValue: 'Sun',
5921
+ }),
5922
+ formI18n.translate.t(`common.weekday_2`, {
5923
+ defaultValue: 'Mon',
5924
+ }),
5925
+ formI18n.translate.t(`common.weekday_3`, {
5926
+ defaultValue: 'Tue',
5927
+ }),
5928
+ formI18n.translate.t(`common.weekday_4`, {
5929
+ defaultValue: 'Wed',
5930
+ }),
5931
+ formI18n.translate.t(`common.weekday_5`, {
5932
+ defaultValue: 'Thu',
5933
+ }),
5934
+ formI18n.translate.t(`common.weekday_6`, {
5935
+ defaultValue: 'Fri',
5936
+ }),
5937
+ formI18n.translate.t(`common.weekday_7`, {
5938
+ defaultValue: 'Sat',
5939
+ }),
5940
+ ],
5941
+ backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
5942
+ formI18n.translate.t(`common.back_button`, {
5943
+ defaultValue: 'Back',
5944
+ }),
5945
+ forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
5946
+ formI18n.translate.t(`common.forward_button`, {
5947
+ defaultValue: 'Forward',
5948
+ }),
5949
+ } })] }) })] }) }));
5603
5950
  };
5604
5951
 
5605
5952
  const SchemaRenderer = ({ schema, prefix, column, }) => {
@@ -5673,13 +6020,18 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
5673
6020
  return jsx(Text, { children: "missing type" });
5674
6021
  };
5675
6022
 
5676
- const ColumnRenderer = ({ column, properties, prefix, }) => {
6023
+ const ColumnRenderer = ({ column, properties, prefix, parentRequired, }) => {
5677
6024
  const colSchema = properties[column];
5678
6025
  const colLabel = `${prefix}${column}`;
5679
6026
  if (colSchema === undefined) {
5680
6027
  throw new Error(`${colLabel} does not exist when using ColumnRenderer`);
5681
6028
  }
5682
- return jsx(SchemaRenderer, { schema: colSchema, prefix, column });
6029
+ // Merge parent's required array with the schema's required array
6030
+ const schemaWithRequired = {
6031
+ ...colSchema,
6032
+ required: parentRequired || colSchema.required,
6033
+ };
6034
+ return jsx(SchemaRenderer, { schema: schemaWithRequired, prefix, column });
5683
6035
  };
5684
6036
 
5685
6037
  const ArrayViewer = ({ schema, column, prefix }) => {
@@ -5802,11 +6154,29 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
5802
6154
  const NumberViewer = ({ schema, column, prefix, }) => {
5803
6155
  const { watch, formState: { errors }, } = useFormContext();
5804
6156
  const { translate } = useSchemaContext();
5805
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
6157
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5806
6158
  const isRequired = required?.some((columnId) => columnId === column);
5807
6159
  const colLabel = `${prefix}${column}`;
5808
6160
  const value = watch(colLabel);
5809
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(Text, { children: value }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
6161
+ // Format the value for display if formatOptions are provided
6162
+ const formatValue = (val) => {
6163
+ if (val === undefined || val === null || val === '')
6164
+ return '';
6165
+ const numValue = typeof val === 'string' ? parseFloat(val) : val;
6166
+ if (isNaN(numValue))
6167
+ return String(val);
6168
+ // Use formatOptions if available, otherwise display as-is
6169
+ if (schema.formatOptions) {
6170
+ try {
6171
+ return new Intl.NumberFormat(undefined, schema.formatOptions).format(numValue);
6172
+ }
6173
+ catch {
6174
+ return String(val);
6175
+ }
6176
+ }
6177
+ return String(val);
6178
+ };
6179
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(Text, { children: formatValue(value) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5810
6180
  };
5811
6181
 
5812
6182
  const ObjectViewer = ({ schema, column, prefix }) => {
@@ -6098,113 +6468,43 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
6098
6468
  };
6099
6469
 
6100
6470
  const SubmitButton = () => {
6101
- const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, } = useSchemaContext();
6471
+ const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, requireConfirmation, onFormSubmit, } = useSchemaContext();
6102
6472
  const methods = useFormContext();
6103
6473
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6104
6474
  const onValid = (data) => {
6105
- const { isValid, errors } = validateData(data, schema);
6106
- if (!isValid) {
6107
- setError({
6108
- type: "validation",
6109
- errors,
6110
- });
6111
- setIsError(true);
6112
- return;
6475
+ // const { isValid, errors } = validateData(data, schema);
6476
+ // if (!isValid) {
6477
+ // setError({
6478
+ // type: 'validation',
6479
+ // errors,
6480
+ // });
6481
+ // setIsError(true);
6482
+ // return;
6483
+ // }
6484
+ // If validation passes, check if confirmation is required
6485
+ if (requireConfirmation) {
6486
+ // Show confirmation (existing behavior)
6487
+ setValidatedData(data);
6488
+ setIsError(false);
6489
+ setIsConfirming(true);
6490
+ }
6491
+ else {
6492
+ // Skip confirmation and submit directly
6493
+ setValidatedData(data);
6494
+ setIsError(false);
6495
+ onFormSubmit(data);
6113
6496
  }
6114
- // If validation passes, proceed to confirmation
6115
- setValidatedData(data);
6116
- setIsError(false);
6117
- setIsConfirming(true);
6118
6497
  };
6119
6498
  return (jsx(Button$1, { onClick: () => {
6120
6499
  methods.handleSubmit(onValid)();
6121
- }, formNoValidate: true, children: translate.t("submit") }));
6500
+ }, formNoValidate: true, children: translate.t('submit') }));
6122
6501
  };
6123
6502
 
6124
6503
  const FormBody = () => {
6125
- const { schema, requestUrl, order, ignore, include, onSubmit, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, } = useSchemaContext();
6504
+ const { schema, order, ignore, include, translate, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, onFormSubmit, } = useSchemaContext();
6126
6505
  const { showSubmitButton, showResetButton } = displayConfig;
6127
6506
  const methods = useFormContext();
6128
6507
  const { properties } = schema;
6129
- const onBeforeSubmit = () => {
6130
- setIsSubmiting(true);
6131
- };
6132
- const onAfterSubmit = () => {
6133
- setIsSubmiting(false);
6134
- };
6135
- const onSubmitError = (error) => {
6136
- setIsError(true);
6137
- setError(error);
6138
- };
6139
- const onSubmitSuccess = () => {
6140
- setIsSuccess(true);
6141
- };
6142
- const validateFormData = (data) => {
6143
- try {
6144
- const { isValid, errors } = validateData(data, schema);
6145
- return {
6146
- isValid,
6147
- errors,
6148
- };
6149
- }
6150
- catch (error) {
6151
- return {
6152
- isValid: false,
6153
- errors: [
6154
- {
6155
- field: "validation",
6156
- message: error instanceof Error ? error.message : "Unknown error",
6157
- },
6158
- ],
6159
- };
6160
- }
6161
- };
6162
- const defaultOnSubmit = async (promise) => {
6163
- try {
6164
- onBeforeSubmit();
6165
- await promise;
6166
- onSubmitSuccess();
6167
- }
6168
- catch (error) {
6169
- onSubmitError(error);
6170
- }
6171
- finally {
6172
- onAfterSubmit();
6173
- }
6174
- };
6175
- const defaultSubmitPromise = (data) => {
6176
- const options = {
6177
- method: "POST",
6178
- url: `${requestUrl}`,
6179
- data: clearEmptyString(data),
6180
- ...requestOptions,
6181
- };
6182
- return axios.request(options);
6183
- };
6184
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6185
- const onFormSubmit = async (data) => {
6186
- // Validate data using AJV before submission
6187
- const validationResult = validateFormData(data);
6188
- if (!validationResult.isValid) {
6189
- // Set validation errors
6190
- const validationErrorMessage = {
6191
- type: "validation",
6192
- errors: validationResult.errors,
6193
- message: translate.t("validation_error"),
6194
- };
6195
- onSubmitError(validationErrorMessage);
6196
- return;
6197
- }
6198
- if (onSubmit === undefined) {
6199
- await defaultOnSubmit(defaultSubmitPromise(data));
6200
- return;
6201
- }
6202
- await defaultOnSubmit(onSubmit(data));
6203
- };
6204
- // Custom error renderer for validation errors with i18n support
6205
- const renderValidationErrors = (validationErrors) => {
6206
- return (jsx(Flex, { flexFlow: "column", gap: "2", children: validationErrors.map((err, index) => (jsxs(Alert.Root, { status: "error", display: "flex", alignItems: "center", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Description, { children: err.message }) })] }, index))) }));
6207
- };
6208
6508
  const renderColumns = ({ order, keys, ignore, include, }) => {
6209
6509
  const included = include.length > 0 ? include : keys;
6210
6510
  const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
@@ -6231,32 +6531,30 @@ const FormBody = () => {
6231
6531
  if (customSuccessRenderer) {
6232
6532
  return customSuccessRenderer(resetHandler);
6233
6533
  }
6234
- return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsxs(Alert.Root, { status: "success", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Title, { children: translate.t("submit_success") }) })] }), jsx(Flex, { justifyContent: "end", children: jsx(Button$1, { onClick: resetHandler, formNoValidate: true, children: translate.t("submit_again") }) })] }));
6534
+ return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsxs(Alert.Root, { status: "success", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Title, { children: translate.t('submit_success') }) })] }), jsx(Flex, { justifyContent: 'end', children: jsx(Button$1, { onClick: resetHandler, formNoValidate: true, children: translate.t('submit_again') }) })] }));
6235
6535
  }
6236
6536
  if (isConfirming) {
6237
- return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: "repeat(12, max-content)", autoFlow: "row", children: ordered.map((column) => {
6537
+ return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: 'repeat(12, 1fr)', gridTemplateRows: 'repeat(12, max-content)', autoFlow: 'row', children: ordered.map((column) => {
6238
6538
  return (jsx(ColumnViewer
6239
6539
  // @ts-expect-error find suitable types
6240
6540
  , {
6241
6541
  // @ts-expect-error find suitable types
6242
6542
  properties: properties, prefix: ``, column }, `form-viewer-${column}`));
6243
- }) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [jsx(Button$1, { onClick: () => {
6543
+ }) }), jsxs(Flex, { justifyContent: 'end', gap: '2', children: [jsx(Button$1, { onClick: () => {
6244
6544
  setIsConfirming(false);
6245
- }, variant: "subtle", children: translate.t("cancel") }), jsx(Button$1, { onClick: () => {
6545
+ }, variant: 'subtle', children: translate.t('cancel') }), jsx(Button$1, { onClick: () => {
6246
6546
  onFormSubmit(validatedData);
6247
- }, children: translate.t("confirm") })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === "validation" &&
6248
- error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
6547
+ }, children: translate.t('confirm') })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && customErrorRenderer && customErrorRenderer(error)] }));
6249
6548
  }
6250
- return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: ordered.map((column) => {
6549
+ return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
6251
6550
  return (jsx(ColumnRenderer
6252
6551
  // @ts-expect-error find suitable types
6253
6552
  , {
6254
6553
  // @ts-expect-error find suitable types
6255
- properties: properties, prefix: ``, column }, `form-input-${column}`));
6256
- }) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
6554
+ properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
6555
+ }) }), jsxs(Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
6257
6556
  methods.reset();
6258
- }, variant: "subtle", children: translate.t("reset") })), showSubmitButton && jsx(SubmitButton, {})] }), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === "validation" &&
6259
- error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
6557
+ }, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
6260
6558
  };
6261
6559
 
6262
6560
  const FormTitle = () => {
@@ -6269,12 +6567,15 @@ const DefaultForm = ({ formConfig, }) => {
6269
6567
  return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
6270
6568
  };
6271
6569
 
6272
- const useForm = ({ preLoadedValues, keyPrefix, namespace }) => {
6570
+ const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
6273
6571
  const form = useForm$1({
6274
6572
  values: preLoadedValues,
6573
+ resolver: schema ? ajvResolver(schema) : undefined,
6574
+ mode: 'onBlur',
6575
+ reValidateMode: 'onBlur',
6275
6576
  });
6276
6577
  const [idMap, setIdMap] = useState({});
6277
- const translate = useTranslation(namespace || "", { keyPrefix });
6578
+ const translate = useTranslation(namespace || '', { keyPrefix });
6278
6579
  return {
6279
6580
  form,
6280
6581
  idMap,
@@ -6344,15 +6645,15 @@ const buildErrorMessages = (config) => {
6344
6645
  }
6345
6646
  // Add global fallback error messages
6346
6647
  const globalKeys = [
6347
- "minLength",
6348
- "maxLength",
6349
- "pattern",
6350
- "minimum",
6351
- "maximum",
6352
- "multipleOf",
6353
- "format",
6354
- "type",
6355
- "enum",
6648
+ 'minLength',
6649
+ 'maxLength',
6650
+ 'pattern',
6651
+ 'minimum',
6652
+ 'maximum',
6653
+ 'multipleOf',
6654
+ 'format',
6655
+ 'type',
6656
+ 'enum',
6356
6657
  ];
6357
6658
  globalKeys.forEach((key) => {
6358
6659
  if (config[key]) {
@@ -6361,6 +6662,46 @@ const buildErrorMessages = (config) => {
6361
6662
  });
6362
6663
  return result;
6363
6664
  };
6665
+ /**
6666
+ * Converts buildErrorMessages result to ajv-errors compatible format
6667
+ */
6668
+ const convertToAjvErrorsFormat = (errorMessages) => {
6669
+ const result = {};
6670
+ // Convert required field errors
6671
+ if (errorMessages.required) {
6672
+ result.required = errorMessages.required;
6673
+ }
6674
+ // Convert properties errors to ajv-errors format
6675
+ if (errorMessages.properties) {
6676
+ result.properties = {};
6677
+ Object.keys(errorMessages.properties).forEach((fieldName) => {
6678
+ const fieldErrors = errorMessages.properties[fieldName];
6679
+ result.properties[fieldName] = {};
6680
+ Object.keys(fieldErrors).forEach((keyword) => {
6681
+ result.properties[fieldName][keyword] =
6682
+ fieldErrors[keyword];
6683
+ });
6684
+ });
6685
+ }
6686
+ // Add global fallback errors
6687
+ const globalKeys = [
6688
+ 'minLength',
6689
+ 'maxLength',
6690
+ 'pattern',
6691
+ 'minimum',
6692
+ 'maximum',
6693
+ 'multipleOf',
6694
+ 'format',
6695
+ 'type',
6696
+ 'enum',
6697
+ ];
6698
+ globalKeys.forEach((key) => {
6699
+ if (errorMessages[key]) {
6700
+ result[key] = errorMessages[key];
6701
+ }
6702
+ });
6703
+ return result;
6704
+ };
6364
6705
  /**
6365
6706
  * Helper function to build required field errors
6366
6707
  *
@@ -6403,10 +6744,10 @@ const buildErrorMessages = (config) => {
6403
6744
  * // Result: { username: "user.username.field_required", email: "user.email.field_required" }
6404
6745
  * ```
6405
6746
  */
6406
- const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = "") => {
6747
+ const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = '') => {
6407
6748
  const result = {};
6408
6749
  fields.forEach((field) => {
6409
- if (typeof messageOrGenerator === "function") {
6750
+ if (typeof messageOrGenerator === 'function') {
6410
6751
  const message = messageOrGenerator(field);
6411
6752
  result[field] = keyPrefix ? `${keyPrefix}.${message}` : message;
6412
6753
  }
@@ -6477,11 +6818,14 @@ const buildFieldErrors = (config) => {
6477
6818
  * ```
6478
6819
  */
6479
6820
  const createErrorMessage = (required, properties, globalFallbacks) => {
6480
- return buildErrorMessages({
6821
+ const config = {
6481
6822
  required,
6482
6823
  properties,
6483
- ...globalFallbacks,
6484
- });
6824
+ };
6825
+ if (globalFallbacks) {
6826
+ Object.assign(config, globalFallbacks);
6827
+ }
6828
+ return buildErrorMessages(config);
6485
6829
  };
6486
6830
 
6487
6831
  const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) => {
@@ -6500,4 +6844,4 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
6500
6844
  }
6501
6845
  };
6502
6846
 
6503
- export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, createErrorMessage, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
6847
+ export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };