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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3671,16 +3671,14 @@ const SchemaFormContext = createContext({
3671
3671
  showResetButton: true,
3672
3672
  showTitle: true,
3673
3673
  },
3674
+ requireConfirmation: false,
3675
+ onFormSubmit: async () => { },
3674
3676
  });
3675
3677
 
3676
3678
  const useSchemaContext = () => {
3677
3679
  return useContext(SchemaFormContext);
3678
3680
  };
3679
3681
 
3680
- const clearEmptyString = (object) => {
3681
- return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
3682
- };
3683
-
3684
3682
  const validateData = (data, schema) => {
3685
3683
  const ajv = new Ajv({
3686
3684
  strict: false,
@@ -3699,6 +3697,10 @@ const validateData = (data, schema) => {
3699
3697
  };
3700
3698
  };
3701
3699
 
3700
+ const clearEmptyString = (object) => {
3701
+ return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
3702
+ };
3703
+
3702
3704
  const idPickerSanityCheck = (column, foreign_key) => {
3703
3705
  if (!!foreign_key == false) {
3704
3706
  throw new Error(`The key foreign_key does not exist in properties of column ${column} when using id-picker.`);
@@ -3718,13 +3720,88 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3718
3720
  showSubmitButton: true,
3719
3721
  showResetButton: true,
3720
3722
  showTitle: true,
3721
- }, dateTimePickerLabels, idPickerLabels, }) => {
3723
+ }, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, }) => {
3722
3724
  const [isSuccess, setIsSuccess] = useState(false);
3723
3725
  const [isError, setIsError] = useState(false);
3724
3726
  const [isSubmiting, setIsSubmiting] = useState(false);
3725
3727
  const [isConfirming, setIsConfirming] = useState(false);
3726
3728
  const [validatedData, setValidatedData] = useState();
3727
3729
  const [error, setError] = useState();
3730
+ const onBeforeSubmit = () => {
3731
+ setIsSubmiting(true);
3732
+ };
3733
+ const onAfterSubmit = () => {
3734
+ setIsSubmiting(false);
3735
+ };
3736
+ const onSubmitError = (error) => {
3737
+ setIsError(true);
3738
+ setError(error);
3739
+ };
3740
+ const onSubmitSuccess = () => {
3741
+ setIsSuccess(true);
3742
+ };
3743
+ const validateFormData = (data) => {
3744
+ try {
3745
+ const { isValid, errors } = validateData(data, schema);
3746
+ return {
3747
+ isValid,
3748
+ errors,
3749
+ };
3750
+ }
3751
+ catch (error) {
3752
+ return {
3753
+ isValid: false,
3754
+ errors: [
3755
+ {
3756
+ field: 'validation',
3757
+ message: error instanceof Error ? error.message : 'Unknown error',
3758
+ },
3759
+ ],
3760
+ };
3761
+ }
3762
+ };
3763
+ const defaultOnSubmit = async (promise) => {
3764
+ try {
3765
+ onBeforeSubmit();
3766
+ await promise;
3767
+ onSubmitSuccess();
3768
+ }
3769
+ catch (error) {
3770
+ onSubmitError(error);
3771
+ }
3772
+ finally {
3773
+ onAfterSubmit();
3774
+ }
3775
+ };
3776
+ const defaultSubmitPromise = (data) => {
3777
+ const options = {
3778
+ method: 'POST',
3779
+ url: `${requestUrl}`,
3780
+ data: clearEmptyString(data),
3781
+ ...requestOptions,
3782
+ };
3783
+ return axios.request(options);
3784
+ };
3785
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3786
+ const onFormSubmit = async (data) => {
3787
+ // Validate data using AJV before submission
3788
+ const validationResult = validateFormData(data);
3789
+ if (!validationResult.isValid) {
3790
+ // Set validation errors
3791
+ const validationErrorMessage = {
3792
+ type: 'validation',
3793
+ errors: validationResult.errors,
3794
+ message: translate.t('validation_error'),
3795
+ };
3796
+ onSubmitError(validationErrorMessage);
3797
+ return;
3798
+ }
3799
+ if (onSubmit === undefined) {
3800
+ await defaultOnSubmit(defaultSubmitPromise(data));
3801
+ return;
3802
+ }
3803
+ await defaultOnSubmit(onSubmit(data));
3804
+ };
3728
3805
  return (jsx(SchemaFormContext.Provider, { value: {
3729
3806
  schema,
3730
3807
  serverUrl,
@@ -3754,8 +3831,11 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3754
3831
  customErrorRenderer,
3755
3832
  customSuccessRenderer,
3756
3833
  displayConfig,
3834
+ requireConfirmation,
3835
+ onFormSubmit,
3757
3836
  dateTimePickerLabels,
3758
3837
  idPickerLabels,
3838
+ enumPickerLabels,
3759
3839
  }, children: jsx(FormProvider, { ...form, children: children }) }));
3760
3840
  };
3761
3841
 
@@ -4014,14 +4094,16 @@ dayjs.extend(utc);
4014
4094
  dayjs.extend(timezone);
4015
4095
  const DatePicker = ({ column, schema, prefix }) => {
4016
4096
  const { watch, formState: { errors }, setValue, } = useFormContext();
4017
- const { timezone } = useSchemaContext();
4097
+ const { timezone, dateTimePickerLabels } = useSchemaContext();
4018
4098
  const formI18n = useFormI18n(column, prefix);
4019
- const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", dateFormat = "YYYY-MM-DD", } = schema;
4099
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
4020
4100
  const isRequired = required?.some((columnId) => columnId === column);
4021
4101
  const colLabel = formI18n.colLabel;
4022
4102
  const [open, setOpen] = useState(false);
4023
4103
  const selectedDate = watch(colLabel);
4024
- const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
4104
+ const displayDate = dayjs(selectedDate)
4105
+ .tz(timezone)
4106
+ .format(displayDateFormat);
4025
4107
  useEffect(() => {
4026
4108
  try {
4027
4109
  if (selectedDate) {
@@ -4045,45 +4127,83 @@ const DatePicker = ({ column, schema, prefix }) => {
4045
4127
  console.error(e);
4046
4128
  }
4047
4129
  }, [selectedDate, dateFormat, colLabel, setValue]);
4048
- return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
4130
+ return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4049
4131
  gridRow, children: [jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
4050
4132
  setOpen(true);
4051
- }, justifyContent: "start", children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsx(PopoverContent, { children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
4133
+ }, justifyContent: 'start', children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsx(PopoverContent, { children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
4052
4134
  setValue(colLabel, dayjs(date).format(dateFormat));
4053
4135
  setOpen(false);
4054
4136
  }, labels: {
4055
- monthNamesShort: [
4056
- formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
4057
- formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
4058
- formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
4059
- formI18n.translate.t(`common.month_4`, { defaultValue: "April" }),
4060
- formI18n.translate.t(`common.month_5`, { defaultValue: "May" }),
4061
- formI18n.translate.t(`common.month_6`, { defaultValue: "June" }),
4062
- formI18n.translate.t(`common.month_7`, { defaultValue: "July" }),
4063
- formI18n.translate.t(`common.month_8`, { defaultValue: "August" }),
4064
- formI18n.translate.t(`common.month_9`, { defaultValue: "September" }),
4065
- formI18n.translate.t(`common.month_10`, { defaultValue: "October" }),
4066
- formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
4067
- formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
4137
+ monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
4138
+ formI18n.translate.t(`common.month_1`, {
4139
+ defaultValue: 'January',
4140
+ }),
4141
+ formI18n.translate.t(`common.month_2`, {
4142
+ defaultValue: 'February',
4143
+ }),
4144
+ formI18n.translate.t(`common.month_3`, {
4145
+ defaultValue: 'March',
4146
+ }),
4147
+ formI18n.translate.t(`common.month_4`, {
4148
+ defaultValue: 'April',
4149
+ }),
4150
+ formI18n.translate.t(`common.month_5`, {
4151
+ defaultValue: 'May',
4152
+ }),
4153
+ formI18n.translate.t(`common.month_6`, {
4154
+ defaultValue: 'June',
4155
+ }),
4156
+ formI18n.translate.t(`common.month_7`, {
4157
+ defaultValue: 'July',
4158
+ }),
4159
+ formI18n.translate.t(`common.month_8`, {
4160
+ defaultValue: 'August',
4161
+ }),
4162
+ formI18n.translate.t(`common.month_9`, {
4163
+ defaultValue: 'September',
4164
+ }),
4165
+ formI18n.translate.t(`common.month_10`, {
4166
+ defaultValue: 'October',
4167
+ }),
4168
+ formI18n.translate.t(`common.month_11`, {
4169
+ defaultValue: 'November',
4170
+ }),
4171
+ formI18n.translate.t(`common.month_12`, {
4172
+ defaultValue: 'December',
4173
+ }),
4068
4174
  ],
4069
- weekdayNamesShort: [
4070
- formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
4071
- formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
4072
- formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
4175
+ weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
4176
+ formI18n.translate.t(`common.weekday_1`, {
4177
+ defaultValue: 'Sun',
4178
+ }),
4179
+ formI18n.translate.t(`common.weekday_2`, {
4180
+ defaultValue: 'Mon',
4181
+ }),
4182
+ formI18n.translate.t(`common.weekday_3`, {
4183
+ defaultValue: 'Tue',
4184
+ }),
4073
4185
  formI18n.translate.t(`common.weekday_4`, {
4074
- defaultValue: "Wed",
4186
+ defaultValue: 'Wed',
4187
+ }),
4188
+ formI18n.translate.t(`common.weekday_5`, {
4189
+ defaultValue: 'Thu',
4190
+ }),
4191
+ formI18n.translate.t(`common.weekday_6`, {
4192
+ defaultValue: 'Fri',
4193
+ }),
4194
+ formI18n.translate.t(`common.weekday_7`, {
4195
+ defaultValue: 'Sat',
4075
4196
  }),
4076
- formI18n.translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
4077
- formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
4078
- formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
4079
4197
  ],
4080
- backButtonLabel: formI18n.translate.t(`common.back_button`, {
4081
- defaultValue: "Back",
4082
- }),
4083
- forwardButtonLabel: formI18n.translate.t(`common.forward_button`, {
4084
- defaultValue: "Forward",
4085
- }),
4086
- } })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
4198
+ backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
4199
+ formI18n.translate.t(`common.back_button`, {
4200
+ defaultValue: 'Back',
4201
+ }),
4202
+ forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
4203
+ formI18n.translate.t(`common.forward_button`, {
4204
+ defaultValue: 'Forward',
4205
+ }),
4206
+ } })] }) })] }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
4087
4207
  };
4088
4208
 
4089
4209
  function filterArray(array, searchTerm) {
@@ -4098,10 +4218,10 @@ function filterArray(array, searchTerm) {
4098
4218
 
4099
4219
  const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
4100
4220
  const { watch, formState: { errors }, setValue, } = useFormContext();
4101
- const { translate } = useSchemaContext();
4221
+ const { translate, enumPickerLabels } = useSchemaContext();
4102
4222
  const { required, variant } = schema;
4103
4223
  const isRequired = required?.some((columnId) => columnId === column);
4104
- const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
4224
+ const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
4105
4225
  const [searchText, setSearchText] = useState();
4106
4226
  const [limit, setLimit] = useState(10);
4107
4227
  const [openSearchResult, setOpenSearchResult] = useState();
@@ -4116,9 +4236,9 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4116
4236
  setSearchText(event.target.value);
4117
4237
  setLimit(10);
4118
4238
  };
4119
- if (variant === "radio") {
4120
- return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
4121
- gridRow, children: jsx(RadioGroup$1.Root, { defaultValue: "1", children: jsx(HStack, { gap: "6", children: filterArray(dataList, searchText ?? "").map((item) => {
4239
+ if (variant === 'radio') {
4240
+ return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4241
+ gridRow, children: jsx(RadioGroup$1.Root, { defaultValue: "1", children: jsx(HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
4122
4242
  return (jsxs(RadioGroup$1.Item, { onClick: () => {
4123
4243
  if (!isMultiple) {
4124
4244
  setOpenSearchResult(false);
@@ -4132,8 +4252,8 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4132
4252
  : translate.t(removeIndex(`${colLabel}.${item}`)) })] }, `${colLabel}-${item}`));
4133
4253
  }) }) }) }));
4134
4254
  }
4135
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
4136
- gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: "wrap", gap: 1, children: [watchEnums.map((enumValue) => {
4255
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4256
+ gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
4137
4257
  const item = enumValue;
4138
4258
  if (!!item === false) {
4139
4259
  return jsx(Fragment, {});
@@ -4143,18 +4263,20 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4143
4263
  }, children: !!renderDisplay === true
4144
4264
  ? renderDisplay(item)
4145
4265
  : translate.t(removeIndex(`${colLabel}.${item}`)) }, item));
4146
- }), jsx(Tag, { size: "lg", cursor: "pointer", onClick: () => {
4266
+ }), jsx(Tag, { size: "lg", cursor: 'pointer', onClick: () => {
4147
4267
  setOpenSearchResult(true);
4148
- }, children: translate.t(removeIndex(`${colLabel}.add_more`)) }, `${colLabel}-add-more-tag`)] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
4268
+ }, children: enumPickerLabels?.addMore ??
4269
+ translate.t(removeIndex(`${colLabel}.add_more`)) }, `${colLabel}-add-more-tag`)] })), !isMultiple && (jsx(Button, { variant: 'outline', onClick: () => {
4149
4270
  setOpenSearchResult(true);
4150
- }, justifyContent: "start", children: !!watchEnum === false
4151
- ? ""
4152
- : translate.t(removeIndex(`${colLabel}.${watchEnum ?? "null"}`)) })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { portalled: false, children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: translate.t(`${colLabel}.type_to_search`), onChange: (event) => {
4271
+ }, justifyContent: 'start', children: !!watchEnum === false
4272
+ ? ''
4273
+ : translate.t(removeIndex(`${colLabel}.${watchEnum ?? 'null'}`)) })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: 'bottom-start' }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { portalled: false, children: jsxs(PopoverBody, { display: 'grid', gap: 1, children: [jsx(Input, { placeholder: enumPickerLabels?.typeToSearch ??
4274
+ translate.t(`${colLabel}.type_to_search`), onChange: (event) => {
4153
4275
  onSearchChange(event);
4154
4276
  setOpenSearchResult(true);
4155
- }, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), showTotalAndLimit && (jsx(Text, { children: `${translate.t(removeIndex(`${colLabel}.total`))}: ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit}` })), jsxs(Grid, { overflow: "auto", maxHeight: "20rem", children: [jsx(Flex, { flexFlow: "column wrap", children: dataList
4277
+ }, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), showTotalAndLimit && (jsx(Text, { children: `${enumPickerLabels?.total ?? translate.t(removeIndex(`${colLabel}.total`))}: ${count}, ${enumPickerLabels?.showing ?? translate.t(removeIndex(`${colLabel}.showing`))} ${limit}` })), jsxs(Grid, { overflow: 'auto', maxHeight: '20rem', children: [jsx(Flex, { flexFlow: 'column wrap', children: dataList
4156
4278
  .filter((item) => {
4157
- const searchTerm = (searchText || "").toLowerCase();
4279
+ const searchTerm = (searchText || '').toLowerCase();
4158
4280
  if (!searchTerm)
4159
4281
  return true;
4160
4282
  // Check if the original enum value contains the search text
@@ -4174,7 +4296,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4174
4296
  const selected = isMultiple
4175
4297
  ? watchEnums.some((enumValue) => item === enumValue)
4176
4298
  : watchEnum == item;
4177
- return (jsx(Box, { cursor: "pointer", onClick: () => {
4299
+ return (jsx(Box, { cursor: 'pointer', onClick: () => {
4178
4300
  if (!isMultiple) {
4179
4301
  setOpenSearchResult(false);
4180
4302
  setValue(colLabel, item);
@@ -4182,10 +4304,11 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
4182
4304
  }
4183
4305
  const newSet = new Set([...(watchEnums ?? []), item]);
4184
4306
  setValue(colLabel, [...newSet]);
4185
- }, ...(selected ? { color: "colorPalette.400/50" } : {}), children: !!renderDisplay === true
4307
+ }, ...(selected ? { color: 'colorPalette.400/50' } : {}), children: !!renderDisplay === true
4186
4308
  ? renderDisplay(item)
4187
4309
  : translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
4188
- }) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Fragment, { children: translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4310
+ }) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Fragment, { children: enumPickerLabels?.emptySearchResult ??
4311
+ translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4189
4312
  };
4190
4313
 
4191
4314
  function isEnteringWindow(_ref) {
@@ -4810,13 +4933,13 @@ NumberInput.Label;
4810
4933
  const NumberInputField = ({ schema, column, prefix, }) => {
4811
4934
  const { setValue, formState: { errors }, watch, } = useFormContext();
4812
4935
  const { translate } = useSchemaContext();
4813
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4936
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
4814
4937
  const isRequired = required?.some((columnId) => columnId === column);
4815
4938
  const colLabel = `${prefix}${column}`;
4816
4939
  const value = watch(`${colLabel}`);
4817
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(NumberInputRoot, { children: jsx(NumberInputField$1, { required: isRequired, value: value, onChange: (event) => {
4818
- setValue(`${colLabel}`, Number(event.target.value));
4819
- } }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4940
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(NumberInputRoot, { value: value, onValueChange: (details) => {
4941
+ setValue(`${colLabel}`, details.value); // Store as string to avoid floating-point precision issues
4942
+ }, min: schema.minimum, max: schema.maximum, step: schema.multipleOf || 0.01, allowOverflow: false, clampValueOnBlur: false, inputMode: "decimal", formatOptions: schema.formatOptions, children: jsx(NumberInputField$1, { required: isRequired }) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4820
4943
  };
4821
4944
 
4822
4945
  const ObjectInput = ({ schema, column, prefix }) => {
@@ -5758,11 +5881,29 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
5758
5881
  const NumberViewer = ({ schema, column, prefix, }) => {
5759
5882
  const { watch, formState: { errors }, } = useFormContext();
5760
5883
  const { translate } = useSchemaContext();
5761
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5884
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5762
5885
  const isRequired = required?.some((columnId) => columnId === column);
5763
5886
  const colLabel = `${prefix}${column}`;
5764
5887
  const value = watch(colLabel);
5765
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(Text, { children: value }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5888
+ // Format the value for display if formatOptions are provided
5889
+ const formatValue = (val) => {
5890
+ if (val === undefined || val === null || val === '')
5891
+ return '';
5892
+ const numValue = typeof val === 'string' ? parseFloat(val) : val;
5893
+ if (isNaN(numValue))
5894
+ return String(val);
5895
+ // Use formatOptions if available, otherwise display as-is
5896
+ if (schema.formatOptions) {
5897
+ try {
5898
+ return new Intl.NumberFormat(undefined, schema.formatOptions).format(numValue);
5899
+ }
5900
+ catch {
5901
+ return String(val);
5902
+ }
5903
+ }
5904
+ return String(val);
5905
+ };
5906
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(Text, { children: formatValue(value) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5766
5907
  };
5767
5908
 
5768
5909
  const ObjectViewer = ({ schema, column, prefix }) => {
@@ -6054,112 +6195,46 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
6054
6195
  };
6055
6196
 
6056
6197
  const SubmitButton = () => {
6057
- const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, } = useSchemaContext();
6198
+ const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, requireConfirmation, onFormSubmit, } = useSchemaContext();
6058
6199
  const methods = useFormContext();
6059
6200
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6060
6201
  const onValid = (data) => {
6061
6202
  const { isValid, errors } = validateData(data, schema);
6062
6203
  if (!isValid) {
6063
6204
  setError({
6064
- type: "validation",
6205
+ type: 'validation',
6065
6206
  errors,
6066
6207
  });
6067
6208
  setIsError(true);
6068
6209
  return;
6069
6210
  }
6070
- // If validation passes, proceed to confirmation
6071
- setValidatedData(data);
6072
- setIsError(false);
6073
- setIsConfirming(true);
6211
+ // If validation passes, check if confirmation is required
6212
+ if (requireConfirmation) {
6213
+ // Show confirmation (existing behavior)
6214
+ setValidatedData(data);
6215
+ setIsError(false);
6216
+ setIsConfirming(true);
6217
+ }
6218
+ else {
6219
+ // Skip confirmation and submit directly
6220
+ setValidatedData(data);
6221
+ setIsError(false);
6222
+ onFormSubmit(data);
6223
+ }
6074
6224
  };
6075
6225
  return (jsx(Button$1, { onClick: () => {
6076
6226
  methods.handleSubmit(onValid)();
6077
- }, formNoValidate: true, children: translate.t("submit") }));
6227
+ }, formNoValidate: true, children: translate.t('submit') }));
6078
6228
  };
6079
6229
 
6080
6230
  const FormBody = () => {
6081
- const { schema, requestUrl, order, ignore, include, onSubmit, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, } = useSchemaContext();
6231
+ const { schema, order, ignore, include, translate, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, onFormSubmit, } = useSchemaContext();
6082
6232
  const { showSubmitButton, showResetButton } = displayConfig;
6083
6233
  const methods = useFormContext();
6084
6234
  const { properties } = schema;
6085
- const onBeforeSubmit = () => {
6086
- setIsSubmiting(true);
6087
- };
6088
- const onAfterSubmit = () => {
6089
- setIsSubmiting(false);
6090
- };
6091
- const onSubmitError = (error) => {
6092
- setIsError(true);
6093
- setError(error);
6094
- };
6095
- const onSubmitSuccess = () => {
6096
- setIsSuccess(true);
6097
- };
6098
- const validateFormData = (data) => {
6099
- try {
6100
- const { isValid, errors } = validateData(data, schema);
6101
- return {
6102
- isValid,
6103
- errors,
6104
- };
6105
- }
6106
- catch (error) {
6107
- return {
6108
- isValid: false,
6109
- errors: [
6110
- {
6111
- field: "validation",
6112
- message: error instanceof Error ? error.message : "Unknown error",
6113
- },
6114
- ],
6115
- };
6116
- }
6117
- };
6118
- const defaultOnSubmit = async (promise) => {
6119
- try {
6120
- onBeforeSubmit();
6121
- await promise;
6122
- onSubmitSuccess();
6123
- }
6124
- catch (error) {
6125
- onSubmitError(error);
6126
- }
6127
- finally {
6128
- onAfterSubmit();
6129
- }
6130
- };
6131
- const defaultSubmitPromise = (data) => {
6132
- const options = {
6133
- method: "POST",
6134
- url: `${requestUrl}`,
6135
- data: clearEmptyString(data),
6136
- ...requestOptions,
6137
- };
6138
- return axios.request(options);
6139
- };
6140
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6141
- const onFormSubmit = async (data) => {
6142
- // Validate data using AJV before submission
6143
- const validationResult = validateFormData(data);
6144
- if (!validationResult.isValid) {
6145
- // Set validation errors
6146
- const validationErrorMessage = {
6147
- type: "validation",
6148
- errors: validationResult.errors,
6149
- message: translate.t("validation_error"),
6150
- };
6151
- onSubmitError(validationErrorMessage);
6152
- return;
6153
- }
6154
- if (onSubmit === undefined) {
6155
- await defaultOnSubmit(defaultSubmitPromise(data));
6156
- return;
6157
- }
6158
- await defaultOnSubmit(onSubmit(data));
6159
- };
6160
6235
  // Custom error renderer for validation errors with i18n support
6161
6236
  const renderValidationErrors = (validationErrors) => {
6162
- return (jsx(Flex, { flexFlow: "column", gap: "2", children: validationErrors.map((err, index) => (jsxs(Alert.Root, { status: "error", display: "flex", alignItems: "center", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Description, { children: err.message }) })] }, index))) }));
6237
+ return (jsx(Flex, { flexFlow: 'column', gap: "2", children: validationErrors.map((err, index) => (jsxs(Alert.Root, { status: "error", display: "flex", alignItems: "center", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Description, { children: err.message }) })] }, index))) }));
6163
6238
  };
6164
6239
  const renderColumns = ({ order, keys, ignore, include, }) => {
6165
6240
  const included = include.length > 0 ? include : keys;
@@ -6187,32 +6262,32 @@ const FormBody = () => {
6187
6262
  if (customSuccessRenderer) {
6188
6263
  return customSuccessRenderer(resetHandler);
6189
6264
  }
6190
- return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsxs(Alert.Root, { status: "success", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Title, { children: translate.t("submit_success") }) })] }), jsx(Flex, { justifyContent: "end", children: jsx(Button$1, { onClick: resetHandler, formNoValidate: true, children: translate.t("submit_again") }) })] }));
6265
+ return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsxs(Alert.Root, { status: "success", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Title, { children: translate.t('submit_success') }) })] }), jsx(Flex, { justifyContent: 'end', children: jsx(Button$1, { onClick: resetHandler, formNoValidate: true, children: translate.t('submit_again') }) })] }));
6191
6266
  }
6192
6267
  if (isConfirming) {
6193
- return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: "repeat(12, max-content)", autoFlow: "row", children: ordered.map((column) => {
6268
+ return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: 'repeat(12, 1fr)', gridTemplateRows: 'repeat(12, max-content)', autoFlow: 'row', children: ordered.map((column) => {
6194
6269
  return (jsx(ColumnViewer
6195
6270
  // @ts-expect-error find suitable types
6196
6271
  , {
6197
6272
  // @ts-expect-error find suitable types
6198
6273
  properties: properties, prefix: ``, column }, `form-viewer-${column}`));
6199
- }) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [jsx(Button$1, { onClick: () => {
6274
+ }) }), jsxs(Flex, { justifyContent: 'end', gap: '2', children: [jsx(Button$1, { onClick: () => {
6200
6275
  setIsConfirming(false);
6201
- }, variant: "subtle", children: translate.t("cancel") }), jsx(Button$1, { onClick: () => {
6276
+ }, variant: 'subtle', children: translate.t('cancel') }), jsx(Button$1, { onClick: () => {
6202
6277
  onFormSubmit(validatedData);
6203
- }, children: translate.t("confirm") })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === "validation" &&
6204
- error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
6278
+ }, children: translate.t('confirm') })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === 'validation' &&
6279
+ error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: 'b', children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
6205
6280
  }
6206
- return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: ordered.map((column) => {
6281
+ return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
6207
6282
  return (jsx(ColumnRenderer
6208
6283
  // @ts-expect-error find suitable types
6209
6284
  , {
6210
6285
  // @ts-expect-error find suitable types
6211
6286
  properties: properties, prefix: ``, column }, `form-input-${column}`));
6212
- }) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
6287
+ }) }), jsxs(Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
6213
6288
  methods.reset();
6214
- }, variant: "subtle", children: translate.t("reset") })), showSubmitButton && jsx(SubmitButton, {})] }), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === "validation" &&
6215
- error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
6289
+ }, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsx(SubmitButton, {})] }), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === 'validation' &&
6290
+ error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: 'b', children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
6216
6291
  };
6217
6292
 
6218
6293
  const FormTitle = () => {
@@ -3,7 +3,7 @@ import { JSONSchema7 } from 'json-schema';
3
3
  import { Dispatch, ReactNode, SetStateAction } from 'react';
4
4
  import { FieldValues } from 'react-hook-form';
5
5
  import { UseTranslationResponse } from 'react-i18next';
6
- import { DateTimePickerLabels, IdPickerLabels } from './components/types/CustomJSONSchema7';
6
+ import { DateTimePickerLabels, IdPickerLabels, EnumPickerLabels } from './components/types/CustomJSONSchema7';
7
7
  export interface SchemaFormContext<TData extends FieldValues> {
8
8
  schema: JSONSchema7;
9
9
  serverUrl: string;
@@ -38,7 +38,10 @@ export interface SchemaFormContext<TData extends FieldValues> {
38
38
  showResetButton?: boolean;
39
39
  showTitle?: boolean;
40
40
  };
41
+ requireConfirmation: boolean;
42
+ onFormSubmit: (data: TData) => Promise<void>;
41
43
  dateTimePickerLabels?: DateTimePickerLabels;
42
44
  idPickerLabels?: IdPickerLabels;
45
+ enumPickerLabels?: EnumPickerLabels;
43
46
  }
44
47
  export declare const SchemaFormContext: import("react").Context<SchemaFormContext<unknown>>;
@@ -4,7 +4,7 @@ import { JSONSchema7 } from 'json-schema';
4
4
  import { Dispatch, ReactNode, SetStateAction } from 'react';
5
5
  import { FieldValues, SubmitHandler, UseFormReturn } from 'react-hook-form';
6
6
  import { UseTranslationResponse } from 'react-i18next';
7
- import { CustomJSONSchema7, DateTimePickerLabels, IdPickerLabels } from '../types/CustomJSONSchema7';
7
+ import { CustomJSONSchema7, DateTimePickerLabels, IdPickerLabels, EnumPickerLabels } from '../types/CustomJSONSchema7';
8
8
  export interface FormRootProps<TData extends FieldValues> {
9
9
  schema: CustomJSONSchema7;
10
10
  serverUrl: string;
@@ -28,8 +28,10 @@ export interface FormRootProps<TData extends FieldValues> {
28
28
  showResetButton?: boolean;
29
29
  showTitle?: boolean;
30
30
  };
31
+ requireConfirmation?: boolean;
31
32
  dateTimePickerLabels?: DateTimePickerLabels;
32
33
  idPickerLabels?: IdPickerLabels;
34
+ enumPickerLabels?: EnumPickerLabels;
33
35
  }
34
36
  export interface CustomJSONSchema7Definition extends JSONSchema7 {
35
37
  variant: string;
@@ -46,4 +48,4 @@ export declare const idPickerSanityCheck: (column: string, foreign_key?: {
46
48
  column?: string | undefined;
47
49
  display_column?: string | undefined;
48
50
  } | undefined) => void;
49
- export declare const FormRoot: <TData extends FieldValues>({ schema, idMap, setIdMap, form, serverUrl, translate, children, order, ignore, include, onSubmit, rowNumber, requestOptions, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, dateTimePickerLabels, idPickerLabels, }: FormRootProps<TData>) => import("react/jsx-runtime").JSX.Element;
51
+ export declare const FormRoot: <TData extends FieldValues>({ schema, idMap, setIdMap, form, serverUrl, translate, children, order, ignore, include, onSubmit, rowNumber, requestOptions, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, requireConfirmation, dateTimePickerLabels, idPickerLabels, enumPickerLabels, }: FormRootProps<TData>) => import("react/jsx-runtime").JSX.Element;
@@ -1,2 +1,2 @@
1
- import { InputDefaultProps } from "./types";
1
+ import { InputDefaultProps } from './types';
2
2
  export declare const DatePicker: ({ column, schema, prefix }: InputDefaultProps) => import("react/jsx-runtime").JSX.Element;