@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.js CHANGED
@@ -31,7 +31,6 @@ var axios = require('axios');
31
31
  var reactHookForm = require('react-hook-form');
32
32
  var Ajv = require('ajv');
33
33
  var addFormats = require('ajv-formats');
34
- var addErrors = require('ajv-errors');
35
34
  var dayjs = require('dayjs');
36
35
  var utc = require('dayjs/plugin/utc');
37
36
  var timezone = require('dayjs/plugin/timezone');
@@ -3664,16 +3663,6 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
3664
3663
  })] }));
3665
3664
  };
3666
3665
 
3667
- const AccordionItemTrigger = React__namespace.forwardRef(function AccordionItemTrigger(props, ref) {
3668
- const { children, indicatorPlacement = "end", ...rest } = props;
3669
- return (jsxRuntime.jsxs(react.Accordion.ItemTrigger, { ...rest, ref: ref, children: [indicatorPlacement === "start" && (jsxRuntime.jsx(react.Accordion.ItemIndicator, { rotate: { base: "-90deg", _open: "0deg" }, children: jsxRuntime.jsx(lu.LuChevronDown, {}) })), jsxRuntime.jsx(react.HStack, { gap: "4", flex: "1", textAlign: "start", width: "full", children: children }), indicatorPlacement === "end" && (jsxRuntime.jsx(react.Accordion.ItemIndicator, { children: jsxRuntime.jsx(lu.LuChevronDown, {}) }))] }));
3670
- });
3671
- const AccordionItemContent = React__namespace.forwardRef(function AccordionItemContent(props, ref) {
3672
- return (jsxRuntime.jsx(react.Accordion.ItemContent, { children: jsxRuntime.jsx(react.Accordion.ItemBody, { ...props, ref: ref }) }));
3673
- });
3674
- const AccordionRoot = react.Accordion.Root;
3675
- const AccordionItem = react.Accordion.Item;
3676
-
3677
3666
  //@ts-expect-error TODO: find appropriate type
3678
3667
  const SchemaFormContext = React.createContext({
3679
3668
  schema: {},
@@ -3693,19 +3682,23 @@ const SchemaFormContext = React.createContext({
3693
3682
  },
3694
3683
  requireConfirmation: false,
3695
3684
  onFormSubmit: async () => { },
3685
+ ajvResolver: async () => ({ values: {}, errors: {} }),
3696
3686
  });
3697
3687
 
3698
3688
  const useSchemaContext = () => {
3699
3689
  return React.useContext(SchemaFormContext);
3700
3690
  };
3701
3691
 
3692
+ const clearEmptyString = (object) => {
3693
+ return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
3694
+ };
3695
+
3702
3696
  const validateData = (data, schema) => {
3703
3697
  const ajv = new Ajv({
3704
3698
  strict: false,
3705
3699
  allErrors: true,
3706
3700
  });
3707
3701
  addFormats(ajv);
3708
- addErrors(ajv);
3709
3702
  const validate = ajv.compile(schema);
3710
3703
  const validationResult = validate(data);
3711
3704
  const errors = validate.errors;
@@ -3717,8 +3710,183 @@ const validateData = (data, schema) => {
3717
3710
  };
3718
3711
  };
3719
3712
 
3720
- const clearEmptyString = (object) => {
3721
- return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
3713
+ /**
3714
+ * Gets the schema node for a field by following the path from root schema
3715
+ */
3716
+ const getSchemaNodeForField = (schema, fieldPath) => {
3717
+ if (!fieldPath || fieldPath === '') {
3718
+ return schema;
3719
+ }
3720
+ const pathParts = fieldPath.split('.');
3721
+ let currentSchema = schema;
3722
+ for (const part of pathParts) {
3723
+ if (currentSchema &&
3724
+ currentSchema.properties &&
3725
+ currentSchema.properties[part] &&
3726
+ typeof currentSchema.properties[part] === 'object' &&
3727
+ currentSchema.properties[part] !== null) {
3728
+ currentSchema = currentSchema.properties[part];
3729
+ }
3730
+ else {
3731
+ return undefined;
3732
+ }
3733
+ }
3734
+ return currentSchema;
3735
+ };
3736
+ /**
3737
+ * Converts AJV error objects to react-hook-form field errors format
3738
+ */
3739
+ const convertAjvErrorsToFieldErrors = (errors, schema) => {
3740
+ if (!errors || errors.length === 0) {
3741
+ return {};
3742
+ }
3743
+ const fieldErrors = {};
3744
+ errors.forEach((error) => {
3745
+ let fieldName = '';
3746
+ // Special handling for required keyword: map to the specific missing property
3747
+ if (error.keyword === 'required') {
3748
+ const basePath = (error.instancePath || '')
3749
+ .replace(/^\//, '')
3750
+ .replace(/\//g, '.');
3751
+ const missingProperty = (error.params &&
3752
+ error.params.missingProperty);
3753
+ if (missingProperty) {
3754
+ fieldName = basePath
3755
+ ? `${basePath}.${missingProperty}`
3756
+ : missingProperty;
3757
+ }
3758
+ else {
3759
+ // Fallback to schemaPath conversion if missingProperty is unavailable
3760
+ fieldName = (error.schemaPath || '')
3761
+ .replace(/^#\//, '#.')
3762
+ .replace(/\//g, '.');
3763
+ }
3764
+ }
3765
+ else {
3766
+ const fieldPath = error.instancePath || error.schemaPath;
3767
+ if (fieldPath) {
3768
+ fieldName = fieldPath.replace(/^\//, '').replace(/\//g, '.');
3769
+ }
3770
+ }
3771
+ if (fieldName) {
3772
+ // Get the schema node for this field to check for custom error messages
3773
+ const fieldSchema = getSchemaNodeForField(schema, fieldName);
3774
+ const customMessage = fieldSchema?.errorMessages?.[error.keyword];
3775
+ // Provide helpful fallback message if no custom message is provided
3776
+ const fallbackMessage = customMessage ||
3777
+ `Missing error message for ${error.keyword}. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`;
3778
+ if (error.keyword === 'required') {
3779
+ // Required errors override any existing non-required errors for this field
3780
+ fieldErrors[fieldName] = {
3781
+ type: 'required',
3782
+ keyword: error.keyword,
3783
+ params: error.params,
3784
+ message: fallbackMessage,
3785
+ };
3786
+ }
3787
+ else {
3788
+ const existing = fieldErrors[fieldName];
3789
+ if (existing) {
3790
+ // Do not override required errors
3791
+ if (existing.type === 'required') {
3792
+ return;
3793
+ }
3794
+ // Combine messages if multiple errors for same field
3795
+ existing.message = existing.message
3796
+ ? `${existing.message}; ${fallbackMessage}`
3797
+ : fallbackMessage;
3798
+ }
3799
+ else {
3800
+ fieldErrors[fieldName] = {
3801
+ type: error.keyword,
3802
+ keyword: error.keyword,
3803
+ params: error.params,
3804
+ message: fallbackMessage,
3805
+ };
3806
+ }
3807
+ }
3808
+ }
3809
+ });
3810
+ return fieldErrors;
3811
+ };
3812
+ /**
3813
+ * AJV resolver for react-hook-form
3814
+ * Integrates AJV validation with react-hook-form's validation system
3815
+ */
3816
+ /**
3817
+ * Strips null, undefined, and empty string values from an object
3818
+ */
3819
+ const stripEmptyValues = (obj) => {
3820
+ if (obj === null || obj === undefined) {
3821
+ return undefined;
3822
+ }
3823
+ if (typeof obj === 'string' && obj.trim() === '') {
3824
+ return undefined;
3825
+ }
3826
+ if (Array.isArray(obj)) {
3827
+ const filtered = obj
3828
+ .map(stripEmptyValues)
3829
+ .filter((item) => item !== undefined);
3830
+ return filtered.length > 0 ? filtered : undefined;
3831
+ }
3832
+ if (typeof obj === 'object' && obj !== null) {
3833
+ const result = {};
3834
+ let hasValues = false;
3835
+ for (const [key, value] of Object.entries(obj)) {
3836
+ const cleanedValue = stripEmptyValues(value);
3837
+ if (cleanedValue !== undefined) {
3838
+ result[key] = cleanedValue;
3839
+ hasValues = true;
3840
+ }
3841
+ }
3842
+ return hasValues ? result : undefined;
3843
+ }
3844
+ return obj;
3845
+ };
3846
+ const ajvResolver = (schema) => {
3847
+ return async (values) => {
3848
+ try {
3849
+ // Strip empty values before validation
3850
+ const cleanedValues = stripEmptyValues(values);
3851
+ // Use empty object for validation if all values were stripped
3852
+ const valuesToValidate = cleanedValues === undefined ? {} : cleanedValues;
3853
+ const { isValid, errors } = validateData(valuesToValidate, schema);
3854
+ console.debug('AJV Validation Result:', {
3855
+ isValid,
3856
+ errors,
3857
+ cleanedValues,
3858
+ valuesToValidate,
3859
+ });
3860
+ if (isValid) {
3861
+ return {
3862
+ values: (cleanedValues || {}),
3863
+ errors: {},
3864
+ };
3865
+ }
3866
+ const fieldErrors = convertAjvErrorsToFieldErrors(errors, schema);
3867
+ console.debug('AJV Validation Failed:', {
3868
+ errors,
3869
+ fieldErrors,
3870
+ cleanedValues,
3871
+ valuesToValidate,
3872
+ });
3873
+ return {
3874
+ values: {},
3875
+ errors: fieldErrors,
3876
+ };
3877
+ }
3878
+ catch (error) {
3879
+ return {
3880
+ values: {},
3881
+ errors: {
3882
+ root: {
3883
+ type: 'validation',
3884
+ message: error instanceof Error ? error.message : 'Validation failed',
3885
+ },
3886
+ },
3887
+ };
3888
+ }
3889
+ };
3722
3890
  };
3723
3891
 
3724
3892
  const idPickerSanityCheck = (column, foreign_key) => {
@@ -3740,7 +3908,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3740
3908
  showSubmitButton: true,
3741
3909
  showResetButton: true,
3742
3910
  showTitle: true,
3743
- }, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, }) => {
3911
+ }, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, }) => {
3744
3912
  const [isSuccess, setIsSuccess] = React.useState(false);
3745
3913
  const [isError, setIsError] = React.useState(false);
3746
3914
  const [isSubmiting, setIsSubmiting] = React.useState(false);
@@ -3760,33 +3928,16 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3760
3928
  const onSubmitSuccess = () => {
3761
3929
  setIsSuccess(true);
3762
3930
  };
3763
- const validateFormData = (data) => {
3764
- try {
3765
- const { isValid, errors } = validateData(data, schema);
3766
- return {
3767
- isValid,
3768
- errors,
3769
- };
3770
- }
3771
- catch (error) {
3772
- return {
3773
- isValid: false,
3774
- errors: [
3775
- {
3776
- field: 'validation',
3777
- message: error instanceof Error ? error.message : 'Unknown error',
3778
- },
3779
- ],
3780
- };
3781
- }
3782
- };
3783
3931
  const defaultOnSubmit = async (promise) => {
3784
3932
  try {
3933
+ console.log('onBeforeSubmit');
3785
3934
  onBeforeSubmit();
3786
3935
  await promise;
3936
+ console.log('onSubmitSuccess');
3787
3937
  onSubmitSuccess();
3788
3938
  }
3789
3939
  catch (error) {
3940
+ console.log('onSubmitError', error);
3790
3941
  onSubmitError(error);
3791
3942
  }
3792
3943
  finally {
@@ -3796,7 +3947,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3796
3947
  const defaultSubmitPromise = (data) => {
3797
3948
  const options = {
3798
3949
  method: 'POST',
3799
- url: `${requestUrl}`,
3950
+ url: `${serverUrl}`,
3800
3951
  data: clearEmptyString(data),
3801
3952
  ...requestOptions,
3802
3953
  };
@@ -3804,23 +3955,13 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3804
3955
  };
3805
3956
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
3806
3957
  const onFormSubmit = async (data) => {
3807
- // Validate data using AJV before submission
3808
- const validationResult = validateFormData(data);
3809
- if (!validationResult.isValid) {
3810
- // Set validation errors
3811
- const validationErrorMessage = {
3812
- type: 'validation',
3813
- errors: validationResult.errors,
3814
- message: translate.t('validation_error'),
3815
- };
3816
- onSubmitError(validationErrorMessage);
3817
- return;
3818
- }
3958
+ // AJV validation is now handled by react-hook-form resolver
3959
+ // This function will only be called if validation passes
3819
3960
  if (onSubmit === undefined) {
3820
- await defaultOnSubmit(defaultSubmitPromise(data));
3961
+ await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
3821
3962
  return;
3822
3963
  }
3823
- await defaultOnSubmit(onSubmit(data));
3964
+ await defaultOnSubmit(Promise.resolve(onSubmit(data)));
3824
3965
  };
3825
3966
  return (jsxRuntime.jsx(SchemaFormContext.Provider, { value: {
3826
3967
  schema,
@@ -3856,6 +3997,8 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3856
3997
  dateTimePickerLabels,
3857
3998
  idPickerLabels,
3858
3999
  enumPickerLabels,
4000
+ filePickerLabels,
4001
+ ajvResolver: ajvResolver(schema),
3859
4002
  }, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
3860
4003
  };
3861
4004
 
@@ -3901,20 +4044,22 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
3901
4044
 
3902
4045
  const Field = React__namespace.forwardRef(function Field(props, ref) {
3903
4046
  const { label, children, helperText, errorText, optionalText, ...rest } = props;
3904
- return (jsxRuntime.jsxs(react.Field.Root, { ref: ref, ...rest, children: [label && (jsxRuntime.jsxs(react.Field.Label, { children: [label, jsxRuntime.jsx(react.Field.RequiredIndicator, { fallback: optionalText })] })), children, helperText && (jsxRuntime.jsx(react.Field.HelperText, { children: helperText })), errorText && (jsxRuntime.jsx(react.Field.ErrorText, { children: errorText }))] }));
4047
+ return (jsxRuntime.jsxs(react.Field.Root, { ref: ref, ...rest, children: [label && (jsxRuntime.jsxs(react.Field.Label, { children: [label, jsxRuntime.jsx(react.Field.RequiredIndicator, { color: rest.invalid && rest.required ? 'red.500' : undefined, fallback: optionalText })] })), children, helperText && (jsxRuntime.jsx(react.Field.HelperText, { children: helperText })), !!errorText && (jsxRuntime.jsxs(react.Field.ErrorText, { children: [rest.required && rest.invalid && (jsxRuntime.jsx("span", { style: { color: 'var(--chakra-colors-red-500)' }, children: "* " })), errorText] }))] }));
3905
4048
  });
3906
4049
 
3907
4050
  const BooleanPicker = ({ schema, column, prefix }) => {
3908
4051
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
3909
4052
  const { translate } = useSchemaContext();
3910
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4053
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
3911
4054
  const isRequired = required?.some((columnId) => columnId === column);
3912
4055
  const colLabel = `${prefix}${column}`;
3913
4056
  const value = watch(colLabel);
3914
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
3915
- gridRow, children: [jsxRuntime.jsx(CheckboxCard, { checked: value, variant: "surface", onChange: () => {
3916
- setValue(colLabel, !value);
3917
- } }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4057
+ return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4058
+ gridRow, errorText: errors[`${colLabel}`]
4059
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4060
+ : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
4061
+ setValue(colLabel, !value);
4062
+ } }) }));
3918
4063
  };
3919
4064
 
3920
4065
  const CustomInput = ({ column, schema, prefix }) => {
@@ -4147,83 +4292,169 @@ const DatePicker = ({ column, schema, prefix }) => {
4147
4292
  console.error(e);
4148
4293
  }
4149
4294
  }, [selectedDate, dateFormat, colLabel, setValue]);
4150
- return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4151
- gridRow, children: [jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
4152
- setOpen(true);
4153
- }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
4154
- setValue(colLabel, dayjs(date).format(dateFormat));
4155
- setOpen(false);
4156
- }, labels: {
4157
- monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
4158
- formI18n.translate.t(`common.month_1`, {
4159
- defaultValue: 'January',
4160
- }),
4161
- formI18n.translate.t(`common.month_2`, {
4162
- defaultValue: 'February',
4163
- }),
4164
- formI18n.translate.t(`common.month_3`, {
4165
- defaultValue: 'March',
4166
- }),
4167
- formI18n.translate.t(`common.month_4`, {
4168
- defaultValue: 'April',
4169
- }),
4170
- formI18n.translate.t(`common.month_5`, {
4171
- defaultValue: 'May',
4172
- }),
4173
- formI18n.translate.t(`common.month_6`, {
4174
- defaultValue: 'June',
4175
- }),
4176
- formI18n.translate.t(`common.month_7`, {
4177
- defaultValue: 'July',
4178
- }),
4179
- formI18n.translate.t(`common.month_8`, {
4180
- defaultValue: 'August',
4181
- }),
4182
- formI18n.translate.t(`common.month_9`, {
4183
- defaultValue: 'September',
4184
- }),
4185
- formI18n.translate.t(`common.month_10`, {
4186
- defaultValue: 'October',
4187
- }),
4188
- formI18n.translate.t(`common.month_11`, {
4189
- defaultValue: 'November',
4190
- }),
4191
- formI18n.translate.t(`common.month_12`, {
4192
- defaultValue: 'December',
4193
- }),
4194
- ],
4195
- weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
4196
- formI18n.translate.t(`common.weekday_1`, {
4197
- defaultValue: 'Sun',
4198
- }),
4199
- formI18n.translate.t(`common.weekday_2`, {
4200
- defaultValue: 'Mon',
4201
- }),
4202
- formI18n.translate.t(`common.weekday_3`, {
4203
- defaultValue: 'Tue',
4204
- }),
4205
- formI18n.translate.t(`common.weekday_4`, {
4206
- defaultValue: 'Wed',
4207
- }),
4208
- formI18n.translate.t(`common.weekday_5`, {
4209
- defaultValue: 'Thu',
4210
- }),
4211
- formI18n.translate.t(`common.weekday_6`, {
4212
- defaultValue: 'Fri',
4213
- }),
4214
- formI18n.translate.t(`common.weekday_7`, {
4215
- defaultValue: 'Sat',
4216
- }),
4217
- ],
4218
- backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
4219
- formI18n.translate.t(`common.back_button`, {
4220
- defaultValue: 'Back',
4221
- }),
4222
- forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
4223
- formI18n.translate.t(`common.forward_button`, {
4224
- defaultValue: 'Forward',
4225
- }),
4226
- } })] }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
4295
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4296
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
4297
+ setOpen(true);
4298
+ }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
4299
+ setValue(colLabel, dayjs(date).format(dateFormat));
4300
+ setOpen(false);
4301
+ }, labels: {
4302
+ monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
4303
+ formI18n.translate.t(`common.month_1`, {
4304
+ defaultValue: 'January',
4305
+ }),
4306
+ formI18n.translate.t(`common.month_2`, {
4307
+ defaultValue: 'February',
4308
+ }),
4309
+ formI18n.translate.t(`common.month_3`, {
4310
+ defaultValue: 'March',
4311
+ }),
4312
+ formI18n.translate.t(`common.month_4`, {
4313
+ defaultValue: 'April',
4314
+ }),
4315
+ formI18n.translate.t(`common.month_5`, {
4316
+ defaultValue: 'May',
4317
+ }),
4318
+ formI18n.translate.t(`common.month_6`, {
4319
+ defaultValue: 'June',
4320
+ }),
4321
+ formI18n.translate.t(`common.month_7`, {
4322
+ defaultValue: 'July',
4323
+ }),
4324
+ formI18n.translate.t(`common.month_8`, {
4325
+ defaultValue: 'August',
4326
+ }),
4327
+ formI18n.translate.t(`common.month_9`, {
4328
+ defaultValue: 'September',
4329
+ }),
4330
+ formI18n.translate.t(`common.month_10`, {
4331
+ defaultValue: 'October',
4332
+ }),
4333
+ formI18n.translate.t(`common.month_11`, {
4334
+ defaultValue: 'November',
4335
+ }),
4336
+ formI18n.translate.t(`common.month_12`, {
4337
+ defaultValue: 'December',
4338
+ }),
4339
+ ],
4340
+ weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
4341
+ formI18n.translate.t(`common.weekday_1`, {
4342
+ defaultValue: 'Sun',
4343
+ }),
4344
+ formI18n.translate.t(`common.weekday_2`, {
4345
+ defaultValue: 'Mon',
4346
+ }),
4347
+ formI18n.translate.t(`common.weekday_3`, {
4348
+ defaultValue: 'Tue',
4349
+ }),
4350
+ formI18n.translate.t(`common.weekday_4`, {
4351
+ defaultValue: 'Wed',
4352
+ }),
4353
+ formI18n.translate.t(`common.weekday_5`, {
4354
+ defaultValue: 'Thu',
4355
+ }),
4356
+ formI18n.translate.t(`common.weekday_6`, {
4357
+ defaultValue: 'Fri',
4358
+ }),
4359
+ formI18n.translate.t(`common.weekday_7`, {
4360
+ defaultValue: 'Sat',
4361
+ }),
4362
+ ],
4363
+ backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
4364
+ formI18n.translate.t(`common.back_button`, {
4365
+ defaultValue: 'Back',
4366
+ }),
4367
+ forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
4368
+ formI18n.translate.t(`common.forward_button`, {
4369
+ defaultValue: 'Forward',
4370
+ }),
4371
+ } })] }) })] }) }));
4372
+ };
4373
+
4374
+ dayjs.extend(utc);
4375
+ dayjs.extend(timezone);
4376
+ const DateRangePicker = ({ column, schema, prefix, }) => {
4377
+ const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
4378
+ const { timezone, dateTimePickerLabels } = useSchemaContext();
4379
+ const formI18n = useFormI18n(column, prefix);
4380
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
4381
+ const isRequired = required?.some((columnId) => columnId === column);
4382
+ const colLabel = formI18n.colLabel;
4383
+ const [open, setOpen] = React.useState(false);
4384
+ const selectedDateRange = watch(colLabel);
4385
+ // Convert string[] to Date[] for the picker
4386
+ const selectedDates = (selectedDateRange ?? [])
4387
+ .map((dateStr) => {
4388
+ if (!dateStr)
4389
+ return null;
4390
+ const parsed = dayjs(dateStr).tz(timezone);
4391
+ return parsed.isValid() ? parsed.toDate() : null;
4392
+ })
4393
+ .filter((date) => date !== null);
4394
+ // Format display string
4395
+ const getDisplayText = () => {
4396
+ if (!selectedDateRange || selectedDateRange.length === 0) {
4397
+ return '';
4398
+ }
4399
+ if (selectedDateRange.length === 1) {
4400
+ const date = dayjs(selectedDateRange[0]).tz(timezone);
4401
+ return date.isValid() ? date.format(displayDateFormat) : '';
4402
+ }
4403
+ if (selectedDateRange.length === 2) {
4404
+ const startDate = dayjs(selectedDateRange[0]).tz(timezone);
4405
+ const endDate = dayjs(selectedDateRange[1]).tz(timezone);
4406
+ if (startDate.isValid() && endDate.isValid()) {
4407
+ return `${startDate.format(displayDateFormat)} - ${endDate.format(displayDateFormat)}`;
4408
+ }
4409
+ }
4410
+ return '';
4411
+ };
4412
+ React.useEffect(() => {
4413
+ try {
4414
+ if (selectedDateRange && selectedDateRange.length > 0) {
4415
+ // Format dates according to dateFormat from schema
4416
+ const formatted = selectedDateRange
4417
+ .map((dateStr) => {
4418
+ if (!dateStr)
4419
+ return null;
4420
+ const parsed = dayjs(dateStr).tz(timezone);
4421
+ return parsed.isValid() ? parsed.format(dateFormat) : null;
4422
+ })
4423
+ .filter((date) => date !== null);
4424
+ // Update the form value only if different to avoid loops
4425
+ // Compare arrays element by element
4426
+ const needsUpdate = formatted.length !== selectedDateRange.length ||
4427
+ formatted.some((val, idx) => val !== selectedDateRange[idx]);
4428
+ if (needsUpdate && formatted.length > 0) {
4429
+ setValue(colLabel, formatted, {
4430
+ shouldValidate: true,
4431
+ shouldDirty: true,
4432
+ });
4433
+ }
4434
+ }
4435
+ }
4436
+ catch (e) {
4437
+ console.error(e);
4438
+ }
4439
+ }, [selectedDateRange, dateFormat, colLabel, setValue, timezone]);
4440
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4441
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
4442
+ setOpen(true);
4443
+ }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), getDisplayText()] }) }), jsxRuntime.jsx(PopoverContent, { minW: '600px', children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(RangeDatePicker, { selected: selectedDates, onDateSelected: ({ selected, selectable, date }) => {
4444
+ const newDates = getRangeDates({
4445
+ selectable,
4446
+ date,
4447
+ selectedDates,
4448
+ }) ?? [];
4449
+ // Convert Date[] to string[]
4450
+ const formattedDates = newDates
4451
+ .map((dateObj) => dayjs(dateObj).tz(timezone).format(dateFormat))
4452
+ .filter((dateStr) => dateStr);
4453
+ setValue(colLabel, formattedDates, {
4454
+ shouldValidate: true,
4455
+ shouldDirty: true,
4456
+ });
4457
+ }, monthsToDisplay: 2 })] }) })] }) }));
4227
4458
  };
4228
4459
 
4229
4460
  function filterArray(array, searchTerm) {
@@ -4258,7 +4489,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4258
4489
  };
4259
4490
  if (variant === 'radio') {
4260
4491
  return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4261
- gridRow, children: jsxRuntime.jsx(react.RadioGroup.Root, { defaultValue: "1", children: jsxRuntime.jsx(react.HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
4492
+ gridRow, errorText: errors[`${colLabel}`]
4493
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4494
+ : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(react.RadioGroup.Root, { defaultValue: "1", children: jsxRuntime.jsx(react.HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
4262
4495
  return (jsxRuntime.jsxs(react.RadioGroup.Item, { onClick: () => {
4263
4496
  if (!isMultiple) {
4264
4497
  setOpenSearchResult(false);
@@ -4273,7 +4506,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4273
4506
  }) }) }) }));
4274
4507
  }
4275
4508
  return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4276
- gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
4509
+ gridRow, errorText: errors[`${colLabel}`]
4510
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4511
+ : undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
4277
4512
  const item = enumValue;
4278
4513
  if (!!item === false) {
4279
4514
  return jsxRuntime.jsx(jsxRuntime.Fragment, {});
@@ -4328,7 +4563,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4328
4563
  ? renderDisplay(item)
4329
4564
  : translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
4330
4565
  }) }), isDirty && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: dataList.length <= 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: enumPickerLabels?.emptySearchResult ??
4331
- translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4566
+ translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] })] }));
4332
4567
  };
4333
4568
 
4334
4569
  function isEnteringWindow(_ref) {
@@ -4683,23 +4918,162 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
4683
4918
  return (jsxRuntime.jsxs(react.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 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(react.Flex, { children: placeholder }), jsxRuntime.jsx(react.Input, { type: "file", multiple: true, style: { display: "none" }, ref: fileInput, onChange: handleChange })] }))] }));
4684
4919
  };
4685
4920
 
4921
+ /**
4922
+ * Format bytes to human-readable string
4923
+ * @param bytes - The number of bytes to format
4924
+ * @returns Formatted string (e.g., "1.5 KB", "2.3 MB")
4925
+ */
4926
+ function formatBytes(bytes) {
4927
+ if (bytes === 0)
4928
+ return '0 Bytes';
4929
+ const k = 1024;
4930
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
4931
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
4932
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
4933
+ }
4934
+
4935
+ function FilePickerDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, labels, translate, colLabel, }) {
4936
+ const [searchTerm, setSearchTerm] = React.useState('');
4937
+ const [selectedFileId, setSelectedFileId] = React.useState('');
4938
+ const { data: filesData, isLoading, isError, } = reactQuery.useQuery({
4939
+ queryKey: ['file-picker-library', searchTerm],
4940
+ queryFn: async () => {
4941
+ if (!onFetchFiles)
4942
+ return { data: [] };
4943
+ const files = await onFetchFiles(searchTerm.trim() || '');
4944
+ return { data: files };
4945
+ },
4946
+ enabled: open && !!onFetchFiles,
4947
+ });
4948
+ const files = (filesData?.data || []);
4949
+ const filteredFiles = filterImageOnly
4950
+ ? files.filter((file) => /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name))
4951
+ : files;
4952
+ const handleSelect = () => {
4953
+ if (selectedFileId) {
4954
+ onSelect(selectedFileId);
4955
+ onClose();
4956
+ setSelectedFileId('');
4957
+ setSearchTerm('');
4958
+ }
4959
+ };
4960
+ const handleClose = () => {
4961
+ onClose();
4962
+ setSelectedFileId('');
4963
+ setSearchTerm('');
4964
+ };
4965
+ if (!onFetchFiles)
4966
+ return null;
4967
+ return (jsxRuntime.jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxRuntime.jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxRuntime.jsxs(DialogHeader, { children: [jsxRuntime.jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsxRuntime.jsx(DialogCloseTrigger, {})] }), jsxRuntime.jsx(DialogBody, { children: jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 4, children: [jsxRuntime.jsxs(react.Box, { position: "relative", children: [jsxRuntime.jsx(react.Input, { placeholder: labels?.searchPlaceholder ??
4968
+ translate(removeIndex(`${colLabel}.search_placeholder`)) ??
4969
+ 'Search files...', value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), bg: "bg.panel", border: "1px solid", borderColor: "border.default", _focus: {
4970
+ borderColor: 'blue.500',
4971
+ boxShadow: '0 0 0 1px var(--chakra-colors-blue-500)',
4972
+ }, pl: 10 }), jsxRuntime.jsx(react.Icon, { as: lu.LuSearch, position: "absolute", left: 3, top: "50%", transform: "translateY(-50%)", color: "fg.muted", boxSize: 4 })] }), isLoading && (jsxRuntime.jsxs(react.Box, { textAlign: "center", py: 8, children: [jsxRuntime.jsx(react.Spinner, { size: "lg", colorPalette: "blue" }), jsxRuntime.jsx(react.Text, { mt: 4, color: "fg.muted", children: labels?.loading ??
4973
+ translate(removeIndex(`${colLabel}.loading`)) ??
4974
+ 'Loading files...' })] })), isError && (jsxRuntime.jsx(react.Box, { bg: "red.50", _dark: { bg: 'red.900/20' }, border: "1px solid", borderColor: "red.200", borderRadius: "md", p: 4, children: jsxRuntime.jsx(react.Text, { color: "red.600", _dark: { color: 'red.300' }, children: labels?.loadingFailed ??
4975
+ translate(removeIndex(`${colLabel}.error.loading_failed`)) ??
4976
+ 'Failed to load files' }) })), !isLoading && !isError && (jsxRuntime.jsx(react.Box, { maxHeight: "400px", overflowY: "auto", children: filteredFiles.length === 0 ? (jsxRuntime.jsx(react.Box, { textAlign: "center", py: 8, children: jsxRuntime.jsx(react.Text, { color: "fg.muted", children: labels?.noFilesFound ??
4977
+ translate(removeIndex(`${colLabel}.no_files_found`)) ??
4978
+ 'No files found' }) })) : (jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: filteredFiles.map((file) => {
4979
+ const isImage = /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name);
4980
+ const isSelected = selectedFileId === file.id;
4981
+ return (jsxRuntime.jsx(react.Box, { p: 3, border: "2px solid", borderColor: isSelected ? 'blue.500' : 'border.default', borderRadius: "md", bg: isSelected ? 'blue.50' : 'bg.panel', _dark: {
4982
+ bg: isSelected ? 'blue.900/20' : 'bg.panel',
4983
+ }, cursor: "pointer", onClick: () => setSelectedFileId(file.id), _hover: {
4984
+ borderColor: isSelected ? 'blue.600' : 'blue.300',
4985
+ bg: isSelected ? 'blue.100' : 'bg.muted',
4986
+ }, transition: "all 0.2s", children: jsxRuntime.jsxs(react.HStack, { gap: 3, children: [jsxRuntime.jsx(react.Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, children: isImage && file.url ? (jsxRuntime.jsx(react.Image, { src: file.url, alt: file.name, boxSize: "60px", objectFit: "cover", borderRadius: "md" })) : (jsxRuntime.jsx(react.Icon, { as: lu.LuFile, boxSize: 6, color: "fg.muted" })) }), jsxRuntime.jsxs(react.VStack, { align: "start", flex: 1, gap: 1, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.name }), jsxRuntime.jsxs(react.HStack, { gap: 2, children: [file.size && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: typeof file.size === 'number'
4987
+ ? formatBytes(file.size)
4988
+ : file.size }) })), file.comment && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [file.size && (jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: "\u2022" })), jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.comment })] }))] })] }), isSelected && (jsxRuntime.jsx(react.Box, { width: "24px", height: "24px", borderRadius: "full", bg: "blue.500", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, children: jsxRuntime.jsx(react.Text, { color: "white", fontSize: "xs", fontWeight: "bold", children: "\u2713" }) }))] }) }, file.id));
4989
+ }) })) }))] }) }), jsxRuntime.jsx(DialogFooter, { children: jsxRuntime.jsxs(react.HStack, { gap: 3, justify: "end", children: [jsxRuntime.jsx(react.Button, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ??
4990
+ translate(removeIndex(`${colLabel}.cancel`)) ??
4991
+ 'Cancel' }), jsxRuntime.jsx(react.Button, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFileId, children: labels?.select ??
4992
+ translate(removeIndex(`${colLabel}.select`)) ??
4993
+ 'Select' })] }) })] }) }));
4994
+ }
4686
4995
  const FilePicker = ({ column, schema, prefix }) => {
4687
4996
  const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
4688
- const { translate } = useSchemaContext();
4689
- const { required, gridColumn = "span 12", gridRow = "span 1", } = schema;
4997
+ const { filePickerLabels } = useSchemaContext();
4998
+ const formI18n = useFormI18n(column, prefix);
4999
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, } = schema;
4690
5000
  const isRequired = required?.some((columnId) => columnId === column);
4691
- const currentFiles = (watch(column) ?? []);
4692
- const colLabel = `${prefix}${column}`;
4693
- return (jsxRuntime.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: [jsxRuntime.jsx(FileDropzone, { onDrop: ({ files }) => {
4694
- const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
4695
- setValue(colLabel, [...currentFiles, ...newFiles]);
4696
- }, placeholder: translate.t(removeIndex(`${colLabel}.fileDropzone`)) }), jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
4697
- return (jsxRuntime.jsx(react.Card.Root, { variant: "subtle", children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", cursor: "pointer", onClick: () => {
4698
- setValue(column, currentFiles.filter(({ name }) => {
4699
- return name !== file.name;
4700
- }));
4701
- }, display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [file.type.startsWith("image/") && (jsxRuntime.jsx(react.Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsxRuntime.jsx(react.Box, { children: file.name }), jsxRuntime.jsx(ti.TiDeleteOutline, {})] }) }, file.name));
4702
- }) }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5001
+ const currentValue = watch(column) ?? [];
5002
+ const currentFiles = Array.isArray(currentValue)
5003
+ ? currentValue
5004
+ : [];
5005
+ const colLabel = formI18n.colLabel;
5006
+ const [dialogOpen, setDialogOpen] = React.useState(false);
5007
+ const { onFetchFiles, enableMediaLibrary = false, filterImageOnly = false, } = filePicker || {};
5008
+ const showMediaLibrary = enableMediaLibrary && !!onFetchFiles;
5009
+ const handleMediaLibrarySelect = (fileId) => {
5010
+ const newFiles = [...currentFiles, fileId];
5011
+ setValue(colLabel, newFiles);
5012
+ };
5013
+ const handleRemove = (index) => {
5014
+ const newFiles = currentFiles.filter((_, i) => i !== index);
5015
+ setValue(colLabel, newFiles);
5016
+ };
5017
+ const isFileObject = (value) => {
5018
+ return value instanceof File;
5019
+ };
5020
+ const getFileIdentifier = (file, index) => {
5021
+ if (isFileObject(file)) {
5022
+ return `${file.name}-${file.size}-${index}`;
5023
+ }
5024
+ return file;
5025
+ };
5026
+ const getFileName = (file) => {
5027
+ if (isFileObject(file)) {
5028
+ return file.name;
5029
+ }
5030
+ return typeof file === 'string' ? file : 'Unknown file';
5031
+ };
5032
+ const getFileSize = (file) => {
5033
+ if (isFileObject(file)) {
5034
+ return file.size;
5035
+ }
5036
+ return undefined;
5037
+ };
5038
+ const isImageFile = (file) => {
5039
+ if (isFileObject(file)) {
5040
+ return file.type.startsWith('image/');
5041
+ }
5042
+ if (typeof file === 'string') {
5043
+ return /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file);
5044
+ }
5045
+ return false;
5046
+ };
5047
+ const getImageUrl = (file) => {
5048
+ if (isFileObject(file)) {
5049
+ return URL.createObjectURL(file);
5050
+ }
5051
+ return undefined;
5052
+ };
5053
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
5054
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 2, children: [jsxRuntime.jsx(FileDropzone, { onDrop: ({ files }) => {
5055
+ const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => {
5056
+ if (isFileObject(cur)) {
5057
+ return cur.name === name;
5058
+ }
5059
+ return false;
5060
+ }));
5061
+ setValue(colLabel, [...currentFiles, ...newFiles]);
5062
+ }, placeholder: filePickerLabels?.fileDropzone ?? formI18n.t('fileDropzone') }), showMediaLibrary && (jsxRuntime.jsx(react.Button, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
5063
+ formI18n.t('browse_library') ??
5064
+ 'Browse from Library' }))] }), showMediaLibrary && (jsxRuntime.jsx(FilePickerDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
5065
+ formI18n.t('dialog_title') ??
5066
+ 'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, labels: filePickerLabels, translate: formI18n.t, colLabel: colLabel })), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
5067
+ const fileIdentifier = getFileIdentifier(file, index);
5068
+ const fileName = getFileName(file);
5069
+ const fileSize = getFileSize(file);
5070
+ const isImage = isImageFile(file);
5071
+ const imageUrl = getImageUrl(file);
5072
+ return (jsxRuntime.jsx(react.Card.Root, { variant: 'subtle', children: jsxRuntime.jsxs(react.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: {
5073
+ borderColor: 'blue.300',
5074
+ bg: 'bg.muted',
5075
+ }, transition: "all 0.2s", children: [jsxRuntime.jsx(react.Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, marginRight: "2", children: isImage && imageUrl ? (jsxRuntime.jsx(react.Image, { src: imageUrl, alt: fileName, boxSize: "60px", objectFit: "cover", borderRadius: "md" })) : (jsxRuntime.jsx(react.Icon, { as: lu.LuFile, boxSize: 6, color: "fg.muted" })) }), jsxRuntime.jsxs(react.VStack, { align: "start", flex: 1, gap: 1, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName }), fileSize !== undefined && (jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: formatBytes(fileSize) }))] }), jsxRuntime.jsx(react.Icon, { as: ti.TiDeleteOutline, boxSize: 5, color: "fg.muted" })] }) }, fileIdentifier));
5076
+ }) })] }));
4703
5077
  };
4704
5078
 
4705
5079
  const ToggleTip = React__namespace.forwardRef(function ToggleTip(props, ref) {
@@ -4888,7 +5262,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4888
5262
  return record[display_column];
4889
5263
  };
4890
5264
  return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4891
- gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
5265
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
4892
5266
  const item = idMap[id];
4893
5267
  if (item === undefined) {
4894
5268
  return (jsxRuntime.jsx(react.Text, { children: idPickerLabels?.undefined ?? formI18n.t('undefined') }, id));
@@ -4939,7 +5313,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4939
5313
  ? idPickerLabels?.emptySearchResult ??
4940
5314
  formI18n.t('empty_search_result')
4941
5315
  : idPickerLabels?.initialResults ??
4942
- formI18n.t('initial_results') })) }), jsxRuntime.jsx(PaginationRoot, { justifySelf: 'center', count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxRuntime.jsxs(react.HStack, { gap: "4", children: [jsxRuntime.jsx(PaginationPrevTrigger, {}), count > 0 && jsxRuntime.jsx(PaginationPageText, {}), jsxRuntime.jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
5316
+ formI18n.t('initial_results') })) }), jsxRuntime.jsx(PaginationRoot, { justifySelf: 'center', count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxRuntime.jsxs(react.HStack, { gap: "4", children: [jsxRuntime.jsx(PaginationPrevTrigger, {}), count > 0 && jsxRuntime.jsx(PaginationPageText, {}), jsxRuntime.jsx(PaginationNextTrigger, {})] }) })] }))] }) })] })] }));
4943
5317
  };
4944
5318
 
4945
5319
  const NumberInputRoot = React__namespace.forwardRef(function NumberInput(props, ref) {
@@ -4950,20 +5324,84 @@ const NumberInputField$1 = react.NumberInput.Input;
4950
5324
  react.NumberInput.Scrubber;
4951
5325
  react.NumberInput.Label;
4952
5326
 
5327
+ /**
5328
+ * Gets the error message for a specific field from react-hook-form errors
5329
+ * Prioritizes required errors (#.required) over field-specific validation errors
5330
+ */
5331
+ const getFieldError = (errors, fieldName) => {
5332
+ // Check for form-level required errors first (highest priority)
5333
+ const requiredError = errors['#.required'];
5334
+ if (requiredError) {
5335
+ const requiredErrorMessage = extractErrorMessage(requiredError);
5336
+ if (requiredErrorMessage) {
5337
+ return requiredErrorMessage;
5338
+ }
5339
+ }
5340
+ // If no required errors, return field-specific error
5341
+ const fieldError = errors[fieldName];
5342
+ if (fieldError) {
5343
+ const fieldErrorMessage = extractErrorMessage(fieldError);
5344
+ if (fieldErrorMessage) {
5345
+ return fieldErrorMessage;
5346
+ }
5347
+ }
5348
+ return undefined;
5349
+ };
5350
+ /**
5351
+ * Helper function to extract error message from various error formats
5352
+ * Only returns message if explicitly provided, no fallback text
5353
+ */
5354
+ const extractErrorMessage = (error) => {
5355
+ if (!error) {
5356
+ return undefined;
5357
+ }
5358
+ // If it's a simple string error
5359
+ if (typeof error === 'string') {
5360
+ return error;
5361
+ }
5362
+ // If it's an error object with a message property
5363
+ if (error && typeof error === 'object' && 'message' in error) {
5364
+ return error.message;
5365
+ }
5366
+ // If it's an array of errors, get the first one
5367
+ if (Array.isArray(error) && error.length > 0) {
5368
+ const firstError = error[0];
5369
+ if (typeof firstError === 'string') {
5370
+ return firstError;
5371
+ }
5372
+ if (firstError &&
5373
+ typeof firstError === 'object' &&
5374
+ 'message' in firstError) {
5375
+ return firstError.message;
5376
+ }
5377
+ }
5378
+ // No fallback - return undefined if no message provided
5379
+ return undefined;
5380
+ };
5381
+
4953
5382
  const NumberInputField = ({ schema, column, prefix, }) => {
4954
5383
  const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
4955
5384
  const { translate } = useSchemaContext();
4956
- const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5385
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', numberStorageType = 'number', } = schema;
4957
5386
  const isRequired = required?.some((columnId) => columnId === column);
4958
5387
  const colLabel = `${prefix}${column}`;
4959
5388
  const value = watch(`${colLabel}`);
4960
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsxRuntime.jsx(NumberInputRoot, { value: value, onValueChange: (details) => {
4961
- setValue(`${colLabel}`, details.value); // Store as string to avoid floating-point precision issues
4962
- }, min: schema.minimum, max: schema.maximum, step: schema.multipleOf || 0.01, allowOverflow: false, clampValueOnBlur: false, inputMode: "decimal", formatOptions: schema.formatOptions, children: jsxRuntime.jsx(NumberInputField$1, { required: isRequired }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5389
+ const fieldError = getFieldError(errors, colLabel);
5390
+ return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, errorText: fieldError
5391
+ ? fieldError.includes('required')
5392
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5393
+ : fieldError
5394
+ : undefined, invalid: !!fieldError, children: jsxRuntime.jsx(NumberInputRoot, { value: value, onValueChange: (details) => {
5395
+ // Store as string or number based on configuration, default to number
5396
+ const value = numberStorageType === 'string'
5397
+ ? details.value
5398
+ : details.valueAsNumber;
5399
+ setValue(`${colLabel}`, value);
5400
+ }, min: schema.minimum, max: schema.maximum, step: schema.multipleOf || 0.01, allowOverflow: false, clampValueOnBlur: false, inputMode: "decimal", formatOptions: schema.formatOptions, children: jsxRuntime.jsx(NumberInputField$1, { required: isRequired }) }) }));
4963
5401
  };
4964
5402
 
4965
5403
  const ObjectInput = ({ schema, column, prefix }) => {
4966
- const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
5404
+ const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
4967
5405
  const { translate } = useSchemaContext();
4968
5406
  const colLabel = `${prefix}${column}`;
4969
5407
  const isRequired = required?.some((columnId) => columnId === column);
@@ -4971,29 +5409,32 @@ const ObjectInput = ({ schema, column, prefix }) => {
4971
5409
  if (properties === undefined) {
4972
5410
  throw new Error(`properties is undefined when using ObjectInput`);
4973
5411
  }
4974
- return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [showLabel && (jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] })), jsxRuntime.jsx(react.Grid, { bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
4975
- base: "colorPalette.200",
4976
- _dark: "colorPalette.800",
4977
- }, gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: Object.keys(properties ?? {}).map((key) => {
5412
+ return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [showLabel && (jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] })), jsxRuntime.jsx(react.Grid, { bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
5413
+ base: 'colorPalette.200',
5414
+ _dark: 'colorPalette.800',
5415
+ }, gap: "4", padding: '4', gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: Object.keys(properties ?? {}).map((key) => {
4978
5416
  return (
4979
5417
  // @ts-expect-error find suitable types
4980
5418
  jsxRuntime.jsx(ColumnRenderer, { column: `${key}`,
4981
5419
  prefix: `${prefix}${column}.`,
4982
- properties }, `form-${colLabel}-${key}`));
4983
- }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5420
+ properties,
5421
+ parentRequired: required }, `form-${colLabel}-${key}`));
5422
+ }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4984
5423
  };
4985
5424
 
4986
5425
  const RecordInput$1 = ({ column, schema, prefix }) => {
4987
5426
  const { formState: { errors }, setValue, getValues, } = reactHookForm.useFormContext();
4988
5427
  const { translate } = useSchemaContext();
4989
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5428
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
4990
5429
  const isRequired = required?.some((columnId) => columnId === column);
4991
5430
  const entries = Object.entries(getValues(column) ?? {});
4992
5431
  const [showNewEntries, setShowNewEntries] = React.useState(false);
4993
5432
  const [newKey, setNewKey] = React.useState();
4994
5433
  const [newValue, setNewValue] = React.useState();
4995
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
4996
- return (jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsxRuntime.jsx(react.Input, { value: key, onChange: (e) => {
5434
+ return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: 'stretch', gridColumn, gridRow, errorText: errors[`${column}`]
5435
+ ? translate.t(`${column}.field_required`)
5436
+ : undefined, invalid: !!errors[column], children: [entries.map(([key, value]) => {
5437
+ return (jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsxRuntime.jsx(react.Input, { value: key, onChange: (e) => {
4997
5438
  const filtered = entries.filter(([target]) => {
4998
5439
  return target !== key;
4999
5440
  });
@@ -5003,17 +5444,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
5003
5444
  ...getValues(column),
5004
5445
  [key]: e.target.value,
5005
5446
  });
5006
- }, autoComplete: "off" }), jsxRuntime.jsx(react.IconButton, { variant: "ghost", onClick: () => {
5447
+ }, autoComplete: "off" }), jsxRuntime.jsx(react.IconButton, { variant: 'ghost', onClick: () => {
5007
5448
  const filtered = entries.filter(([target]) => {
5008
5449
  return target !== key;
5009
5450
  });
5010
5451
  setValue(column, Object.fromEntries([...filtered]));
5011
5452
  }, children: jsxRuntime.jsx(cg.CgClose, {}) })] }));
5012
- }), jsxRuntime.jsx(react.Show, { when: showNewEntries, children: jsxRuntime.jsxs(react.Card.Root, { children: [jsxRuntime.jsx(react.Card.Body, { gap: "2", children: jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsxRuntime.jsx(react.Input, { value: newKey, onChange: (e) => {
5453
+ }), jsxRuntime.jsx(react.Show, { when: showNewEntries, children: jsxRuntime.jsxs(react.Card.Root, { children: [jsxRuntime.jsx(react.Card.Body, { gap: "2", children: jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsxRuntime.jsx(react.Input, { value: newKey, onChange: (e) => {
5013
5454
  setNewKey(e.target.value);
5014
5455
  }, autoComplete: "off" }), jsxRuntime.jsx(react.Input, { value: newValue, onChange: (e) => {
5015
5456
  setNewValue(e.target.value);
5016
- }, autoComplete: "off" })] }) }), jsxRuntime.jsxs(react.Card.Footer, { justifyContent: "flex-end", children: [jsxRuntime.jsx(react.IconButton, { variant: "subtle", onClick: () => {
5457
+ }, autoComplete: "off" })] }) }), jsxRuntime.jsxs(react.Card.Footer, { justifyContent: "flex-end", children: [jsxRuntime.jsx(react.IconButton, { variant: 'subtle', onClick: () => {
5017
5458
  setShowNewEntries(false);
5018
5459
  setNewKey(undefined);
5019
5460
  setNewValue(undefined);
@@ -5032,16 +5473,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
5032
5473
  setShowNewEntries(true);
5033
5474
  setNewKey(undefined);
5034
5475
  setNewValue(undefined);
5035
- }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
5476
+ }, children: translate.t(`${column}.addNew`) })] }));
5036
5477
  };
5037
5478
 
5038
5479
  const StringInputField = ({ column, schema, prefix, }) => {
5039
5480
  const { register, formState: { errors }, } = reactHookForm.useFormContext();
5040
5481
  const { translate } = useSchemaContext();
5041
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5482
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5042
5483
  const isRequired = required?.some((columnId) => columnId === column);
5043
5484
  const colLabel = `${prefix}${column}`;
5044
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsxRuntime.jsx(react.Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }), errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
5485
+ const fieldError = getFieldError(errors, colLabel);
5486
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, errorText: fieldError, invalid: !!fieldError, children: jsxRuntime.jsx(react.Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }) }) }));
5045
5487
  };
5046
5488
 
5047
5489
  const RadioCardItem = React__namespace.forwardRef(function RadioCardItem(props, ref) {
@@ -5227,13 +5669,18 @@ Textarea.displayName = "Textarea";
5227
5669
  const TextAreaInput = ({ column, schema, prefix, }) => {
5228
5670
  const { register, formState: { errors }, } = reactHookForm.useFormContext();
5229
5671
  const { translate } = useSchemaContext();
5230
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5672
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5231
5673
  const isRequired = required?.some((columnId) => columnId === column);
5232
5674
  const colLabel = `${prefix}${column}`;
5233
5675
  const form = reactHookForm.useFormContext();
5234
5676
  const { setValue, watch } = form;
5677
+ const fieldError = getFieldError(errors, colLabel);
5235
5678
  const watchValue = watch(colLabel);
5236
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", display: "grid", children: [jsxRuntime.jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }), errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
5679
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
5680
+ ? fieldError.includes('required')
5681
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5682
+ : fieldError
5683
+ : undefined, invalid: !!fieldError, children: jsxRuntime.jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }) }) }));
5237
5684
  };
5238
5685
 
5239
5686
  function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
@@ -5364,25 +5811,25 @@ dayjs.extend(timezone);
5364
5811
  const TimePicker = ({ column, schema, prefix }) => {
5365
5812
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
5366
5813
  const { translate, timezone } = useSchemaContext();
5367
- const { required, gridColumn = "span 12", gridRow = "span 1", timeFormat = "HH:mm:ssZ", displayTimeFormat = "hh:mm A", } = schema;
5814
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
5368
5815
  const isRequired = required?.some((columnId) => columnId === column);
5369
5816
  const colLabel = `${prefix}${column}`;
5370
5817
  const [open, setOpen] = React.useState(false);
5371
5818
  const value = watch(colLabel);
5372
5819
  const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
5373
5820
  ? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
5374
- : "";
5821
+ : '';
5375
5822
  // Parse the initial time parts from the time string (HH:mm:ssZ)
5376
5823
  const parseTime = (time) => {
5377
5824
  if (!time)
5378
- return { hour: 12, minute: 0, meridiem: "am" };
5825
+ return { hour: 12, minute: 0, meridiem: 'am' };
5379
5826
  const parsed = dayjs(`1970-01-01T${time}`).tz(timezone);
5380
5827
  if (!parsed.isValid()) {
5381
- return { hour: 12, minute: 0, meridiem: "am" };
5828
+ return { hour: 12, minute: 0, meridiem: 'am' };
5382
5829
  }
5383
5830
  let hour = parsed.hour();
5384
5831
  const minute = parsed.minute();
5385
- const meridiem = hour >= 12 ? "pm" : "am";
5832
+ const meridiem = hour >= 12 ? 'pm' : 'am';
5386
5833
  if (hour === 0)
5387
5834
  hour = 12;
5388
5835
  else if (hour > 12)
@@ -5403,10 +5850,15 @@ const TimePicker = ({ column, schema, prefix }) => {
5403
5850
  if (hour === null || minute === null || meridiem === null)
5404
5851
  return null;
5405
5852
  let newHour = hour;
5406
- if (meridiem === "pm" && hour !== 12) {
5853
+ if (meridiem === 'pm' && hour !== 12) {
5407
5854
  newHour = hour + 12;
5408
5855
  }
5409
- return dayjs().tz(timezone).hour(newHour).minute(minute).second(0).format(timeFormat);
5856
+ return dayjs()
5857
+ .tz(timezone)
5858
+ .hour(newHour)
5859
+ .minute(minute)
5860
+ .second(0)
5861
+ .format(timeFormat);
5410
5862
  };
5411
5863
  // Handle changes to time parts
5412
5864
  const handleTimeChange = ({ hour: newHour, minute: newMinute, meridiem: newMeridiem, }) => {
@@ -5416,13 +5868,15 @@ const TimePicker = ({ column, schema, prefix }) => {
5416
5868
  const timeString = getTimeString(newHour, newMinute, newMeridiem);
5417
5869
  setValue(colLabel, timeString, { shouldValidate: true, shouldDirty: true });
5418
5870
  };
5419
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
5420
- gridRow, children: [jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
5421
- setOpen(true);
5422
- }, justifyContent: "start", children: [jsxRuntime.jsx(io.IoMdClock, {}), !!value ? `${displayedTime}` : ""] }) }), jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { children: jsxRuntime.jsx(react.Popover.Body, { children: jsxRuntime.jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
5423
- am: translate.t(`common.am`, { defaultValue: "AM" }),
5424
- pm: translate.t(`common.pm`, { defaultValue: "PM" }),
5425
- } }) }) }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5871
+ return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
5872
+ gridRow, errorText: errors[`${colLabel}`]
5873
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5874
+ : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
5875
+ setOpen(true);
5876
+ }, justifyContent: 'start', children: [jsxRuntime.jsx(io.IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { children: jsxRuntime.jsx(react.Popover.Body, { children: jsxRuntime.jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
5877
+ am: translate.t(`common.am`, { defaultValue: 'AM' }),
5878
+ pm: translate.t(`common.pm`, { defaultValue: 'PM' }),
5879
+ } }) }) }) })] }) }));
5426
5880
  };
5427
5881
 
5428
5882
  function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
@@ -5628,9 +6082,9 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
5628
6082
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
5629
6083
  const { timezone, dateTimePickerLabels } = useSchemaContext();
5630
6084
  const formI18n = useFormI18n(column, prefix);
5631
- const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
6085
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
5632
6086
  // with timezone
5633
- dateFormat = "YYYY-MM-DD[T]HH:mm:ssZ", } = schema;
6087
+ dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
5634
6088
  const isRequired = required?.some((columnId) => columnId === column);
5635
6089
  const colLabel = formI18n.colLabel;
5636
6090
  const [open, setOpen] = React.useState(false);
@@ -5661,102 +6115,143 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
5661
6115
  console.error(e);
5662
6116
  }
5663
6117
  }, [selectedDate, dateFormat, colLabel, setValue]);
5664
- return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
5665
- gridRow, children: [jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
5666
- setOpen(true);
5667
- }, justifyContent: "start", children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsxRuntime.jsx(PopoverContent, { minW: "450px", children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
5668
- setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
5669
- }, timezone: timezone, labels: {
5670
- monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
5671
- formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
5672
- formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
5673
- formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
5674
- formI18n.translate.t(`common.month_4`, { defaultValue: "April" }),
5675
- formI18n.translate.t(`common.month_5`, { defaultValue: "May" }),
5676
- formI18n.translate.t(`common.month_6`, { defaultValue: "June" }),
5677
- formI18n.translate.t(`common.month_7`, { defaultValue: "July" }),
5678
- formI18n.translate.t(`common.month_8`, { defaultValue: "August" }),
5679
- formI18n.translate.t(`common.month_9`, { defaultValue: "September" }),
5680
- formI18n.translate.t(`common.month_10`, { defaultValue: "October" }),
5681
- formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
5682
- formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
5683
- ],
5684
- weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
5685
- formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
5686
- formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
5687
- formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
5688
- formI18n.translate.t(`common.weekday_4`, {
5689
- defaultValue: "Wed",
5690
- }),
5691
- formI18n.translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
5692
- formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
5693
- formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
5694
- ],
5695
- backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? formI18n.translate.t(`common.back_button`, {
5696
- defaultValue: "Back",
6118
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
6119
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
6120
+ setOpen(true);
6121
+ }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsxRuntime.jsx(PopoverContent, { minW: '450px', children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
6122
+ setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
6123
+ }, timezone: timezone, labels: {
6124
+ monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
6125
+ formI18n.translate.t(`common.month_1`, {
6126
+ defaultValue: 'January',
6127
+ }),
6128
+ formI18n.translate.t(`common.month_2`, {
6129
+ defaultValue: 'February',
6130
+ }),
6131
+ formI18n.translate.t(`common.month_3`, {
6132
+ defaultValue: 'March',
6133
+ }),
6134
+ formI18n.translate.t(`common.month_4`, {
6135
+ defaultValue: 'April',
6136
+ }),
6137
+ formI18n.translate.t(`common.month_5`, {
6138
+ defaultValue: 'May',
6139
+ }),
6140
+ formI18n.translate.t(`common.month_6`, {
6141
+ defaultValue: 'June',
6142
+ }),
6143
+ formI18n.translate.t(`common.month_7`, {
6144
+ defaultValue: 'July',
6145
+ }),
6146
+ formI18n.translate.t(`common.month_8`, {
6147
+ defaultValue: 'August',
6148
+ }),
6149
+ formI18n.translate.t(`common.month_9`, {
6150
+ defaultValue: 'September',
6151
+ }),
6152
+ formI18n.translate.t(`common.month_10`, {
6153
+ defaultValue: 'October',
5697
6154
  }),
5698
- forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? formI18n.translate.t(`common.forward_button`, {
5699
- defaultValue: "Forward",
6155
+ formI18n.translate.t(`common.month_11`, {
6156
+ defaultValue: 'November',
5700
6157
  }),
5701
- } })] }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: formI18n.required() }))] }));
6158
+ formI18n.translate.t(`common.month_12`, {
6159
+ defaultValue: 'December',
6160
+ }),
6161
+ ],
6162
+ weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
6163
+ formI18n.translate.t(`common.weekday_1`, {
6164
+ defaultValue: 'Sun',
6165
+ }),
6166
+ formI18n.translate.t(`common.weekday_2`, {
6167
+ defaultValue: 'Mon',
6168
+ }),
6169
+ formI18n.translate.t(`common.weekday_3`, {
6170
+ defaultValue: 'Tue',
6171
+ }),
6172
+ formI18n.translate.t(`common.weekday_4`, {
6173
+ defaultValue: 'Wed',
6174
+ }),
6175
+ formI18n.translate.t(`common.weekday_5`, {
6176
+ defaultValue: 'Thu',
6177
+ }),
6178
+ formI18n.translate.t(`common.weekday_6`, {
6179
+ defaultValue: 'Fri',
6180
+ }),
6181
+ formI18n.translate.t(`common.weekday_7`, {
6182
+ defaultValue: 'Sat',
6183
+ }),
6184
+ ],
6185
+ backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
6186
+ formI18n.translate.t(`common.back_button`, {
6187
+ defaultValue: 'Back',
6188
+ }),
6189
+ forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
6190
+ formI18n.translate.t(`common.forward_button`, {
6191
+ defaultValue: 'Forward',
6192
+ }),
6193
+ } })] }) })] }) }));
5702
6194
  };
5703
6195
 
5704
6196
  const SchemaRenderer = ({ schema, prefix, column, }) => {
5705
6197
  const colSchema = schema;
5706
6198
  const { type, variant, properties: innerProperties, foreign_key, format, items, } = schema;
5707
- if (variant === "custom-input") {
6199
+ if (variant === 'custom-input') {
5708
6200
  return jsxRuntime.jsx(CustomInput, { schema: colSchema, prefix, column });
5709
6201
  }
5710
- if (type === "string") {
6202
+ if (type === 'string') {
5711
6203
  if ((schema.enum ?? []).length > 0) {
5712
6204
  return jsxRuntime.jsx(EnumPicker, { schema: colSchema, prefix, column });
5713
6205
  }
5714
- if (variant === "id-picker") {
6206
+ if (variant === 'id-picker') {
5715
6207
  idPickerSanityCheck(column, foreign_key);
5716
6208
  return jsxRuntime.jsx(IdPicker, { schema: colSchema, prefix, column });
5717
6209
  }
5718
- if (format === "date") {
6210
+ if (format === 'date') {
5719
6211
  return jsxRuntime.jsx(DatePicker, { schema: colSchema, prefix, column });
5720
6212
  }
5721
- if (format === "time") {
6213
+ if (format === 'time') {
5722
6214
  return jsxRuntime.jsx(TimePicker, { schema: colSchema, prefix, column });
5723
6215
  }
5724
- if (format === "date-time") {
6216
+ if (format === 'date-time') {
5725
6217
  return jsxRuntime.jsx(DateTimePicker, { schema: colSchema, prefix, column });
5726
6218
  }
5727
- if (variant === "text-area") {
6219
+ if (variant === 'text-area') {
5728
6220
  return jsxRuntime.jsx(TextAreaInput, { schema: colSchema, prefix, column });
5729
6221
  }
5730
6222
  return jsxRuntime.jsx(StringInputField, { schema: colSchema, prefix, column });
5731
6223
  }
5732
- if (type === "number" || type === "integer") {
6224
+ if (type === 'number' || type === 'integer') {
5733
6225
  return jsxRuntime.jsx(NumberInputField, { schema: colSchema, prefix, column });
5734
6226
  }
5735
- if (type === "boolean") {
6227
+ if (type === 'boolean') {
5736
6228
  return jsxRuntime.jsx(BooleanPicker, { schema: colSchema, prefix, column });
5737
6229
  }
5738
- if (type === "object") {
6230
+ if (type === 'object') {
5739
6231
  if (innerProperties) {
5740
6232
  return jsxRuntime.jsx(ObjectInput, { schema: colSchema, prefix, column });
5741
6233
  }
5742
6234
  return jsxRuntime.jsx(RecordInput$1, { schema: colSchema, prefix, column });
5743
6235
  }
5744
- if (type === "array") {
5745
- if (variant === "id-picker") {
6236
+ if (type === 'array') {
6237
+ if (variant === 'id-picker') {
5746
6238
  idPickerSanityCheck(column, foreign_key);
5747
6239
  return (jsxRuntime.jsx(IdPicker, { schema: colSchema, prefix, column, isMultiple: true }));
5748
6240
  }
5749
- if (variant === "tag-picker") {
6241
+ if (variant === 'tag-picker') {
5750
6242
  return jsxRuntime.jsx(TagPicker, { schema: colSchema, prefix, column });
5751
6243
  }
5752
- if (variant === "file-picker") {
6244
+ if (variant === 'file-picker') {
5753
6245
  return jsxRuntime.jsx(FilePicker, { schema: colSchema, prefix, column });
5754
6246
  }
5755
- if (variant === "enum-picker") {
6247
+ if (variant === 'date-range') {
6248
+ return jsxRuntime.jsx(DateRangePicker, { schema: colSchema, prefix, column });
6249
+ }
6250
+ if (variant === 'enum-picker') {
5756
6251
  const { items } = colSchema;
5757
6252
  const { enum: enumItems } = items;
5758
6253
  const enumSchema = {
5759
- type: "string",
6254
+ type: 'string',
5760
6255
  enum: enumItems,
5761
6256
  };
5762
6257
  return (jsxRuntime.jsx(EnumPicker, { isMultiple: true, schema: enumSchema, prefix, column }));
@@ -5766,19 +6261,24 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
5766
6261
  }
5767
6262
  return jsxRuntime.jsx(react.Text, { children: `array ${column}` });
5768
6263
  }
5769
- if (type === "null") {
6264
+ if (type === 'null') {
5770
6265
  return jsxRuntime.jsx(react.Text, { children: `null ${column}` });
5771
6266
  }
5772
6267
  return jsxRuntime.jsx(react.Text, { children: "missing type" });
5773
6268
  };
5774
6269
 
5775
- const ColumnRenderer = ({ column, properties, prefix, }) => {
6270
+ const ColumnRenderer = ({ column, properties, prefix, parentRequired, }) => {
5776
6271
  const colSchema = properties[column];
5777
6272
  const colLabel = `${prefix}${column}`;
5778
6273
  if (colSchema === undefined) {
5779
6274
  throw new Error(`${colLabel} does not exist when using ColumnRenderer`);
5780
6275
  }
5781
- return jsxRuntime.jsx(SchemaRenderer, { schema: colSchema, prefix, column });
6276
+ // Merge parent's required array with the schema's required array
6277
+ const schemaWithRequired = {
6278
+ ...colSchema,
6279
+ required: parentRequired || colSchema.required,
6280
+ };
6281
+ return jsxRuntime.jsx(SchemaRenderer, { schema: schemaWithRequired, prefix, column });
5782
6282
  };
5783
6283
 
5784
6284
  const ArrayViewer = ({ schema, column, prefix }) => {
@@ -6219,15 +6719,15 @@ const SubmitButton = () => {
6219
6719
  const methods = reactHookForm.useFormContext();
6220
6720
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6221
6721
  const onValid = (data) => {
6222
- const { isValid, errors } = validateData(data, schema);
6223
- if (!isValid) {
6224
- setError({
6225
- type: 'validation',
6226
- errors,
6227
- });
6228
- setIsError(true);
6229
- return;
6230
- }
6722
+ // const { isValid, errors } = validateData(data, schema);
6723
+ // if (!isValid) {
6724
+ // setError({
6725
+ // type: 'validation',
6726
+ // errors,
6727
+ // });
6728
+ // setIsError(true);
6729
+ // return;
6730
+ // }
6231
6731
  // If validation passes, check if confirmation is required
6232
6732
  if (requireConfirmation) {
6233
6733
  // Show confirmation (existing behavior)
@@ -6252,10 +6752,6 @@ const FormBody = () => {
6252
6752
  const { showSubmitButton, showResetButton } = displayConfig;
6253
6753
  const methods = reactHookForm.useFormContext();
6254
6754
  const { properties } = schema;
6255
- // Custom error renderer for validation errors with i18n support
6256
- const renderValidationErrors = (validationErrors) => {
6257
- return (jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: "2", children: validationErrors.map((err, index) => (jsxRuntime.jsxs(react.Alert.Root, { status: "error", display: "flex", alignItems: "center", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Content, { children: jsxRuntime.jsx(react.Alert.Description, { children: err.message }) })] }, index))) }));
6258
- };
6259
6755
  const renderColumns = ({ order, keys, ignore, include, }) => {
6260
6756
  const included = include.length > 0 ? include : keys;
6261
6757
  const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
@@ -6295,19 +6791,17 @@ const FormBody = () => {
6295
6791
  setIsConfirming(false);
6296
6792
  }, variant: 'subtle', children: translate.t('cancel') }), jsxRuntime.jsx(react.Button, { onClick: () => {
6297
6793
  onFormSubmit(validatedData);
6298
- }, children: translate.t('confirm') })] }), isSubmiting && (jsxRuntime.jsx(react.Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsxRuntime.jsx(react.Center, { h: "full", children: jsxRuntime.jsx(react.Spinner, { color: "teal.500" }) }) })), isError && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: error?.type === 'validation' &&
6299
- error?.errors ? (renderValidationErrors(error.errors)) : (jsxRuntime.jsxs(react.Alert.Root, { status: "error", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsxs(react.Alert.Content, { children: [jsxRuntime.jsx(react.Alert.Title, { children: "Error" }), jsxRuntime.jsx(react.Alert.Description, { children: jsxRuntime.jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxRuntime.jsxs(AccordionItem, { value: 'b', children: [jsxRuntime.jsx(AccordionItemTrigger, { children: `${error}` }), jsxRuntime.jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
6794
+ }, children: translate.t('confirm') })] }), isSubmiting && (jsxRuntime.jsx(react.Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsxRuntime.jsx(react.Center, { h: "full", children: jsxRuntime.jsx(react.Spinner, { color: "teal.500" }) }) })), isError && customErrorRenderer && customErrorRenderer(error)] }));
6300
6795
  }
6301
6796
  return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
6302
6797
  return (jsxRuntime.jsx(ColumnRenderer
6303
6798
  // @ts-expect-error find suitable types
6304
6799
  , {
6305
6800
  // @ts-expect-error find suitable types
6306
- properties: properties, prefix: ``, column }, `form-input-${column}`));
6801
+ properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
6307
6802
  }) }), jsxRuntime.jsxs(react.Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsxRuntime.jsx(react.Button, { onClick: () => {
6308
6803
  methods.reset();
6309
- }, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsxRuntime.jsx(SubmitButton, {})] }), isError && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: error?.type === 'validation' &&
6310
- error?.errors ? (renderValidationErrors(error.errors)) : (jsxRuntime.jsxs(react.Alert.Root, { status: "error", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsxs(react.Alert.Content, { children: [jsxRuntime.jsx(react.Alert.Title, { children: "Error" }), jsxRuntime.jsx(react.Alert.Description, { children: jsxRuntime.jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxRuntime.jsxs(AccordionItem, { value: 'b', children: [jsxRuntime.jsx(AccordionItemTrigger, { children: `${error}` }), jsxRuntime.jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
6804
+ }, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsxRuntime.jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
6311
6805
  };
6312
6806
 
6313
6807
  const FormTitle = () => {
@@ -6320,12 +6814,15 @@ const DefaultForm = ({ formConfig, }) => {
6320
6814
  return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [showTitle && jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
6321
6815
  };
6322
6816
 
6323
- const useForm = ({ preLoadedValues, keyPrefix, namespace }) => {
6817
+ const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
6324
6818
  const form = reactHookForm.useForm({
6325
6819
  values: preLoadedValues,
6820
+ resolver: schema ? ajvResolver(schema) : undefined,
6821
+ mode: 'onBlur',
6822
+ reValidateMode: 'onBlur',
6326
6823
  });
6327
6824
  const [idMap, setIdMap] = React.useState({});
6328
- const translate = reactI18next.useTranslation(namespace || "", { keyPrefix });
6825
+ const translate = reactI18next.useTranslation(namespace || '', { keyPrefix });
6329
6826
  return {
6330
6827
  form,
6331
6828
  idMap,
@@ -6395,15 +6892,15 @@ const buildErrorMessages = (config) => {
6395
6892
  }
6396
6893
  // Add global fallback error messages
6397
6894
  const globalKeys = [
6398
- "minLength",
6399
- "maxLength",
6400
- "pattern",
6401
- "minimum",
6402
- "maximum",
6403
- "multipleOf",
6404
- "format",
6405
- "type",
6406
- "enum",
6895
+ 'minLength',
6896
+ 'maxLength',
6897
+ 'pattern',
6898
+ 'minimum',
6899
+ 'maximum',
6900
+ 'multipleOf',
6901
+ 'format',
6902
+ 'type',
6903
+ 'enum',
6407
6904
  ];
6408
6905
  globalKeys.forEach((key) => {
6409
6906
  if (config[key]) {
@@ -6412,6 +6909,46 @@ const buildErrorMessages = (config) => {
6412
6909
  });
6413
6910
  return result;
6414
6911
  };
6912
+ /**
6913
+ * Converts buildErrorMessages result to ajv-errors compatible format
6914
+ */
6915
+ const convertToAjvErrorsFormat = (errorMessages) => {
6916
+ const result = {};
6917
+ // Convert required field errors
6918
+ if (errorMessages.required) {
6919
+ result.required = errorMessages.required;
6920
+ }
6921
+ // Convert properties errors to ajv-errors format
6922
+ if (errorMessages.properties) {
6923
+ result.properties = {};
6924
+ Object.keys(errorMessages.properties).forEach((fieldName) => {
6925
+ const fieldErrors = errorMessages.properties[fieldName];
6926
+ result.properties[fieldName] = {};
6927
+ Object.keys(fieldErrors).forEach((keyword) => {
6928
+ result.properties[fieldName][keyword] =
6929
+ fieldErrors[keyword];
6930
+ });
6931
+ });
6932
+ }
6933
+ // Add global fallback errors
6934
+ const globalKeys = [
6935
+ 'minLength',
6936
+ 'maxLength',
6937
+ 'pattern',
6938
+ 'minimum',
6939
+ 'maximum',
6940
+ 'multipleOf',
6941
+ 'format',
6942
+ 'type',
6943
+ 'enum',
6944
+ ];
6945
+ globalKeys.forEach((key) => {
6946
+ if (errorMessages[key]) {
6947
+ result[key] = errorMessages[key];
6948
+ }
6949
+ });
6950
+ return result;
6951
+ };
6415
6952
  /**
6416
6953
  * Helper function to build required field errors
6417
6954
  *
@@ -6454,10 +6991,10 @@ const buildErrorMessages = (config) => {
6454
6991
  * // Result: { username: "user.username.field_required", email: "user.email.field_required" }
6455
6992
  * ```
6456
6993
  */
6457
- const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = "") => {
6994
+ const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = '') => {
6458
6995
  const result = {};
6459
6996
  fields.forEach((field) => {
6460
- if (typeof messageOrGenerator === "function") {
6997
+ if (typeof messageOrGenerator === 'function') {
6461
6998
  const message = messageOrGenerator(field);
6462
6999
  result[field] = keyPrefix ? `${keyPrefix}.${message}` : message;
6463
7000
  }
@@ -6528,11 +7065,14 @@ const buildFieldErrors = (config) => {
6528
7065
  * ```
6529
7066
  */
6530
7067
  const createErrorMessage = (required, properties, globalFallbacks) => {
6531
- return buildErrorMessages({
7068
+ const config = {
6532
7069
  required,
6533
7070
  properties,
6534
- ...globalFallbacks,
6535
- });
7071
+ };
7072
+ if (globalFallbacks) {
7073
+ Object.assign(config, globalFallbacks);
7074
+ }
7075
+ return buildErrorMessages(config);
6536
7076
  };
6537
7077
 
6538
7078
  const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) => {
@@ -6595,6 +7135,7 @@ exports.ViewDialog = ViewDialog;
6595
7135
  exports.buildErrorMessages = buildErrorMessages;
6596
7136
  exports.buildFieldErrors = buildFieldErrors;
6597
7137
  exports.buildRequiredErrors = buildRequiredErrors;
7138
+ exports.convertToAjvErrorsFormat = convertToAjvErrorsFormat;
6598
7139
  exports.createErrorMessage = createErrorMessage;
6599
7140
  exports.getColumns = getColumns;
6600
7141
  exports.getMultiDates = getMultiDates;