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

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.js CHANGED
@@ -3677,8 +3677,8 @@ const AccordionItem = react.Accordion.Item;
3677
3677
  //@ts-expect-error TODO: find appropriate type
3678
3678
  const SchemaFormContext = React.createContext({
3679
3679
  schema: {},
3680
- serverUrl: "",
3681
- requestUrl: "",
3680
+ serverUrl: '',
3681
+ requestUrl: '',
3682
3682
  order: [],
3683
3683
  ignore: [],
3684
3684
  include: [],
@@ -3734,11 +3734,11 @@ const idPickerSanityCheck = (column, foreign_key) => {
3734
3734
  throw new Error(`The key column does not exist in properties of column ${column} when using id-picker.`);
3735
3735
  }
3736
3736
  };
3737
- const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, displayConfig = {
3737
+ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
3738
3738
  showSubmitButton: true,
3739
3739
  showResetButton: true,
3740
3740
  showTitle: true,
3741
- }, }) => {
3741
+ }, dateTimePickerLabels, idPickerLabels, }) => {
3742
3742
  const [isSuccess, setIsSuccess] = React.useState(false);
3743
3743
  const [isError, setIsError] = React.useState(false);
3744
3744
  const [isSubmiting, setIsSubmiting] = React.useState(false);
@@ -3772,7 +3772,10 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3772
3772
  setError,
3773
3773
  getUpdatedData,
3774
3774
  customErrorRenderer,
3775
+ customSuccessRenderer,
3775
3776
  displayConfig,
3777
+ dateTimePickerLabels,
3778
+ idPickerLabels,
3776
3779
  }, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
3777
3780
  };
3778
3781
 
@@ -4615,12 +4618,12 @@ const getTableData = async ({ serverUrl, in_table, searching = "", where = [], l
4615
4618
 
4616
4619
  const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4617
4620
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
4618
- const { serverUrl, idMap, setIdMap, schema: parentSchema, } = useSchemaContext();
4621
+ const { serverUrl, idMap, setIdMap, schema: parentSchema, idPickerLabels, } = useSchemaContext();
4619
4622
  const formI18n = useFormI18n(column, prefix);
4620
- const { required, gridColumn = "span 12", gridRow = "span 1", renderDisplay, foreign_key, } = schema;
4623
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
4621
4624
  const isRequired = required?.some((columnId) => columnId === column);
4622
4625
  const { table, column: column_ref, display_column, customQueryFn, } = foreign_key;
4623
- const [searchText, setSearchText] = React.useState("");
4626
+ const [searchText, setSearchText] = React.useState('');
4624
4627
  const [limit, setLimit] = React.useState(10);
4625
4628
  const [openSearchResult, setOpenSearchResult] = React.useState();
4626
4629
  const [page, setPage] = React.useState(0);
@@ -4634,7 +4637,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4634
4637
  queryFn: async () => {
4635
4638
  if (customQueryFn) {
4636
4639
  const { data, idMap } = await customQueryFn({
4637
- searching: searchText ?? "",
4640
+ searching: searchText ?? '',
4638
4641
  limit: limit,
4639
4642
  offset: page * limit,
4640
4643
  });
@@ -4645,7 +4648,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4645
4648
  }
4646
4649
  const data = await getTableData({
4647
4650
  serverUrl,
4648
- searching: searchText ?? "",
4651
+ searching: searchText ?? '',
4649
4652
  in_table: table,
4650
4653
  limit: limit,
4651
4654
  offset: page * limit,
@@ -4675,7 +4678,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4675
4678
  queryFn: async () => {
4676
4679
  if (customQueryFn) {
4677
4680
  const { data, idMap } = await customQueryFn({
4678
- searching: watchIds.join(","),
4681
+ searching: watchIds.join(','),
4679
4682
  limit: isMultiple ? watchIds.length : 1,
4680
4683
  offset: 0,
4681
4684
  });
@@ -4687,7 +4690,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4687
4690
  if (!watchId && (!watchIds || watchIds.length === 0)) {
4688
4691
  return { data: [] };
4689
4692
  }
4690
- const searchValue = isMultiple ? watchIds.join(",") : watchId;
4693
+ const searchValue = isMultiple ? watchIds.join(',') : watchId;
4691
4694
  const data = await getTableData({
4692
4695
  serverUrl,
4693
4696
  searching: searchValue,
@@ -4724,7 +4727,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4724
4727
  React.useEffect(() => {
4725
4728
  if (openSearchResult) {
4726
4729
  // Reset search text when opening the popover
4727
- setSearchText("");
4730
+ setSearchText('');
4728
4731
  // Reset page to first page
4729
4732
  setPage(0);
4730
4733
  // Fetch initial data
@@ -4750,44 +4753,44 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4750
4753
  const count = data?.count ?? 0;
4751
4754
  const getPickedValue = () => {
4752
4755
  if (Object.keys(idMap).length <= 0) {
4753
- return "";
4756
+ return '';
4754
4757
  }
4755
4758
  const record = idMap[watchId];
4756
4759
  if (record === undefined) {
4757
- return "";
4760
+ return '';
4758
4761
  }
4759
4762
  if (!!renderDisplay === true) {
4760
4763
  return renderDisplay(record);
4761
4764
  }
4762
4765
  return record[display_column];
4763
4766
  };
4764
- return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
4765
- gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: "wrap", gap: 1, children: [watchIds.map((id) => {
4767
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4768
+ gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
4766
4769
  const item = idMap[id];
4767
4770
  if (item === undefined) {
4768
- return (jsxRuntime.jsx(react.Text, { children: formI18n.t('undefined') }, id));
4771
+ return (jsxRuntime.jsx(react.Text, { children: idPickerLabels?.undefined ?? formI18n.t('undefined') }, id));
4769
4772
  }
4770
4773
  return (jsxRuntime.jsx(Tag, { closable: true, onClick: () => {
4771
4774
  setValue(colLabel, watchIds.filter((itemId) => itemId !== item[column_ref]));
4772
4775
  }, children: !!renderDisplay === true
4773
4776
  ? renderDisplay(item)
4774
4777
  : item[display_column] }, id));
4775
- }), jsxRuntime.jsx(Tag, { cursor: "pointer", onClick: () => {
4778
+ }), jsxRuntime.jsx(Tag, { cursor: 'pointer', onClick: () => {
4776
4779
  setOpenSearchResult(true);
4777
- }, children: formI18n.t('add_more') })] })), !isMultiple && (jsxRuntime.jsx(Button, { variant: "outline", onClick: () => {
4780
+ }, children: idPickerLabels?.addMore ?? formI18n.t('add_more') })] })), !isMultiple && (jsxRuntime.jsx(Button, { variant: 'outline', onClick: () => {
4778
4781
  setOpenSearchResult(true);
4779
- }, justifyContent: "start", children: queryDefault.isLoading ? jsxRuntime.jsx(react.Spinner, { size: "sm" }) : getPickedValue() })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start", strategy: "fixed" }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { portalled: false, children: jsxRuntime.jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: formI18n.t('type_to_search'), onChange: onSearchChange, autoComplete: "off", ref: ref, value: searchText }), jsxRuntime.jsx(PopoverTitle, {}), openSearchResult && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, {}), isError && (jsxRuntime.jsx(react.Icon, { color: "red.400", children: jsxRuntime.jsx(bi.BiError, {}) })), jsxRuntime.jsxs(react.Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", children: [jsxRuntime.jsx(InfoTip, { children: `${formI18n.t('total')} ${count}, ${formI18n.t('showing')} ${limit} ${formI18n.t('per_page', { defaultValue: 'per page' })}` }), jsxRuntime.jsxs(react.Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxRuntime.jsxs(react.Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/", " ", count > 0
4782
+ }, justifyContent: 'start', children: queryDefault.isLoading ? jsxRuntime.jsx(react.Spinner, { size: "sm" }) : getPickedValue() })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: 'bottom-start', strategy: 'fixed' }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { portalled: false, children: jsxRuntime.jsxs(PopoverBody, { display: 'grid', gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: idPickerLabels?.typeToSearch ?? formI18n.t('type_to_search'), onChange: onSearchChange, autoComplete: "off", ref: ref, value: searchText }), jsxRuntime.jsx(PopoverTitle, {}), openSearchResult && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, {}), isError && (jsxRuntime.jsx(react.Icon, { color: 'red.400', children: jsxRuntime.jsx(bi.BiError, {}) })), jsxRuntime.jsxs(react.Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", children: [jsxRuntime.jsx(InfoTip, { children: `${idPickerLabels?.total ?? formI18n.t('total')} ${count}, ${idPickerLabels?.showing ?? formI18n.t('showing')} ${limit} ${idPickerLabels?.perPage ?? formI18n.t('per_page', { defaultValue: 'per page' })}` }), jsxRuntime.jsxs(react.Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxRuntime.jsxs(react.Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/", ' ', count > 0
4780
4783
  ? `${page * limit + 1}-${Math.min((page + 1) * limit, count)}`
4781
- : "0"] })] })] }), jsxRuntime.jsx(react.Box, { children: jsxRuntime.jsxs("select", { value: limit, onChange: handleLimitChange, style: {
4782
- padding: "4px 8px",
4783
- borderRadius: "4px",
4784
- border: "1px solid #ccc",
4785
- fontSize: "14px",
4786
- }, children: [jsxRuntime.jsx("option", { value: "5", children: "5" }), jsxRuntime.jsx("option", { value: "10", children: "10" }), jsxRuntime.jsx("option", { value: "20", children: "20" }), jsxRuntime.jsx("option", { value: "30", children: "30" })] }) })] }), jsxRuntime.jsx(react.Grid, { overflowY: "auto", children: dataList.length > 0 ? (jsxRuntime.jsx(react.Flex, { flexFlow: "column wrap", gap: 1, children: dataList.map((item) => {
4784
+ : '0'] })] })] }), jsxRuntime.jsx(react.Box, { children: jsxRuntime.jsxs("select", { value: limit, onChange: handleLimitChange, style: {
4785
+ padding: '4px 8px',
4786
+ borderRadius: '4px',
4787
+ border: '1px solid #ccc',
4788
+ fontSize: '14px',
4789
+ }, children: [jsxRuntime.jsx("option", { value: "5", children: "5" }), jsxRuntime.jsx("option", { value: "10", children: "10" }), jsxRuntime.jsx("option", { value: "20", children: "20" }), jsxRuntime.jsx("option", { value: "30", children: "30" })] }) })] }), jsxRuntime.jsx(react.Grid, { overflowY: 'auto', children: dataList.length > 0 ? (jsxRuntime.jsx(react.Flex, { flexFlow: 'column wrap', gap: 1, children: dataList.map((item) => {
4787
4790
  const selected = isMultiple
4788
4791
  ? watchIds.some((id) => item[column_ref] === id)
4789
4792
  : watchId === item[column_ref];
4790
- return (jsxRuntime.jsx(react.Box, { cursor: "pointer", onClick: () => {
4793
+ return (jsxRuntime.jsx(react.Box, { cursor: 'pointer', onClick: () => {
4791
4794
  if (!isMultiple) {
4792
4795
  setOpenSearchResult(false);
4793
4796
  setValue(colLabel, item[column_ref]);
@@ -4803,15 +4806,17 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4803
4806
  setValue(colLabel, [...newSet]);
4804
4807
  }, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
4805
4808
  ? {
4806
- color: "colorPalette.400/50",
4807
- fontWeight: "bold",
4809
+ color: 'colorPalette.400/50',
4810
+ fontWeight: 'bold',
4808
4811
  }
4809
4812
  : {}), children: !!renderDisplay === true
4810
4813
  ? renderDisplay(item)
4811
4814
  : item[display_column] }, item[column_ref]));
4812
4815
  }) })) : (jsxRuntime.jsx(react.Text, { children: searchText
4813
- ? formI18n.t('empty_search_result')
4814
- : 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() }))] }));
4816
+ ? idPickerLabels?.emptySearchResult ??
4817
+ formI18n.t('empty_search_result')
4818
+ : idPickerLabels?.initialResults ??
4819
+ 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() }))] }));
4815
4820
  };
4816
4821
 
4817
4822
  const NumberInputRoot = React__namespace.forwardRef(function NumberInput(props, ref) {
@@ -5498,7 +5503,7 @@ dayjs.extend(utc);
5498
5503
  dayjs.extend(timezone);
5499
5504
  const DateTimePicker = ({ column, schema, prefix, }) => {
5500
5505
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
5501
- const { timezone } = useSchemaContext();
5506
+ const { timezone, dateTimePickerLabels } = useSchemaContext();
5502
5507
  const formI18n = useFormI18n(column, prefix);
5503
5508
  const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
5504
5509
  // with timezone
@@ -5539,7 +5544,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
5539
5544
  }, 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) => {
5540
5545
  setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
5541
5546
  }, timezone: timezone, labels: {
5542
- monthNamesShort: [
5547
+ monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
5543
5548
  formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
5544
5549
  formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
5545
5550
  formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
@@ -5553,7 +5558,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
5553
5558
  formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
5554
5559
  formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
5555
5560
  ],
5556
- weekdayNamesShort: [
5561
+ weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
5557
5562
  formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
5558
5563
  formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
5559
5564
  formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
@@ -5564,10 +5569,10 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
5564
5569
  formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
5565
5570
  formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
5566
5571
  ],
5567
- backButtonLabel: formI18n.translate.t(`common.back_button`, {
5572
+ backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? formI18n.translate.t(`common.back_button`, {
5568
5573
  defaultValue: "Back",
5569
5574
  }),
5570
- forwardButtonLabel: formI18n.translate.t(`common.forward_button`, {
5575
+ forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? formI18n.translate.t(`common.forward_button`, {
5571
5576
  defaultValue: "Forward",
5572
5577
  }),
5573
5578
  } })] }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: formI18n.required() }))] }));
@@ -6093,7 +6098,7 @@ const SubmitButton = () => {
6093
6098
  };
6094
6099
 
6095
6100
  const FormBody = () => {
6096
- const { schema, requestUrl, order, ignore, include, onSubmit, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, displayConfig, } = useSchemaContext();
6101
+ 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();
6097
6102
  const { showSubmitButton, showResetButton } = displayConfig;
6098
6103
  const methods = reactHookForm.useFormContext();
6099
6104
  const { properties } = schema;
@@ -6190,15 +6195,19 @@ const FormBody = () => {
6190
6195
  include,
6191
6196
  });
6192
6197
  if (isSuccess) {
6193
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "2", children: [jsxRuntime.jsxs(react.Alert.Root, { status: "success", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Content, { children: jsxRuntime.jsx(react.Alert.Title, { children: translate.t("submit_success") }) })] }), jsxRuntime.jsx(react.Flex, { justifyContent: "end", children: jsxRuntime.jsx(react.Button, { onClick: async () => {
6194
- setIsError(false);
6195
- setIsSubmiting(false);
6196
- setIsSuccess(false);
6197
- setIsConfirming(false);
6198
- setValidatedData(undefined);
6199
- const data = await getUpdatedData();
6200
- methods.reset(data);
6201
- }, formNoValidate: true, children: translate.t("submit_again") }) })] }));
6198
+ const resetHandler = async () => {
6199
+ setIsError(false);
6200
+ setIsSubmiting(false);
6201
+ setIsSuccess(false);
6202
+ setIsConfirming(false);
6203
+ setValidatedData(undefined);
6204
+ const data = await getUpdatedData();
6205
+ methods.reset(data);
6206
+ };
6207
+ if (customSuccessRenderer) {
6208
+ return customSuccessRenderer(resetHandler);
6209
+ }
6210
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "2", children: [jsxRuntime.jsxs(react.Alert.Root, { status: "success", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Content, { children: jsxRuntime.jsx(react.Alert.Title, { children: translate.t("submit_success") }) })] }), jsxRuntime.jsx(react.Flex, { justifyContent: "end", children: jsxRuntime.jsx(react.Button, { onClick: resetHandler, formNoValidate: true, children: translate.t("submit_again") }) })] }));
6202
6211
  }
6203
6212
  if (isConfirming) {
6204
6213
  return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: 4, gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: "repeat(12, max-content)", autoFlow: "row", children: ordered.map((column) => {
@@ -6236,12 +6245,12 @@ const DefaultForm = ({ formConfig, }) => {
6236
6245
  return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [showTitle && jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
6237
6246
  };
6238
6247
 
6239
- const useForm = ({ preLoadedValues, keyPrefix }) => {
6248
+ const useForm = ({ preLoadedValues, keyPrefix, namespace }) => {
6240
6249
  const form = reactHookForm.useForm({
6241
6250
  values: preLoadedValues,
6242
6251
  });
6243
6252
  const [idMap, setIdMap] = React.useState({});
6244
- const translate = reactI18next.useTranslation("", { keyPrefix });
6253
+ const translate = reactI18next.useTranslation(namespace || "", { keyPrefix });
6245
6254
  return {
6246
6255
  form,
6247
6256
  idMap,
@@ -6250,6 +6259,207 @@ const useForm = ({ preLoadedValues, keyPrefix }) => {
6250
6259
  };
6251
6260
  };
6252
6261
 
6262
+ /**
6263
+ * Type definitions for error message configuration
6264
+ */
6265
+ /**
6266
+ * Schema-level error message builder
6267
+ *
6268
+ * Builds a complete errorMessage object compatible with ajv-errors plugin.
6269
+ * Supports both i18n translation keys and plain string messages.
6270
+ *
6271
+ * @param config - Error message configuration
6272
+ * @returns Complete errorMessage object for JSON Schema
6273
+ *
6274
+ * @example
6275
+ * ```typescript
6276
+ * // Simple required field errors
6277
+ * const errorMessage = buildErrorMessages({
6278
+ * required: {
6279
+ * username: "Username is required",
6280
+ * email: "user.email.field_required" // i18n key
6281
+ * }
6282
+ * });
6283
+ *
6284
+ * // With validation rules
6285
+ * const errorMessage = buildErrorMessages({
6286
+ * required: {
6287
+ * password: "Password is required"
6288
+ * },
6289
+ * properties: {
6290
+ * password: {
6291
+ * minLength: "Password must be at least 8 characters",
6292
+ * pattern: "Password must contain letters and numbers"
6293
+ * },
6294
+ * age: {
6295
+ * minimum: "Must be 18 or older",
6296
+ * maximum: "Must be under 120"
6297
+ * }
6298
+ * }
6299
+ * });
6300
+ *
6301
+ * // With global fallbacks
6302
+ * const errorMessage = buildErrorMessages({
6303
+ * required: {
6304
+ * email: "Email is required"
6305
+ * },
6306
+ * minLength: "This field is too short", // applies to all fields
6307
+ * minimum: "Value is too small"
6308
+ * });
6309
+ * ```
6310
+ */
6311
+ const buildErrorMessages = (config) => {
6312
+ const result = {};
6313
+ // Add required field errors
6314
+ if (config.required && Object.keys(config.required).length > 0) {
6315
+ result.required = config.required;
6316
+ }
6317
+ // Add field-specific validation errors
6318
+ if (config.properties && Object.keys(config.properties).length > 0) {
6319
+ result.properties = config.properties;
6320
+ }
6321
+ // Add global fallback error messages
6322
+ const globalKeys = [
6323
+ "minLength",
6324
+ "maxLength",
6325
+ "pattern",
6326
+ "minimum",
6327
+ "maximum",
6328
+ "multipleOf",
6329
+ "format",
6330
+ "type",
6331
+ "enum",
6332
+ ];
6333
+ globalKeys.forEach((key) => {
6334
+ if (config[key]) {
6335
+ result[key] = config[key];
6336
+ }
6337
+ });
6338
+ return result;
6339
+ };
6340
+ /**
6341
+ * Helper function to build required field errors
6342
+ *
6343
+ * Simplifies creating required field error messages, especially useful
6344
+ * for generating i18n translation keys following a pattern.
6345
+ *
6346
+ * @param fields - Array of required field names
6347
+ * @param messageOrGenerator - Either a string template or function to generate messages
6348
+ * @returns Required field error configuration
6349
+ *
6350
+ * @example
6351
+ * ```typescript
6352
+ * // Plain string messages
6353
+ * const required = buildRequiredErrors(
6354
+ * ["username", "email", "password"],
6355
+ * (field) => `${field} is required`
6356
+ * );
6357
+ * // Result: { username: "username is required", email: "email is required", ... }
6358
+ *
6359
+ * // i18n translation keys
6360
+ * const required = buildRequiredErrors(
6361
+ * ["username", "email"],
6362
+ * (field) => `user.${field}.field_required`
6363
+ * );
6364
+ * // Result: { username: "user.username.field_required", email: "user.email.field_required" }
6365
+ *
6366
+ * // Same message for all fields
6367
+ * const required = buildRequiredErrors(
6368
+ * ["username", "email"],
6369
+ * "This field is required"
6370
+ * );
6371
+ * // Result: { username: "This field is required", email: "This field is required" }
6372
+ *
6373
+ * // With keyPrefix for i18n
6374
+ * const required = buildRequiredErrors(
6375
+ * ["username", "email"],
6376
+ * (field) => `${field}.field_required`,
6377
+ * "user"
6378
+ * );
6379
+ * // Result: { username: "user.username.field_required", email: "user.email.field_required" }
6380
+ * ```
6381
+ */
6382
+ const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = "") => {
6383
+ const result = {};
6384
+ fields.forEach((field) => {
6385
+ if (typeof messageOrGenerator === "function") {
6386
+ const message = messageOrGenerator(field);
6387
+ result[field] = keyPrefix ? `${keyPrefix}.${message}` : message;
6388
+ }
6389
+ else {
6390
+ result[field] = messageOrGenerator;
6391
+ }
6392
+ });
6393
+ return result;
6394
+ };
6395
+ /**
6396
+ * Helper function to build field-specific validation errors
6397
+ *
6398
+ * Creates property-specific error messages for multiple fields at once.
6399
+ *
6400
+ * @param config - Maps field names to their validation error configurations
6401
+ * @returns Properties error configuration
6402
+ *
6403
+ * @example
6404
+ * ```typescript
6405
+ * const properties = buildFieldErrors({
6406
+ * username: {
6407
+ * minLength: "Username must be at least 3 characters",
6408
+ * pattern: "Username can only contain letters and numbers"
6409
+ * },
6410
+ * age: {
6411
+ * minimum: "Must be 18 or older",
6412
+ * maximum: "Must be under 120"
6413
+ * },
6414
+ * email: {
6415
+ * format: "Please enter a valid email address"
6416
+ * }
6417
+ * });
6418
+ * ```
6419
+ */
6420
+ const buildFieldErrors = (config) => {
6421
+ return config;
6422
+ };
6423
+ /**
6424
+ * Helper function to create a complete error message configuration in one call
6425
+ *
6426
+ * Convenient wrapper that combines required and validation errors.
6427
+ *
6428
+ * @param required - Required field error messages
6429
+ * @param properties - Field-specific validation error messages
6430
+ * @param globalFallbacks - Global fallback error messages
6431
+ * @returns Complete error message configuration
6432
+ *
6433
+ * @example
6434
+ * ```typescript
6435
+ * const errorMessage = createErrorMessage(
6436
+ * {
6437
+ * username: "Username is required",
6438
+ * email: "Email is required"
6439
+ * },
6440
+ * {
6441
+ * username: {
6442
+ * minLength: "Username must be at least 3 characters"
6443
+ * },
6444
+ * email: {
6445
+ * format: "Please enter a valid email"
6446
+ * }
6447
+ * },
6448
+ * {
6449
+ * minLength: "This field is too short",
6450
+ * format: "Invalid format"
6451
+ * }
6452
+ * );
6453
+ * ```
6454
+ */
6455
+ const createErrorMessage = (required, properties, globalFallbacks) => {
6456
+ return buildErrorMessages({
6457
+ required,
6458
+ properties,
6459
+ ...globalFallbacks,
6460
+ });
6461
+ };
6462
+
6253
6463
  const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) => {
6254
6464
  if (!selectable) {
6255
6465
  return [...selectedDates];
@@ -6307,6 +6517,10 @@ exports.TableSorter = TableSorter;
6307
6517
  exports.TableViewer = TableViewer;
6308
6518
  exports.TextCell = TextCell;
6309
6519
  exports.ViewDialog = ViewDialog;
6520
+ exports.buildErrorMessages = buildErrorMessages;
6521
+ exports.buildFieldErrors = buildFieldErrors;
6522
+ exports.buildRequiredErrors = buildRequiredErrors;
6523
+ exports.createErrorMessage = createErrorMessage;
6310
6524
  exports.getColumns = getColumns;
6311
6525
  exports.getMultiDates = getMultiDates;
6312
6526
  exports.getRangeDates = getRangeDates;