@bsol-oss/react-datatable5 13.0.1-beta.6 → 13.0.1-beta.8

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
@@ -1,12 +1,12 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, CheckboxCard as CheckboxCard$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, Tooltip as Tooltip$1, Group, InputElement, Icon, EmptyState as EmptyState$2, VStack, List, Table as Table$1, Checkbox as Checkbox$1, Card, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Clipboard, Badge, Link, Tag as Tag$1, Image, Alert, Field as Field$1, Popover, useFilter, useListCollection, Combobox, Tabs, Skeleton, NumberInput, Show, RadioCard, CheckboxGroup, InputGroup as InputGroup$1, Center, Heading, Stack } from '@chakra-ui/react';
2
+ import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, CheckboxCard as CheckboxCard$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, Tooltip as Tooltip$1, Group, InputElement, Icon, EmptyState as EmptyState$2, VStack, List, Table as Table$1, Checkbox as Checkbox$1, Card, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Clipboard, Badge, Link, Tag as Tag$1, Image, Alert, Field as Field$1, Popover, useFilter, useListCollection, Combobox, Tabs, useCombobox, Show, Skeleton, NumberInput, RadioCard, CheckboxGroup, InputGroup as InputGroup$1, Center, Heading, Stack } from '@chakra-ui/react';
3
3
  import { AiOutlineColumnWidth } from 'react-icons/ai';
4
4
  import * as React from 'react';
5
5
  import { createContext, useContext, useState, useMemo, useCallback, useEffect, useRef, forwardRef } from 'react';
6
6
  import { LuX, LuCheck, LuChevronRight, LuCopy, LuExternalLink, LuSearch, LuImage, LuFile } from 'react-icons/lu';
7
7
  import { MdOutlineSort, MdFilterAlt, MdSearch, MdOutlineChecklist, MdClear, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdDateRange } from 'react-icons/md';
8
8
  import { FaUpDown, FaGripLinesVertical, FaTrash } from 'react-icons/fa6';
9
- import { BiDownArrow, BiUpArrow, BiError } from 'react-icons/bi';
9
+ import { BiDownArrow, BiUpArrow, BiX, BiError } from 'react-icons/bi';
10
10
  import { CgClose, CgTrash } from 'react-icons/cg';
11
11
  import { HiMiniEllipsisHorizontal, HiChevronLeft, HiChevronRight } from 'react-icons/hi2';
12
12
  import { IoMdEye, IoMdCheckbox, IoMdClock } from 'react-icons/io';
@@ -4373,39 +4373,31 @@ const FormRoot = ({ schema, idMap, setIdMap, form, translate, children, order =
4373
4373
  }, children: jsx(FormProvider, { ...form, children: children }) }));
4374
4374
  };
4375
4375
 
4376
- function removeIndex(str) {
4377
- return str.replace(/\.\d+\./g, ".");
4378
- }
4379
-
4380
4376
  /**
4381
- * Custom hook for form field labels and fallback text.
4382
- * Automatically handles colLabel construction and removeIndex logic.
4383
- * Uses schema.title when available, otherwise falls back to translate function.
4377
+ * Custom hook for form field labels.
4378
+ * Automatically handles colLabel construction.
4379
+ * Uses schema.title for labels and schema.errorMessages for error messages.
4384
4380
  *
4385
4381
  * @param column - The column name
4386
4382
  * @param prefix - The prefix for the field (usually empty string or parent path)
4387
- * @param schema - Required schema object with title property
4383
+ * @param schema - Required schema object with title and errorMessages properties
4388
4384
  * @returns Object with label helper functions
4389
4385
  *
4390
4386
  * @example
4391
4387
  * ```tsx
4392
4388
  * const formI18n = useFormI18n(column, prefix, schema);
4393
4389
  *
4394
- * // Get field label (prefers schema.title)
4390
+ * // Get field label (from schema.title)
4395
4391
  * <Field label={formI18n.label()} />
4396
4392
  *
4397
- * // Get required error message
4393
+ * // Get required error message (from schema.errorMessages?.required)
4398
4394
  * <Text>{formI18n.required()}</Text>
4399
4395
  *
4400
- * // Get custom text
4401
- * <Text>{formI18n.t('add_more')}</Text>
4402
- *
4403
4396
  * // Access the raw colLabel
4404
4397
  * const colLabel = formI18n.colLabel;
4405
4398
  * ```
4406
4399
  */
4407
4400
  const useFormI18n = (column, prefix = '', schema) => {
4408
- const { translate } = useSchemaContext();
4409
4401
  const colLabel = `${prefix}${column}`;
4410
4402
  return {
4411
4403
  /**
@@ -4413,10 +4405,10 @@ const useFormI18n = (column, prefix = '', schema) => {
4413
4405
  */
4414
4406
  colLabel,
4415
4407
  /**
4416
- * Get the field label from schema title prop, or fall back to translate function
4417
- * Uses schema.title if available, otherwise: translate.t(removeIndex(`${colLabel}.field_label`))
4408
+ * Get the field label from schema title property.
4409
+ * Logs a debug message if title is missing.
4418
4410
  */
4419
- label: (options) => {
4411
+ label: () => {
4420
4412
  if (schema.title) {
4421
4413
  return schema.title;
4422
4414
  }
@@ -4432,29 +4424,36 @@ const useFormI18n = (column, prefix = '', schema) => {
4432
4424
  : undefined,
4433
4425
  },
4434
4426
  });
4435
- return translate.t(removeIndex(`${colLabel}.field_label`), options);
4427
+ // Return column name as fallback
4428
+ return column;
4436
4429
  },
4437
4430
  /**
4438
- * Get the required error message
4439
- * Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
4431
+ * Get the required error message from schema.errorMessages?.required.
4432
+ * Returns a helpful fallback message if not provided.
4440
4433
  */
4441
- required: (options) => {
4442
- return translate.t(removeIndex(`${colLabel}.field_required`), options);
4443
- },
4444
- /**
4445
- * Get text for any custom key relative to the field
4446
- * Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
4447
- *
4448
- * @param key - The key suffix (e.g., 'add_more', 'total', etc.)
4449
- * @param options - Optional options (e.g., defaultValue, interpolation variables)
4450
- */
4451
- t: (key, options) => {
4452
- return translate.t(removeIndex(`${colLabel}.${key}`), options);
4434
+ required: () => {
4435
+ const errorMessage = schema.errorMessages?.required;
4436
+ if (errorMessage) {
4437
+ return errorMessage;
4438
+ }
4439
+ // Debug log when error message is missing
4440
+ console.debug(`[Form Field Required] Missing error message for required field '${colLabel}'. Add errorMessages.required to schema for field '${colLabel}'.`, {
4441
+ fieldName: column,
4442
+ colLabel,
4443
+ prefix,
4444
+ schema: {
4445
+ type: schema.type,
4446
+ title: schema.title,
4447
+ required: schema.required,
4448
+ hasErrorMessages: !!schema.errorMessages,
4449
+ errorMessageKeys: schema.errorMessages
4450
+ ? Object.keys(schema.errorMessages)
4451
+ : undefined,
4452
+ },
4453
+ });
4454
+ // Return helpful fallback message
4455
+ return `Missing error message for required. Add errorMessages.required to schema for field '${colLabel}'`;
4453
4456
  },
4454
- /**
4455
- * Access to the original translate object for edge cases
4456
- */
4457
- translate,
4458
4457
  };
4459
4458
  };
4460
4459
 
@@ -5070,27 +5069,82 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
5070
5069
  const watchEnum = watch(colLabel);
5071
5070
  const watchEnums = (watch(colLabel) ?? []);
5072
5071
  const dataList = schema.enum ?? [];
5072
+ // Helper function to render enum value (returns ReactNode)
5073
+ // If renderDisplay is provided, use it; otherwise show the enum string value directly
5074
+ const renderEnumValue = (value) => {
5075
+ if (renderDisplay) {
5076
+ return renderDisplay(value);
5077
+ }
5078
+ // If no renderDisplay provided, show the enum string value directly
5079
+ return value;
5080
+ };
5081
+ // Helper function to get string representation for input display
5082
+ // Converts ReactNode to string for combobox input display
5083
+ const getDisplayString = (value) => {
5084
+ if (renderDisplay) {
5085
+ const rendered = renderDisplay(value);
5086
+ // If renderDisplay returns a string, use it directly
5087
+ if (typeof rendered === 'string') {
5088
+ return rendered;
5089
+ }
5090
+ // If it's a React element, try to extract text content
5091
+ // For now, fallback to the raw value if we can't extract text
5092
+ // In most cases, renderDisplay should return a string or simple element
5093
+ if (typeof rendered === 'object' &&
5094
+ rendered !== null &&
5095
+ 'props' in rendered) {
5096
+ const props = rendered.props;
5097
+ // Try to extract text from React element props
5098
+ if (props?.children) {
5099
+ const children = props.children;
5100
+ if (typeof children === 'string') {
5101
+ return children;
5102
+ }
5103
+ }
5104
+ }
5105
+ // Fallback: use raw value if we can't extract string
5106
+ return value;
5107
+ }
5108
+ return value;
5109
+ };
5110
+ // Debug log when renderDisplay is missing
5111
+ if (!renderDisplay) {
5112
+ console.debug(`[EnumPicker] Missing renderDisplay for field '${colLabel}'. Add renderDisplay function to schema for field '${colLabel}' to provide custom UI rendering. Currently showing enum string values directly.`, {
5113
+ fieldName: column,
5114
+ colLabel,
5115
+ prefix,
5116
+ enumValues: dataList,
5117
+ });
5118
+ }
5073
5119
  // Current value for combobox (array format)
5074
5120
  const currentValue = isMultiple
5075
5121
  ? watchEnums.filter((val) => val != null && val !== '')
5076
5122
  : watchEnum
5077
5123
  ? [watchEnum]
5078
5124
  : [];
5079
- // Transform enum data for combobox collection
5125
+ // Track input focus state for single selection
5126
+ const [isInputFocused, setIsInputFocused] = useState(false);
5127
+ // Get the selected value for single selection display
5128
+ const selectedSingleValue = !isMultiple && watchEnum ? watchEnum : null;
5129
+ const selectedSingleRendered = selectedSingleValue
5130
+ ? renderEnumValue(selectedSingleValue)
5131
+ : null;
5132
+ const isSelectedSingleValueString = typeof selectedSingleRendered === 'string';
5080
5133
  const comboboxItems = useMemo(() => {
5081
5134
  return dataList.map((item) => ({
5082
- label: !!renderDisplay === true
5083
- ? String(renderDisplay(item))
5084
- : formI18n.t(item),
5135
+ label: item, // Internal: used for search/filtering only
5085
5136
  value: item,
5137
+ raw: item, // Passed to renderEnumValue for UI rendering
5138
+ displayLabel: getDisplayString(item), // Used for input display when selected
5086
5139
  }));
5087
- }, [dataList, renderDisplay, formI18n]);
5140
+ }, [dataList, renderDisplay]);
5088
5141
  // Use filter hook for combobox
5089
5142
  const { contains } = useFilter({ sensitivity: 'base' });
5090
5143
  // Create collection for combobox
5144
+ // itemToString uses displayLabel to show rendered display in input when selected
5091
5145
  const { collection, filter } = useListCollection({
5092
5146
  initialItems: comboboxItems,
5093
- itemToString: (item) => item.label,
5147
+ itemToString: (item) => item.displayLabel, // Use displayLabel for selected value display
5094
5148
  itemToValue: (item) => item.value,
5095
5149
  filter: contains,
5096
5150
  });
@@ -5114,9 +5168,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
5114
5168
  setValue(colLabel, details.value);
5115
5169
  }
5116
5170
  }, children: jsx(HStack, { gap: "6", children: dataList.map((item) => {
5117
- return (jsxs(RadioGroup$1.Item, { value: item, children: [jsx(RadioGroup$1.ItemHiddenInput, {}), jsx(RadioGroup$1.ItemIndicator, {}), jsx(RadioGroup$1.ItemText, { children: !!renderDisplay === true
5118
- ? renderDisplay(item)
5119
- : formI18n.t(item) })] }, `${colLabel}-${item}`));
5171
+ return (jsxs(RadioGroup$1.Item, { value: item, children: [jsx(RadioGroup$1.ItemHiddenInput, {}), jsx(RadioGroup$1.ItemIndicator, {}), jsx(RadioGroup$1.ItemText, { children: renderEnumValue(item) })] }, `${colLabel}-${item}`));
5120
5172
  }) }) }) }));
5121
5173
  }
5122
5174
  return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
@@ -5127,16 +5179,31 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
5127
5179
  return (jsx(Tag, { size: "lg", closable: true, onClick: () => {
5128
5180
  const newValue = currentValue.filter((val) => val !== enumValue);
5129
5181
  setValue(colLabel, newValue);
5130
- }, children: !!renderDisplay === true
5131
- ? renderDisplay(enumValue)
5132
- : formI18n.t(enumValue) }, enumValue));
5182
+ }, children: renderEnumValue(enumValue) }, enumValue));
5133
5183
  }) })), jsxs(Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: isMultiple, closeOnSelect: !isMultiple, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
5134
5184
  ? { strategy: 'fixed', hideWhenDetached: true }
5135
- : undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: enumPickerLabels?.typeToSearch ?? formI18n.t('type_to_search') }), jsxs(Combobox.IndicatorGroup, { children: [!isMultiple && currentValue.length > 0 && (jsx(Combobox.ClearTrigger, { onClick: () => {
5185
+ : undefined, children: [jsxs(Combobox.Control, { position: "relative", children: [!isMultiple &&
5186
+ selectedSingleValue &&
5187
+ !isInputFocused &&
5188
+ !isSelectedSingleValueString &&
5189
+ selectedSingleRendered && (jsx(Box, { position: "absolute", left: 3, top: "50%", transform: "translateY(-50%)", pointerEvents: "none", zIndex: 1, maxWidth: "calc(100% - 60px)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: selectedSingleRendered })), jsx(Combobox.Input, { placeholder: !isMultiple && selectedSingleValue && !isInputFocused
5190
+ ? undefined
5191
+ : enumPickerLabels?.typeToSearch ?? 'Type to search', onFocus: () => setIsInputFocused(true), onBlur: () => setIsInputFocused(false), style: {
5192
+ color: !isMultiple &&
5193
+ selectedSingleValue &&
5194
+ !isInputFocused &&
5195
+ !isSelectedSingleValueString
5196
+ ? 'transparent'
5197
+ : undefined,
5198
+ caretColor: !isMultiple &&
5199
+ selectedSingleValue &&
5200
+ !isInputFocused &&
5201
+ !isSelectedSingleValueString
5202
+ ? 'transparent'
5203
+ : undefined,
5204
+ } }), jsxs(Combobox.IndicatorGroup, { children: [!isMultiple && currentValue.length > 0 && (jsx(Combobox.ClearTrigger, { onClick: () => {
5136
5205
  setValue(colLabel, '');
5137
- } })), jsx(Combobox.Trigger, {})] })] }), insideDialog ? (jsx(Combobox.Positioner, { children: jsxs(Combobox.Content, { children: [showTotalAndLimit && (jsx(Text, { p: 2, fontSize: "sm", color: "fg.muted", children: `${enumPickerLabels?.total ?? formI18n.t('total')}: ${collection.items.length}` })), collection.items.length === 0 ? (jsx(Combobox.Empty, { children: enumPickerLabels?.emptySearchResult ??
5138
- formI18n.t('empty_search_result') })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) }))] }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsxs(Combobox.Content, { children: [showTotalAndLimit && (jsx(Text, { p: 2, fontSize: "sm", color: "fg.muted", children: `${enumPickerLabels?.total ?? formI18n.t('total')}: ${collection.items.length}` })), collection.items.length === 0 ? (jsx(Combobox.Empty, { children: enumPickerLabels?.emptySearchResult ??
5139
- formI18n.t('empty_search_result') })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) }))] }) }) }))] })] }));
5206
+ } })), jsx(Combobox.Trigger, {})] })] }), insideDialog ? (jsx(Combobox.Positioner, { children: jsxs(Combobox.Content, { children: [showTotalAndLimit && (jsx(Text, { p: 2, fontSize: "sm", color: "fg.muted", children: `${enumPickerLabels?.total ?? 'Total'}: ${collection.items.length}` })), collection.items.length === 0 ? (jsx(Combobox.Empty, { children: enumPickerLabels?.emptySearchResult ?? 'No results found' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: renderEnumValue(item.raw) }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) }))] }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsxs(Combobox.Content, { children: [showTotalAndLimit && (jsx(Text, { p: 2, fontSize: "sm", color: "fg.muted", children: `${enumPickerLabels?.total ?? 'Total'}: ${collection.items.length}` })), collection.items.length === 0 ? (jsx(Combobox.Empty, { children: enumPickerLabels?.emptySearchResult ?? 'No results found' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: renderEnumValue(item.raw) }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) }))] }) }) }))] })] }));
5140
5207
  };
5141
5208
 
5142
5209
  function isEnteringWindow(_ref) {
@@ -5751,7 +5818,7 @@ const FilePicker = ({ column, schema, prefix }) => {
5751
5818
  const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
5752
5819
  setValue(colLabel, [...currentFiles, ...newFiles]);
5753
5820
  }
5754
- }, placeholder: filePickerLabels?.fileDropzone ?? formI18n.t('fileDropzone') }) }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
5821
+ }, placeholder: filePickerLabels?.fileDropzone ?? 'Drop files here' }) }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
5755
5822
  const fileIdentifier = getFileIdentifier(file, index);
5756
5823
  const fileName = getFileName(file);
5757
5824
  const fileSize = getFileSize(file);
@@ -5862,9 +5929,7 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
5862
5929
  }
5863
5930
  };
5864
5931
  return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
5865
- gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsx(VStack, { align: "stretch", gap: 2, children: jsx(Button$1, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
5866
- formI18n.t('browse_library') ??
5867
- 'Browse from Library' }) }), jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ?? formI18n.label() ?? 'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
5932
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsx(VStack, { align: "stretch", gap: 2, children: jsx(Button$1, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ?? 'Browse from Library' }) }), jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ?? formI18n.label() ?? 'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
5868
5933
  const file = fileMap.get(fileId);
5869
5934
  const isImage = file
5870
5935
  ? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
@@ -5880,15 +5945,46 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
5880
5945
  }) })] }));
5881
5946
  };
5882
5947
 
5883
- // Default renderDisplay function that stringifies JSON
5948
+ // Default renderDisplay function that intelligently displays items
5949
+ // If item is an object, tries to find common display fields (name, title, label, etc.)
5950
+ // Otherwise falls back to JSON.stringify
5884
5951
  const defaultRenderDisplay = (item) => {
5952
+ // Check if item is an object (not null, not array, not primitive)
5953
+ if (item !== null &&
5954
+ typeof item === 'object' &&
5955
+ !Array.isArray(item) &&
5956
+ !(item instanceof Date)) {
5957
+ const obj = item;
5958
+ // Try common display fields in order of preference
5959
+ const displayFields = [
5960
+ 'name',
5961
+ 'title',
5962
+ 'label',
5963
+ 'displayName',
5964
+ 'display_name',
5965
+ 'text',
5966
+ 'value',
5967
+ ];
5968
+ for (const field of displayFields) {
5969
+ if (obj[field] !== undefined && obj[field] !== null) {
5970
+ const value = obj[field];
5971
+ // Return the value if it's a string or number, otherwise stringify it
5972
+ if (typeof value === 'string' || typeof value === 'number') {
5973
+ return String(value);
5974
+ }
5975
+ }
5976
+ }
5977
+ // If no display field found, fall back to JSON.stringify
5978
+ return JSON.stringify(item);
5979
+ }
5980
+ // For non-objects (primitives, arrays, dates), use JSON.stringify
5885
5981
  return JSON.stringify(item);
5886
5982
  };
5887
5983
 
5888
5984
  const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5889
5985
  const { watch, getValues, formState: { errors }, setValue, } = useFormContext();
5890
5986
  const { idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
5891
- const { renderDisplay, loadInitialValues, foreign_key, variant } = schema;
5987
+ const { renderDisplay, itemToValue: schemaItemToValue, loadInitialValues, foreign_key, variant, } = schema;
5892
5988
  // loadInitialValues should be provided in schema for id-picker fields
5893
5989
  // It's used to load the record of the id so the display is human-readable
5894
5990
  if (variant === 'id-picker' && !loadInitialValues) {
@@ -6021,17 +6117,51 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6021
6117
  // Depend on idMapKey which only changes when items we care about change
6022
6118
  // eslint-disable-next-line react-hooks/exhaustive-deps
6023
6119
  }, [currentValueKey, idMapKey]);
6120
+ // Default itemToValue function: extract value from item using column_ref
6121
+ const defaultItemToValue = (item) => String(item[column_ref]);
6122
+ // Use schema's itemToValue if provided, otherwise use default
6123
+ const itemToValueFn = schemaItemToValue
6124
+ ? (item) => schemaItemToValue(item)
6125
+ : defaultItemToValue;
6126
+ // itemToString function: convert item to readable string using renderDisplay
6127
+ // This ensures items can always be displayed as readable strings in the combobox
6128
+ const renderFn = renderDisplay || defaultRenderDisplay;
6129
+ const itemToStringFn = (item) => {
6130
+ const rendered = renderFn(item);
6131
+ // If already a string or number, return it
6132
+ if (typeof rendered === 'string')
6133
+ return rendered;
6134
+ if (typeof rendered === 'number')
6135
+ return String(rendered);
6136
+ // For ReactNode, fall back to defaultRenderDisplay which converts to string
6137
+ return String(defaultRenderDisplay(item));
6138
+ };
6024
6139
  // Transform data for combobox collection
6025
6140
  // label is used for filtering/searching (must be a string)
6141
+ // displayLabel is used for input display when selected (string representation of rendered display)
6026
6142
  // raw item is stored for custom rendering
6027
6143
  // Also include items from idMap that match currentValue (for initial values display)
6028
6144
  const comboboxItems = useMemo(() => {
6029
6145
  const renderFn = renderDisplay || defaultRenderDisplay;
6146
+ // Helper to convert rendered display to string for displayLabel
6147
+ // For ReactNodes (non-string/number), we can't safely stringify due to circular refs
6148
+ // So we use the label (which is already a string) as fallback
6149
+ const getDisplayString = (rendered, fallbackLabel) => {
6150
+ if (typeof rendered === 'string')
6151
+ return rendered;
6152
+ if (typeof rendered === 'number')
6153
+ return String(rendered);
6154
+ // For ReactNode, use the fallback label (which is already a string representation)
6155
+ // The actual ReactNode will be rendered in the overlay, not in the input
6156
+ return fallbackLabel;
6157
+ };
6030
6158
  const itemsFromDataList = dataList.map((item) => {
6031
6159
  const rendered = renderFn(item);
6160
+ const label = typeof rendered === 'string' ? rendered : JSON.stringify(item); // Use string for filtering
6032
6161
  return {
6033
- label: typeof rendered === 'string' ? rendered : JSON.stringify(item), // Use string for filtering
6034
- value: String(item[column_ref]),
6162
+ label, // Use string for filtering
6163
+ displayLabel: getDisplayString(rendered, label), // String representation for input display
6164
+ value: itemToValueFn(item),
6035
6165
  raw: item,
6036
6166
  };
6037
6167
  });
@@ -6040,25 +6170,28 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6040
6170
  const itemsFromIdMap = idMapItems
6041
6171
  .map((item) => {
6042
6172
  // Check if this item is already in itemsFromDataList
6043
- const alreadyIncluded = itemsFromDataList.some((i) => i.value === String(item[column_ref]));
6173
+ const alreadyIncluded = itemsFromDataList.some((i) => i.value === itemToValueFn(item));
6044
6174
  if (alreadyIncluded)
6045
6175
  return null;
6046
6176
  const rendered = renderFn(item);
6177
+ const label = typeof rendered === 'string' ? rendered : JSON.stringify(item);
6047
6178
  return {
6048
- label: typeof rendered === 'string' ? rendered : JSON.stringify(item),
6049
- value: String(item[column_ref]),
6179
+ label,
6180
+ displayLabel: getDisplayString(rendered, label), // String representation for input display
6181
+ value: itemToValueFn(item),
6050
6182
  raw: item,
6051
6183
  };
6052
6184
  })
6053
6185
  .filter((item) => item !== null);
6054
6186
  return [...itemsFromIdMap, ...itemsFromDataList];
6055
- }, [dataList, column_ref, renderDisplay, idMapItems]);
6187
+ }, [dataList, column_ref, renderDisplay, idMapItems, itemToValueFn]);
6056
6188
  // Use filter hook for combobox
6057
6189
  const { contains } = useFilter({ sensitivity: 'base' });
6058
6190
  // Create collection for combobox
6191
+ // itemToString uses displayLabel to show rendered display in input when selected
6059
6192
  const { collection, filter, set } = useListCollection({
6060
6193
  initialItems: comboboxItems,
6061
- itemToString: (item) => item.label,
6194
+ itemToString: (item) => item.displayLabel, // Use displayLabel for selected value display
6062
6195
  itemToValue: (item) => item.value,
6063
6196
  filter: contains,
6064
6197
  });
@@ -6113,6 +6246,8 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6113
6246
  idPickerLabels,
6114
6247
  insideDialog: insideDialog ?? false,
6115
6248
  renderDisplay,
6249
+ itemToValue: itemToValueFn,
6250
+ itemToString: itemToStringFn,
6116
6251
  loadInitialValues: loadInitialValues ??
6117
6252
  (async () => ({ data: { data: [], count: 0 }, idMap: {} })), // Fallback if not provided
6118
6253
  column_ref,
@@ -6123,60 +6258,69 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
6123
6258
 
6124
6259
  const IdPickerSingle = ({ column, schema, prefix, }) => {
6125
6260
  const formI18n = useFormI18n(column, prefix, schema);
6126
- const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, } = schema;
6261
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
6127
6262
  const isRequired = required?.some((columnId) => columnId === column);
6128
- const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
6263
+ const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, collection, filter, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, itemToValue, itemToString, errors, setValue, } = useIdPickerData({
6129
6264
  column,
6130
6265
  schema,
6131
6266
  prefix,
6132
6267
  isMultiple: false,
6133
6268
  });
6134
- const handleInputValueChange = (details) => {
6135
- setSearchText(details.inputValue);
6136
- };
6137
- const handleValueChange = (details) => {
6138
- setValue(colLabel, details.value[0] || '');
6139
- };
6140
- const renderDisplayFunction = renderDisplayFn || renderDisplay || defaultRenderDisplay;
6141
- return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
6142
- gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [currentValue.length > 0 && (jsx(Flex, { mb: 2, children: (() => {
6143
- const id = currentValue[0];
6144
- const item = idMap[id];
6145
- // Show loading skeleton while fetching initial values
6146
- if (item === undefined &&
6147
- (isLoadingInitialValues || isFetchingInitialValues) &&
6148
- missingIds.includes(id)) {
6149
- return jsx(Skeleton, { height: "24px", width: "100px", borderRadius: "md" });
6150
- }
6151
- // Only show "not found" if we're not loading and item is still missing
6152
- if (item === undefined) {
6153
- return (jsx(Text, { fontSize: "sm", children: idPickerLabels?.undefined ?? 'Undefined' }));
6154
- }
6155
- return jsx(Text, { fontSize: "sm", children: renderDisplayFunction(item) });
6156
- })() })), jsxs(Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: false, closeOnSelect: true, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
6157
- ? { strategy: 'fixed', hideWhenDetached: true }
6158
- : undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ?? 'Type to search' }), jsxs(Combobox.IndicatorGroup, { children: [(isFetching || isLoading || isPending) && jsx(Spinner, { size: "xs" }), isError && (jsx(Icon, { color: "fg.error", children: jsx(BiError, {}) })), currentValue.length > 0 && (jsx(Combobox.ClearTrigger, { onClick: () => {
6159
- setValue(colLabel, '');
6160
- } })), jsx(Combobox.Trigger, {})] })] }), insideDialog ? (jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
6269
+ // Get the selected value for single selection display
6270
+ const selectedId = currentValue.length > 0 ? currentValue[0] : null;
6271
+ const selectedItem = selectedId
6272
+ ? idMap[selectedId]
6273
+ : undefined;
6274
+ // Use itemToValue to get the combobox value from the selected item, or use the ID directly
6275
+ const comboboxValue = selectedItem
6276
+ ? itemToString(selectedItem)
6277
+ : selectedId || '';
6278
+ // itemToString is available from the hook and can be used to get a readable string
6279
+ // representation of any item. The collection's itemToString is automatically used
6280
+ // by the combobox to display selected values.
6281
+ // Use useCombobox hook to control input value
6282
+ const combobox = useCombobox({
6283
+ collection,
6284
+ value: [comboboxValue],
6285
+ onInputValueChange(e) {
6286
+ setSearchText(e.inputValue);
6287
+ filter(e.inputValue);
6288
+ },
6289
+ onValueChange(e) {
6290
+ setValue(colLabel, e.value[0] || '');
6291
+ // Clear the input value after selection
6292
+ setSearchText('');
6293
+ },
6294
+ multiple: false,
6295
+ closeOnSelect: true,
6296
+ openOnClick: true,
6297
+ invalid: !!errors[colLabel],
6298
+ });
6299
+ // Use renderDisplay from hook (which comes from schema) or fallback to default
6300
+ const renderDisplayFunction = renderDisplayFn || defaultRenderDisplay;
6301
+ // Get the selected value for single selection display (already computed above)
6302
+ const selectedRendered = selectedItem
6303
+ ? renderDisplayFunction(selectedItem)
6304
+ : null;
6305
+ return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
6306
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxs(Combobox.RootProvider, { value: combobox, width: "100%", children: [jsx(Show, { when: selectedId && selectedRendered, children: jsxs(HStack, { justifyContent: 'space-between', children: [jsx(Box, { children: selectedRendered }), currentValue.length > 0 && (jsx(Button$1, { variant: "ghost", size: "sm", onClick: () => {
6307
+ setValue(colLabel, '');
6308
+ }, children: jsx(Icon, { children: jsx(BiX, {}) }) }))] }) }), jsx(Show, { when: !selectedId || !selectedRendered, children: jsxs(Combobox.Control, { position: "relative", children: [jsx(Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ?? 'Type to search' }), jsxs(Combobox.IndicatorGroup, { children: [(isFetching || isLoading || isPending) && jsx(Spinner, { size: "xs" }), isError && (jsx(Icon, { color: "fg.error", children: jsx(BiError, {}) })), jsx(Combobox.Trigger, {})] })] }) }), insideDialog ? (jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
6309
+ // Show skeleton items to prevent UI shift
6310
+ jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
6311
+ ? idPickerLabels?.emptySearchResult ?? 'No results found'
6312
+ : idPickerLabels?.initialResults ??
6313
+ 'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [renderDisplayFunction(item.raw), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
6161
6314
  // Show skeleton items to prevent UI shift
6162
6315
  jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
6163
6316
  ? idPickerLabels?.emptySearchResult ?? 'No results found'
6164
6317
  : idPickerLabels?.initialResults ??
6165
- 'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
6166
- ? renderDisplayFunction(item.raw)
6167
- : item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
6168
- // Show skeleton items to prevent UI shift
6169
- jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
6170
- ? idPickerLabels?.emptySearchResult ?? 'No results found'
6171
- : idPickerLabels?.initialResults ??
6172
- 'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
6173
- ? renderDisplayFunction(item.raw)
6174
- : item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
6318
+ 'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsx(Combobox.Item, { item: item, children: renderDisplayFunction(item.raw) }, item.value ?? `item-${index}`))) })) }) }) }))] }) }));
6175
6319
  };
6176
6320
 
6177
6321
  const IdPickerMultiple = ({ column, schema, prefix, }) => {
6178
6322
  const formI18n = useFormI18n(column, prefix, schema);
6179
- const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, } = schema;
6323
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
6180
6324
  const isRequired = required?.some((columnId) => columnId === column);
6181
6325
  const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
6182
6326
  column,
@@ -6190,7 +6334,8 @@ const IdPickerMultiple = ({ column, schema, prefix, }) => {
6190
6334
  const handleValueChange = (details) => {
6191
6335
  setValue(colLabel, details.value);
6192
6336
  };
6193
- const renderDisplayFunction = renderDisplayFn || renderDisplay || defaultRenderDisplay;
6337
+ // Use renderDisplay from hook (which comes from schema) or fallback to default
6338
+ const renderDisplayFunction = renderDisplayFn || defaultRenderDisplay;
6194
6339
  return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
6195
6340
  gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [currentValue.length > 0 && (jsx(Flex, { flexFlow: 'wrap', gap: 1, mb: 2, children: currentValue.map((id) => {
6196
6341
  const item = idMap[id];
@@ -6215,16 +6360,12 @@ const IdPickerMultiple = ({ column, schema, prefix, }) => {
6215
6360
  jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
6216
6361
  ? idPickerLabels?.emptySearchResult ?? 'No results found'
6217
6362
  : idPickerLabels?.initialResults ??
6218
- 'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
6219
- ? renderDisplayFunction(item.raw)
6220
- : item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
6363
+ 'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [renderDisplayFunction(item.raw), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
6221
6364
  // Show skeleton items to prevent UI shift
6222
6365
  jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
6223
6366
  ? idPickerLabels?.emptySearchResult ?? 'No results found'
6224
6367
  : idPickerLabels?.initialResults ??
6225
- 'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
6226
- ? renderDisplayFunction(item.raw)
6227
- : item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
6368
+ 'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [renderDisplayFunction(item.raw), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
6228
6369
  };
6229
6370
 
6230
6371
  const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
@@ -7361,7 +7502,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7361
7502
  backButtonLabel: 'Back',
7362
7503
  forwardButtonLabel: 'Next',
7363
7504
  }, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, defaultDate, defaultTime, }) {
7364
- console.log('[DateTimePicker] Component initialized with props:', {
7505
+ console.debug('[DateTimePicker] Component initialized with props:', {
7365
7506
  value,
7366
7507
  format,
7367
7508
  showSeconds,
@@ -7380,13 +7521,13 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7380
7521
  const [selectedDate, setSelectedDate] = useState(getDateString(value));
7381
7522
  // Helper to get time values from value prop with timezone
7382
7523
  const getTimeFromValue = useCallback((val) => {
7383
- console.log('[DateTimePicker] getTimeFromValue called:', {
7524
+ console.debug('[DateTimePicker] getTimeFromValue called:', {
7384
7525
  val,
7385
7526
  timezone,
7386
7527
  showSeconds,
7387
7528
  });
7388
7529
  if (!val) {
7389
- console.log('[DateTimePicker] No value provided, returning nulls');
7530
+ console.debug('[DateTimePicker] No value provided, returning nulls');
7390
7531
  return {
7391
7532
  hour12: null,
7392
7533
  minute: null,
@@ -7396,7 +7537,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7396
7537
  };
7397
7538
  }
7398
7539
  const dateObj = dayjs(val).tz(timezone);
7399
- console.log('[DateTimePicker] Parsed date object:', {
7540
+ console.debug('[DateTimePicker] Parsed date object:', {
7400
7541
  original: val,
7401
7542
  timezone,
7402
7543
  isValid: dateObj.isValid(),
@@ -7406,7 +7547,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7406
7547
  second: dateObj.second(),
7407
7548
  });
7408
7549
  if (!dateObj.isValid()) {
7409
- console.log('[DateTimePicker] Invalid date object, returning nulls');
7550
+ console.debug('[DateTimePicker] Invalid date object, returning nulls');
7410
7551
  return {
7411
7552
  hour12: null,
7412
7553
  minute: null,
@@ -7427,11 +7568,11 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7427
7568
  hour24: hour24Value,
7428
7569
  second: secondValue,
7429
7570
  };
7430
- console.log('[DateTimePicker] Extracted time values:', result);
7571
+ console.debug('[DateTimePicker] Extracted time values:', result);
7431
7572
  return result;
7432
7573
  }, [timezone, showSeconds]);
7433
7574
  const initialTime = getTimeFromValue(value);
7434
- console.log('[DateTimePicker] Initial time from value:', {
7575
+ console.debug('[DateTimePicker] Initial time from value:', {
7435
7576
  value,
7436
7577
  initialTime,
7437
7578
  });
@@ -7508,14 +7649,14 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7508
7649
  const [second, setSecond] = useState(initialTimeValues.second);
7509
7650
  // Sync selectedDate and time states when value prop changes
7510
7651
  useEffect(() => {
7511
- console.log('[DateTimePicker] useEffect triggered - value changed:', {
7652
+ console.debug('[DateTimePicker] useEffect triggered - value changed:', {
7512
7653
  value,
7513
7654
  timezone,
7514
7655
  format,
7515
7656
  });
7516
7657
  // If value is null, undefined, or invalid, clear date but keep default time values
7517
7658
  if (!value || value === null || value === undefined) {
7518
- console.log('[DateTimePicker] Value is null/undefined, clearing date but keeping default time');
7659
+ console.debug('[DateTimePicker] Value is null/undefined, clearing date but keeping default time');
7519
7660
  setSelectedDate('');
7520
7661
  // Keep default time values instead of clearing them
7521
7662
  if (format === 'iso-date-time') {
@@ -7537,7 +7678,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7537
7678
  // Check if value is valid
7538
7679
  const dateObj = dayjs(value).tz(timezone);
7539
7680
  if (!dateObj.isValid()) {
7540
- console.log('[DateTimePicker] Invalid value, clearing date but keeping default time');
7681
+ console.debug('[DateTimePicker] Invalid value, clearing date but keeping default time');
7541
7682
  setSelectedDate('');
7542
7683
  // Keep default time values instead of clearing them
7543
7684
  if (format === 'iso-date-time') {
@@ -7557,10 +7698,10 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7557
7698
  return;
7558
7699
  }
7559
7700
  const dateString = getDateString(value);
7560
- console.log('[DateTimePicker] Setting selectedDate:', dateString);
7701
+ console.debug('[DateTimePicker] Setting selectedDate:', dateString);
7561
7702
  setSelectedDate(dateString);
7562
7703
  const timeData = getTimeFromValue(value);
7563
- console.log('[DateTimePicker] Updating time states:', {
7704
+ console.debug('[DateTimePicker] Updating time states:', {
7564
7705
  timeData,
7565
7706
  });
7566
7707
  setHour12(timeData.hour12);
@@ -7570,7 +7711,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7570
7711
  setSecond(timeData.second);
7571
7712
  }, [value, getTimeFromValue, getDateString, timezone]);
7572
7713
  const handleDateChange = (date) => {
7573
- console.log('[DateTimePicker] handleDateChange called:', {
7714
+ console.debug('[DateTimePicker] handleDateChange called:', {
7574
7715
  date,
7575
7716
  timezone,
7576
7717
  showSeconds,
@@ -7578,7 +7719,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7578
7719
  });
7579
7720
  // If date is empty or invalid, clear all fields
7580
7721
  if (!date || date === '') {
7581
- console.log('[DateTimePicker] Empty date, clearing all fields');
7722
+ console.debug('[DateTimePicker] Empty date, clearing all fields');
7582
7723
  setSelectedDate('');
7583
7724
  setHour12(null);
7584
7725
  setMinute(null);
@@ -7591,7 +7732,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7591
7732
  setSelectedDate(date);
7592
7733
  // Parse the date string (YYYY-MM-DD) in the specified timezone
7593
7734
  const dateObj = dayjs.tz(date, timezone);
7594
- console.log('[DateTimePicker] Parsed date object:', {
7735
+ console.debug('[DateTimePicker] Parsed date object:', {
7595
7736
  date,
7596
7737
  timezone,
7597
7738
  isValid: dateObj.isValid(),
@@ -7617,7 +7758,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7617
7758
  if (!hasTimeValues) {
7618
7759
  // Use defaultTime if provided, otherwise default to 00:00
7619
7760
  if (defaultTime) {
7620
- console.log('[DateTimePicker] No time values set, using defaultTime');
7761
+ console.debug('[DateTimePicker] No time values set, using defaultTime');
7621
7762
  if (format === 'iso-date-time') {
7622
7763
  const defaultTime24 = defaultTime;
7623
7764
  setHour24(defaultTime24.hour ?? 0);
@@ -7644,7 +7785,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7644
7785
  }
7645
7786
  }
7646
7787
  else {
7647
- console.log('[DateTimePicker] No time values set, defaulting to 00:00');
7788
+ console.debug('[DateTimePicker] No time values set, defaulting to 00:00');
7648
7789
  if (format === 'iso-date-time') {
7649
7790
  setHour24(0);
7650
7791
  setMinute(0);
@@ -7672,17 +7813,17 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7672
7813
  // When showSeconds is false, ignore seconds from the date
7673
7814
  if (!showSeconds) {
7674
7815
  const dateWithoutSeconds = dateObj.second(0).millisecond(0).toISOString();
7675
- console.log('[DateTimePicker] Updating date without seconds:', dateWithoutSeconds);
7816
+ console.debug('[DateTimePicker] Updating date without seconds:', dateWithoutSeconds);
7676
7817
  updateDateTime(dateWithoutSeconds, timeDataToUse);
7677
7818
  }
7678
7819
  else {
7679
7820
  const dateWithSeconds = dateObj.toISOString();
7680
- console.log('[DateTimePicker] Updating date with seconds:', dateWithSeconds);
7821
+ console.debug('[DateTimePicker] Updating date with seconds:', dateWithSeconds);
7681
7822
  updateDateTime(dateWithSeconds, timeDataToUse);
7682
7823
  }
7683
7824
  };
7684
7825
  const handleTimeChange = (timeData) => {
7685
- console.log('[DateTimePicker] handleTimeChange called:', {
7826
+ console.debug('[DateTimePicker] handleTimeChange called:', {
7686
7827
  timeData,
7687
7828
  format,
7688
7829
  selectedDate,
@@ -7690,7 +7831,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7690
7831
  });
7691
7832
  if (format === 'iso-date-time') {
7692
7833
  const data = timeData;
7693
- console.log('[DateTimePicker] ISO format - setting 24-hour time:', data);
7834
+ console.debug('[DateTimePicker] ISO format - setting 24-hour time:', data);
7694
7835
  setHour24(data.hour);
7695
7836
  setMinute(data.minute);
7696
7837
  if (showSeconds) {
@@ -7703,7 +7844,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7703
7844
  }
7704
7845
  else {
7705
7846
  const data = timeData;
7706
- console.log('[DateTimePicker] 12-hour format - setting time:', data);
7847
+ console.debug('[DateTimePicker] 12-hour format - setting time:', data);
7707
7848
  setHour12(data.hour);
7708
7849
  setMinute(data.minute);
7709
7850
  setMeridiem(data.meridiem);
@@ -7712,7 +7853,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7712
7853
  if (!selectedDate || !dayjs(selectedDate).isValid()) {
7713
7854
  // If effectiveDefaultDate is available, use it instead of clearing
7714
7855
  if (effectiveDefaultDate && dayjs(effectiveDefaultDate).isValid()) {
7715
- console.log('[DateTimePicker] No valid selectedDate, using effectiveDefaultDate:', effectiveDefaultDate);
7856
+ console.debug('[DateTimePicker] No valid selectedDate, using effectiveDefaultDate:', effectiveDefaultDate);
7716
7857
  setSelectedDate(effectiveDefaultDate);
7717
7858
  const dateObj = dayjs(effectiveDefaultDate).tz(timezone);
7718
7859
  if (dateObj.isValid()) {
@@ -7731,7 +7872,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7731
7872
  return;
7732
7873
  }
7733
7874
  else {
7734
- console.log('[DateTimePicker] No valid selectedDate and no effectiveDefaultDate, keeping time values but no date');
7875
+ console.debug('[DateTimePicker] No valid selectedDate and no effectiveDefaultDate, keeping time values but no date');
7735
7876
  // Keep the time values that were just set, but don't set a date
7736
7877
  // This should rarely happen as effectiveDefaultDate always defaults to today
7737
7878
  setSelectedDate('');
@@ -7755,14 +7896,14 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7755
7896
  }
7756
7897
  };
7757
7898
  const updateDateTime = (date, timeData) => {
7758
- console.log('[DateTimePicker] updateDateTime called:', {
7899
+ console.debug('[DateTimePicker] updateDateTime called:', {
7759
7900
  date,
7760
7901
  timeData,
7761
7902
  format,
7762
7903
  currentStates: { hour12, minute, meridiem, hour24, second },
7763
7904
  });
7764
7905
  if (!date || date === null || date === undefined) {
7765
- console.log('[DateTimePicker] No date provided, clearing all fields and calling onChange(undefined)');
7906
+ console.debug('[DateTimePicker] No date provided, clearing all fields and calling onChange(undefined)');
7766
7907
  setSelectedDate('');
7767
7908
  setHour12(null);
7768
7909
  setMinute(null);
@@ -7800,11 +7941,11 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7800
7941
  : 0;
7801
7942
  // If all time values are null, clear the value
7802
7943
  if (h === null && m === null && (showSeconds ? s === null : true)) {
7803
- console.log('[DateTimePicker] All time values are null, clearing value');
7944
+ console.debug('[DateTimePicker] All time values are null, clearing value');
7804
7945
  onChange?.(undefined);
7805
7946
  return;
7806
7947
  }
7807
- console.log('[DateTimePicker] ISO format - setting time on date:', {
7948
+ console.debug('[DateTimePicker] ISO format - setting time on date:', {
7808
7949
  h,
7809
7950
  m,
7810
7951
  s,
@@ -7818,7 +7959,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7818
7959
  }
7819
7960
  else {
7820
7961
  const data = timeData;
7821
- console.log('[DateTimePicker] Processing 12-hour format:', {
7962
+ console.debug('[DateTimePicker] Processing 12-hour format:', {
7822
7963
  'data !== undefined': data !== undefined,
7823
7964
  'data?.hour': data?.hour,
7824
7965
  'data?.minute': data?.minute,
@@ -7831,14 +7972,14 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7831
7972
  const h = data !== undefined ? data.hour : hour12;
7832
7973
  const m = data !== undefined ? data.minute : minute;
7833
7974
  const mer = data !== undefined ? data.meridiem : meridiem;
7834
- console.log('[DateTimePicker] Resolved time values:', { h, m, mer });
7975
+ console.debug('[DateTimePicker] Resolved time values:', { h, m, mer });
7835
7976
  // If all time values are null, clear the value
7836
7977
  if (h === null && m === null && mer === null) {
7837
- console.log('[DateTimePicker] All time values are null, clearing value');
7978
+ console.debug('[DateTimePicker] All time values are null, clearing value');
7838
7979
  onChange?.(undefined);
7839
7980
  return;
7840
7981
  }
7841
- console.log('[DateTimePicker] 12-hour format - converting time:', {
7982
+ console.debug('[DateTimePicker] 12-hour format - converting time:', {
7842
7983
  h,
7843
7984
  m,
7844
7985
  mer,
@@ -7849,7 +7990,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7849
7990
  hour24 = 0;
7850
7991
  else if (mer === 'pm' && h < 12)
7851
7992
  hour24 = h + 12;
7852
- console.log('[DateTimePicker] Converted to 24-hour:', {
7993
+ console.debug('[DateTimePicker] Converted to 24-hour:', {
7853
7994
  h,
7854
7995
  mer,
7855
7996
  hour24,
@@ -7857,7 +7998,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7857
7998
  newDate.setHours(hour24);
7858
7999
  }
7859
8000
  else {
7860
- console.log('[DateTimePicker] Skipping hour update - h or mer is null:', {
8001
+ console.debug('[DateTimePicker] Skipping hour update - h or mer is null:', {
7861
8002
  h,
7862
8003
  mer,
7863
8004
  });
@@ -7866,12 +8007,12 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7866
8007
  newDate.setMinutes(m);
7867
8008
  }
7868
8009
  else {
7869
- console.log('[DateTimePicker] Skipping minute update - m is null');
8010
+ console.debug('[DateTimePicker] Skipping minute update - m is null');
7870
8011
  }
7871
8012
  newDate.setSeconds(0);
7872
8013
  }
7873
8014
  const finalISO = dayjs(newDate).tz(timezone).toISOString();
7874
- console.log('[DateTimePicker] Final ISO string to emit:', {
8015
+ console.debug('[DateTimePicker] Final ISO string to emit:', {
7875
8016
  newDate: newDate.toISOString(),
7876
8017
  timezone,
7877
8018
  finalISO,
@@ -7906,7 +8047,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7906
8047
  : undefined;
7907
8048
  // Log current state before render
7908
8049
  useEffect(() => {
7909
- console.log('[DateTimePicker] Current state before render:', {
8050
+ console.debug('[DateTimePicker] Current state before render:', {
7910
8051
  isISO,
7911
8052
  hour12,
7912
8053
  minute,
@@ -8166,7 +8307,7 @@ const BooleanViewer = ({ schema, column, prefix, }) => {
8166
8307
  const value = watch(colLabel);
8167
8308
  const formI18n = useFormI18n(column, prefix, schema);
8168
8309
  return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
8169
- gridRow, children: [jsx(Text, { children: value ? formI18n.t('true') : formI18n.t('false') }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
8310
+ gridRow, children: [jsx(Text, { children: value ? 'True' : 'False' }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
8170
8311
  };
8171
8312
 
8172
8313
  const CustomViewer = ({ column, schema, prefix }) => {
@@ -8205,16 +8346,15 @@ const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
8205
8346
  const colLabel = formI18n.colLabel;
8206
8347
  const watchEnum = watch(colLabel);
8207
8348
  const watchEnums = (watch(colLabel) ?? []);
8349
+ const renderDisplayFunction = renderDisplay || defaultRenderDisplay;
8208
8350
  return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
8209
8351
  gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: 'wrap', gap: 1, children: watchEnums.map((enumValue) => {
8210
8352
  const item = enumValue;
8211
8353
  if (item === undefined) {
8212
8354
  return jsx(Fragment, { children: "undefined" });
8213
8355
  }
8214
- return (jsx(Tag, { size: "lg", children: !!renderDisplay === true
8215
- ? renderDisplay(item)
8216
- : formI18n.t(item) }, item));
8217
- }) })), !isMultiple && jsx(Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
8356
+ return (jsx(Tag, { size: "lg", children: renderDisplayFunction(item) }, item));
8357
+ }) })), !isMultiple && jsx(Text, { children: renderDisplayFunction(watchEnum) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
8218
8358
  };
8219
8359
 
8220
8360
  const FileViewer = ({ column, schema, prefix }) => {