@bsol-oss/react-datatable5 13.0.1-beta.21 → 13.0.1-beta.22

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.d.ts CHANGED
@@ -7,8 +7,8 @@ import { TableHeaderProps as TableHeaderProps$1, TableRowProps, GridProps, Table
7
7
  import { IconType } from 'react-icons';
8
8
  import { UseQueryResult } from '@tanstack/react-query';
9
9
  import { RankingInfo } from '@tanstack/match-sorter-utils';
10
- import { JSONSchema7 } from 'json-schema';
11
10
  import { AxiosRequestConfig } from 'axios';
11
+ import { JSONSchema7 } from 'json-schema';
12
12
  import * as react_hook_form from 'react-hook-form';
13
13
  import { UseFormReturn, FieldValues, SubmitHandler } from 'react-hook-form';
14
14
 
@@ -488,19 +488,6 @@ interface DataTableContextProps<TData = unknown> extends Omit<DataTableProps, 't
488
488
 
489
489
  declare const useDataTableContext: <TData>() => DataTableContextProps<TData>;
490
490
 
491
- interface GetColumnsConfigs<K extends RowData> {
492
- schema: JSONSchema7;
493
- include?: K[];
494
- ignore?: K[];
495
- width?: number[];
496
- meta?: {
497
- [key in K as string]?: object;
498
- };
499
- defaultWidth?: number;
500
- }
501
- declare const widthSanityCheck: <K extends unknown>(widthList: number[], ignoreList: K[], properties: { [key in K as string]?: object | undefined; }) => void;
502
- declare const getColumns: <TData extends unknown>({ schema, include, ignore, width, meta, defaultWidth, }: GetColumnsConfigs<TData>) => ColumnDef<TData>[];
503
-
504
491
  interface CustomQueryFnResponse {
505
492
  /**
506
493
  * The data of the query
@@ -591,7 +578,6 @@ interface TimePickerLabels {
591
578
  interface LoadInitialValuesParams {
592
579
  ids: string[];
593
580
  customQueryFn: CustomQueryFn;
594
- idColumn: string;
595
581
  setIdMap: React__default.Dispatch<React__default.SetStateAction<Record<string, object>>>;
596
582
  }
597
583
  interface LoadInitialValuesResult {
@@ -605,7 +591,6 @@ interface CustomJSONSchema7 extends JSONSchema7 {
605
591
  gridColumn?: string;
606
592
  gridRow?: string;
607
593
  customQueryFn?: CustomQueryFn;
608
- idColumn?: string;
609
594
  variant?: string;
610
595
  renderDisplay?: (item: unknown) => ReactNode;
611
596
  itemToValue?: (item: unknown) => string;
@@ -740,10 +725,8 @@ interface CustomJSONSchema7Definition extends JSONSchema7 {
740
725
  gridColumn: string;
741
726
  gridRow: string;
742
727
  customQueryFn: any;
743
- idColumn: string;
744
728
  children: ReactNode;
745
729
  }
746
- declare const idPickerSanityCheck: (column: string, customQueryFn?: any, idColumn?: string) => void;
747
730
  declare const FormRoot: <TData extends FieldValues>({ schema, idMap, setIdMap, form, children, order, ignore, include, onSubmit, rowNumber, requestOptions, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog, }: FormRootProps<TData>) => react_jsx_runtime.JSX.Element;
748
731
 
749
732
  interface DefaultFormProps<TData extends FieldValues> {
@@ -1253,4 +1236,4 @@ declare module '@tanstack/react-table' {
1253
1236
  }
1254
1237
  }
1255
1238
 
1256
- export { CalendarDisplay, type CalendarDisplayProps, type CalendarEvent, type CalendarProps, CardHeader, type CardHeaderProps, type CustomJSONSchema7, type CustomJSONSchema7Definition, DataDisplay, type DataDisplayProps, type DataResponse, DataTable, type DataTableDefaultState, type DataTableProps, DataTableServer, type DataTableServerProps, DatePickerContext, DatePickerInput, type DatePickerInputProps, type DatePickerLabels, type DatePickerProps, type DateTimePickerLabels, DefaultCardTitle, DefaultForm, type DefaultFormProps, DefaultTable, type DefaultTableProps, DefaultTableServer, type DefaultTableServerProps, DensityToggleButton, type DensityToggleButtonProps, type EditFilterButtonProps, EditSortingButton, type EditSortingButtonProps, type EditViewButtonProps, EmptyState, type EmptyStateProps, type EnumPickerLabels, ErrorAlert, type ErrorAlertProps, type FilePickerLabels, type FilePickerMediaFile, type FilePickerProps, FilterDialog, FormBody, type FormButtonLabels, FormRoot, type FormRootProps, FormTitle, type GetColumnsConfigs, type GetDateColorProps, type GetMultiDatesProps, type GetRangeDatesProps, type GetStyleProps, type GetVariantProps, GlobalFilter, type IdPickerLabels, type LoadInitialValuesParams, type LoadInitialValuesResult, MediaLibraryBrowser, type MediaLibraryBrowserProps, PageSizeControl, type PageSizeControlProps, Pagination, type QueryParams, type RangeCalendarProps, type RangeDatePickerLabels, type RangeDatePickerProps, RecordDisplay, type RecordDisplayProps, ReloadButton, type ReloadButtonProps, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, type Result, RowCountText, SelectAllRowsToggle, type SelectAllRowsToggleProps, Table, TableBody, type TableBodyProps, TableCardContainer, type TableCardContainerProps, TableCards, type TableCardsProps, TableComponent, TableControls, type TableControlsProps, TableDataDisplay, type TableDataDisplayProps, TableFilter, TableFilterTags, type TableFilterTagsProps, TableFooter, type TableFooterProps, TableHeader, type TableHeaderProps, type TableHeaderTexts, TableLoadingComponent, type TableLoadingComponentProps, type TableProps, type TableRendererProps, type TableRowSelectorProps, TableSelector, TableSorter, TableViewer, type TagPickerProps, TextCell, type TextCellProps, type TimePickerLabels, type Translate, type UseDataTableProps, type UseDataTableReturn, type UseDataTableServerProps, type UseDataTableServerReturn, type UseFormProps, type ValidationErrorType, ViewDialog, defaultRenderDisplay, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
1239
+ export { CalendarDisplay, type CalendarDisplayProps, type CalendarEvent, type CalendarProps, CardHeader, type CardHeaderProps, type CustomJSONSchema7, type CustomJSONSchema7Definition, DataDisplay, type DataDisplayProps, type DataResponse, DataTable, type DataTableDefaultState, type DataTableProps, DataTableServer, type DataTableServerProps, DatePickerContext, DatePickerInput, type DatePickerInputProps, type DatePickerLabels, type DatePickerProps, type DateTimePickerLabels, DefaultCardTitle, DefaultForm, type DefaultFormProps, DefaultTable, type DefaultTableProps, DefaultTableServer, type DefaultTableServerProps, DensityToggleButton, type DensityToggleButtonProps, type EditFilterButtonProps, EditSortingButton, type EditSortingButtonProps, type EditViewButtonProps, EmptyState, type EmptyStateProps, type EnumPickerLabels, ErrorAlert, type ErrorAlertProps, type FilePickerLabels, type FilePickerMediaFile, type FilePickerProps, FilterDialog, FormBody, type FormButtonLabels, FormRoot, type FormRootProps, FormTitle, type GetDateColorProps, type GetMultiDatesProps, type GetRangeDatesProps, type GetStyleProps, type GetVariantProps, GlobalFilter, type IdPickerLabels, type LoadInitialValuesParams, type LoadInitialValuesResult, MediaLibraryBrowser, type MediaLibraryBrowserProps, PageSizeControl, type PageSizeControlProps, Pagination, type QueryParams, type RangeCalendarProps, type RangeDatePickerLabels, type RangeDatePickerProps, RecordDisplay, type RecordDisplayProps, ReloadButton, type ReloadButtonProps, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, type Result, RowCountText, SelectAllRowsToggle, type SelectAllRowsToggleProps, Table, TableBody, type TableBodyProps, TableCardContainer, type TableCardContainerProps, TableCards, type TableCardsProps, TableComponent, TableControls, type TableControlsProps, TableDataDisplay, type TableDataDisplayProps, TableFilter, TableFilterTags, type TableFilterTagsProps, TableFooter, type TableFooterProps, TableHeader, type TableHeaderProps, type TableHeaderTexts, TableLoadingComponent, type TableLoadingComponentProps, type TableProps, type TableRendererProps, type TableRowSelectorProps, TableSelector, TableSorter, TableViewer, type TagPickerProps, TextCell, type TextCellProps, type TimePickerLabels, type Translate, type UseDataTableProps, type UseDataTableReturn, type UseDataTableServerProps, type UseDataTableServerReturn, type UseFormProps, type ValidationErrorType, ViewDialog, defaultRenderDisplay, getMultiDates, getRangeDates, useDataTable, useDataTableContext, useDataTableServer, useForm };
package/dist/index.js CHANGED
@@ -4186,88 +4186,6 @@ const useDataTableServer = (props) => {
4186
4186
  };
4187
4187
  };
4188
4188
 
4189
- const idListSanityCheck = (param, idList, properties) => {
4190
- const allKeyExists = idList.every((key) => Object.keys(properties).some((column) => column == key));
4191
- if (!allKeyExists) {
4192
- const wrongKey = idList.find((key) => !Object.keys(properties).some((column) => column == key));
4193
- throw new Error(`The key ${wrongKey} in ${param} does not exist in schema.`);
4194
- }
4195
- };
4196
-
4197
- const snakeToLabel = (str) => {
4198
- return str
4199
- .split("_") // Split by underscore
4200
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word
4201
- .join(" "); // Join with space
4202
- };
4203
-
4204
- const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
4205
- const getColumn = ({ field }) => {
4206
- return snakeToLabel(field);
4207
- };
4208
- if (object === null) {
4209
- return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "null" });
4210
- }
4211
- return (jsxRuntime.jsx(react.Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
4212
- const uniqueKey = `${prefix}${field}-${index}`;
4213
- return (jsxRuntime.jsxs(react.Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsxRuntime.jsx(react.Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsxRuntime.jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsxRuntime.jsx(react.Text, { children: JSON.stringify(value) }))] }, uniqueKey));
4214
- }) }));
4215
- };
4216
-
4217
- const widthSanityCheck = (widthList, ignoreList, properties) => {
4218
- const widthListToolong = widthList.length > Object.keys(properties).length;
4219
- if (widthListToolong) {
4220
- throw new Error(`The width list is too long given from the number of properties.`);
4221
- }
4222
- const widthListToolongWithIgnore = widthList.length > Object.keys(properties).length - ignoreList.length;
4223
- if (widthListToolongWithIgnore) {
4224
- throw new Error(`The width list is too long given from the number of remaining properties after ignore some.`);
4225
- }
4226
- };
4227
- const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400, }) => {
4228
- const { properties } = schema;
4229
- idListSanityCheck('ignore', ignore, properties);
4230
- widthSanityCheck(width, ignore, properties);
4231
- idListSanityCheck('meta', Object.keys(meta), properties);
4232
- const getColumn = ({ column }) => {
4233
- return snakeToLabel(column);
4234
- };
4235
- const keys = Object.keys(properties);
4236
- const included = include.length > 0 ? include : keys;
4237
- const ignored = included.filter((key) => {
4238
- return !ignore.some((shouldIgnoreKey) => key === shouldIgnoreKey);
4239
- });
4240
- const columnHelper = reactTable.createColumnHelper();
4241
- const columns = [
4242
- ...ignored.map((column, index) => {
4243
- // @ts-expect-error column accessor type issue with generic TData
4244
- return columnHelper.accessor(column, {
4245
- cell: (props) => {
4246
- // @ts-expect-error find type for unknown
4247
- const value = props.row.original[column];
4248
- if (typeof value === 'object') {
4249
- return (jsxRuntime.jsx(react.Grid, { overflow: 'auto', children: jsxRuntime.jsx(RecordDisplay, { object: value }) }));
4250
- }
4251
- return jsxRuntime.jsx(TextCell, { children: value });
4252
- },
4253
- header: (columnHeader) => {
4254
- const displayName = columnHeader.column.columnDef.meta?.displayName ??
4255
- getColumn({ column });
4256
- return jsxRuntime.jsx("span", { children: displayName });
4257
- },
4258
- footer: (columnFooter) => {
4259
- const displayName = columnFooter.column.columnDef.meta?.displayName ??
4260
- getColumn({ column });
4261
- return jsxRuntime.jsx("span", { children: displayName });
4262
- },
4263
- size: width[index] ?? defaultWidth,
4264
- meta: Object.keys(meta).length > 0 ? meta[column] : {},
4265
- });
4266
- }),
4267
- ];
4268
- return columns;
4269
- };
4270
-
4271
4189
  //@ts-expect-error TODO: find appropriate type
4272
4190
  const SchemaFormContext = React.createContext({
4273
4191
  schema: {},
@@ -4291,114 +4209,6 @@ const useSchemaContext = () => {
4291
4209
  return React.useContext(SchemaFormContext);
4292
4210
  };
4293
4211
 
4294
- const clearEmptyString = (object) => {
4295
- return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
4296
- };
4297
-
4298
- const idPickerSanityCheck = (column, customQueryFn, idColumn) => {
4299
- if (!customQueryFn) {
4300
- throw new Error(`customQueryFn is required in properties of column ${column} when using id-picker.`);
4301
- }
4302
- if (!idColumn) {
4303
- throw new Error(`idColumn is required in properties of column ${column} when using id-picker.`);
4304
- }
4305
- };
4306
- const FormRoot = ({ schema, idMap, setIdMap, form, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
4307
- showSubmitButton: true,
4308
- showResetButton: true,
4309
- showTitle: true,
4310
- }, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
4311
- const [isSuccess, setIsSuccess] = React.useState(false);
4312
- const [isError, setIsError] = React.useState(false);
4313
- const [isSubmiting, setIsSubmiting] = React.useState(false);
4314
- const [validatedData, setValidatedData] = React.useState();
4315
- const [error, setError] = React.useState();
4316
- const onBeforeSubmit = () => {
4317
- setIsSubmiting(true);
4318
- };
4319
- const onAfterSubmit = () => {
4320
- setIsSubmiting(false);
4321
- };
4322
- const onSubmitError = (error) => {
4323
- setIsError(true);
4324
- setError(error);
4325
- };
4326
- const onSubmitSuccess = () => {
4327
- setIsSuccess(true);
4328
- };
4329
- const defaultOnSubmit = async (promise) => {
4330
- try {
4331
- console.log('onBeforeSubmit');
4332
- onBeforeSubmit();
4333
- await promise;
4334
- console.log('onSubmitSuccess');
4335
- onSubmitSuccess();
4336
- }
4337
- catch (error) {
4338
- console.log('onSubmitError', error);
4339
- onSubmitError(error);
4340
- }
4341
- finally {
4342
- onAfterSubmit();
4343
- }
4344
- };
4345
- const defaultSubmitPromise = (data) => {
4346
- if (!requestOptions.url) {
4347
- throw new Error('requestOptions.url is required when onSubmit is not provided');
4348
- }
4349
- const options = {
4350
- method: 'POST',
4351
- data: clearEmptyString(data),
4352
- ...requestOptions,
4353
- };
4354
- return axios.request(options);
4355
- };
4356
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4357
- const onFormSubmit = async (data) => {
4358
- // Validation is handled by react-hook-form
4359
- // This function will only be called if validation passes
4360
- if (onSubmit === undefined) {
4361
- await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
4362
- return;
4363
- }
4364
- await defaultOnSubmit(Promise.resolve(onSubmit(data)));
4365
- };
4366
- return (jsxRuntime.jsx(SchemaFormContext.Provider, { value: {
4367
- schema,
4368
- order,
4369
- ignore,
4370
- include,
4371
- // @ts-expect-error TODO: find appropriate types
4372
- onSubmit,
4373
- rowNumber,
4374
- idMap,
4375
- setIdMap,
4376
- requestOptions,
4377
- isSuccess,
4378
- setIsSuccess,
4379
- isError,
4380
- setIsError,
4381
- isSubmiting,
4382
- setIsSubmiting,
4383
- validatedData,
4384
- setValidatedData,
4385
- error,
4386
- setError,
4387
- getUpdatedData,
4388
- customErrorRenderer,
4389
- customSuccessRenderer,
4390
- displayConfig,
4391
- onFormSubmit,
4392
- dateTimePickerLabels,
4393
- idPickerLabels,
4394
- enumPickerLabels,
4395
- filePickerLabels,
4396
- formButtonLabels,
4397
- timePickerLabels,
4398
- insideDialog,
4399
- }, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
4400
- };
4401
-
4402
4212
  const useFormLabel = (column, prefix = '', schema) => {
4403
4213
  const colLabel = `${prefix}${column}`;
4404
4214
  return {
@@ -6012,13 +5822,12 @@ const defaultRenderDisplay = (item) => {
6012
5822
  const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6013
5823
  const { watch, getValues, formState: { errors }, setValue, } = reactHookForm.useFormContext();
6014
5824
  const { idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
6015
- const { renderDisplay, itemToValue: schemaItemToValue, loadInitialValues, customQueryFn, idColumn, variant, } = schema;
5825
+ const { renderDisplay, itemToValue: schemaItemToValue, loadInitialValues, customQueryFn, variant, } = schema;
6016
5826
  // loadInitialValues should be provided in schema for id-picker fields
6017
5827
  // It's used to load the record of the id so the display is human-readable
6018
5828
  if (variant === 'id-picker' && !loadInitialValues) {
6019
5829
  console.warn(`loadInitialValues is recommended in schema for IdPicker field '${column}'. Please provide loadInitialValues function in the schema to load records for human-readable display.`);
6020
5830
  }
6021
- const column_ref = idColumn || 'id';
6022
5831
  const [searchText, setSearchText] = React.useState('');
6023
5832
  const debouncedSearchText = usehooks.useDebounce(searchText, 300);
6024
5833
  const [limit] = React.useState(50); // Increased limit for combobox
@@ -6078,7 +5887,6 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6078
5887
  const result = await loadInitialValues({
6079
5888
  ids: missingIds,
6080
5889
  customQueryFn: customQueryFn,
6081
- idColumn: column_ref,
6082
5890
  setIdMap,
6083
5891
  });
6084
5892
  return result.data;
@@ -6139,12 +5947,15 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6139
5947
  // Depend on idMapKey which only changes when items we care about change
6140
5948
  // eslint-disable-next-line react-hooks/exhaustive-deps
6141
5949
  }, [currentValueKey, idMapKey]);
6142
- // Default itemToValue function: extract value from item using column_ref
6143
- const defaultItemToValue = (item) => String(item[column_ref]);
6144
- // Use schema's itemToValue if provided, otherwise use default
5950
+ // Use schema's itemToValue if provided, otherwise throw error
5951
+ // schemaItemToValue should be provided in schema for id-picker fields
6145
5952
  const itemToValueFn = schemaItemToValue
6146
5953
  ? (item) => schemaItemToValue(item)
6147
- : defaultItemToValue;
5954
+ : (item) => {
5955
+ console.warn(`itemToValue is required in schema for IdPicker field '${column}'. Please provide itemToValue function in the schema. Currently trying to get 'id' field as last resort`);
5956
+ // Fallback: try to get 'id' field as last resort
5957
+ return String(item?.id ?? item);
5958
+ };
6148
5959
  // itemToString function: convert item to readable string using renderDisplay
6149
5960
  // This ensures items can always be displayed as readable strings in the combobox
6150
5961
  const renderFn = renderDisplay || defaultRenderDisplay;
@@ -6206,7 +6017,7 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6206
6017
  })
6207
6018
  .filter((item) => item !== null);
6208
6019
  return [...itemsFromIdMap, ...itemsFromDataList];
6209
- }, [dataList, column_ref, renderDisplay, idMapItems, itemToValueFn]);
6020
+ }, [dataList, renderDisplay, idMapItems, itemToValueFn]);
6210
6021
  // Use filter hook for combobox
6211
6022
  const { contains } = react.useFilter({ sensitivity: 'base' });
6212
6023
  // Create collection for combobox
@@ -6272,7 +6083,6 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6272
6083
  itemToString: itemToStringFn,
6273
6084
  loadInitialValues: loadInitialValues ??
6274
6085
  (async () => ({ data: { data: [], count: 0 }, idMap: {} })), // Fallback if not provided
6275
- column_ref,
6276
6086
  errors,
6277
6087
  setValue,
6278
6088
  };
@@ -8121,7 +7931,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
8121
7931
 
8122
7932
  const SchemaRenderer = ({ schema, prefix, column, }) => {
8123
7933
  const colSchema = schema;
8124
- const { type, variant, properties: innerProperties, customQueryFn, idColumn, format, items, } = schema;
7934
+ const { type, variant, properties: innerProperties, format, items } = schema;
8125
7935
  if (variant === 'custom-input') {
8126
7936
  return jsxRuntime.jsx(CustomInput, { schema: colSchema, prefix, column });
8127
7937
  }
@@ -8130,7 +7940,6 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
8130
7940
  return jsxRuntime.jsx(EnumPicker, { schema: colSchema, prefix, column });
8131
7941
  }
8132
7942
  if (variant === 'id-picker') {
8133
- idPickerSanityCheck(column, customQueryFn, idColumn);
8134
7943
  return jsxRuntime.jsx(IdPickerSingle, { schema: colSchema, prefix, column });
8135
7944
  }
8136
7945
  if (format === 'date') {
@@ -8164,7 +7973,6 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
8164
7973
  }
8165
7974
  if (type === 'array') {
8166
7975
  if (variant === 'id-picker') {
8167
- idPickerSanityCheck(column, customQueryFn, idColumn);
8168
7976
  return jsxRuntime.jsx(IdPickerMultiple, { schema: colSchema, prefix, column });
8169
7977
  }
8170
7978
  if (variant === 'tag-picker') {
@@ -8278,6 +8086,106 @@ const FormTitle = () => {
8278
8086
  return jsxRuntime.jsx(react.Heading, { children: schema.title ?? 'Form' });
8279
8087
  };
8280
8088
 
8089
+ const clearEmptyString = (object) => {
8090
+ return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
8091
+ };
8092
+
8093
+ const FormRoot = ({ schema, idMap, setIdMap, form, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
8094
+ showSubmitButton: true,
8095
+ showResetButton: true,
8096
+ showTitle: true,
8097
+ }, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
8098
+ const [isSuccess, setIsSuccess] = React.useState(false);
8099
+ const [isError, setIsError] = React.useState(false);
8100
+ const [isSubmiting, setIsSubmiting] = React.useState(false);
8101
+ const [validatedData, setValidatedData] = React.useState();
8102
+ const [error, setError] = React.useState();
8103
+ const onBeforeSubmit = () => {
8104
+ setIsSubmiting(true);
8105
+ };
8106
+ const onAfterSubmit = () => {
8107
+ setIsSubmiting(false);
8108
+ };
8109
+ const onSubmitError = (error) => {
8110
+ setIsError(true);
8111
+ setError(error);
8112
+ };
8113
+ const onSubmitSuccess = () => {
8114
+ setIsSuccess(true);
8115
+ };
8116
+ const defaultOnSubmit = async (promise) => {
8117
+ try {
8118
+ console.log('onBeforeSubmit');
8119
+ onBeforeSubmit();
8120
+ await promise;
8121
+ console.log('onSubmitSuccess');
8122
+ onSubmitSuccess();
8123
+ }
8124
+ catch (error) {
8125
+ console.log('onSubmitError', error);
8126
+ onSubmitError(error);
8127
+ }
8128
+ finally {
8129
+ onAfterSubmit();
8130
+ }
8131
+ };
8132
+ const defaultSubmitPromise = (data) => {
8133
+ if (!requestOptions.url) {
8134
+ throw new Error('requestOptions.url is required when onSubmit is not provided');
8135
+ }
8136
+ const options = {
8137
+ method: 'POST',
8138
+ data: clearEmptyString(data),
8139
+ ...requestOptions,
8140
+ };
8141
+ return axios.request(options);
8142
+ };
8143
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8144
+ const onFormSubmit = async (data) => {
8145
+ // Validation is handled by react-hook-form
8146
+ // This function will only be called if validation passes
8147
+ if (onSubmit === undefined) {
8148
+ await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
8149
+ return;
8150
+ }
8151
+ await defaultOnSubmit(Promise.resolve(onSubmit(data)));
8152
+ };
8153
+ return (jsxRuntime.jsx(SchemaFormContext.Provider, { value: {
8154
+ schema,
8155
+ order,
8156
+ ignore,
8157
+ include,
8158
+ // @ts-expect-error TODO: find appropriate types
8159
+ onSubmit,
8160
+ rowNumber,
8161
+ idMap,
8162
+ setIdMap,
8163
+ requestOptions,
8164
+ isSuccess,
8165
+ setIsSuccess,
8166
+ isError,
8167
+ setIsError,
8168
+ isSubmiting,
8169
+ setIsSubmiting,
8170
+ validatedData,
8171
+ setValidatedData,
8172
+ error,
8173
+ setError,
8174
+ getUpdatedData,
8175
+ customErrorRenderer,
8176
+ customSuccessRenderer,
8177
+ displayConfig,
8178
+ onFormSubmit,
8179
+ dateTimePickerLabels,
8180
+ idPickerLabels,
8181
+ enumPickerLabels,
8182
+ filePickerLabels,
8183
+ formButtonLabels,
8184
+ timePickerLabels,
8185
+ insideDialog,
8186
+ }, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
8187
+ };
8188
+
8281
8189
  const DefaultForm = ({ formConfig, }) => {
8282
8190
  const { showTitle } = formConfig.displayConfig ?? {};
8283
8191
  return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [showTitle && jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
@@ -8526,6 +8434,26 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
8526
8434
  }
8527
8435
  };
8528
8436
 
8437
+ const snakeToLabel = (str) => {
8438
+ return str
8439
+ .split("_") // Split by underscore
8440
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word
8441
+ .join(" "); // Join with space
8442
+ };
8443
+
8444
+ const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
8445
+ const getColumn = ({ field }) => {
8446
+ return snakeToLabel(field);
8447
+ };
8448
+ if (object === null) {
8449
+ return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "null" });
8450
+ }
8451
+ return (jsxRuntime.jsx(react.Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
8452
+ const uniqueKey = `${prefix}${field}-${index}`;
8453
+ return (jsxRuntime.jsxs(react.Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsxRuntime.jsx(react.Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsxRuntime.jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsxRuntime.jsx(react.Text, { children: JSON.stringify(value) }))] }, uniqueKey));
8454
+ }) }));
8455
+ };
8456
+
8529
8457
  const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
8530
8458
  const { columns, data } = useDataTableContext();
8531
8459
  const columnsMap = Object.fromEntries(columns.map((def) => {
@@ -9457,12 +9385,9 @@ exports.TableViewer = TableViewer;
9457
9385
  exports.TextCell = TextCell;
9458
9386
  exports.ViewDialog = ViewDialog;
9459
9387
  exports.defaultRenderDisplay = defaultRenderDisplay;
9460
- exports.getColumns = getColumns;
9461
9388
  exports.getMultiDates = getMultiDates;
9462
9389
  exports.getRangeDates = getRangeDates;
9463
- exports.idPickerSanityCheck = idPickerSanityCheck;
9464
9390
  exports.useDataTable = useDataTable;
9465
9391
  exports.useDataTableContext = useDataTableContext;
9466
9392
  exports.useDataTableServer = useDataTableServer;
9467
9393
  exports.useForm = useForm;
9468
- exports.widthSanityCheck = widthSanityCheck;
package/dist/index.mjs CHANGED
@@ -21,10 +21,10 @@ import { IoReload } from 'react-icons/io5';
21
21
  import { useDebounce } from '@uidotdev/usehooks';
22
22
  import { BsExclamationCircleFill, BsClock } from 'react-icons/bs';
23
23
  import { HiColorSwatch } from 'react-icons/hi';
24
- import { flexRender, createColumnHelper, makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel } from '@tanstack/react-table';
24
+ import { flexRender, makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel } from '@tanstack/react-table';
25
25
  import { GrAscend, GrDescend } from 'react-icons/gr';
26
26
  import axios from 'axios';
27
- import { FormProvider, useFormContext, useForm as useForm$1 } from 'react-hook-form';
27
+ import { useFormContext, FormProvider, useForm as useForm$1 } from 'react-hook-form';
28
28
  import dayjs from 'dayjs';
29
29
  import customParseFormat from 'dayjs/plugin/customParseFormat';
30
30
  import timezone from 'dayjs/plugin/timezone';
@@ -4166,88 +4166,6 @@ const useDataTableServer = (props) => {
4166
4166
  };
4167
4167
  };
4168
4168
 
4169
- const idListSanityCheck = (param, idList, properties) => {
4170
- const allKeyExists = idList.every((key) => Object.keys(properties).some((column) => column == key));
4171
- if (!allKeyExists) {
4172
- const wrongKey = idList.find((key) => !Object.keys(properties).some((column) => column == key));
4173
- throw new Error(`The key ${wrongKey} in ${param} does not exist in schema.`);
4174
- }
4175
- };
4176
-
4177
- const snakeToLabel = (str) => {
4178
- return str
4179
- .split("_") // Split by underscore
4180
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word
4181
- .join(" "); // Join with space
4182
- };
4183
-
4184
- const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
4185
- const getColumn = ({ field }) => {
4186
- return snakeToLabel(field);
4187
- };
4188
- if (object === null) {
4189
- return jsx(Fragment, { children: "null" });
4190
- }
4191
- return (jsx(Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
4192
- const uniqueKey = `${prefix}${field}-${index}`;
4193
- return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsx(Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsx(Text, { children: JSON.stringify(value) }))] }, uniqueKey));
4194
- }) }));
4195
- };
4196
-
4197
- const widthSanityCheck = (widthList, ignoreList, properties) => {
4198
- const widthListToolong = widthList.length > Object.keys(properties).length;
4199
- if (widthListToolong) {
4200
- throw new Error(`The width list is too long given from the number of properties.`);
4201
- }
4202
- const widthListToolongWithIgnore = widthList.length > Object.keys(properties).length - ignoreList.length;
4203
- if (widthListToolongWithIgnore) {
4204
- throw new Error(`The width list is too long given from the number of remaining properties after ignore some.`);
4205
- }
4206
- };
4207
- const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400, }) => {
4208
- const { properties } = schema;
4209
- idListSanityCheck('ignore', ignore, properties);
4210
- widthSanityCheck(width, ignore, properties);
4211
- idListSanityCheck('meta', Object.keys(meta), properties);
4212
- const getColumn = ({ column }) => {
4213
- return snakeToLabel(column);
4214
- };
4215
- const keys = Object.keys(properties);
4216
- const included = include.length > 0 ? include : keys;
4217
- const ignored = included.filter((key) => {
4218
- return !ignore.some((shouldIgnoreKey) => key === shouldIgnoreKey);
4219
- });
4220
- const columnHelper = createColumnHelper();
4221
- const columns = [
4222
- ...ignored.map((column, index) => {
4223
- // @ts-expect-error column accessor type issue with generic TData
4224
- return columnHelper.accessor(column, {
4225
- cell: (props) => {
4226
- // @ts-expect-error find type for unknown
4227
- const value = props.row.original[column];
4228
- if (typeof value === 'object') {
4229
- return (jsx(Grid, { overflow: 'auto', children: jsx(RecordDisplay, { object: value }) }));
4230
- }
4231
- return jsx(TextCell, { children: value });
4232
- },
4233
- header: (columnHeader) => {
4234
- const displayName = columnHeader.column.columnDef.meta?.displayName ??
4235
- getColumn({ column });
4236
- return jsx("span", { children: displayName });
4237
- },
4238
- footer: (columnFooter) => {
4239
- const displayName = columnFooter.column.columnDef.meta?.displayName ??
4240
- getColumn({ column });
4241
- return jsx("span", { children: displayName });
4242
- },
4243
- size: width[index] ?? defaultWidth,
4244
- meta: Object.keys(meta).length > 0 ? meta[column] : {},
4245
- });
4246
- }),
4247
- ];
4248
- return columns;
4249
- };
4250
-
4251
4169
  //@ts-expect-error TODO: find appropriate type
4252
4170
  const SchemaFormContext = createContext({
4253
4171
  schema: {},
@@ -4271,114 +4189,6 @@ const useSchemaContext = () => {
4271
4189
  return useContext(SchemaFormContext);
4272
4190
  };
4273
4191
 
4274
- const clearEmptyString = (object) => {
4275
- return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
4276
- };
4277
-
4278
- const idPickerSanityCheck = (column, customQueryFn, idColumn) => {
4279
- if (!customQueryFn) {
4280
- throw new Error(`customQueryFn is required in properties of column ${column} when using id-picker.`);
4281
- }
4282
- if (!idColumn) {
4283
- throw new Error(`idColumn is required in properties of column ${column} when using id-picker.`);
4284
- }
4285
- };
4286
- const FormRoot = ({ schema, idMap, setIdMap, form, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
4287
- showSubmitButton: true,
4288
- showResetButton: true,
4289
- showTitle: true,
4290
- }, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
4291
- const [isSuccess, setIsSuccess] = useState(false);
4292
- const [isError, setIsError] = useState(false);
4293
- const [isSubmiting, setIsSubmiting] = useState(false);
4294
- const [validatedData, setValidatedData] = useState();
4295
- const [error, setError] = useState();
4296
- const onBeforeSubmit = () => {
4297
- setIsSubmiting(true);
4298
- };
4299
- const onAfterSubmit = () => {
4300
- setIsSubmiting(false);
4301
- };
4302
- const onSubmitError = (error) => {
4303
- setIsError(true);
4304
- setError(error);
4305
- };
4306
- const onSubmitSuccess = () => {
4307
- setIsSuccess(true);
4308
- };
4309
- const defaultOnSubmit = async (promise) => {
4310
- try {
4311
- console.log('onBeforeSubmit');
4312
- onBeforeSubmit();
4313
- await promise;
4314
- console.log('onSubmitSuccess');
4315
- onSubmitSuccess();
4316
- }
4317
- catch (error) {
4318
- console.log('onSubmitError', error);
4319
- onSubmitError(error);
4320
- }
4321
- finally {
4322
- onAfterSubmit();
4323
- }
4324
- };
4325
- const defaultSubmitPromise = (data) => {
4326
- if (!requestOptions.url) {
4327
- throw new Error('requestOptions.url is required when onSubmit is not provided');
4328
- }
4329
- const options = {
4330
- method: 'POST',
4331
- data: clearEmptyString(data),
4332
- ...requestOptions,
4333
- };
4334
- return axios.request(options);
4335
- };
4336
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4337
- const onFormSubmit = async (data) => {
4338
- // Validation is handled by react-hook-form
4339
- // This function will only be called if validation passes
4340
- if (onSubmit === undefined) {
4341
- await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
4342
- return;
4343
- }
4344
- await defaultOnSubmit(Promise.resolve(onSubmit(data)));
4345
- };
4346
- return (jsx(SchemaFormContext.Provider, { value: {
4347
- schema,
4348
- order,
4349
- ignore,
4350
- include,
4351
- // @ts-expect-error TODO: find appropriate types
4352
- onSubmit,
4353
- rowNumber,
4354
- idMap,
4355
- setIdMap,
4356
- requestOptions,
4357
- isSuccess,
4358
- setIsSuccess,
4359
- isError,
4360
- setIsError,
4361
- isSubmiting,
4362
- setIsSubmiting,
4363
- validatedData,
4364
- setValidatedData,
4365
- error,
4366
- setError,
4367
- getUpdatedData,
4368
- customErrorRenderer,
4369
- customSuccessRenderer,
4370
- displayConfig,
4371
- onFormSubmit,
4372
- dateTimePickerLabels,
4373
- idPickerLabels,
4374
- enumPickerLabels,
4375
- filePickerLabels,
4376
- formButtonLabels,
4377
- timePickerLabels,
4378
- insideDialog,
4379
- }, children: jsx(FormProvider, { ...form, children: children }) }));
4380
- };
4381
-
4382
4192
  const useFormLabel = (column, prefix = '', schema) => {
4383
4193
  const colLabel = `${prefix}${column}`;
4384
4194
  return {
@@ -5992,13 +5802,12 @@ const defaultRenderDisplay = (item) => {
5992
5802
  const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5993
5803
  const { watch, getValues, formState: { errors }, setValue, } = useFormContext();
5994
5804
  const { idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
5995
- const { renderDisplay, itemToValue: schemaItemToValue, loadInitialValues, customQueryFn, idColumn, variant, } = schema;
5805
+ const { renderDisplay, itemToValue: schemaItemToValue, loadInitialValues, customQueryFn, variant, } = schema;
5996
5806
  // loadInitialValues should be provided in schema for id-picker fields
5997
5807
  // It's used to load the record of the id so the display is human-readable
5998
5808
  if (variant === 'id-picker' && !loadInitialValues) {
5999
5809
  console.warn(`loadInitialValues is recommended in schema for IdPicker field '${column}'. Please provide loadInitialValues function in the schema to load records for human-readable display.`);
6000
5810
  }
6001
- const column_ref = idColumn || 'id';
6002
5811
  const [searchText, setSearchText] = useState('');
6003
5812
  const debouncedSearchText = useDebounce(searchText, 300);
6004
5813
  const [limit] = useState(50); // Increased limit for combobox
@@ -6058,7 +5867,6 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6058
5867
  const result = await loadInitialValues({
6059
5868
  ids: missingIds,
6060
5869
  customQueryFn: customQueryFn,
6061
- idColumn: column_ref,
6062
5870
  setIdMap,
6063
5871
  });
6064
5872
  return result.data;
@@ -6119,12 +5927,15 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6119
5927
  // Depend on idMapKey which only changes when items we care about change
6120
5928
  // eslint-disable-next-line react-hooks/exhaustive-deps
6121
5929
  }, [currentValueKey, idMapKey]);
6122
- // Default itemToValue function: extract value from item using column_ref
6123
- const defaultItemToValue = (item) => String(item[column_ref]);
6124
- // Use schema's itemToValue if provided, otherwise use default
5930
+ // Use schema's itemToValue if provided, otherwise throw error
5931
+ // schemaItemToValue should be provided in schema for id-picker fields
6125
5932
  const itemToValueFn = schemaItemToValue
6126
5933
  ? (item) => schemaItemToValue(item)
6127
- : defaultItemToValue;
5934
+ : (item) => {
5935
+ console.warn(`itemToValue is required in schema for IdPicker field '${column}'. Please provide itemToValue function in the schema. Currently trying to get 'id' field as last resort`);
5936
+ // Fallback: try to get 'id' field as last resort
5937
+ return String(item?.id ?? item);
5938
+ };
6128
5939
  // itemToString function: convert item to readable string using renderDisplay
6129
5940
  // This ensures items can always be displayed as readable strings in the combobox
6130
5941
  const renderFn = renderDisplay || defaultRenderDisplay;
@@ -6186,7 +5997,7 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6186
5997
  })
6187
5998
  .filter((item) => item !== null);
6188
5999
  return [...itemsFromIdMap, ...itemsFromDataList];
6189
- }, [dataList, column_ref, renderDisplay, idMapItems, itemToValueFn]);
6000
+ }, [dataList, renderDisplay, idMapItems, itemToValueFn]);
6190
6001
  // Use filter hook for combobox
6191
6002
  const { contains } = useFilter({ sensitivity: 'base' });
6192
6003
  // Create collection for combobox
@@ -6252,7 +6063,6 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6252
6063
  itemToString: itemToStringFn,
6253
6064
  loadInitialValues: loadInitialValues ??
6254
6065
  (async () => ({ data: { data: [], count: 0 }, idMap: {} })), // Fallback if not provided
6255
- column_ref,
6256
6066
  errors,
6257
6067
  setValue,
6258
6068
  };
@@ -8101,7 +7911,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
8101
7911
 
8102
7912
  const SchemaRenderer = ({ schema, prefix, column, }) => {
8103
7913
  const colSchema = schema;
8104
- const { type, variant, properties: innerProperties, customQueryFn, idColumn, format, items, } = schema;
7914
+ const { type, variant, properties: innerProperties, format, items } = schema;
8105
7915
  if (variant === 'custom-input') {
8106
7916
  return jsx(CustomInput, { schema: colSchema, prefix, column });
8107
7917
  }
@@ -8110,7 +7920,6 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
8110
7920
  return jsx(EnumPicker, { schema: colSchema, prefix, column });
8111
7921
  }
8112
7922
  if (variant === 'id-picker') {
8113
- idPickerSanityCheck(column, customQueryFn, idColumn);
8114
7923
  return jsx(IdPickerSingle, { schema: colSchema, prefix, column });
8115
7924
  }
8116
7925
  if (format === 'date') {
@@ -8144,7 +7953,6 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
8144
7953
  }
8145
7954
  if (type === 'array') {
8146
7955
  if (variant === 'id-picker') {
8147
- idPickerSanityCheck(column, customQueryFn, idColumn);
8148
7956
  return jsx(IdPickerMultiple, { schema: colSchema, prefix, column });
8149
7957
  }
8150
7958
  if (variant === 'tag-picker') {
@@ -8258,6 +8066,106 @@ const FormTitle = () => {
8258
8066
  return jsx(Heading, { children: schema.title ?? 'Form' });
8259
8067
  };
8260
8068
 
8069
+ const clearEmptyString = (object) => {
8070
+ return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
8071
+ };
8072
+
8073
+ const FormRoot = ({ schema, idMap, setIdMap, form, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
8074
+ showSubmitButton: true,
8075
+ showResetButton: true,
8076
+ showTitle: true,
8077
+ }, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
8078
+ const [isSuccess, setIsSuccess] = useState(false);
8079
+ const [isError, setIsError] = useState(false);
8080
+ const [isSubmiting, setIsSubmiting] = useState(false);
8081
+ const [validatedData, setValidatedData] = useState();
8082
+ const [error, setError] = useState();
8083
+ const onBeforeSubmit = () => {
8084
+ setIsSubmiting(true);
8085
+ };
8086
+ const onAfterSubmit = () => {
8087
+ setIsSubmiting(false);
8088
+ };
8089
+ const onSubmitError = (error) => {
8090
+ setIsError(true);
8091
+ setError(error);
8092
+ };
8093
+ const onSubmitSuccess = () => {
8094
+ setIsSuccess(true);
8095
+ };
8096
+ const defaultOnSubmit = async (promise) => {
8097
+ try {
8098
+ console.log('onBeforeSubmit');
8099
+ onBeforeSubmit();
8100
+ await promise;
8101
+ console.log('onSubmitSuccess');
8102
+ onSubmitSuccess();
8103
+ }
8104
+ catch (error) {
8105
+ console.log('onSubmitError', error);
8106
+ onSubmitError(error);
8107
+ }
8108
+ finally {
8109
+ onAfterSubmit();
8110
+ }
8111
+ };
8112
+ const defaultSubmitPromise = (data) => {
8113
+ if (!requestOptions.url) {
8114
+ throw new Error('requestOptions.url is required when onSubmit is not provided');
8115
+ }
8116
+ const options = {
8117
+ method: 'POST',
8118
+ data: clearEmptyString(data),
8119
+ ...requestOptions,
8120
+ };
8121
+ return axios.request(options);
8122
+ };
8123
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8124
+ const onFormSubmit = async (data) => {
8125
+ // Validation is handled by react-hook-form
8126
+ // This function will only be called if validation passes
8127
+ if (onSubmit === undefined) {
8128
+ await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
8129
+ return;
8130
+ }
8131
+ await defaultOnSubmit(Promise.resolve(onSubmit(data)));
8132
+ };
8133
+ return (jsx(SchemaFormContext.Provider, { value: {
8134
+ schema,
8135
+ order,
8136
+ ignore,
8137
+ include,
8138
+ // @ts-expect-error TODO: find appropriate types
8139
+ onSubmit,
8140
+ rowNumber,
8141
+ idMap,
8142
+ setIdMap,
8143
+ requestOptions,
8144
+ isSuccess,
8145
+ setIsSuccess,
8146
+ isError,
8147
+ setIsError,
8148
+ isSubmiting,
8149
+ setIsSubmiting,
8150
+ validatedData,
8151
+ setValidatedData,
8152
+ error,
8153
+ setError,
8154
+ getUpdatedData,
8155
+ customErrorRenderer,
8156
+ customSuccessRenderer,
8157
+ displayConfig,
8158
+ onFormSubmit,
8159
+ dateTimePickerLabels,
8160
+ idPickerLabels,
8161
+ enumPickerLabels,
8162
+ filePickerLabels,
8163
+ formButtonLabels,
8164
+ timePickerLabels,
8165
+ insideDialog,
8166
+ }, children: jsx(FormProvider, { ...form, children: children }) }));
8167
+ };
8168
+
8261
8169
  const DefaultForm = ({ formConfig, }) => {
8262
8170
  const { showTitle } = formConfig.displayConfig ?? {};
8263
8171
  return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
@@ -8506,6 +8414,26 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
8506
8414
  }
8507
8415
  };
8508
8416
 
8417
+ const snakeToLabel = (str) => {
8418
+ return str
8419
+ .split("_") // Split by underscore
8420
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // Capitalize each word
8421
+ .join(" "); // Join with space
8422
+ };
8423
+
8424
+ const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
8425
+ const getColumn = ({ field }) => {
8426
+ return snakeToLabel(field);
8427
+ };
8428
+ if (object === null) {
8429
+ return jsx(Fragment, { children: "null" });
8430
+ }
8431
+ return (jsx(Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
8432
+ const uniqueKey = `${prefix}${field}-${index}`;
8433
+ return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsx(Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsx(Text, { children: JSON.stringify(value) }))] }, uniqueKey));
8434
+ }) }));
8435
+ };
8436
+
8509
8437
  const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
8510
8438
  const { columns, data } = useDataTableContext();
8511
8439
  const columnsMap = Object.fromEntries(columns.map((def) => {
@@ -9389,4 +9317,4 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
9389
9317
  }, children: jsx(DataTableServerContext.Provider, { value: { url: url ?? '', query }, children: children }) }));
9390
9318
  }
9391
9319
 
9392
- export { CalendarDisplay, CardHeader, DataDisplay, DataTable, DataTableServer, DatePickerContext, DatePickerInput, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, SelectAllRowsToggle, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, defaultRenderDisplay, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
9320
+ export { CalendarDisplay, CardHeader, DataDisplay, DataTable, DataTableServer, DatePickerContext, DatePickerInput, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, SelectAllRowsToggle, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, defaultRenderDisplay, getMultiDates, getRangeDates, useDataTable, useDataTableContext, useDataTableServer, useForm };
@@ -62,8 +62,6 @@ export interface CustomJSONSchema7Definition extends JSONSchema7 {
62
62
  gridColumn: string;
63
63
  gridRow: string;
64
64
  customQueryFn: any;
65
- idColumn: string;
66
65
  children: ReactNode;
67
66
  }
68
- export declare const idPickerSanityCheck: (column: string, customQueryFn?: any, idColumn?: string) => void;
69
67
  export declare const FormRoot: <TData extends FieldValues>({ schema, idMap, setIdMap, form, children, order, ignore, include, onSubmit, rowNumber, requestOptions, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog, }: FormRootProps<TData>) => import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { CustomJSONSchema7, LoadInitialValuesParams, LoadInitialValuesResult } from '../types/CustomJSONSchema7';
2
+ import { CustomJSONSchema7, IdPickerLabels, LoadInitialValuesParams, LoadInitialValuesResult } from '../types/CustomJSONSchema7';
3
3
  export interface RecordType {
4
4
  [key: string]: any;
5
5
  }
@@ -39,13 +39,12 @@ export interface UseIdPickerDataReturn {
39
39
  raw: RecordType;
40
40
  }>) => void;
41
41
  idMap: Record<string, object>;
42
- idPickerLabels: any;
42
+ idPickerLabels?: IdPickerLabels;
43
43
  insideDialog: boolean;
44
44
  renderDisplay: ((item: RecordType) => React.ReactNode) | undefined;
45
45
  itemToValue: (item: RecordType) => string;
46
46
  itemToString: (item: RecordType) => string;
47
47
  loadInitialValues: (params: LoadInitialValuesParams) => Promise<LoadInitialValuesResult>;
48
- column_ref: string;
49
48
  errors: any;
50
49
  setValue: (name: string, value: any) => void;
51
50
  }
@@ -72,7 +72,6 @@ export interface TimePickerLabels {
72
72
  export interface LoadInitialValuesParams {
73
73
  ids: string[];
74
74
  customQueryFn: CustomQueryFn;
75
- idColumn: string;
76
75
  setIdMap: React.Dispatch<React.SetStateAction<Record<string, object>>>;
77
76
  }
78
77
  export interface LoadInitialValuesResult {
@@ -86,7 +85,6 @@ export interface CustomJSONSchema7 extends JSONSchema7 {
86
85
  gridColumn?: string;
87
86
  gridRow?: string;
88
87
  customQueryFn?: CustomQueryFn;
89
- idColumn?: string;
90
88
  variant?: string;
91
89
  renderDisplay?: (item: unknown) => ReactNode;
92
90
  itemToValue?: (item: unknown) => string;
@@ -123,7 +123,6 @@ export * from './components/DataTable/display/ErrorAlert';
123
123
  export * from './components/DataTable/useDataTable';
124
124
  export * from './components/DataTable/useDataTableServer';
125
125
  export * from './components/DataTable/context/useDataTableContext';
126
- export * from './components/DataTable/utils/getColumns';
127
126
  export * from './components/Form/components/core/DefaultForm';
128
127
  export * from './components/Form/components/core/FormRoot';
129
128
  export * from './components/Form/components/core/FormTitle';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsol-oss/react-datatable5",
3
- "version": "13.0.1-beta.21",
3
+ "version": "13.0.1-beta.22",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -1,14 +0,0 @@
1
- import { ColumnDef, RowData } from '@tanstack/react-table';
2
- import { JSONSchema7 } from 'json-schema';
3
- export interface GetColumnsConfigs<K extends RowData> {
4
- schema: JSONSchema7;
5
- include?: K[];
6
- ignore?: K[];
7
- width?: number[];
8
- meta?: {
9
- [key in K as string]?: object;
10
- };
11
- defaultWidth?: number;
12
- }
13
- export declare const widthSanityCheck: <K extends unknown>(widthList: number[], ignoreList: K[], properties: { [key in K as string]?: object | undefined; }) => void;
14
- export declare const getColumns: <TData extends unknown>({ schema, include, ignore, width, meta, defaultWidth, }: GetColumnsConfigs<TData>) => ColumnDef<TData>[];
@@ -1 +0,0 @@
1
- export declare const idListSanityCheck: (param: string, idList: string[], properties: object) => void;