@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.d.ts +1 -0
- package/dist/index.js +294 -154
- package/dist/index.mjs +296 -156
- package/dist/types/components/Form/components/fields/useIdPickerData.d.ts +4 -0
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +1 -0
- package/dist/types/components/Form/utils/useFormI18n.d.ts +14 -30
- package/package.json +7 -4
package/dist/index.js
CHANGED
|
@@ -4393,39 +4393,31 @@ const FormRoot = ({ schema, idMap, setIdMap, form, translate, children, order =
|
|
|
4393
4393
|
}, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
|
|
4394
4394
|
};
|
|
4395
4395
|
|
|
4396
|
-
function removeIndex(str) {
|
|
4397
|
-
return str.replace(/\.\d+\./g, ".");
|
|
4398
|
-
}
|
|
4399
|
-
|
|
4400
4396
|
/**
|
|
4401
|
-
* Custom hook for form field labels
|
|
4402
|
-
* Automatically handles colLabel construction
|
|
4403
|
-
* Uses schema.title
|
|
4397
|
+
* Custom hook for form field labels.
|
|
4398
|
+
* Automatically handles colLabel construction.
|
|
4399
|
+
* Uses schema.title for labels and schema.errorMessages for error messages.
|
|
4404
4400
|
*
|
|
4405
4401
|
* @param column - The column name
|
|
4406
4402
|
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
4407
|
-
* @param schema - Required schema object with title
|
|
4403
|
+
* @param schema - Required schema object with title and errorMessages properties
|
|
4408
4404
|
* @returns Object with label helper functions
|
|
4409
4405
|
*
|
|
4410
4406
|
* @example
|
|
4411
4407
|
* ```tsx
|
|
4412
4408
|
* const formI18n = useFormI18n(column, prefix, schema);
|
|
4413
4409
|
*
|
|
4414
|
-
* // Get field label (
|
|
4410
|
+
* // Get field label (from schema.title)
|
|
4415
4411
|
* <Field label={formI18n.label()} />
|
|
4416
4412
|
*
|
|
4417
|
-
* // Get required error message
|
|
4413
|
+
* // Get required error message (from schema.errorMessages?.required)
|
|
4418
4414
|
* <Text>{formI18n.required()}</Text>
|
|
4419
4415
|
*
|
|
4420
|
-
* // Get custom text
|
|
4421
|
-
* <Text>{formI18n.t('add_more')}</Text>
|
|
4422
|
-
*
|
|
4423
4416
|
* // Access the raw colLabel
|
|
4424
4417
|
* const colLabel = formI18n.colLabel;
|
|
4425
4418
|
* ```
|
|
4426
4419
|
*/
|
|
4427
4420
|
const useFormI18n = (column, prefix = '', schema) => {
|
|
4428
|
-
const { translate } = useSchemaContext();
|
|
4429
4421
|
const colLabel = `${prefix}${column}`;
|
|
4430
4422
|
return {
|
|
4431
4423
|
/**
|
|
@@ -4433,10 +4425,10 @@ const useFormI18n = (column, prefix = '', schema) => {
|
|
|
4433
4425
|
*/
|
|
4434
4426
|
colLabel,
|
|
4435
4427
|
/**
|
|
4436
|
-
* Get the field label from schema title
|
|
4437
|
-
*
|
|
4428
|
+
* Get the field label from schema title property.
|
|
4429
|
+
* Logs a debug message if title is missing.
|
|
4438
4430
|
*/
|
|
4439
|
-
label: (
|
|
4431
|
+
label: () => {
|
|
4440
4432
|
if (schema.title) {
|
|
4441
4433
|
return schema.title;
|
|
4442
4434
|
}
|
|
@@ -4452,29 +4444,36 @@ const useFormI18n = (column, prefix = '', schema) => {
|
|
|
4452
4444
|
: undefined,
|
|
4453
4445
|
},
|
|
4454
4446
|
});
|
|
4455
|
-
|
|
4447
|
+
// Return column name as fallback
|
|
4448
|
+
return column;
|
|
4456
4449
|
},
|
|
4457
4450
|
/**
|
|
4458
|
-
* Get the required error message
|
|
4459
|
-
*
|
|
4451
|
+
* Get the required error message from schema.errorMessages?.required.
|
|
4452
|
+
* Returns a helpful fallback message if not provided.
|
|
4460
4453
|
*/
|
|
4461
|
-
required: (
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4454
|
+
required: () => {
|
|
4455
|
+
const errorMessage = schema.errorMessages?.required;
|
|
4456
|
+
if (errorMessage) {
|
|
4457
|
+
return errorMessage;
|
|
4458
|
+
}
|
|
4459
|
+
// Debug log when error message is missing
|
|
4460
|
+
console.debug(`[Form Field Required] Missing error message for required field '${colLabel}'. Add errorMessages.required to schema for field '${colLabel}'.`, {
|
|
4461
|
+
fieldName: column,
|
|
4462
|
+
colLabel,
|
|
4463
|
+
prefix,
|
|
4464
|
+
schema: {
|
|
4465
|
+
type: schema.type,
|
|
4466
|
+
title: schema.title,
|
|
4467
|
+
required: schema.required,
|
|
4468
|
+
hasErrorMessages: !!schema.errorMessages,
|
|
4469
|
+
errorMessageKeys: schema.errorMessages
|
|
4470
|
+
? Object.keys(schema.errorMessages)
|
|
4471
|
+
: undefined,
|
|
4472
|
+
},
|
|
4473
|
+
});
|
|
4474
|
+
// Return helpful fallback message
|
|
4475
|
+
return `Missing error message for required. Add errorMessages.required to schema for field '${colLabel}'`;
|
|
4473
4476
|
},
|
|
4474
|
-
/**
|
|
4475
|
-
* Access to the original translate object for edge cases
|
|
4476
|
-
*/
|
|
4477
|
-
translate,
|
|
4478
4477
|
};
|
|
4479
4478
|
};
|
|
4480
4479
|
|
|
@@ -5090,27 +5089,82 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
5090
5089
|
const watchEnum = watch(colLabel);
|
|
5091
5090
|
const watchEnums = (watch(colLabel) ?? []);
|
|
5092
5091
|
const dataList = schema.enum ?? [];
|
|
5092
|
+
// Helper function to render enum value (returns ReactNode)
|
|
5093
|
+
// If renderDisplay is provided, use it; otherwise show the enum string value directly
|
|
5094
|
+
const renderEnumValue = (value) => {
|
|
5095
|
+
if (renderDisplay) {
|
|
5096
|
+
return renderDisplay(value);
|
|
5097
|
+
}
|
|
5098
|
+
// If no renderDisplay provided, show the enum string value directly
|
|
5099
|
+
return value;
|
|
5100
|
+
};
|
|
5101
|
+
// Helper function to get string representation for input display
|
|
5102
|
+
// Converts ReactNode to string for combobox input display
|
|
5103
|
+
const getDisplayString = (value) => {
|
|
5104
|
+
if (renderDisplay) {
|
|
5105
|
+
const rendered = renderDisplay(value);
|
|
5106
|
+
// If renderDisplay returns a string, use it directly
|
|
5107
|
+
if (typeof rendered === 'string') {
|
|
5108
|
+
return rendered;
|
|
5109
|
+
}
|
|
5110
|
+
// If it's a React element, try to extract text content
|
|
5111
|
+
// For now, fallback to the raw value if we can't extract text
|
|
5112
|
+
// In most cases, renderDisplay should return a string or simple element
|
|
5113
|
+
if (typeof rendered === 'object' &&
|
|
5114
|
+
rendered !== null &&
|
|
5115
|
+
'props' in rendered) {
|
|
5116
|
+
const props = rendered.props;
|
|
5117
|
+
// Try to extract text from React element props
|
|
5118
|
+
if (props?.children) {
|
|
5119
|
+
const children = props.children;
|
|
5120
|
+
if (typeof children === 'string') {
|
|
5121
|
+
return children;
|
|
5122
|
+
}
|
|
5123
|
+
}
|
|
5124
|
+
}
|
|
5125
|
+
// Fallback: use raw value if we can't extract string
|
|
5126
|
+
return value;
|
|
5127
|
+
}
|
|
5128
|
+
return value;
|
|
5129
|
+
};
|
|
5130
|
+
// Debug log when renderDisplay is missing
|
|
5131
|
+
if (!renderDisplay) {
|
|
5132
|
+
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.`, {
|
|
5133
|
+
fieldName: column,
|
|
5134
|
+
colLabel,
|
|
5135
|
+
prefix,
|
|
5136
|
+
enumValues: dataList,
|
|
5137
|
+
});
|
|
5138
|
+
}
|
|
5093
5139
|
// Current value for combobox (array format)
|
|
5094
5140
|
const currentValue = isMultiple
|
|
5095
5141
|
? watchEnums.filter((val) => val != null && val !== '')
|
|
5096
5142
|
: watchEnum
|
|
5097
5143
|
? [watchEnum]
|
|
5098
5144
|
: [];
|
|
5099
|
-
//
|
|
5145
|
+
// Track input focus state for single selection
|
|
5146
|
+
const [isInputFocused, setIsInputFocused] = React.useState(false);
|
|
5147
|
+
// Get the selected value for single selection display
|
|
5148
|
+
const selectedSingleValue = !isMultiple && watchEnum ? watchEnum : null;
|
|
5149
|
+
const selectedSingleRendered = selectedSingleValue
|
|
5150
|
+
? renderEnumValue(selectedSingleValue)
|
|
5151
|
+
: null;
|
|
5152
|
+
const isSelectedSingleValueString = typeof selectedSingleRendered === 'string';
|
|
5100
5153
|
const comboboxItems = React.useMemo(() => {
|
|
5101
5154
|
return dataList.map((item) => ({
|
|
5102
|
-
label:
|
|
5103
|
-
? String(renderDisplay(item))
|
|
5104
|
-
: formI18n.t(item),
|
|
5155
|
+
label: item, // Internal: used for search/filtering only
|
|
5105
5156
|
value: item,
|
|
5157
|
+
raw: item, // Passed to renderEnumValue for UI rendering
|
|
5158
|
+
displayLabel: getDisplayString(item), // Used for input display when selected
|
|
5106
5159
|
}));
|
|
5107
|
-
}, [dataList, renderDisplay
|
|
5160
|
+
}, [dataList, renderDisplay]);
|
|
5108
5161
|
// Use filter hook for combobox
|
|
5109
5162
|
const { contains } = react.useFilter({ sensitivity: 'base' });
|
|
5110
5163
|
// Create collection for combobox
|
|
5164
|
+
// itemToString uses displayLabel to show rendered display in input when selected
|
|
5111
5165
|
const { collection, filter } = react.useListCollection({
|
|
5112
5166
|
initialItems: comboboxItems,
|
|
5113
|
-
itemToString: (item) => item.
|
|
5167
|
+
itemToString: (item) => item.displayLabel, // Use displayLabel for selected value display
|
|
5114
5168
|
itemToValue: (item) => item.value,
|
|
5115
5169
|
filter: contains,
|
|
5116
5170
|
});
|
|
@@ -5134,9 +5188,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
5134
5188
|
setValue(colLabel, details.value);
|
|
5135
5189
|
}
|
|
5136
5190
|
}, children: jsxRuntime.jsx(react.HStack, { gap: "6", children: dataList.map((item) => {
|
|
5137
|
-
return (jsxRuntime.jsxs(react.RadioGroup.Item, { value: item, children: [jsxRuntime.jsx(react.RadioGroup.ItemHiddenInput, {}), jsxRuntime.jsx(react.RadioGroup.ItemIndicator, {}), jsxRuntime.jsx(react.RadioGroup.ItemText, { children:
|
|
5138
|
-
? renderDisplay(item)
|
|
5139
|
-
: formI18n.t(item) })] }, `${colLabel}-${item}`));
|
|
5191
|
+
return (jsxRuntime.jsxs(react.RadioGroup.Item, { value: item, children: [jsxRuntime.jsx(react.RadioGroup.ItemHiddenInput, {}), jsxRuntime.jsx(react.RadioGroup.ItemIndicator, {}), jsxRuntime.jsx(react.RadioGroup.ItemText, { children: renderEnumValue(item) })] }, `${colLabel}-${item}`));
|
|
5140
5192
|
}) }) }) }));
|
|
5141
5193
|
}
|
|
5142
5194
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
@@ -5147,16 +5199,31 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
5147
5199
|
return (jsxRuntime.jsx(Tag, { size: "lg", closable: true, onClick: () => {
|
|
5148
5200
|
const newValue = currentValue.filter((val) => val !== enumValue);
|
|
5149
5201
|
setValue(colLabel, newValue);
|
|
5150
|
-
}, children:
|
|
5151
|
-
? renderDisplay(enumValue)
|
|
5152
|
-
: formI18n.t(enumValue) }, enumValue));
|
|
5202
|
+
}, children: renderEnumValue(enumValue) }, enumValue));
|
|
5153
5203
|
}) })), jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: isMultiple, closeOnSelect: !isMultiple, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
|
|
5154
5204
|
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5155
|
-
: undefined, children: [jsxRuntime.jsxs(react.Combobox.Control, {
|
|
5205
|
+
: undefined, children: [jsxRuntime.jsxs(react.Combobox.Control, { position: "relative", children: [!isMultiple &&
|
|
5206
|
+
selectedSingleValue &&
|
|
5207
|
+
!isInputFocused &&
|
|
5208
|
+
!isSelectedSingleValueString &&
|
|
5209
|
+
selectedSingleRendered && (jsxRuntime.jsx(react.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 })), jsxRuntime.jsx(react.Combobox.Input, { placeholder: !isMultiple && selectedSingleValue && !isInputFocused
|
|
5210
|
+
? undefined
|
|
5211
|
+
: enumPickerLabels?.typeToSearch ?? 'Type to search', onFocus: () => setIsInputFocused(true), onBlur: () => setIsInputFocused(false), style: {
|
|
5212
|
+
color: !isMultiple &&
|
|
5213
|
+
selectedSingleValue &&
|
|
5214
|
+
!isInputFocused &&
|
|
5215
|
+
!isSelectedSingleValueString
|
|
5216
|
+
? 'transparent'
|
|
5217
|
+
: undefined,
|
|
5218
|
+
caretColor: !isMultiple &&
|
|
5219
|
+
selectedSingleValue &&
|
|
5220
|
+
!isInputFocused &&
|
|
5221
|
+
!isSelectedSingleValueString
|
|
5222
|
+
? 'transparent'
|
|
5223
|
+
: undefined,
|
|
5224
|
+
} }), jsxRuntime.jsxs(react.Combobox.IndicatorGroup, { children: [!isMultiple && currentValue.length > 0 && (jsxRuntime.jsx(react.Combobox.ClearTrigger, { onClick: () => {
|
|
5156
5225
|
setValue(colLabel, '');
|
|
5157
|
-
} })), jsxRuntime.jsx(react.Combobox.Trigger, {})] })] }), insideDialog ? (jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsxs(react.Combobox.Content, { children: [showTotalAndLimit && (jsxRuntime.jsx(react.Text, { p: 2, fontSize: "sm", color: "fg.muted", children: `${enumPickerLabels?.total ??
|
|
5158
|
-
formI18n.t('empty_search_result') })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) }))] }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsxs(react.Combobox.Content, { children: [showTotalAndLimit && (jsxRuntime.jsx(react.Text, { p: 2, fontSize: "sm", color: "fg.muted", children: `${enumPickerLabels?.total ?? formI18n.t('total')}: ${collection.items.length}` })), collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: enumPickerLabels?.emptySearchResult ??
|
|
5159
|
-
formI18n.t('empty_search_result') })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) }))] }) }) }))] })] }));
|
|
5226
|
+
} })), jsxRuntime.jsx(react.Combobox.Trigger, {})] })] }), insideDialog ? (jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsxs(react.Combobox.Content, { children: [showTotalAndLimit && (jsxRuntime.jsx(react.Text, { p: 2, fontSize: "sm", color: "fg.muted", children: `${enumPickerLabels?.total ?? 'Total'}: ${collection.items.length}` })), collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: enumPickerLabels?.emptySearchResult ?? 'No results found' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: renderEnumValue(item.raw) }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) }))] }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsxs(react.Combobox.Content, { children: [showTotalAndLimit && (jsxRuntime.jsx(react.Text, { p: 2, fontSize: "sm", color: "fg.muted", children: `${enumPickerLabels?.total ?? 'Total'}: ${collection.items.length}` })), collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: enumPickerLabels?.emptySearchResult ?? 'No results found' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: renderEnumValue(item.raw) }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) }))] }) }) }))] })] }));
|
|
5160
5227
|
};
|
|
5161
5228
|
|
|
5162
5229
|
function isEnteringWindow(_ref) {
|
|
@@ -5771,7 +5838,7 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5771
5838
|
const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
|
|
5772
5839
|
setValue(colLabel, [...currentFiles, ...newFiles]);
|
|
5773
5840
|
}
|
|
5774
|
-
}, placeholder: filePickerLabels?.fileDropzone ??
|
|
5841
|
+
}, placeholder: filePickerLabels?.fileDropzone ?? 'Drop files here' }) }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
|
|
5775
5842
|
const fileIdentifier = getFileIdentifier(file, index);
|
|
5776
5843
|
const fileName = getFileName(file);
|
|
5777
5844
|
const fileSize = getFileSize(file);
|
|
@@ -5882,9 +5949,7 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5882
5949
|
}
|
|
5883
5950
|
};
|
|
5884
5951
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5885
|
-
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: jsxRuntime.jsx(react.Button, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
|
|
5886
|
-
formI18n.t('browse_library') ??
|
|
5887
|
-
'Browse from Library' }) }), jsxRuntime.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 }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
5952
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: jsxRuntime.jsx(react.Button, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ?? 'Browse from Library' }) }), jsxRuntime.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 }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
5888
5953
|
const file = fileMap.get(fileId);
|
|
5889
5954
|
const isImage = file
|
|
5890
5955
|
? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
|
|
@@ -5900,15 +5965,46 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5900
5965
|
}) })] }));
|
|
5901
5966
|
};
|
|
5902
5967
|
|
|
5903
|
-
// Default renderDisplay function that
|
|
5968
|
+
// Default renderDisplay function that intelligently displays items
|
|
5969
|
+
// If item is an object, tries to find common display fields (name, title, label, etc.)
|
|
5970
|
+
// Otherwise falls back to JSON.stringify
|
|
5904
5971
|
const defaultRenderDisplay = (item) => {
|
|
5972
|
+
// Check if item is an object (not null, not array, not primitive)
|
|
5973
|
+
if (item !== null &&
|
|
5974
|
+
typeof item === 'object' &&
|
|
5975
|
+
!Array.isArray(item) &&
|
|
5976
|
+
!(item instanceof Date)) {
|
|
5977
|
+
const obj = item;
|
|
5978
|
+
// Try common display fields in order of preference
|
|
5979
|
+
const displayFields = [
|
|
5980
|
+
'name',
|
|
5981
|
+
'title',
|
|
5982
|
+
'label',
|
|
5983
|
+
'displayName',
|
|
5984
|
+
'display_name',
|
|
5985
|
+
'text',
|
|
5986
|
+
'value',
|
|
5987
|
+
];
|
|
5988
|
+
for (const field of displayFields) {
|
|
5989
|
+
if (obj[field] !== undefined && obj[field] !== null) {
|
|
5990
|
+
const value = obj[field];
|
|
5991
|
+
// Return the value if it's a string or number, otherwise stringify it
|
|
5992
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
5993
|
+
return String(value);
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
}
|
|
5997
|
+
// If no display field found, fall back to JSON.stringify
|
|
5998
|
+
return JSON.stringify(item);
|
|
5999
|
+
}
|
|
6000
|
+
// For non-objects (primitives, arrays, dates), use JSON.stringify
|
|
5905
6001
|
return JSON.stringify(item);
|
|
5906
6002
|
};
|
|
5907
6003
|
|
|
5908
6004
|
const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
5909
6005
|
const { watch, getValues, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
5910
6006
|
const { idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
|
|
5911
|
-
const { renderDisplay, loadInitialValues, foreign_key, variant } = schema;
|
|
6007
|
+
const { renderDisplay, itemToValue: schemaItemToValue, loadInitialValues, foreign_key, variant, } = schema;
|
|
5912
6008
|
// loadInitialValues should be provided in schema for id-picker fields
|
|
5913
6009
|
// It's used to load the record of the id so the display is human-readable
|
|
5914
6010
|
if (variant === 'id-picker' && !loadInitialValues) {
|
|
@@ -6041,17 +6137,51 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6041
6137
|
// Depend on idMapKey which only changes when items we care about change
|
|
6042
6138
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6043
6139
|
}, [currentValueKey, idMapKey]);
|
|
6140
|
+
// Default itemToValue function: extract value from item using column_ref
|
|
6141
|
+
const defaultItemToValue = (item) => String(item[column_ref]);
|
|
6142
|
+
// Use schema's itemToValue if provided, otherwise use default
|
|
6143
|
+
const itemToValueFn = schemaItemToValue
|
|
6144
|
+
? (item) => schemaItemToValue(item)
|
|
6145
|
+
: defaultItemToValue;
|
|
6146
|
+
// itemToString function: convert item to readable string using renderDisplay
|
|
6147
|
+
// This ensures items can always be displayed as readable strings in the combobox
|
|
6148
|
+
const renderFn = renderDisplay || defaultRenderDisplay;
|
|
6149
|
+
const itemToStringFn = (item) => {
|
|
6150
|
+
const rendered = renderFn(item);
|
|
6151
|
+
// If already a string or number, return it
|
|
6152
|
+
if (typeof rendered === 'string')
|
|
6153
|
+
return rendered;
|
|
6154
|
+
if (typeof rendered === 'number')
|
|
6155
|
+
return String(rendered);
|
|
6156
|
+
// For ReactNode, fall back to defaultRenderDisplay which converts to string
|
|
6157
|
+
return String(defaultRenderDisplay(item));
|
|
6158
|
+
};
|
|
6044
6159
|
// Transform data for combobox collection
|
|
6045
6160
|
// label is used for filtering/searching (must be a string)
|
|
6161
|
+
// displayLabel is used for input display when selected (string representation of rendered display)
|
|
6046
6162
|
// raw item is stored for custom rendering
|
|
6047
6163
|
// Also include items from idMap that match currentValue (for initial values display)
|
|
6048
6164
|
const comboboxItems = React.useMemo(() => {
|
|
6049
6165
|
const renderFn = renderDisplay || defaultRenderDisplay;
|
|
6166
|
+
// Helper to convert rendered display to string for displayLabel
|
|
6167
|
+
// For ReactNodes (non-string/number), we can't safely stringify due to circular refs
|
|
6168
|
+
// So we use the label (which is already a string) as fallback
|
|
6169
|
+
const getDisplayString = (rendered, fallbackLabel) => {
|
|
6170
|
+
if (typeof rendered === 'string')
|
|
6171
|
+
return rendered;
|
|
6172
|
+
if (typeof rendered === 'number')
|
|
6173
|
+
return String(rendered);
|
|
6174
|
+
// For ReactNode, use the fallback label (which is already a string representation)
|
|
6175
|
+
// The actual ReactNode will be rendered in the overlay, not in the input
|
|
6176
|
+
return fallbackLabel;
|
|
6177
|
+
};
|
|
6050
6178
|
const itemsFromDataList = dataList.map((item) => {
|
|
6051
6179
|
const rendered = renderFn(item);
|
|
6180
|
+
const label = typeof rendered === 'string' ? rendered : JSON.stringify(item); // Use string for filtering
|
|
6052
6181
|
return {
|
|
6053
|
-
label
|
|
6054
|
-
|
|
6182
|
+
label, // Use string for filtering
|
|
6183
|
+
displayLabel: getDisplayString(rendered, label), // String representation for input display
|
|
6184
|
+
value: itemToValueFn(item),
|
|
6055
6185
|
raw: item,
|
|
6056
6186
|
};
|
|
6057
6187
|
});
|
|
@@ -6060,25 +6190,28 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6060
6190
|
const itemsFromIdMap = idMapItems
|
|
6061
6191
|
.map((item) => {
|
|
6062
6192
|
// Check if this item is already in itemsFromDataList
|
|
6063
|
-
const alreadyIncluded = itemsFromDataList.some((i) => i.value ===
|
|
6193
|
+
const alreadyIncluded = itemsFromDataList.some((i) => i.value === itemToValueFn(item));
|
|
6064
6194
|
if (alreadyIncluded)
|
|
6065
6195
|
return null;
|
|
6066
6196
|
const rendered = renderFn(item);
|
|
6197
|
+
const label = typeof rendered === 'string' ? rendered : JSON.stringify(item);
|
|
6067
6198
|
return {
|
|
6068
|
-
label
|
|
6069
|
-
|
|
6199
|
+
label,
|
|
6200
|
+
displayLabel: getDisplayString(rendered, label), // String representation for input display
|
|
6201
|
+
value: itemToValueFn(item),
|
|
6070
6202
|
raw: item,
|
|
6071
6203
|
};
|
|
6072
6204
|
})
|
|
6073
6205
|
.filter((item) => item !== null);
|
|
6074
6206
|
return [...itemsFromIdMap, ...itemsFromDataList];
|
|
6075
|
-
}, [dataList, column_ref, renderDisplay, idMapItems]);
|
|
6207
|
+
}, [dataList, column_ref, renderDisplay, idMapItems, itemToValueFn]);
|
|
6076
6208
|
// Use filter hook for combobox
|
|
6077
6209
|
const { contains } = react.useFilter({ sensitivity: 'base' });
|
|
6078
6210
|
// Create collection for combobox
|
|
6211
|
+
// itemToString uses displayLabel to show rendered display in input when selected
|
|
6079
6212
|
const { collection, filter, set } = react.useListCollection({
|
|
6080
6213
|
initialItems: comboboxItems,
|
|
6081
|
-
itemToString: (item) => item.
|
|
6214
|
+
itemToString: (item) => item.displayLabel, // Use displayLabel for selected value display
|
|
6082
6215
|
itemToValue: (item) => item.value,
|
|
6083
6216
|
filter: contains,
|
|
6084
6217
|
});
|
|
@@ -6133,6 +6266,8 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6133
6266
|
idPickerLabels,
|
|
6134
6267
|
insideDialog: insideDialog ?? false,
|
|
6135
6268
|
renderDisplay,
|
|
6269
|
+
itemToValue: itemToValueFn,
|
|
6270
|
+
itemToString: itemToStringFn,
|
|
6136
6271
|
loadInitialValues: loadInitialValues ??
|
|
6137
6272
|
(async () => ({ data: { data: [], count: 0 }, idMap: {} })), // Fallback if not provided
|
|
6138
6273
|
column_ref,
|
|
@@ -6143,60 +6278,69 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
|
6143
6278
|
|
|
6144
6279
|
const IdPickerSingle = ({ column, schema, prefix, }) => {
|
|
6145
6280
|
const formI18n = useFormI18n(column, prefix, schema);
|
|
6146
|
-
const { required, gridColumn = 'span 12', gridRow = 'span 1'
|
|
6281
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
6147
6282
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
6148
|
-
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching,
|
|
6283
|
+
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, collection, filter, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, itemToValue, itemToString, errors, setValue, } = useIdPickerData({
|
|
6149
6284
|
column,
|
|
6150
6285
|
schema,
|
|
6151
6286
|
prefix,
|
|
6152
6287
|
isMultiple: false,
|
|
6153
6288
|
});
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
const
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6289
|
+
// Get the selected value for single selection display
|
|
6290
|
+
const selectedId = currentValue.length > 0 ? currentValue[0] : null;
|
|
6291
|
+
const selectedItem = selectedId
|
|
6292
|
+
? idMap[selectedId]
|
|
6293
|
+
: undefined;
|
|
6294
|
+
// Use itemToValue to get the combobox value from the selected item, or use the ID directly
|
|
6295
|
+
const comboboxValue = selectedItem
|
|
6296
|
+
? itemToString(selectedItem)
|
|
6297
|
+
: selectedId || '';
|
|
6298
|
+
// itemToString is available from the hook and can be used to get a readable string
|
|
6299
|
+
// representation of any item. The collection's itemToString is automatically used
|
|
6300
|
+
// by the combobox to display selected values.
|
|
6301
|
+
// Use useCombobox hook to control input value
|
|
6302
|
+
const combobox = react.useCombobox({
|
|
6303
|
+
collection,
|
|
6304
|
+
value: [comboboxValue],
|
|
6305
|
+
onInputValueChange(e) {
|
|
6306
|
+
setSearchText(e.inputValue);
|
|
6307
|
+
filter(e.inputValue);
|
|
6308
|
+
},
|
|
6309
|
+
onValueChange(e) {
|
|
6310
|
+
setValue(colLabel, e.value[0] || '');
|
|
6311
|
+
// Clear the input value after selection
|
|
6312
|
+
setSearchText('');
|
|
6313
|
+
},
|
|
6314
|
+
multiple: false,
|
|
6315
|
+
closeOnSelect: true,
|
|
6316
|
+
openOnClick: true,
|
|
6317
|
+
invalid: !!errors[colLabel],
|
|
6318
|
+
});
|
|
6319
|
+
// Use renderDisplay from hook (which comes from schema) or fallback to default
|
|
6320
|
+
const renderDisplayFunction = renderDisplayFn || defaultRenderDisplay;
|
|
6321
|
+
// Get the selected value for single selection display (already computed above)
|
|
6322
|
+
const selectedRendered = selectedItem
|
|
6323
|
+
? renderDisplayFunction(selectedItem)
|
|
6324
|
+
: null;
|
|
6325
|
+
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
6326
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(react.Combobox.RootProvider, { value: combobox, width: "100%", children: [jsxRuntime.jsx(react.Show, { when: selectedId && selectedRendered, children: jsxRuntime.jsxs(react.HStack, { justifyContent: 'space-between', children: [jsxRuntime.jsx(react.Box, { children: selectedRendered }), currentValue.length > 0 && (jsxRuntime.jsx(react.Button, { variant: "ghost", size: "sm", onClick: () => {
|
|
6327
|
+
setValue(colLabel, '');
|
|
6328
|
+
}, children: jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(bi.BiX, {}) }) }))] }) }), jsxRuntime.jsx(react.Show, { when: !selectedId || !selectedRendered, children: jsxRuntime.jsxs(react.Combobox.Control, { position: "relative", children: [jsxRuntime.jsx(react.Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ?? 'Type to search' }), jsxRuntime.jsxs(react.Combobox.IndicatorGroup, { children: [(isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, { size: "xs" }), isError && (jsxRuntime.jsx(react.Icon, { color: "fg.error", children: jsxRuntime.jsx(bi.BiError, {}) })), jsxRuntime.jsx(react.Combobox.Trigger, {})] })] }) }), insideDialog ? (jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
6329
|
+
// Show skeleton items to prevent UI shift
|
|
6330
|
+
jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsxRuntime.jsx(react.Flex, { p: 2, align: "center", gap: 2, children: jsxRuntime.jsx(react.Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: searchText
|
|
6331
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
6332
|
+
: idPickerLabels?.initialResults ??
|
|
6333
|
+
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [renderDisplayFunction(item.raw), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
6181
6334
|
// Show skeleton items to prevent UI shift
|
|
6182
6335
|
jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsxRuntime.jsx(react.Flex, { p: 2, align: "center", gap: 2, children: jsxRuntime.jsx(react.Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: searchText
|
|
6183
6336
|
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
6184
6337
|
: idPickerLabels?.initialResults ??
|
|
6185
|
-
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.
|
|
6186
|
-
? renderDisplayFunction(item.raw)
|
|
6187
|
-
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
6188
|
-
// Show skeleton items to prevent UI shift
|
|
6189
|
-
jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsxRuntime.jsx(react.Flex, { p: 2, align: "center", gap: 2, children: jsxRuntime.jsx(react.Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: searchText
|
|
6190
|
-
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
6191
|
-
: idPickerLabels?.initialResults ??
|
|
6192
|
-
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
6193
|
-
? renderDisplayFunction(item.raw)
|
|
6194
|
-
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
6338
|
+
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsx(react.Combobox.Item, { item: item, children: renderDisplayFunction(item.raw) }, item.value ?? `item-${index}`))) })) }) }) }))] }) }));
|
|
6195
6339
|
};
|
|
6196
6340
|
|
|
6197
6341
|
const IdPickerMultiple = ({ column, schema, prefix, }) => {
|
|
6198
6342
|
const formI18n = useFormI18n(column, prefix, schema);
|
|
6199
|
-
const { required, gridColumn = 'span 12', gridRow = 'span 1'
|
|
6343
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
6200
6344
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
6201
6345
|
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
|
|
6202
6346
|
column,
|
|
@@ -6210,7 +6354,8 @@ const IdPickerMultiple = ({ column, schema, prefix, }) => {
|
|
|
6210
6354
|
const handleValueChange = (details) => {
|
|
6211
6355
|
setValue(colLabel, details.value);
|
|
6212
6356
|
};
|
|
6213
|
-
|
|
6357
|
+
// Use renderDisplay from hook (which comes from schema) or fallback to default
|
|
6358
|
+
const renderDisplayFunction = renderDisplayFn || defaultRenderDisplay;
|
|
6214
6359
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
6215
6360
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [currentValue.length > 0 && (jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 1, mb: 2, children: currentValue.map((id) => {
|
|
6216
6361
|
const item = idMap[id];
|
|
@@ -6235,16 +6380,12 @@ const IdPickerMultiple = ({ column, schema, prefix, }) => {
|
|
|
6235
6380
|
jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsxRuntime.jsx(react.Flex, { p: 2, align: "center", gap: 2, children: jsxRuntime.jsx(react.Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: searchText
|
|
6236
6381
|
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
6237
6382
|
: idPickerLabels?.initialResults ??
|
|
6238
|
-
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.
|
|
6239
|
-
? renderDisplayFunction(item.raw)
|
|
6240
|
-
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
6383
|
+
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [renderDisplayFunction(item.raw), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
6241
6384
|
// Show skeleton items to prevent UI shift
|
|
6242
6385
|
jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsxRuntime.jsx(react.Flex, { p: 2, align: "center", gap: 2, children: jsxRuntime.jsx(react.Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: searchText
|
|
6243
6386
|
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
6244
6387
|
: idPickerLabels?.initialResults ??
|
|
6245
|
-
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.
|
|
6246
|
-
? renderDisplayFunction(item.raw)
|
|
6247
|
-
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
6388
|
+
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [renderDisplayFunction(item.raw), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
6248
6389
|
};
|
|
6249
6390
|
|
|
6250
6391
|
const NumberInputRoot = React__namespace.forwardRef(function NumberInput(props, ref) {
|
|
@@ -7381,7 +7522,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7381
7522
|
backButtonLabel: 'Back',
|
|
7382
7523
|
forwardButtonLabel: 'Next',
|
|
7383
7524
|
}, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, defaultDate, defaultTime, }) {
|
|
7384
|
-
console.
|
|
7525
|
+
console.debug('[DateTimePicker] Component initialized with props:', {
|
|
7385
7526
|
value,
|
|
7386
7527
|
format,
|
|
7387
7528
|
showSeconds,
|
|
@@ -7400,13 +7541,13 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7400
7541
|
const [selectedDate, setSelectedDate] = React.useState(getDateString(value));
|
|
7401
7542
|
// Helper to get time values from value prop with timezone
|
|
7402
7543
|
const getTimeFromValue = React.useCallback((val) => {
|
|
7403
|
-
console.
|
|
7544
|
+
console.debug('[DateTimePicker] getTimeFromValue called:', {
|
|
7404
7545
|
val,
|
|
7405
7546
|
timezone,
|
|
7406
7547
|
showSeconds,
|
|
7407
7548
|
});
|
|
7408
7549
|
if (!val) {
|
|
7409
|
-
console.
|
|
7550
|
+
console.debug('[DateTimePicker] No value provided, returning nulls');
|
|
7410
7551
|
return {
|
|
7411
7552
|
hour12: null,
|
|
7412
7553
|
minute: null,
|
|
@@ -7416,7 +7557,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7416
7557
|
};
|
|
7417
7558
|
}
|
|
7418
7559
|
const dateObj = dayjs(val).tz(timezone);
|
|
7419
|
-
console.
|
|
7560
|
+
console.debug('[DateTimePicker] Parsed date object:', {
|
|
7420
7561
|
original: val,
|
|
7421
7562
|
timezone,
|
|
7422
7563
|
isValid: dateObj.isValid(),
|
|
@@ -7426,7 +7567,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7426
7567
|
second: dateObj.second(),
|
|
7427
7568
|
});
|
|
7428
7569
|
if (!dateObj.isValid()) {
|
|
7429
|
-
console.
|
|
7570
|
+
console.debug('[DateTimePicker] Invalid date object, returning nulls');
|
|
7430
7571
|
return {
|
|
7431
7572
|
hour12: null,
|
|
7432
7573
|
minute: null,
|
|
@@ -7447,11 +7588,11 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7447
7588
|
hour24: hour24Value,
|
|
7448
7589
|
second: secondValue,
|
|
7449
7590
|
};
|
|
7450
|
-
console.
|
|
7591
|
+
console.debug('[DateTimePicker] Extracted time values:', result);
|
|
7451
7592
|
return result;
|
|
7452
7593
|
}, [timezone, showSeconds]);
|
|
7453
7594
|
const initialTime = getTimeFromValue(value);
|
|
7454
|
-
console.
|
|
7595
|
+
console.debug('[DateTimePicker] Initial time from value:', {
|
|
7455
7596
|
value,
|
|
7456
7597
|
initialTime,
|
|
7457
7598
|
});
|
|
@@ -7528,14 +7669,14 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7528
7669
|
const [second, setSecond] = React.useState(initialTimeValues.second);
|
|
7529
7670
|
// Sync selectedDate and time states when value prop changes
|
|
7530
7671
|
React.useEffect(() => {
|
|
7531
|
-
console.
|
|
7672
|
+
console.debug('[DateTimePicker] useEffect triggered - value changed:', {
|
|
7532
7673
|
value,
|
|
7533
7674
|
timezone,
|
|
7534
7675
|
format,
|
|
7535
7676
|
});
|
|
7536
7677
|
// If value is null, undefined, or invalid, clear date but keep default time values
|
|
7537
7678
|
if (!value || value === null || value === undefined) {
|
|
7538
|
-
console.
|
|
7679
|
+
console.debug('[DateTimePicker] Value is null/undefined, clearing date but keeping default time');
|
|
7539
7680
|
setSelectedDate('');
|
|
7540
7681
|
// Keep default time values instead of clearing them
|
|
7541
7682
|
if (format === 'iso-date-time') {
|
|
@@ -7557,7 +7698,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7557
7698
|
// Check if value is valid
|
|
7558
7699
|
const dateObj = dayjs(value).tz(timezone);
|
|
7559
7700
|
if (!dateObj.isValid()) {
|
|
7560
|
-
console.
|
|
7701
|
+
console.debug('[DateTimePicker] Invalid value, clearing date but keeping default time');
|
|
7561
7702
|
setSelectedDate('');
|
|
7562
7703
|
// Keep default time values instead of clearing them
|
|
7563
7704
|
if (format === 'iso-date-time') {
|
|
@@ -7577,10 +7718,10 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7577
7718
|
return;
|
|
7578
7719
|
}
|
|
7579
7720
|
const dateString = getDateString(value);
|
|
7580
|
-
console.
|
|
7721
|
+
console.debug('[DateTimePicker] Setting selectedDate:', dateString);
|
|
7581
7722
|
setSelectedDate(dateString);
|
|
7582
7723
|
const timeData = getTimeFromValue(value);
|
|
7583
|
-
console.
|
|
7724
|
+
console.debug('[DateTimePicker] Updating time states:', {
|
|
7584
7725
|
timeData,
|
|
7585
7726
|
});
|
|
7586
7727
|
setHour12(timeData.hour12);
|
|
@@ -7590,7 +7731,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7590
7731
|
setSecond(timeData.second);
|
|
7591
7732
|
}, [value, getTimeFromValue, getDateString, timezone]);
|
|
7592
7733
|
const handleDateChange = (date) => {
|
|
7593
|
-
console.
|
|
7734
|
+
console.debug('[DateTimePicker] handleDateChange called:', {
|
|
7594
7735
|
date,
|
|
7595
7736
|
timezone,
|
|
7596
7737
|
showSeconds,
|
|
@@ -7598,7 +7739,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7598
7739
|
});
|
|
7599
7740
|
// If date is empty or invalid, clear all fields
|
|
7600
7741
|
if (!date || date === '') {
|
|
7601
|
-
console.
|
|
7742
|
+
console.debug('[DateTimePicker] Empty date, clearing all fields');
|
|
7602
7743
|
setSelectedDate('');
|
|
7603
7744
|
setHour12(null);
|
|
7604
7745
|
setMinute(null);
|
|
@@ -7611,7 +7752,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7611
7752
|
setSelectedDate(date);
|
|
7612
7753
|
// Parse the date string (YYYY-MM-DD) in the specified timezone
|
|
7613
7754
|
const dateObj = dayjs.tz(date, timezone);
|
|
7614
|
-
console.
|
|
7755
|
+
console.debug('[DateTimePicker] Parsed date object:', {
|
|
7615
7756
|
date,
|
|
7616
7757
|
timezone,
|
|
7617
7758
|
isValid: dateObj.isValid(),
|
|
@@ -7637,7 +7778,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7637
7778
|
if (!hasTimeValues) {
|
|
7638
7779
|
// Use defaultTime if provided, otherwise default to 00:00
|
|
7639
7780
|
if (defaultTime) {
|
|
7640
|
-
console.
|
|
7781
|
+
console.debug('[DateTimePicker] No time values set, using defaultTime');
|
|
7641
7782
|
if (format === 'iso-date-time') {
|
|
7642
7783
|
const defaultTime24 = defaultTime;
|
|
7643
7784
|
setHour24(defaultTime24.hour ?? 0);
|
|
@@ -7664,7 +7805,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7664
7805
|
}
|
|
7665
7806
|
}
|
|
7666
7807
|
else {
|
|
7667
|
-
console.
|
|
7808
|
+
console.debug('[DateTimePicker] No time values set, defaulting to 00:00');
|
|
7668
7809
|
if (format === 'iso-date-time') {
|
|
7669
7810
|
setHour24(0);
|
|
7670
7811
|
setMinute(0);
|
|
@@ -7692,17 +7833,17 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7692
7833
|
// When showSeconds is false, ignore seconds from the date
|
|
7693
7834
|
if (!showSeconds) {
|
|
7694
7835
|
const dateWithoutSeconds = dateObj.second(0).millisecond(0).toISOString();
|
|
7695
|
-
console.
|
|
7836
|
+
console.debug('[DateTimePicker] Updating date without seconds:', dateWithoutSeconds);
|
|
7696
7837
|
updateDateTime(dateWithoutSeconds, timeDataToUse);
|
|
7697
7838
|
}
|
|
7698
7839
|
else {
|
|
7699
7840
|
const dateWithSeconds = dateObj.toISOString();
|
|
7700
|
-
console.
|
|
7841
|
+
console.debug('[DateTimePicker] Updating date with seconds:', dateWithSeconds);
|
|
7701
7842
|
updateDateTime(dateWithSeconds, timeDataToUse);
|
|
7702
7843
|
}
|
|
7703
7844
|
};
|
|
7704
7845
|
const handleTimeChange = (timeData) => {
|
|
7705
|
-
console.
|
|
7846
|
+
console.debug('[DateTimePicker] handleTimeChange called:', {
|
|
7706
7847
|
timeData,
|
|
7707
7848
|
format,
|
|
7708
7849
|
selectedDate,
|
|
@@ -7710,7 +7851,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7710
7851
|
});
|
|
7711
7852
|
if (format === 'iso-date-time') {
|
|
7712
7853
|
const data = timeData;
|
|
7713
|
-
console.
|
|
7854
|
+
console.debug('[DateTimePicker] ISO format - setting 24-hour time:', data);
|
|
7714
7855
|
setHour24(data.hour);
|
|
7715
7856
|
setMinute(data.minute);
|
|
7716
7857
|
if (showSeconds) {
|
|
@@ -7723,7 +7864,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7723
7864
|
}
|
|
7724
7865
|
else {
|
|
7725
7866
|
const data = timeData;
|
|
7726
|
-
console.
|
|
7867
|
+
console.debug('[DateTimePicker] 12-hour format - setting time:', data);
|
|
7727
7868
|
setHour12(data.hour);
|
|
7728
7869
|
setMinute(data.minute);
|
|
7729
7870
|
setMeridiem(data.meridiem);
|
|
@@ -7732,7 +7873,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7732
7873
|
if (!selectedDate || !dayjs(selectedDate).isValid()) {
|
|
7733
7874
|
// If effectiveDefaultDate is available, use it instead of clearing
|
|
7734
7875
|
if (effectiveDefaultDate && dayjs(effectiveDefaultDate).isValid()) {
|
|
7735
|
-
console.
|
|
7876
|
+
console.debug('[DateTimePicker] No valid selectedDate, using effectiveDefaultDate:', effectiveDefaultDate);
|
|
7736
7877
|
setSelectedDate(effectiveDefaultDate);
|
|
7737
7878
|
const dateObj = dayjs(effectiveDefaultDate).tz(timezone);
|
|
7738
7879
|
if (dateObj.isValid()) {
|
|
@@ -7751,7 +7892,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7751
7892
|
return;
|
|
7752
7893
|
}
|
|
7753
7894
|
else {
|
|
7754
|
-
console.
|
|
7895
|
+
console.debug('[DateTimePicker] No valid selectedDate and no effectiveDefaultDate, keeping time values but no date');
|
|
7755
7896
|
// Keep the time values that were just set, but don't set a date
|
|
7756
7897
|
// This should rarely happen as effectiveDefaultDate always defaults to today
|
|
7757
7898
|
setSelectedDate('');
|
|
@@ -7775,14 +7916,14 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7775
7916
|
}
|
|
7776
7917
|
};
|
|
7777
7918
|
const updateDateTime = (date, timeData) => {
|
|
7778
|
-
console.
|
|
7919
|
+
console.debug('[DateTimePicker] updateDateTime called:', {
|
|
7779
7920
|
date,
|
|
7780
7921
|
timeData,
|
|
7781
7922
|
format,
|
|
7782
7923
|
currentStates: { hour12, minute, meridiem, hour24, second },
|
|
7783
7924
|
});
|
|
7784
7925
|
if (!date || date === null || date === undefined) {
|
|
7785
|
-
console.
|
|
7926
|
+
console.debug('[DateTimePicker] No date provided, clearing all fields and calling onChange(undefined)');
|
|
7786
7927
|
setSelectedDate('');
|
|
7787
7928
|
setHour12(null);
|
|
7788
7929
|
setMinute(null);
|
|
@@ -7820,11 +7961,11 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7820
7961
|
: 0;
|
|
7821
7962
|
// If all time values are null, clear the value
|
|
7822
7963
|
if (h === null && m === null && (showSeconds ? s === null : true)) {
|
|
7823
|
-
console.
|
|
7964
|
+
console.debug('[DateTimePicker] All time values are null, clearing value');
|
|
7824
7965
|
onChange?.(undefined);
|
|
7825
7966
|
return;
|
|
7826
7967
|
}
|
|
7827
|
-
console.
|
|
7968
|
+
console.debug('[DateTimePicker] ISO format - setting time on date:', {
|
|
7828
7969
|
h,
|
|
7829
7970
|
m,
|
|
7830
7971
|
s,
|
|
@@ -7838,7 +7979,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7838
7979
|
}
|
|
7839
7980
|
else {
|
|
7840
7981
|
const data = timeData;
|
|
7841
|
-
console.
|
|
7982
|
+
console.debug('[DateTimePicker] Processing 12-hour format:', {
|
|
7842
7983
|
'data !== undefined': data !== undefined,
|
|
7843
7984
|
'data?.hour': data?.hour,
|
|
7844
7985
|
'data?.minute': data?.minute,
|
|
@@ -7851,14 +7992,14 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7851
7992
|
const h = data !== undefined ? data.hour : hour12;
|
|
7852
7993
|
const m = data !== undefined ? data.minute : minute;
|
|
7853
7994
|
const mer = data !== undefined ? data.meridiem : meridiem;
|
|
7854
|
-
console.
|
|
7995
|
+
console.debug('[DateTimePicker] Resolved time values:', { h, m, mer });
|
|
7855
7996
|
// If all time values are null, clear the value
|
|
7856
7997
|
if (h === null && m === null && mer === null) {
|
|
7857
|
-
console.
|
|
7998
|
+
console.debug('[DateTimePicker] All time values are null, clearing value');
|
|
7858
7999
|
onChange?.(undefined);
|
|
7859
8000
|
return;
|
|
7860
8001
|
}
|
|
7861
|
-
console.
|
|
8002
|
+
console.debug('[DateTimePicker] 12-hour format - converting time:', {
|
|
7862
8003
|
h,
|
|
7863
8004
|
m,
|
|
7864
8005
|
mer,
|
|
@@ -7869,7 +8010,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7869
8010
|
hour24 = 0;
|
|
7870
8011
|
else if (mer === 'pm' && h < 12)
|
|
7871
8012
|
hour24 = h + 12;
|
|
7872
|
-
console.
|
|
8013
|
+
console.debug('[DateTimePicker] Converted to 24-hour:', {
|
|
7873
8014
|
h,
|
|
7874
8015
|
mer,
|
|
7875
8016
|
hour24,
|
|
@@ -7877,7 +8018,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7877
8018
|
newDate.setHours(hour24);
|
|
7878
8019
|
}
|
|
7879
8020
|
else {
|
|
7880
|
-
console.
|
|
8021
|
+
console.debug('[DateTimePicker] Skipping hour update - h or mer is null:', {
|
|
7881
8022
|
h,
|
|
7882
8023
|
mer,
|
|
7883
8024
|
});
|
|
@@ -7886,12 +8027,12 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7886
8027
|
newDate.setMinutes(m);
|
|
7887
8028
|
}
|
|
7888
8029
|
else {
|
|
7889
|
-
console.
|
|
8030
|
+
console.debug('[DateTimePicker] Skipping minute update - m is null');
|
|
7890
8031
|
}
|
|
7891
8032
|
newDate.setSeconds(0);
|
|
7892
8033
|
}
|
|
7893
8034
|
const finalISO = dayjs(newDate).tz(timezone).toISOString();
|
|
7894
|
-
console.
|
|
8035
|
+
console.debug('[DateTimePicker] Final ISO string to emit:', {
|
|
7895
8036
|
newDate: newDate.toISOString(),
|
|
7896
8037
|
timezone,
|
|
7897
8038
|
finalISO,
|
|
@@ -7926,7 +8067,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7926
8067
|
: undefined;
|
|
7927
8068
|
// Log current state before render
|
|
7928
8069
|
React.useEffect(() => {
|
|
7929
|
-
console.
|
|
8070
|
+
console.debug('[DateTimePicker] Current state before render:', {
|
|
7930
8071
|
isISO,
|
|
7931
8072
|
hour12,
|
|
7932
8073
|
minute,
|
|
@@ -8186,7 +8327,7 @@ const BooleanViewer = ({ schema, column, prefix, }) => {
|
|
|
8186
8327
|
const value = watch(colLabel);
|
|
8187
8328
|
const formI18n = useFormI18n(column, prefix, schema);
|
|
8188
8329
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
8189
|
-
gridRow, children: [jsxRuntime.jsx(react.Text, { children: value ?
|
|
8330
|
+
gridRow, children: [jsxRuntime.jsx(react.Text, { children: value ? 'True' : 'False' }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
8190
8331
|
};
|
|
8191
8332
|
|
|
8192
8333
|
const CustomViewer = ({ column, schema, prefix }) => {
|
|
@@ -8225,16 +8366,15 @@ const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
|
8225
8366
|
const colLabel = formI18n.colLabel;
|
|
8226
8367
|
const watchEnum = watch(colLabel);
|
|
8227
8368
|
const watchEnums = (watch(colLabel) ?? []);
|
|
8369
|
+
const renderDisplayFunction = renderDisplay || defaultRenderDisplay;
|
|
8228
8370
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
8229
8371
|
gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 1, children: watchEnums.map((enumValue) => {
|
|
8230
8372
|
const item = enumValue;
|
|
8231
8373
|
if (item === undefined) {
|
|
8232
8374
|
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "undefined" });
|
|
8233
8375
|
}
|
|
8234
|
-
return (jsxRuntime.jsx(Tag, { size: "lg", children:
|
|
8235
|
-
|
|
8236
|
-
: formI18n.t(item) }, item));
|
|
8237
|
-
}) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
8376
|
+
return (jsxRuntime.jsx(Tag, { size: "lg", children: renderDisplayFunction(item) }, item));
|
|
8377
|
+
}) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: renderDisplayFunction(watchEnum) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
8238
8378
|
};
|
|
8239
8379
|
|
|
8240
8380
|
const FileViewer = ({ column, schema, prefix }) => {
|