@bsol-oss/react-datatable5 12.0.0-beta.74 → 12.0.0-beta.76

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 (85) hide show
  1. package/dist/index.d.ts +159 -126
  2. package/dist/index.js +820 -279
  3. package/dist/index.mjs +822 -282
  4. package/dist/types/components/Form/SchemaFormContext.d.ts +5 -3
  5. package/dist/types/components/Form/components/core/FormRoot.d.ts +3 -2
  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/DateRangePicker.d.ts +2 -0
  9. package/dist/types/components/Form/components/fields/DateTimePicker.d.ts +1 -1
  10. package/dist/types/components/Form/components/fields/FilePicker.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/SchemaRenderer.d.ts +1 -1
  14. package/dist/types/components/Form/components/fields/StringInputField.d.ts +1 -1
  15. package/dist/types/components/Form/components/fields/TextAreaInput.d.ts +1 -1
  16. package/dist/types/components/Form/components/fields/TimePicker.d.ts +1 -1
  17. package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +28 -0
  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/formatBytes.d.ts +6 -0
  22. package/dist/types/components/Form/utils/getFieldError.d.ts +6 -0
  23. package/dist/types/components/Form/utils/useFormI18n.d.ts +1 -1
  24. package/dist/types/components/Form/utils/validateData.d.ts +2 -2
  25. package/dist/types/components/ui/field.d.ts +3 -3
  26. package/package.json +1 -1
  27. package/dist/types/components/Controls/DensityFeature.d.ts +0 -23
  28. package/dist/types/components/Controls/DensityToggleButton.d.ts +0 -6
  29. package/dist/types/components/Controls/EditFilterButton.d.ts +0 -9
  30. package/dist/types/components/Controls/EditOrderButton.d.ts +0 -7
  31. package/dist/types/components/Controls/EditSortingButton.d.ts +0 -7
  32. package/dist/types/components/Controls/EditViewButton.d.ts +0 -7
  33. package/dist/types/components/Controls/FilterDialog.d.ts +0 -5
  34. package/dist/types/components/Controls/PageSizeControl.d.ts +0 -4
  35. package/dist/types/components/Controls/Pagination.d.ts +0 -1
  36. package/dist/types/components/Controls/ResetFilteringButton.d.ts +0 -4
  37. package/dist/types/components/Controls/ResetSelectionButton.d.ts +0 -4
  38. package/dist/types/components/Controls/ResetSortingButton.d.ts +0 -4
  39. package/dist/types/components/Controls/RowCountText.d.ts +0 -1
  40. package/dist/types/components/Controls/SelectAllRowsToggle.d.ts +0 -8
  41. package/dist/types/components/Controls/TablePagination.d.ts +0 -1
  42. package/dist/types/components/Controls/ViewDialog.d.ts +0 -5
  43. package/dist/types/components/DataTable/CardHeader.d.ts +0 -13
  44. package/dist/types/components/DataTable/DataDisplay.d.ts +0 -6
  45. package/dist/types/components/DataTable/ReloadButton.d.ts +0 -5
  46. package/dist/types/components/DataTable/Table.d.ts +0 -10
  47. package/dist/types/components/DataTable/TableBody.d.ts +0 -21
  48. package/dist/types/components/DataTable/TableCardContainer.d.ts +0 -7
  49. package/dist/types/components/DataTable/TableCards.d.ts +0 -11
  50. package/dist/types/components/DataTable/TableComponent.d.ts +0 -6
  51. package/dist/types/components/DataTable/TableControls.d.ts +0 -21
  52. package/dist/types/components/DataTable/TableFilter.d.ts +0 -1
  53. package/dist/types/components/DataTable/TableFilterTags.d.ts +0 -1
  54. package/dist/types/components/DataTable/TableFilters.d.ts +0 -1
  55. package/dist/types/components/DataTable/TableFooter.d.ts +0 -9
  56. package/dist/types/components/DataTable/TableHeader.d.ts +0 -13
  57. package/dist/types/components/DataTable/TableLoadingComponent.d.ts +0 -5
  58. package/dist/types/components/DataTable/TableOrderer.d.ts +0 -1
  59. package/dist/types/components/DataTable/TableSelector.d.ts +0 -1
  60. package/dist/types/components/DataTable/TableSorter.d.ts +0 -1
  61. package/dist/types/components/DataTable/TableViewer.d.ts +0 -1
  62. package/dist/types/components/DataTable/TextCell.d.ts +0 -10
  63. package/dist/types/components/DataTable/components/EmptyState.d.ts +0 -5
  64. package/dist/types/components/DataTable/components/ErrorAlert.d.ts +0 -4
  65. package/dist/types/components/DataTable/components/RecordDisplay.d.ts +0 -9
  66. package/dist/types/components/DataTable/components/TextCell.d.ts +0 -10
  67. package/dist/types/components/Filter/DateRangeFilter.d.ts +0 -9
  68. package/dist/types/components/Filter/FilterOptions.d.ts +0 -4
  69. package/dist/types/components/Form/Form.d.ts +0 -36
  70. package/dist/types/components/Form/components/ArrayRenderer.d.ts +0 -7
  71. package/dist/types/components/Form/components/BooleanPicker.d.ts +0 -7
  72. package/dist/types/components/Form/components/ColumnRenderer.d.ts +0 -7
  73. package/dist/types/components/Form/components/DatePicker.d.ts +0 -7
  74. package/dist/types/components/Form/components/EnumPicker.d.ts +0 -8
  75. package/dist/types/components/Form/components/FilePicker.d.ts +0 -5
  76. package/dist/types/components/Form/components/IdPicker.d.ts +0 -8
  77. package/dist/types/components/Form/components/IdViewer.d.ts +0 -5
  78. package/dist/types/components/Form/components/NumberInputField.d.ts +0 -7
  79. package/dist/types/components/Form/components/ObjectInput.d.ts +0 -7
  80. package/dist/types/components/Form/components/RecordInput.d.ts +0 -7
  81. package/dist/types/components/Form/components/SchemaRenderer.d.ts +0 -7
  82. package/dist/types/components/Form/components/StringInputField.d.ts +0 -20
  83. package/dist/types/components/Form/components/TagPicker.d.ts +0 -30
  84. package/dist/types/components/Form/utils/translateWrapper.d.ts +0 -6
  85. 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, LuFile, LuSearch } 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: {},
@@ -3673,19 +3662,23 @@ const SchemaFormContext = createContext({
3673
3662
  },
3674
3663
  requireConfirmation: false,
3675
3664
  onFormSubmit: async () => { },
3665
+ ajvResolver: async () => ({ values: {}, errors: {} }),
3676
3666
  });
3677
3667
 
3678
3668
  const useSchemaContext = () => {
3679
3669
  return useContext(SchemaFormContext);
3680
3670
  };
3681
3671
 
3672
+ const clearEmptyString = (object) => {
3673
+ return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
3674
+ };
3675
+
3682
3676
  const validateData = (data, schema) => {
3683
3677
  const ajv = new Ajv({
3684
3678
  strict: false,
3685
3679
  allErrors: true,
3686
3680
  });
3687
3681
  addFormats(ajv);
3688
- addErrors(ajv);
3689
3682
  const validate = ajv.compile(schema);
3690
3683
  const validationResult = validate(data);
3691
3684
  const errors = validate.errors;
@@ -3697,8 +3690,183 @@ const validateData = (data, schema) => {
3697
3690
  };
3698
3691
  };
3699
3692
 
3700
- const clearEmptyString = (object) => {
3701
- return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
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
+ };
3702
3870
  };
3703
3871
 
3704
3872
  const idPickerSanityCheck = (column, foreign_key) => {
@@ -3720,7 +3888,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3720
3888
  showSubmitButton: true,
3721
3889
  showResetButton: true,
3722
3890
  showTitle: true,
3723
- }, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, }) => {
3891
+ }, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, }) => {
3724
3892
  const [isSuccess, setIsSuccess] = useState(false);
3725
3893
  const [isError, setIsError] = useState(false);
3726
3894
  const [isSubmiting, setIsSubmiting] = useState(false);
@@ -3740,33 +3908,16 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3740
3908
  const onSubmitSuccess = () => {
3741
3909
  setIsSuccess(true);
3742
3910
  };
3743
- const validateFormData = (data) => {
3744
- try {
3745
- const { isValid, errors } = validateData(data, schema);
3746
- return {
3747
- isValid,
3748
- errors,
3749
- };
3750
- }
3751
- catch (error) {
3752
- return {
3753
- isValid: false,
3754
- errors: [
3755
- {
3756
- field: 'validation',
3757
- message: error instanceof Error ? error.message : 'Unknown error',
3758
- },
3759
- ],
3760
- };
3761
- }
3762
- };
3763
3911
  const defaultOnSubmit = async (promise) => {
3764
3912
  try {
3913
+ console.log('onBeforeSubmit');
3765
3914
  onBeforeSubmit();
3766
3915
  await promise;
3916
+ console.log('onSubmitSuccess');
3767
3917
  onSubmitSuccess();
3768
3918
  }
3769
3919
  catch (error) {
3920
+ console.log('onSubmitError', error);
3770
3921
  onSubmitError(error);
3771
3922
  }
3772
3923
  finally {
@@ -3776,7 +3927,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3776
3927
  const defaultSubmitPromise = (data) => {
3777
3928
  const options = {
3778
3929
  method: 'POST',
3779
- url: `${requestUrl}`,
3930
+ url: `${serverUrl}`,
3780
3931
  data: clearEmptyString(data),
3781
3932
  ...requestOptions,
3782
3933
  };
@@ -3784,23 +3935,13 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3784
3935
  };
3785
3936
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3786
3937
  const onFormSubmit = async (data) => {
3787
- // Validate data using AJV before submission
3788
- const validationResult = validateFormData(data);
3789
- if (!validationResult.isValid) {
3790
- // Set validation errors
3791
- const validationErrorMessage = {
3792
- type: 'validation',
3793
- errors: validationResult.errors,
3794
- message: translate.t('validation_error'),
3795
- };
3796
- onSubmitError(validationErrorMessage);
3797
- return;
3798
- }
3938
+ // AJV validation is now handled by react-hook-form resolver
3939
+ // This function will only be called if validation passes
3799
3940
  if (onSubmit === undefined) {
3800
- await defaultOnSubmit(defaultSubmitPromise(data));
3941
+ await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
3801
3942
  return;
3802
3943
  }
3803
- await defaultOnSubmit(onSubmit(data));
3944
+ await defaultOnSubmit(Promise.resolve(onSubmit(data)));
3804
3945
  };
3805
3946
  return (jsx(SchemaFormContext.Provider, { value: {
3806
3947
  schema,
@@ -3836,6 +3977,8 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3836
3977
  dateTimePickerLabels,
3837
3978
  idPickerLabels,
3838
3979
  enumPickerLabels,
3980
+ filePickerLabels,
3981
+ ajvResolver: ajvResolver(schema),
3839
3982
  }, children: jsx(FormProvider, { ...form, children: children }) }));
3840
3983
  };
3841
3984
 
@@ -3881,20 +4024,22 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
3881
4024
 
3882
4025
  const Field = React.forwardRef(function Field(props, ref) {
3883
4026
  const { label, children, helperText, errorText, optionalText, ...rest } = props;
3884
- 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 }))] }));
4027
+ 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] }))] }));
3885
4028
  });
3886
4029
 
3887
4030
  const BooleanPicker = ({ schema, column, prefix }) => {
3888
4031
  const { watch, formState: { errors }, setValue, } = useFormContext();
3889
4032
  const { translate } = useSchemaContext();
3890
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4033
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
3891
4034
  const isRequired = required?.some((columnId) => columnId === column);
3892
4035
  const colLabel = `${prefix}${column}`;
3893
4036
  const value = watch(colLabel);
3894
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
3895
- gridRow, children: [jsx(CheckboxCard, { checked: value, variant: "surface", onChange: () => {
3896
- setValue(colLabel, !value);
3897
- } }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4037
+ return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4038
+ gridRow, errorText: errors[`${colLabel}`]
4039
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4040
+ : undefined, invalid: !!errors[colLabel], children: jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
4041
+ setValue(colLabel, !value);
4042
+ } }) }));
3898
4043
  };
3899
4044
 
3900
4045
  const CustomInput = ({ column, schema, prefix }) => {
@@ -4127,83 +4272,169 @@ const DatePicker = ({ column, schema, prefix }) => {
4127
4272
  console.error(e);
4128
4273
  }
4129
4274
  }, [selectedDate, dateFormat, colLabel, setValue]);
4130
- return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4131
- 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: () => {
4132
- setOpen(true);
4133
- }, 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 }) => {
4134
- setValue(colLabel, dayjs(date).format(dateFormat));
4135
- setOpen(false);
4136
- }, labels: {
4137
- monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
4138
- formI18n.translate.t(`common.month_1`, {
4139
- defaultValue: 'January',
4140
- }),
4141
- formI18n.translate.t(`common.month_2`, {
4142
- defaultValue: 'February',
4143
- }),
4144
- formI18n.translate.t(`common.month_3`, {
4145
- defaultValue: 'March',
4146
- }),
4147
- formI18n.translate.t(`common.month_4`, {
4148
- defaultValue: 'April',
4149
- }),
4150
- formI18n.translate.t(`common.month_5`, {
4151
- defaultValue: 'May',
4152
- }),
4153
- formI18n.translate.t(`common.month_6`, {
4154
- defaultValue: 'June',
4155
- }),
4156
- formI18n.translate.t(`common.month_7`, {
4157
- defaultValue: 'July',
4158
- }),
4159
- formI18n.translate.t(`common.month_8`, {
4160
- defaultValue: 'August',
4161
- }),
4162
- formI18n.translate.t(`common.month_9`, {
4163
- defaultValue: 'September',
4164
- }),
4165
- formI18n.translate.t(`common.month_10`, {
4166
- defaultValue: 'October',
4167
- }),
4168
- formI18n.translate.t(`common.month_11`, {
4169
- defaultValue: 'November',
4170
- }),
4171
- formI18n.translate.t(`common.month_12`, {
4172
- defaultValue: 'December',
4173
- }),
4174
- ],
4175
- weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
4176
- formI18n.translate.t(`common.weekday_1`, {
4177
- defaultValue: 'Sun',
4178
- }),
4179
- formI18n.translate.t(`common.weekday_2`, {
4180
- defaultValue: 'Mon',
4181
- }),
4182
- formI18n.translate.t(`common.weekday_3`, {
4183
- defaultValue: 'Tue',
4184
- }),
4185
- formI18n.translate.t(`common.weekday_4`, {
4186
- defaultValue: 'Wed',
4187
- }),
4188
- formI18n.translate.t(`common.weekday_5`, {
4189
- defaultValue: 'Thu',
4190
- }),
4191
- formI18n.translate.t(`common.weekday_6`, {
4192
- defaultValue: 'Fri',
4193
- }),
4194
- formI18n.translate.t(`common.weekday_7`, {
4195
- defaultValue: 'Sat',
4196
- }),
4197
- ],
4198
- backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
4199
- formI18n.translate.t(`common.back_button`, {
4200
- defaultValue: 'Back',
4201
- }),
4202
- forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
4203
- formI18n.translate.t(`common.forward_button`, {
4204
- defaultValue: 'Forward',
4205
- }),
4206
- } })] }) })] }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
4275
+ return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4276
+ 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: () => {
4277
+ setOpen(true);
4278
+ }, 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 }) => {
4279
+ setValue(colLabel, dayjs(date).format(dateFormat));
4280
+ setOpen(false);
4281
+ }, labels: {
4282
+ monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
4283
+ formI18n.translate.t(`common.month_1`, {
4284
+ defaultValue: 'January',
4285
+ }),
4286
+ formI18n.translate.t(`common.month_2`, {
4287
+ defaultValue: 'February',
4288
+ }),
4289
+ formI18n.translate.t(`common.month_3`, {
4290
+ defaultValue: 'March',
4291
+ }),
4292
+ formI18n.translate.t(`common.month_4`, {
4293
+ defaultValue: 'April',
4294
+ }),
4295
+ formI18n.translate.t(`common.month_5`, {
4296
+ defaultValue: 'May',
4297
+ }),
4298
+ formI18n.translate.t(`common.month_6`, {
4299
+ defaultValue: 'June',
4300
+ }),
4301
+ formI18n.translate.t(`common.month_7`, {
4302
+ defaultValue: 'July',
4303
+ }),
4304
+ formI18n.translate.t(`common.month_8`, {
4305
+ defaultValue: 'August',
4306
+ }),
4307
+ formI18n.translate.t(`common.month_9`, {
4308
+ defaultValue: 'September',
4309
+ }),
4310
+ formI18n.translate.t(`common.month_10`, {
4311
+ defaultValue: 'October',
4312
+ }),
4313
+ formI18n.translate.t(`common.month_11`, {
4314
+ defaultValue: 'November',
4315
+ }),
4316
+ formI18n.translate.t(`common.month_12`, {
4317
+ defaultValue: 'December',
4318
+ }),
4319
+ ],
4320
+ weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
4321
+ formI18n.translate.t(`common.weekday_1`, {
4322
+ defaultValue: 'Sun',
4323
+ }),
4324
+ formI18n.translate.t(`common.weekday_2`, {
4325
+ defaultValue: 'Mon',
4326
+ }),
4327
+ formI18n.translate.t(`common.weekday_3`, {
4328
+ defaultValue: 'Tue',
4329
+ }),
4330
+ formI18n.translate.t(`common.weekday_4`, {
4331
+ defaultValue: 'Wed',
4332
+ }),
4333
+ formI18n.translate.t(`common.weekday_5`, {
4334
+ defaultValue: 'Thu',
4335
+ }),
4336
+ formI18n.translate.t(`common.weekday_6`, {
4337
+ defaultValue: 'Fri',
4338
+ }),
4339
+ formI18n.translate.t(`common.weekday_7`, {
4340
+ defaultValue: 'Sat',
4341
+ }),
4342
+ ],
4343
+ backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
4344
+ formI18n.translate.t(`common.back_button`, {
4345
+ defaultValue: 'Back',
4346
+ }),
4347
+ forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
4348
+ formI18n.translate.t(`common.forward_button`, {
4349
+ defaultValue: 'Forward',
4350
+ }),
4351
+ } })] }) })] }) }));
4352
+ };
4353
+
4354
+ dayjs.extend(utc);
4355
+ dayjs.extend(timezone);
4356
+ const DateRangePicker = ({ column, schema, prefix, }) => {
4357
+ const { watch, formState: { errors }, setValue, } = useFormContext();
4358
+ const { timezone, dateTimePickerLabels } = useSchemaContext();
4359
+ const formI18n = useFormI18n(column, prefix);
4360
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
4361
+ const isRequired = required?.some((columnId) => columnId === column);
4362
+ const colLabel = formI18n.colLabel;
4363
+ const [open, setOpen] = useState(false);
4364
+ const selectedDateRange = watch(colLabel);
4365
+ // Convert string[] to Date[] for the picker
4366
+ const selectedDates = (selectedDateRange ?? [])
4367
+ .map((dateStr) => {
4368
+ if (!dateStr)
4369
+ return null;
4370
+ const parsed = dayjs(dateStr).tz(timezone);
4371
+ return parsed.isValid() ? parsed.toDate() : null;
4372
+ })
4373
+ .filter((date) => date !== null);
4374
+ // Format display string
4375
+ const getDisplayText = () => {
4376
+ if (!selectedDateRange || selectedDateRange.length === 0) {
4377
+ return '';
4378
+ }
4379
+ if (selectedDateRange.length === 1) {
4380
+ const date = dayjs(selectedDateRange[0]).tz(timezone);
4381
+ return date.isValid() ? date.format(displayDateFormat) : '';
4382
+ }
4383
+ if (selectedDateRange.length === 2) {
4384
+ const startDate = dayjs(selectedDateRange[0]).tz(timezone);
4385
+ const endDate = dayjs(selectedDateRange[1]).tz(timezone);
4386
+ if (startDate.isValid() && endDate.isValid()) {
4387
+ return `${startDate.format(displayDateFormat)} - ${endDate.format(displayDateFormat)}`;
4388
+ }
4389
+ }
4390
+ return '';
4391
+ };
4392
+ useEffect(() => {
4393
+ try {
4394
+ if (selectedDateRange && selectedDateRange.length > 0) {
4395
+ // Format dates according to dateFormat from schema
4396
+ const formatted = selectedDateRange
4397
+ .map((dateStr) => {
4398
+ if (!dateStr)
4399
+ return null;
4400
+ const parsed = dayjs(dateStr).tz(timezone);
4401
+ return parsed.isValid() ? parsed.format(dateFormat) : null;
4402
+ })
4403
+ .filter((date) => date !== null);
4404
+ // Update the form value only if different to avoid loops
4405
+ // Compare arrays element by element
4406
+ const needsUpdate = formatted.length !== selectedDateRange.length ||
4407
+ formatted.some((val, idx) => val !== selectedDateRange[idx]);
4408
+ if (needsUpdate && formatted.length > 0) {
4409
+ setValue(colLabel, formatted, {
4410
+ shouldValidate: true,
4411
+ shouldDirty: true,
4412
+ });
4413
+ }
4414
+ }
4415
+ }
4416
+ catch (e) {
4417
+ console.error(e);
4418
+ }
4419
+ }, [selectedDateRange, dateFormat, colLabel, setValue, timezone]);
4420
+ return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4421
+ 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: () => {
4422
+ setOpen(true);
4423
+ }, justifyContent: 'start', children: [jsx(MdDateRange, {}), getDisplayText()] }) }), jsx(PopoverContent, { minW: '600px', children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(RangeDatePicker, { selected: selectedDates, onDateSelected: ({ selected, selectable, date }) => {
4424
+ const newDates = getRangeDates({
4425
+ selectable,
4426
+ date,
4427
+ selectedDates,
4428
+ }) ?? [];
4429
+ // Convert Date[] to string[]
4430
+ const formattedDates = newDates
4431
+ .map((dateObj) => dayjs(dateObj).tz(timezone).format(dateFormat))
4432
+ .filter((dateStr) => dateStr);
4433
+ setValue(colLabel, formattedDates, {
4434
+ shouldValidate: true,
4435
+ shouldDirty: true,
4436
+ });
4437
+ }, monthsToDisplay: 2 })] }) })] }) }));
4207
4438
  };
4208
4439
 
4209
4440
  function filterArray(array, searchTerm) {
@@ -4238,7 +4469,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4238
4469
  };
4239
4470
  if (variant === 'radio') {
4240
4471
  return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4241
- gridRow, children: jsx(RadioGroup$1.Root, { defaultValue: "1", children: jsx(HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
4472
+ gridRow, errorText: errors[`${colLabel}`]
4473
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4474
+ : undefined, invalid: !!errors[colLabel], children: jsx(RadioGroup$1.Root, { defaultValue: "1", children: jsx(HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
4242
4475
  return (jsxs(RadioGroup$1.Item, { onClick: () => {
4243
4476
  if (!isMultiple) {
4244
4477
  setOpenSearchResult(false);
@@ -4253,7 +4486,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4253
4486
  }) }) }) }));
4254
4487
  }
4255
4488
  return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4256
- gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
4489
+ gridRow, errorText: errors[`${colLabel}`]
4490
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4491
+ : undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
4257
4492
  const item = enumValue;
4258
4493
  if (!!item === false) {
4259
4494
  return jsx(Fragment, {});
@@ -4308,7 +4543,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4308
4543
  ? renderDisplay(item)
4309
4544
  : translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
4310
4545
  }) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Fragment, { children: enumPickerLabels?.emptySearchResult ??
4311
- translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4546
+ translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] })] }));
4312
4547
  };
4313
4548
 
4314
4549
  function isEnteringWindow(_ref) {
@@ -4663,23 +4898,162 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
4663
4898
  return (jsxs(Grid, { ...getColor(isDraggedOver), ref: ref, cursor: "pointer", onClick: handleClick, borderStyle: "dashed", borderColor: "colorPalette.400", alignContent: "center", justifyContent: "center", borderWidth: 1, borderRadius: 4, ...gridProps, children: [children, !!children === false && (jsxs(Fragment, { children: [jsx(Flex, { children: placeholder }), jsx(Input, { type: "file", multiple: true, style: { display: "none" }, ref: fileInput, onChange: handleChange })] }))] }));
4664
4899
  };
4665
4900
 
4901
+ /**
4902
+ * Format bytes to human-readable string
4903
+ * @param bytes - The number of bytes to format
4904
+ * @returns Formatted string (e.g., "1.5 KB", "2.3 MB")
4905
+ */
4906
+ function formatBytes(bytes) {
4907
+ if (bytes === 0)
4908
+ return '0 Bytes';
4909
+ const k = 1024;
4910
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
4911
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
4912
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
4913
+ }
4914
+
4915
+ function FilePickerDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, labels, translate, colLabel, }) {
4916
+ const [searchTerm, setSearchTerm] = useState('');
4917
+ const [selectedFileId, setSelectedFileId] = useState('');
4918
+ const { data: filesData, isLoading, isError, } = useQuery({
4919
+ queryKey: ['file-picker-library', searchTerm],
4920
+ queryFn: async () => {
4921
+ if (!onFetchFiles)
4922
+ return { data: [] };
4923
+ const files = await onFetchFiles(searchTerm.trim() || '');
4924
+ return { data: files };
4925
+ },
4926
+ enabled: open && !!onFetchFiles,
4927
+ });
4928
+ const files = (filesData?.data || []);
4929
+ const filteredFiles = filterImageOnly
4930
+ ? files.filter((file) => /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name))
4931
+ : files;
4932
+ const handleSelect = () => {
4933
+ if (selectedFileId) {
4934
+ onSelect(selectedFileId);
4935
+ onClose();
4936
+ setSelectedFileId('');
4937
+ setSearchTerm('');
4938
+ }
4939
+ };
4940
+ const handleClose = () => {
4941
+ onClose();
4942
+ setSelectedFileId('');
4943
+ setSearchTerm('');
4944
+ };
4945
+ if (!onFetchFiles)
4946
+ return null;
4947
+ return (jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsx(DialogCloseTrigger, {})] }), jsx(DialogBody, { children: jsxs(VStack, { align: "stretch", gap: 4, children: [jsxs(Box, { position: "relative", children: [jsx(Input, { placeholder: labels?.searchPlaceholder ??
4948
+ translate(removeIndex(`${colLabel}.search_placeholder`)) ??
4949
+ 'Search files...', value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), bg: "bg.panel", border: "1px solid", borderColor: "border.default", _focus: {
4950
+ borderColor: 'blue.500',
4951
+ boxShadow: '0 0 0 1px var(--chakra-colors-blue-500)',
4952
+ }, pl: 10 }), jsx(Icon, { as: LuSearch, position: "absolute", left: 3, top: "50%", transform: "translateY(-50%)", color: "fg.muted", boxSize: 4 })] }), isLoading && (jsxs(Box, { textAlign: "center", py: 8, children: [jsx(Spinner, { size: "lg", colorPalette: "blue" }), jsx(Text, { mt: 4, color: "fg.muted", children: labels?.loading ??
4953
+ translate(removeIndex(`${colLabel}.loading`)) ??
4954
+ 'Loading files...' })] })), isError && (jsx(Box, { bg: "red.50", _dark: { bg: 'red.900/20' }, border: "1px solid", borderColor: "red.200", borderRadius: "md", p: 4, children: jsx(Text, { color: "red.600", _dark: { color: 'red.300' }, children: labels?.loadingFailed ??
4955
+ translate(removeIndex(`${colLabel}.error.loading_failed`)) ??
4956
+ 'Failed to load files' }) })), !isLoading && !isError && (jsx(Box, { maxHeight: "400px", overflowY: "auto", children: filteredFiles.length === 0 ? (jsx(Box, { textAlign: "center", py: 8, children: jsx(Text, { color: "fg.muted", children: labels?.noFilesFound ??
4957
+ translate(removeIndex(`${colLabel}.no_files_found`)) ??
4958
+ 'No files found' }) })) : (jsx(VStack, { align: "stretch", gap: 2, children: filteredFiles.map((file) => {
4959
+ const isImage = /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name);
4960
+ const isSelected = selectedFileId === file.id;
4961
+ return (jsx(Box, { p: 3, border: "2px solid", borderColor: isSelected ? 'blue.500' : 'border.default', borderRadius: "md", bg: isSelected ? 'blue.50' : 'bg.panel', _dark: {
4962
+ bg: isSelected ? 'blue.900/20' : 'bg.panel',
4963
+ }, cursor: "pointer", onClick: () => setSelectedFileId(file.id), _hover: {
4964
+ borderColor: isSelected ? 'blue.600' : 'blue.300',
4965
+ bg: isSelected ? 'blue.100' : 'bg.muted',
4966
+ }, transition: "all 0.2s", children: jsxs(HStack, { gap: 3, children: [jsx(Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, children: isImage && file.url ? (jsx(Image, { src: file.url, alt: file.name, boxSize: "60px", objectFit: "cover", borderRadius: "md" })) : (jsx(Icon, { as: LuFile, boxSize: 6, color: "fg.muted" })) }), jsxs(VStack, { align: "start", flex: 1, gap: 1, children: [jsx(Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.name }), jsxs(HStack, { gap: 2, children: [file.size && (jsx(Fragment, { children: jsx(Text, { fontSize: "xs", color: "fg.muted", children: typeof file.size === 'number'
4967
+ ? formatBytes(file.size)
4968
+ : file.size }) })), file.comment && (jsxs(Fragment, { children: [file.size && (jsx(Text, { fontSize: "xs", color: "fg.muted", children: "\u2022" })), jsx(Text, { fontSize: "xs", color: "fg.muted", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.comment })] }))] })] }), isSelected && (jsx(Box, { width: "24px", height: "24px", borderRadius: "full", bg: "blue.500", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, children: jsx(Text, { color: "white", fontSize: "xs", fontWeight: "bold", children: "\u2713" }) }))] }) }, file.id));
4969
+ }) })) }))] }) }), jsx(DialogFooter, { children: jsxs(HStack, { gap: 3, justify: "end", children: [jsx(Button$1, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ??
4970
+ translate(removeIndex(`${colLabel}.cancel`)) ??
4971
+ 'Cancel' }), jsx(Button$1, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFileId, children: labels?.select ??
4972
+ translate(removeIndex(`${colLabel}.select`)) ??
4973
+ 'Select' })] }) })] }) }));
4974
+ }
4666
4975
  const FilePicker = ({ column, schema, prefix }) => {
4667
4976
  const { setValue, formState: { errors }, watch, } = useFormContext();
4668
- const { translate } = useSchemaContext();
4669
- const { required, gridColumn = "span 12", gridRow = "span 1", } = schema;
4977
+ const { filePickerLabels } = useSchemaContext();
4978
+ const formI18n = useFormI18n(column, prefix);
4979
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, } = schema;
4670
4980
  const isRequired = required?.some((columnId) => columnId === column);
4671
- const currentFiles = (watch(column) ?? []);
4672
- const colLabel = `${prefix}${column}`;
4673
- 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 }) => {
4674
- const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
4675
- setValue(colLabel, [...currentFiles, ...newFiles]);
4676
- }, placeholder: translate.t(removeIndex(`${colLabel}.fileDropzone`)) }), jsx(Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
4677
- return (jsx(Card.Root, { variant: "subtle", children: jsxs(Card.Body, { gap: "2", cursor: "pointer", onClick: () => {
4678
- setValue(column, currentFiles.filter(({ name }) => {
4679
- return name !== file.name;
4680
- }));
4681
- }, 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));
4682
- }) }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4981
+ const currentValue = watch(column) ?? [];
4982
+ const currentFiles = Array.isArray(currentValue)
4983
+ ? currentValue
4984
+ : [];
4985
+ const colLabel = formI18n.colLabel;
4986
+ const [dialogOpen, setDialogOpen] = useState(false);
4987
+ const { onFetchFiles, enableMediaLibrary = false, filterImageOnly = false, } = filePicker || {};
4988
+ const showMediaLibrary = enableMediaLibrary && !!onFetchFiles;
4989
+ const handleMediaLibrarySelect = (fileId) => {
4990
+ const newFiles = [...currentFiles, fileId];
4991
+ setValue(colLabel, newFiles);
4992
+ };
4993
+ const handleRemove = (index) => {
4994
+ const newFiles = currentFiles.filter((_, i) => i !== index);
4995
+ setValue(colLabel, newFiles);
4996
+ };
4997
+ const isFileObject = (value) => {
4998
+ return value instanceof File;
4999
+ };
5000
+ const getFileIdentifier = (file, index) => {
5001
+ if (isFileObject(file)) {
5002
+ return `${file.name}-${file.size}-${index}`;
5003
+ }
5004
+ return file;
5005
+ };
5006
+ const getFileName = (file) => {
5007
+ if (isFileObject(file)) {
5008
+ return file.name;
5009
+ }
5010
+ return typeof file === 'string' ? file : 'Unknown file';
5011
+ };
5012
+ const getFileSize = (file) => {
5013
+ if (isFileObject(file)) {
5014
+ return file.size;
5015
+ }
5016
+ return undefined;
5017
+ };
5018
+ const isImageFile = (file) => {
5019
+ if (isFileObject(file)) {
5020
+ return file.type.startsWith('image/');
5021
+ }
5022
+ if (typeof file === 'string') {
5023
+ return /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file);
5024
+ }
5025
+ return false;
5026
+ };
5027
+ const getImageUrl = (file) => {
5028
+ if (isFileObject(file)) {
5029
+ return URL.createObjectURL(file);
5030
+ }
5031
+ return undefined;
5032
+ };
5033
+ return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
5034
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxs(VStack, { align: "stretch", gap: 2, children: [jsx(FileDropzone, { onDrop: ({ files }) => {
5035
+ const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => {
5036
+ if (isFileObject(cur)) {
5037
+ return cur.name === name;
5038
+ }
5039
+ return false;
5040
+ }));
5041
+ setValue(colLabel, [...currentFiles, ...newFiles]);
5042
+ }, placeholder: filePickerLabels?.fileDropzone ?? formI18n.t('fileDropzone') }), showMediaLibrary && (jsx(Button$1, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
5043
+ formI18n.t('browse_library') ??
5044
+ 'Browse from Library' }))] }), showMediaLibrary && (jsx(FilePickerDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
5045
+ formI18n.t('dialog_title') ??
5046
+ 'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, labels: filePickerLabels, translate: formI18n.t, colLabel: colLabel })), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
5047
+ const fileIdentifier = getFileIdentifier(file, index);
5048
+ const fileName = getFileName(file);
5049
+ const fileSize = getFileSize(file);
5050
+ const isImage = isImageFile(file);
5051
+ const imageUrl = getImageUrl(file);
5052
+ return (jsx(Card.Root, { variant: 'subtle', children: jsxs(Card.Body, { gap: "2", cursor: 'pointer', onClick: () => handleRemove(index), display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', border: "2px solid", borderColor: "border.default", borderRadius: "md", _hover: {
5053
+ borderColor: 'blue.300',
5054
+ bg: 'bg.muted',
5055
+ }, transition: "all 0.2s", children: [jsx(Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, marginRight: "2", children: isImage && imageUrl ? (jsx(Image, { src: imageUrl, alt: fileName, boxSize: "60px", objectFit: "cover", borderRadius: "md" })) : (jsx(Icon, { as: LuFile, boxSize: 6, color: "fg.muted" })) }), jsxs(VStack, { align: "start", flex: 1, gap: 1, children: [jsx(Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName }), fileSize !== undefined && (jsx(Text, { fontSize: "xs", color: "fg.muted", children: formatBytes(fileSize) }))] }), jsx(Icon, { as: TiDeleteOutline, boxSize: 5, color: "fg.muted" })] }) }, fileIdentifier));
5056
+ }) })] }));
4683
5057
  };
4684
5058
 
4685
5059
  const ToggleTip = React.forwardRef(function ToggleTip(props, ref) {
@@ -4868,7 +5242,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4868
5242
  return record[display_column];
4869
5243
  };
4870
5244
  return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4871
- gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
5245
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
4872
5246
  const item = idMap[id];
4873
5247
  if (item === undefined) {
4874
5248
  return (jsx(Text, { children: idPickerLabels?.undefined ?? formI18n.t('undefined') }, id));
@@ -4919,7 +5293,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4919
5293
  ? idPickerLabels?.emptySearchResult ??
4920
5294
  formI18n.t('empty_search_result')
4921
5295
  : idPickerLabels?.initialResults ??
4922
- 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() }))] }));
5296
+ 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, {})] }) })] }))] }) })] })] }));
4923
5297
  };
4924
5298
 
4925
5299
  const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
@@ -4930,20 +5304,84 @@ const NumberInputField$1 = NumberInput.Input;
4930
5304
  NumberInput.Scrubber;
4931
5305
  NumberInput.Label;
4932
5306
 
5307
+ /**
5308
+ * Gets the error message for a specific field from react-hook-form errors
5309
+ * Prioritizes required errors (#.required) over field-specific validation errors
5310
+ */
5311
+ const getFieldError = (errors, fieldName) => {
5312
+ // Check for form-level required errors first (highest priority)
5313
+ const requiredError = errors['#.required'];
5314
+ if (requiredError) {
5315
+ const requiredErrorMessage = extractErrorMessage(requiredError);
5316
+ if (requiredErrorMessage) {
5317
+ return requiredErrorMessage;
5318
+ }
5319
+ }
5320
+ // If no required errors, return field-specific error
5321
+ const fieldError = errors[fieldName];
5322
+ if (fieldError) {
5323
+ const fieldErrorMessage = extractErrorMessage(fieldError);
5324
+ if (fieldErrorMessage) {
5325
+ return fieldErrorMessage;
5326
+ }
5327
+ }
5328
+ return undefined;
5329
+ };
5330
+ /**
5331
+ * Helper function to extract error message from various error formats
5332
+ * Only returns message if explicitly provided, no fallback text
5333
+ */
5334
+ const extractErrorMessage = (error) => {
5335
+ if (!error) {
5336
+ return undefined;
5337
+ }
5338
+ // If it's a simple string error
5339
+ if (typeof error === 'string') {
5340
+ return error;
5341
+ }
5342
+ // If it's an error object with a message property
5343
+ if (error && typeof error === 'object' && 'message' in error) {
5344
+ return error.message;
5345
+ }
5346
+ // If it's an array of errors, get the first one
5347
+ if (Array.isArray(error) && error.length > 0) {
5348
+ const firstError = error[0];
5349
+ if (typeof firstError === 'string') {
5350
+ return firstError;
5351
+ }
5352
+ if (firstError &&
5353
+ typeof firstError === 'object' &&
5354
+ 'message' in firstError) {
5355
+ return firstError.message;
5356
+ }
5357
+ }
5358
+ // No fallback - return undefined if no message provided
5359
+ return undefined;
5360
+ };
5361
+
4933
5362
  const NumberInputField = ({ schema, column, prefix, }) => {
4934
5363
  const { setValue, formState: { errors }, watch, } = useFormContext();
4935
5364
  const { translate } = useSchemaContext();
4936
- const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5365
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', numberStorageType = 'number', } = schema;
4937
5366
  const isRequired = required?.some((columnId) => columnId === column);
4938
5367
  const colLabel = `${prefix}${column}`;
4939
5368
  const value = watch(`${colLabel}`);
4940
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(NumberInputRoot, { value: value, onValueChange: (details) => {
4941
- setValue(`${colLabel}`, details.value); // Store as string to avoid floating-point precision issues
4942
- }, 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 }) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5369
+ const fieldError = getFieldError(errors, colLabel);
5370
+ return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, errorText: fieldError
5371
+ ? fieldError.includes('required')
5372
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5373
+ : fieldError
5374
+ : undefined, invalid: !!fieldError, children: jsx(NumberInputRoot, { value: value, onValueChange: (details) => {
5375
+ // Store as string or number based on configuration, default to number
5376
+ const value = numberStorageType === 'string'
5377
+ ? details.value
5378
+ : details.valueAsNumber;
5379
+ setValue(`${colLabel}`, value);
5380
+ }, 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 }) }) }));
4943
5381
  };
4944
5382
 
4945
5383
  const ObjectInput = ({ schema, column, prefix }) => {
4946
- const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
5384
+ const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
4947
5385
  const { translate } = useSchemaContext();
4948
5386
  const colLabel = `${prefix}${column}`;
4949
5387
  const isRequired = required?.some((columnId) => columnId === column);
@@ -4951,29 +5389,32 @@ const ObjectInput = ({ schema, column, prefix }) => {
4951
5389
  if (properties === undefined) {
4952
5390
  throw new Error(`properties is undefined when using ObjectInput`);
4953
5391
  }
4954
- 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: {
4955
- base: "colorPalette.200",
4956
- _dark: "colorPalette.800",
4957
- }, gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: Object.keys(properties ?? {}).map((key) => {
5392
+ 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: {
5393
+ base: 'colorPalette.200',
5394
+ _dark: 'colorPalette.800',
5395
+ }, gap: "4", padding: '4', gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: Object.keys(properties ?? {}).map((key) => {
4958
5396
  return (
4959
5397
  // @ts-expect-error find suitable types
4960
5398
  jsx(ColumnRenderer, { column: `${key}`,
4961
5399
  prefix: `${prefix}${column}.`,
4962
- properties }, `form-${colLabel}-${key}`));
4963
- }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5400
+ properties,
5401
+ parentRequired: required }, `form-${colLabel}-${key}`));
5402
+ }) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4964
5403
  };
4965
5404
 
4966
5405
  const RecordInput$1 = ({ column, schema, prefix }) => {
4967
5406
  const { formState: { errors }, setValue, getValues, } = useFormContext();
4968
5407
  const { translate } = useSchemaContext();
4969
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5408
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
4970
5409
  const isRequired = required?.some((columnId) => columnId === column);
4971
5410
  const entries = Object.entries(getValues(column) ?? {});
4972
5411
  const [showNewEntries, setShowNewEntries] = useState(false);
4973
5412
  const [newKey, setNewKey] = useState();
4974
5413
  const [newValue, setNewValue] = useState();
4975
- return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
4976
- return (jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
5414
+ return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: 'stretch', gridColumn, gridRow, errorText: errors[`${column}`]
5415
+ ? translate.t(`${column}.field_required`)
5416
+ : undefined, invalid: !!errors[column], children: [entries.map(([key, value]) => {
5417
+ return (jsxs(Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
4977
5418
  const filtered = entries.filter(([target]) => {
4978
5419
  return target !== key;
4979
5420
  });
@@ -4983,17 +5424,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
4983
5424
  ...getValues(column),
4984
5425
  [key]: e.target.value,
4985
5426
  });
4986
- }, autoComplete: "off" }), jsx(IconButton, { variant: "ghost", onClick: () => {
5427
+ }, autoComplete: "off" }), jsx(IconButton, { variant: 'ghost', onClick: () => {
4987
5428
  const filtered = entries.filter(([target]) => {
4988
5429
  return target !== key;
4989
5430
  });
4990
5431
  setValue(column, Object.fromEntries([...filtered]));
4991
5432
  }, children: jsx(CgClose, {}) })] }));
4992
- }), 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) => {
5433
+ }), 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) => {
4993
5434
  setNewKey(e.target.value);
4994
5435
  }, autoComplete: "off" }), jsx(Input, { value: newValue, onChange: (e) => {
4995
5436
  setNewValue(e.target.value);
4996
- }, autoComplete: "off" })] }) }), jsxs(Card.Footer, { justifyContent: "flex-end", children: [jsx(IconButton, { variant: "subtle", onClick: () => {
5437
+ }, autoComplete: "off" })] }) }), jsxs(Card.Footer, { justifyContent: "flex-end", children: [jsx(IconButton, { variant: 'subtle', onClick: () => {
4997
5438
  setShowNewEntries(false);
4998
5439
  setNewKey(undefined);
4999
5440
  setNewValue(undefined);
@@ -5012,16 +5453,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
5012
5453
  setShowNewEntries(true);
5013
5454
  setNewKey(undefined);
5014
5455
  setNewValue(undefined);
5015
- }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
5456
+ }, children: translate.t(`${column}.addNew`) })] }));
5016
5457
  };
5017
5458
 
5018
5459
  const StringInputField = ({ column, schema, prefix, }) => {
5019
5460
  const { register, formState: { errors }, } = useFormContext();
5020
5461
  const { translate } = useSchemaContext();
5021
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5462
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5022
5463
  const isRequired = required?.some((columnId) => columnId === column);
5023
5464
  const colLabel = `${prefix}${column}`;
5024
- 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`)) }))] }) }));
5465
+ const fieldError = getFieldError(errors, colLabel);
5466
+ 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" }) }) }));
5025
5467
  };
5026
5468
 
5027
5469
  const RadioCardItem = React.forwardRef(function RadioCardItem(props, ref) {
@@ -5207,13 +5649,18 @@ Textarea.displayName = "Textarea";
5207
5649
  const TextAreaInput = ({ column, schema, prefix, }) => {
5208
5650
  const { register, formState: { errors }, } = useFormContext();
5209
5651
  const { translate } = useSchemaContext();
5210
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5652
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5211
5653
  const isRequired = required?.some((columnId) => columnId === column);
5212
5654
  const colLabel = `${prefix}${column}`;
5213
5655
  const form = useFormContext();
5214
5656
  const { setValue, watch } = form;
5657
+ const fieldError = getFieldError(errors, colLabel);
5215
5658
  const watchValue = watch(colLabel);
5216
- 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`)) }))] }) }));
5659
+ 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
5660
+ ? fieldError.includes('required')
5661
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5662
+ : fieldError
5663
+ : undefined, invalid: !!fieldError, children: jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }) }) }));
5217
5664
  };
5218
5665
 
5219
5666
  function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
@@ -5344,25 +5791,25 @@ dayjs.extend(timezone);
5344
5791
  const TimePicker = ({ column, schema, prefix }) => {
5345
5792
  const { watch, formState: { errors }, setValue, } = useFormContext();
5346
5793
  const { translate, timezone } = useSchemaContext();
5347
- const { required, gridColumn = "span 12", gridRow = "span 1", timeFormat = "HH:mm:ssZ", displayTimeFormat = "hh:mm A", } = schema;
5794
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
5348
5795
  const isRequired = required?.some((columnId) => columnId === column);
5349
5796
  const colLabel = `${prefix}${column}`;
5350
5797
  const [open, setOpen] = useState(false);
5351
5798
  const value = watch(colLabel);
5352
5799
  const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
5353
5800
  ? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
5354
- : "";
5801
+ : '';
5355
5802
  // Parse the initial time parts from the time string (HH:mm:ssZ)
5356
5803
  const parseTime = (time) => {
5357
5804
  if (!time)
5358
- return { hour: 12, minute: 0, meridiem: "am" };
5805
+ return { hour: 12, minute: 0, meridiem: 'am' };
5359
5806
  const parsed = dayjs(`1970-01-01T${time}`).tz(timezone);
5360
5807
  if (!parsed.isValid()) {
5361
- return { hour: 12, minute: 0, meridiem: "am" };
5808
+ return { hour: 12, minute: 0, meridiem: 'am' };
5362
5809
  }
5363
5810
  let hour = parsed.hour();
5364
5811
  const minute = parsed.minute();
5365
- const meridiem = hour >= 12 ? "pm" : "am";
5812
+ const meridiem = hour >= 12 ? 'pm' : 'am';
5366
5813
  if (hour === 0)
5367
5814
  hour = 12;
5368
5815
  else if (hour > 12)
@@ -5383,10 +5830,15 @@ const TimePicker = ({ column, schema, prefix }) => {
5383
5830
  if (hour === null || minute === null || meridiem === null)
5384
5831
  return null;
5385
5832
  let newHour = hour;
5386
- if (meridiem === "pm" && hour !== 12) {
5833
+ if (meridiem === 'pm' && hour !== 12) {
5387
5834
  newHour = hour + 12;
5388
5835
  }
5389
- return dayjs().tz(timezone).hour(newHour).minute(minute).second(0).format(timeFormat);
5836
+ return dayjs()
5837
+ .tz(timezone)
5838
+ .hour(newHour)
5839
+ .minute(minute)
5840
+ .second(0)
5841
+ .format(timeFormat);
5390
5842
  };
5391
5843
  // Handle changes to time parts
5392
5844
  const handleTimeChange = ({ hour: newHour, minute: newMinute, meridiem: newMeridiem, }) => {
@@ -5396,13 +5848,15 @@ const TimePicker = ({ column, schema, prefix }) => {
5396
5848
  const timeString = getTimeString(newHour, newMinute, newMeridiem);
5397
5849
  setValue(colLabel, timeString, { shouldValidate: true, shouldDirty: true });
5398
5850
  };
5399
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
5400
- 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: () => {
5401
- setOpen(true);
5402
- }, 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: {
5403
- am: translate.t(`common.am`, { defaultValue: "AM" }),
5404
- pm: translate.t(`common.pm`, { defaultValue: "PM" }),
5405
- } }) }) }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5851
+ return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
5852
+ gridRow, errorText: errors[`${colLabel}`]
5853
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5854
+ : 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: () => {
5855
+ setOpen(true);
5856
+ }, 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: {
5857
+ am: translate.t(`common.am`, { defaultValue: 'AM' }),
5858
+ pm: translate.t(`common.pm`, { defaultValue: 'PM' }),
5859
+ } }) }) }) })] }) }));
5406
5860
  };
5407
5861
 
5408
5862
  function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
@@ -5608,9 +6062,9 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
5608
6062
  const { watch, formState: { errors }, setValue, } = useFormContext();
5609
6063
  const { timezone, dateTimePickerLabels } = useSchemaContext();
5610
6064
  const formI18n = useFormI18n(column, prefix);
5611
- const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
6065
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
5612
6066
  // with timezone
5613
- dateFormat = "YYYY-MM-DD[T]HH:mm:ssZ", } = schema;
6067
+ dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
5614
6068
  const isRequired = required?.some((columnId) => columnId === column);
5615
6069
  const colLabel = formI18n.colLabel;
5616
6070
  const [open, setOpen] = useState(false);
@@ -5641,102 +6095,143 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
5641
6095
  console.error(e);
5642
6096
  }
5643
6097
  }, [selectedDate, dateFormat, colLabel, setValue]);
5644
- return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
5645
- 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: () => {
5646
- setOpen(true);
5647
- }, 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) => {
5648
- setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
5649
- }, timezone: timezone, labels: {
5650
- monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
5651
- formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
5652
- formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
5653
- formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
5654
- formI18n.translate.t(`common.month_4`, { defaultValue: "April" }),
5655
- formI18n.translate.t(`common.month_5`, { defaultValue: "May" }),
5656
- formI18n.translate.t(`common.month_6`, { defaultValue: "June" }),
5657
- formI18n.translate.t(`common.month_7`, { defaultValue: "July" }),
5658
- formI18n.translate.t(`common.month_8`, { defaultValue: "August" }),
5659
- formI18n.translate.t(`common.month_9`, { defaultValue: "September" }),
5660
- formI18n.translate.t(`common.month_10`, { defaultValue: "October" }),
5661
- formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
5662
- formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
5663
- ],
5664
- weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
5665
- formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
5666
- formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
5667
- formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
5668
- formI18n.translate.t(`common.weekday_4`, {
5669
- defaultValue: "Wed",
5670
- }),
5671
- formI18n.translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
5672
- formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
5673
- formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
5674
- ],
5675
- backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? formI18n.translate.t(`common.back_button`, {
5676
- defaultValue: "Back",
6098
+ return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
6099
+ 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: () => {
6100
+ setOpen(true);
6101
+ }, 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) => {
6102
+ setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
6103
+ }, timezone: timezone, labels: {
6104
+ monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
6105
+ formI18n.translate.t(`common.month_1`, {
6106
+ defaultValue: 'January',
6107
+ }),
6108
+ formI18n.translate.t(`common.month_2`, {
6109
+ defaultValue: 'February',
6110
+ }),
6111
+ formI18n.translate.t(`common.month_3`, {
6112
+ defaultValue: 'March',
6113
+ }),
6114
+ formI18n.translate.t(`common.month_4`, {
6115
+ defaultValue: 'April',
6116
+ }),
6117
+ formI18n.translate.t(`common.month_5`, {
6118
+ defaultValue: 'May',
6119
+ }),
6120
+ formI18n.translate.t(`common.month_6`, {
6121
+ defaultValue: 'June',
6122
+ }),
6123
+ formI18n.translate.t(`common.month_7`, {
6124
+ defaultValue: 'July',
6125
+ }),
6126
+ formI18n.translate.t(`common.month_8`, {
6127
+ defaultValue: 'August',
6128
+ }),
6129
+ formI18n.translate.t(`common.month_9`, {
6130
+ defaultValue: 'September',
6131
+ }),
6132
+ formI18n.translate.t(`common.month_10`, {
6133
+ defaultValue: 'October',
5677
6134
  }),
5678
- forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? formI18n.translate.t(`common.forward_button`, {
5679
- defaultValue: "Forward",
6135
+ formI18n.translate.t(`common.month_11`, {
6136
+ defaultValue: 'November',
5680
6137
  }),
5681
- } })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
6138
+ formI18n.translate.t(`common.month_12`, {
6139
+ defaultValue: 'December',
6140
+ }),
6141
+ ],
6142
+ weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
6143
+ formI18n.translate.t(`common.weekday_1`, {
6144
+ defaultValue: 'Sun',
6145
+ }),
6146
+ formI18n.translate.t(`common.weekday_2`, {
6147
+ defaultValue: 'Mon',
6148
+ }),
6149
+ formI18n.translate.t(`common.weekday_3`, {
6150
+ defaultValue: 'Tue',
6151
+ }),
6152
+ formI18n.translate.t(`common.weekday_4`, {
6153
+ defaultValue: 'Wed',
6154
+ }),
6155
+ formI18n.translate.t(`common.weekday_5`, {
6156
+ defaultValue: 'Thu',
6157
+ }),
6158
+ formI18n.translate.t(`common.weekday_6`, {
6159
+ defaultValue: 'Fri',
6160
+ }),
6161
+ formI18n.translate.t(`common.weekday_7`, {
6162
+ defaultValue: 'Sat',
6163
+ }),
6164
+ ],
6165
+ backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
6166
+ formI18n.translate.t(`common.back_button`, {
6167
+ defaultValue: 'Back',
6168
+ }),
6169
+ forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
6170
+ formI18n.translate.t(`common.forward_button`, {
6171
+ defaultValue: 'Forward',
6172
+ }),
6173
+ } })] }) })] }) }));
5682
6174
  };
5683
6175
 
5684
6176
  const SchemaRenderer = ({ schema, prefix, column, }) => {
5685
6177
  const colSchema = schema;
5686
6178
  const { type, variant, properties: innerProperties, foreign_key, format, items, } = schema;
5687
- if (variant === "custom-input") {
6179
+ if (variant === 'custom-input') {
5688
6180
  return jsx(CustomInput, { schema: colSchema, prefix, column });
5689
6181
  }
5690
- if (type === "string") {
6182
+ if (type === 'string') {
5691
6183
  if ((schema.enum ?? []).length > 0) {
5692
6184
  return jsx(EnumPicker, { schema: colSchema, prefix, column });
5693
6185
  }
5694
- if (variant === "id-picker") {
6186
+ if (variant === 'id-picker') {
5695
6187
  idPickerSanityCheck(column, foreign_key);
5696
6188
  return jsx(IdPicker, { schema: colSchema, prefix, column });
5697
6189
  }
5698
- if (format === "date") {
6190
+ if (format === 'date') {
5699
6191
  return jsx(DatePicker, { schema: colSchema, prefix, column });
5700
6192
  }
5701
- if (format === "time") {
6193
+ if (format === 'time') {
5702
6194
  return jsx(TimePicker, { schema: colSchema, prefix, column });
5703
6195
  }
5704
- if (format === "date-time") {
6196
+ if (format === 'date-time') {
5705
6197
  return jsx(DateTimePicker, { schema: colSchema, prefix, column });
5706
6198
  }
5707
- if (variant === "text-area") {
6199
+ if (variant === 'text-area') {
5708
6200
  return jsx(TextAreaInput, { schema: colSchema, prefix, column });
5709
6201
  }
5710
6202
  return jsx(StringInputField, { schema: colSchema, prefix, column });
5711
6203
  }
5712
- if (type === "number" || type === "integer") {
6204
+ if (type === 'number' || type === 'integer') {
5713
6205
  return jsx(NumberInputField, { schema: colSchema, prefix, column });
5714
6206
  }
5715
- if (type === "boolean") {
6207
+ if (type === 'boolean') {
5716
6208
  return jsx(BooleanPicker, { schema: colSchema, prefix, column });
5717
6209
  }
5718
- if (type === "object") {
6210
+ if (type === 'object') {
5719
6211
  if (innerProperties) {
5720
6212
  return jsx(ObjectInput, { schema: colSchema, prefix, column });
5721
6213
  }
5722
6214
  return jsx(RecordInput$1, { schema: colSchema, prefix, column });
5723
6215
  }
5724
- if (type === "array") {
5725
- if (variant === "id-picker") {
6216
+ if (type === 'array') {
6217
+ if (variant === 'id-picker') {
5726
6218
  idPickerSanityCheck(column, foreign_key);
5727
6219
  return (jsx(IdPicker, { schema: colSchema, prefix, column, isMultiple: true }));
5728
6220
  }
5729
- if (variant === "tag-picker") {
6221
+ if (variant === 'tag-picker') {
5730
6222
  return jsx(TagPicker, { schema: colSchema, prefix, column });
5731
6223
  }
5732
- if (variant === "file-picker") {
6224
+ if (variant === 'file-picker') {
5733
6225
  return jsx(FilePicker, { schema: colSchema, prefix, column });
5734
6226
  }
5735
- if (variant === "enum-picker") {
6227
+ if (variant === 'date-range') {
6228
+ return jsx(DateRangePicker, { schema: colSchema, prefix, column });
6229
+ }
6230
+ if (variant === 'enum-picker') {
5736
6231
  const { items } = colSchema;
5737
6232
  const { enum: enumItems } = items;
5738
6233
  const enumSchema = {
5739
- type: "string",
6234
+ type: 'string',
5740
6235
  enum: enumItems,
5741
6236
  };
5742
6237
  return (jsx(EnumPicker, { isMultiple: true, schema: enumSchema, prefix, column }));
@@ -5746,19 +6241,24 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
5746
6241
  }
5747
6242
  return jsx(Text, { children: `array ${column}` });
5748
6243
  }
5749
- if (type === "null") {
6244
+ if (type === 'null') {
5750
6245
  return jsx(Text, { children: `null ${column}` });
5751
6246
  }
5752
6247
  return jsx(Text, { children: "missing type" });
5753
6248
  };
5754
6249
 
5755
- const ColumnRenderer = ({ column, properties, prefix, }) => {
6250
+ const ColumnRenderer = ({ column, properties, prefix, parentRequired, }) => {
5756
6251
  const colSchema = properties[column];
5757
6252
  const colLabel = `${prefix}${column}`;
5758
6253
  if (colSchema === undefined) {
5759
6254
  throw new Error(`${colLabel} does not exist when using ColumnRenderer`);
5760
6255
  }
5761
- return jsx(SchemaRenderer, { schema: colSchema, prefix, column });
6256
+ // Merge parent's required array with the schema's required array
6257
+ const schemaWithRequired = {
6258
+ ...colSchema,
6259
+ required: parentRequired || colSchema.required,
6260
+ };
6261
+ return jsx(SchemaRenderer, { schema: schemaWithRequired, prefix, column });
5762
6262
  };
5763
6263
 
5764
6264
  const ArrayViewer = ({ schema, column, prefix }) => {
@@ -6199,15 +6699,15 @@ const SubmitButton = () => {
6199
6699
  const methods = useFormContext();
6200
6700
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6201
6701
  const onValid = (data) => {
6202
- const { isValid, errors } = validateData(data, schema);
6203
- if (!isValid) {
6204
- setError({
6205
- type: 'validation',
6206
- errors,
6207
- });
6208
- setIsError(true);
6209
- return;
6210
- }
6702
+ // const { isValid, errors } = validateData(data, schema);
6703
+ // if (!isValid) {
6704
+ // setError({
6705
+ // type: 'validation',
6706
+ // errors,
6707
+ // });
6708
+ // setIsError(true);
6709
+ // return;
6710
+ // }
6211
6711
  // If validation passes, check if confirmation is required
6212
6712
  if (requireConfirmation) {
6213
6713
  // Show confirmation (existing behavior)
@@ -6232,10 +6732,6 @@ const FormBody = () => {
6232
6732
  const { showSubmitButton, showResetButton } = displayConfig;
6233
6733
  const methods = useFormContext();
6234
6734
  const { properties } = schema;
6235
- // Custom error renderer for validation errors with i18n support
6236
- const renderValidationErrors = (validationErrors) => {
6237
- 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))) }));
6238
- };
6239
6735
  const renderColumns = ({ order, keys, ignore, include, }) => {
6240
6736
  const included = include.length > 0 ? include : keys;
6241
6737
  const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
@@ -6275,19 +6771,17 @@ const FormBody = () => {
6275
6771
  setIsConfirming(false);
6276
6772
  }, variant: 'subtle', children: translate.t('cancel') }), jsx(Button$1, { onClick: () => {
6277
6773
  onFormSubmit(validatedData);
6278
- }, 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' &&
6279
- 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)}` })] }) }) })] })] })) })) }))] }));
6774
+ }, 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)] }));
6280
6775
  }
6281
6776
  return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
6282
6777
  return (jsx(ColumnRenderer
6283
6778
  // @ts-expect-error find suitable types
6284
6779
  , {
6285
6780
  // @ts-expect-error find suitable types
6286
- properties: properties, prefix: ``, column }, `form-input-${column}`));
6781
+ properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
6287
6782
  }) }), jsxs(Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
6288
6783
  methods.reset();
6289
- }, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsx(SubmitButton, {})] }), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === 'validation' &&
6290
- 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)}` })] }) }) })] })] })) })) }))] }));
6784
+ }, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
6291
6785
  };
6292
6786
 
6293
6787
  const FormTitle = () => {
@@ -6300,12 +6794,15 @@ const DefaultForm = ({ formConfig, }) => {
6300
6794
  return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
6301
6795
  };
6302
6796
 
6303
- const useForm = ({ preLoadedValues, keyPrefix, namespace }) => {
6797
+ const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
6304
6798
  const form = useForm$1({
6305
6799
  values: preLoadedValues,
6800
+ resolver: schema ? ajvResolver(schema) : undefined,
6801
+ mode: 'onBlur',
6802
+ reValidateMode: 'onBlur',
6306
6803
  });
6307
6804
  const [idMap, setIdMap] = useState({});
6308
- const translate = useTranslation(namespace || "", { keyPrefix });
6805
+ const translate = useTranslation(namespace || '', { keyPrefix });
6309
6806
  return {
6310
6807
  form,
6311
6808
  idMap,
@@ -6375,15 +6872,15 @@ const buildErrorMessages = (config) => {
6375
6872
  }
6376
6873
  // Add global fallback error messages
6377
6874
  const globalKeys = [
6378
- "minLength",
6379
- "maxLength",
6380
- "pattern",
6381
- "minimum",
6382
- "maximum",
6383
- "multipleOf",
6384
- "format",
6385
- "type",
6386
- "enum",
6875
+ 'minLength',
6876
+ 'maxLength',
6877
+ 'pattern',
6878
+ 'minimum',
6879
+ 'maximum',
6880
+ 'multipleOf',
6881
+ 'format',
6882
+ 'type',
6883
+ 'enum',
6387
6884
  ];
6388
6885
  globalKeys.forEach((key) => {
6389
6886
  if (config[key]) {
@@ -6392,6 +6889,46 @@ const buildErrorMessages = (config) => {
6392
6889
  });
6393
6890
  return result;
6394
6891
  };
6892
+ /**
6893
+ * Converts buildErrorMessages result to ajv-errors compatible format
6894
+ */
6895
+ const convertToAjvErrorsFormat = (errorMessages) => {
6896
+ const result = {};
6897
+ // Convert required field errors
6898
+ if (errorMessages.required) {
6899
+ result.required = errorMessages.required;
6900
+ }
6901
+ // Convert properties errors to ajv-errors format
6902
+ if (errorMessages.properties) {
6903
+ result.properties = {};
6904
+ Object.keys(errorMessages.properties).forEach((fieldName) => {
6905
+ const fieldErrors = errorMessages.properties[fieldName];
6906
+ result.properties[fieldName] = {};
6907
+ Object.keys(fieldErrors).forEach((keyword) => {
6908
+ result.properties[fieldName][keyword] =
6909
+ fieldErrors[keyword];
6910
+ });
6911
+ });
6912
+ }
6913
+ // Add global fallback errors
6914
+ const globalKeys = [
6915
+ 'minLength',
6916
+ 'maxLength',
6917
+ 'pattern',
6918
+ 'minimum',
6919
+ 'maximum',
6920
+ 'multipleOf',
6921
+ 'format',
6922
+ 'type',
6923
+ 'enum',
6924
+ ];
6925
+ globalKeys.forEach((key) => {
6926
+ if (errorMessages[key]) {
6927
+ result[key] = errorMessages[key];
6928
+ }
6929
+ });
6930
+ return result;
6931
+ };
6395
6932
  /**
6396
6933
  * Helper function to build required field errors
6397
6934
  *
@@ -6434,10 +6971,10 @@ const buildErrorMessages = (config) => {
6434
6971
  * // Result: { username: "user.username.field_required", email: "user.email.field_required" }
6435
6972
  * ```
6436
6973
  */
6437
- const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = "") => {
6974
+ const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = '') => {
6438
6975
  const result = {};
6439
6976
  fields.forEach((field) => {
6440
- if (typeof messageOrGenerator === "function") {
6977
+ if (typeof messageOrGenerator === 'function') {
6441
6978
  const message = messageOrGenerator(field);
6442
6979
  result[field] = keyPrefix ? `${keyPrefix}.${message}` : message;
6443
6980
  }
@@ -6508,11 +7045,14 @@ const buildFieldErrors = (config) => {
6508
7045
  * ```
6509
7046
  */
6510
7047
  const createErrorMessage = (required, properties, globalFallbacks) => {
6511
- return buildErrorMessages({
7048
+ const config = {
6512
7049
  required,
6513
7050
  properties,
6514
- ...globalFallbacks,
6515
- });
7051
+ };
7052
+ if (globalFallbacks) {
7053
+ Object.assign(config, globalFallbacks);
7054
+ }
7055
+ return buildErrorMessages(config);
6516
7056
  };
6517
7057
 
6518
7058
  const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) => {
@@ -6531,4 +7071,4 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
6531
7071
  }
6532
7072
  };
6533
7073
 
6534
- 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 };
7074
+ 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 };