@bsol-oss/react-datatable5 13.0.1-beta.6 → 13.0.1-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +66 -60
- package/dist/index.mjs +66 -60
- package/dist/types/components/Form/utils/useFormI18n.d.ts +14 -30
- package/package.json +1 -1
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
|
-
*
|
|
4460
|
-
*/
|
|
4461
|
-
required: (options) => {
|
|
4462
|
-
return translate.t(removeIndex(`${colLabel}.field_required`), options);
|
|
4463
|
-
},
|
|
4464
|
-
/**
|
|
4465
|
-
* Get text for any custom key relative to the field
|
|
4466
|
-
* Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
|
|
4467
|
-
*
|
|
4468
|
-
* @param key - The key suffix (e.g., 'add_more', 'total', etc.)
|
|
4469
|
-
* @param options - Optional options (e.g., defaultValue, interpolation variables)
|
|
4451
|
+
* Get the required error message from schema.errorMessages?.required.
|
|
4452
|
+
* Returns a helpful fallback message if not provided.
|
|
4470
4453
|
*/
|
|
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,21 +5089,37 @@ 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
|
|
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
|
+
// Debug log when renderDisplay is missing
|
|
5102
|
+
if (!renderDisplay) {
|
|
5103
|
+
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.`, {
|
|
5104
|
+
fieldName: column,
|
|
5105
|
+
colLabel,
|
|
5106
|
+
prefix,
|
|
5107
|
+
enumValues: dataList,
|
|
5108
|
+
});
|
|
5109
|
+
}
|
|
5093
5110
|
// Current value for combobox (array format)
|
|
5094
5111
|
const currentValue = isMultiple
|
|
5095
5112
|
? watchEnums.filter((val) => val != null && val !== '')
|
|
5096
5113
|
: watchEnum
|
|
5097
5114
|
? [watchEnum]
|
|
5098
5115
|
: [];
|
|
5099
|
-
// Transform enum data for combobox collection
|
|
5100
5116
|
const comboboxItems = React.useMemo(() => {
|
|
5101
5117
|
return dataList.map((item) => ({
|
|
5102
|
-
label:
|
|
5103
|
-
? String(renderDisplay(item))
|
|
5104
|
-
: formI18n.t(item),
|
|
5118
|
+
label: item, // Internal: used for search/filtering only
|
|
5105
5119
|
value: item,
|
|
5120
|
+
raw: item, // Passed to renderEnumValue for UI rendering
|
|
5106
5121
|
}));
|
|
5107
|
-
}, [dataList
|
|
5122
|
+
}, [dataList]);
|
|
5108
5123
|
// Use filter hook for combobox
|
|
5109
5124
|
const { contains } = react.useFilter({ sensitivity: 'base' });
|
|
5110
5125
|
// Create collection for combobox
|
|
@@ -5134,9 +5149,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
5134
5149
|
setValue(colLabel, details.value);
|
|
5135
5150
|
}
|
|
5136
5151
|
}, 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}`));
|
|
5152
|
+
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
5153
|
}) }) }) }));
|
|
5141
5154
|
}
|
|
5142
5155
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
@@ -5147,16 +5160,12 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
5147
5160
|
return (jsxRuntime.jsx(Tag, { size: "lg", closable: true, onClick: () => {
|
|
5148
5161
|
const newValue = currentValue.filter((val) => val !== enumValue);
|
|
5149
5162
|
setValue(colLabel, newValue);
|
|
5150
|
-
}, children:
|
|
5151
|
-
? renderDisplay(enumValue)
|
|
5152
|
-
: formI18n.t(enumValue) }, enumValue));
|
|
5163
|
+
}, children: renderEnumValue(enumValue) }, enumValue));
|
|
5153
5164
|
}) })), 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
5165
|
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5155
|
-
: undefined, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.Combobox.Input, { placeholder: enumPickerLabels?.typeToSearch ??
|
|
5166
|
+
: undefined, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.Combobox.Input, { placeholder: enumPickerLabels?.typeToSearch ?? 'Type to search' }), jsxRuntime.jsxs(react.Combobox.IndicatorGroup, { children: [!isMultiple && currentValue.length > 0 && (jsxRuntime.jsx(react.Combobox.ClearTrigger, { onClick: () => {
|
|
5156
5167
|
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}`))) }))] }) }) }))] })] }));
|
|
5168
|
+
} })), 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
5169
|
};
|
|
5161
5170
|
|
|
5162
5171
|
function isEnteringWindow(_ref) {
|
|
@@ -5771,7 +5780,7 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5771
5780
|
const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
|
|
5772
5781
|
setValue(colLabel, [...currentFiles, ...newFiles]);
|
|
5773
5782
|
}
|
|
5774
|
-
}, placeholder: filePickerLabels?.fileDropzone ??
|
|
5783
|
+
}, placeholder: filePickerLabels?.fileDropzone ?? 'Drop files here' }) }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
|
|
5775
5784
|
const fileIdentifier = getFileIdentifier(file, index);
|
|
5776
5785
|
const fileName = getFileName(file);
|
|
5777
5786
|
const fileSize = getFileSize(file);
|
|
@@ -5882,9 +5891,7 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5882
5891
|
}
|
|
5883
5892
|
};
|
|
5884
5893
|
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) => {
|
|
5894
|
+
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
5895
|
const file = fileMap.get(fileId);
|
|
5889
5896
|
const isImage = file
|
|
5890
5897
|
? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
|
|
@@ -8186,7 +8193,7 @@ const BooleanViewer = ({ schema, column, prefix, }) => {
|
|
|
8186
8193
|
const value = watch(colLabel);
|
|
8187
8194
|
const formI18n = useFormI18n(column, prefix, schema);
|
|
8188
8195
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
8189
|
-
gridRow, children: [jsxRuntime.jsx(react.Text, { children: value ?
|
|
8196
|
+
gridRow, children: [jsxRuntime.jsx(react.Text, { children: value ? 'True' : 'False' }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
8190
8197
|
};
|
|
8191
8198
|
|
|
8192
8199
|
const CustomViewer = ({ column, schema, prefix }) => {
|
|
@@ -8225,16 +8232,15 @@ const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
|
8225
8232
|
const colLabel = formI18n.colLabel;
|
|
8226
8233
|
const watchEnum = watch(colLabel);
|
|
8227
8234
|
const watchEnums = (watch(colLabel) ?? []);
|
|
8235
|
+
const renderDisplayFunction = renderDisplay || defaultRenderDisplay;
|
|
8228
8236
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
8229
8237
|
gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 1, children: watchEnums.map((enumValue) => {
|
|
8230
8238
|
const item = enumValue;
|
|
8231
8239
|
if (item === undefined) {
|
|
8232
8240
|
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "undefined" });
|
|
8233
8241
|
}
|
|
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() }))] }));
|
|
8242
|
+
return (jsxRuntime.jsx(Tag, { size: "lg", children: renderDisplayFunction(item) }, item));
|
|
8243
|
+
}) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: renderDisplayFunction(watchEnum) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
8238
8244
|
};
|
|
8239
8245
|
|
|
8240
8246
|
const FileViewer = ({ column, schema, prefix }) => {
|
package/dist/index.mjs
CHANGED
|
@@ -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
|
|
4382
|
-
* Automatically handles colLabel construction
|
|
4383
|
-
* Uses schema.title
|
|
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
|
|
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 (
|
|
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
|
|
4417
|
-
*
|
|
4408
|
+
* Get the field label from schema title property.
|
|
4409
|
+
* Logs a debug message if title is missing.
|
|
4418
4410
|
*/
|
|
4419
|
-
label: (
|
|
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
|
-
|
|
4427
|
+
// Return column name as fallback
|
|
4428
|
+
return column;
|
|
4436
4429
|
},
|
|
4437
4430
|
/**
|
|
4438
|
-
* Get the required error message
|
|
4439
|
-
*
|
|
4440
|
-
*/
|
|
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)
|
|
4431
|
+
* Get the required error message from schema.errorMessages?.required.
|
|
4432
|
+
* Returns a helpful fallback message if not provided.
|
|
4450
4433
|
*/
|
|
4451
|
-
|
|
4452
|
-
|
|
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,21 +5069,37 @@ 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
|
|
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
|
+
// Debug log when renderDisplay is missing
|
|
5082
|
+
if (!renderDisplay) {
|
|
5083
|
+
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.`, {
|
|
5084
|
+
fieldName: column,
|
|
5085
|
+
colLabel,
|
|
5086
|
+
prefix,
|
|
5087
|
+
enumValues: dataList,
|
|
5088
|
+
});
|
|
5089
|
+
}
|
|
5073
5090
|
// Current value for combobox (array format)
|
|
5074
5091
|
const currentValue = isMultiple
|
|
5075
5092
|
? watchEnums.filter((val) => val != null && val !== '')
|
|
5076
5093
|
: watchEnum
|
|
5077
5094
|
? [watchEnum]
|
|
5078
5095
|
: [];
|
|
5079
|
-
// Transform enum data for combobox collection
|
|
5080
5096
|
const comboboxItems = useMemo(() => {
|
|
5081
5097
|
return dataList.map((item) => ({
|
|
5082
|
-
label:
|
|
5083
|
-
? String(renderDisplay(item))
|
|
5084
|
-
: formI18n.t(item),
|
|
5098
|
+
label: item, // Internal: used for search/filtering only
|
|
5085
5099
|
value: item,
|
|
5100
|
+
raw: item, // Passed to renderEnumValue for UI rendering
|
|
5086
5101
|
}));
|
|
5087
|
-
}, [dataList
|
|
5102
|
+
}, [dataList]);
|
|
5088
5103
|
// Use filter hook for combobox
|
|
5089
5104
|
const { contains } = useFilter({ sensitivity: 'base' });
|
|
5090
5105
|
// Create collection for combobox
|
|
@@ -5114,9 +5129,7 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
5114
5129
|
setValue(colLabel, details.value);
|
|
5115
5130
|
}
|
|
5116
5131
|
}, 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:
|
|
5118
|
-
? renderDisplay(item)
|
|
5119
|
-
: formI18n.t(item) })] }, `${colLabel}-${item}`));
|
|
5132
|
+
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
5133
|
}) }) }) }));
|
|
5121
5134
|
}
|
|
5122
5135
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
@@ -5127,16 +5140,12 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
|
|
|
5127
5140
|
return (jsx(Tag, { size: "lg", closable: true, onClick: () => {
|
|
5128
5141
|
const newValue = currentValue.filter((val) => val !== enumValue);
|
|
5129
5142
|
setValue(colLabel, newValue);
|
|
5130
|
-
}, children:
|
|
5131
|
-
? renderDisplay(enumValue)
|
|
5132
|
-
: formI18n.t(enumValue) }, enumValue));
|
|
5143
|
+
}, children: renderEnumValue(enumValue) }, enumValue));
|
|
5133
5144
|
}) })), 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
5145
|
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5135
|
-
: undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: enumPickerLabels?.typeToSearch ??
|
|
5146
|
+
: undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: enumPickerLabels?.typeToSearch ?? 'Type to search' }), jsxs(Combobox.IndicatorGroup, { children: [!isMultiple && currentValue.length > 0 && (jsx(Combobox.ClearTrigger, { onClick: () => {
|
|
5136
5147
|
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 ??
|
|
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}`))) }))] }) }) }))] })] }));
|
|
5148
|
+
} })), 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
5149
|
};
|
|
5141
5150
|
|
|
5142
5151
|
function isEnteringWindow(_ref) {
|
|
@@ -5751,7 +5760,7 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5751
5760
|
const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
|
|
5752
5761
|
setValue(colLabel, [...currentFiles, ...newFiles]);
|
|
5753
5762
|
}
|
|
5754
|
-
}, placeholder: filePickerLabels?.fileDropzone ??
|
|
5763
|
+
}, placeholder: filePickerLabels?.fileDropzone ?? 'Drop files here' }) }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
|
|
5755
5764
|
const fileIdentifier = getFileIdentifier(file, index);
|
|
5756
5765
|
const fileName = getFileName(file);
|
|
5757
5766
|
const fileSize = getFileSize(file);
|
|
@@ -5862,9 +5871,7 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5862
5871
|
}
|
|
5863
5872
|
};
|
|
5864
5873
|
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) => {
|
|
5874
|
+
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
5875
|
const file = fileMap.get(fileId);
|
|
5869
5876
|
const isImage = file
|
|
5870
5877
|
? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
|
|
@@ -8166,7 +8173,7 @@ const BooleanViewer = ({ schema, column, prefix, }) => {
|
|
|
8166
8173
|
const value = watch(colLabel);
|
|
8167
8174
|
const formI18n = useFormI18n(column, prefix, schema);
|
|
8168
8175
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
8169
|
-
gridRow, children: [jsx(Text, { children: value ?
|
|
8176
|
+
gridRow, children: [jsx(Text, { children: value ? 'True' : 'False' }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
8170
8177
|
};
|
|
8171
8178
|
|
|
8172
8179
|
const CustomViewer = ({ column, schema, prefix }) => {
|
|
@@ -8205,16 +8212,15 @@ const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
|
8205
8212
|
const colLabel = formI18n.colLabel;
|
|
8206
8213
|
const watchEnum = watch(colLabel);
|
|
8207
8214
|
const watchEnums = (watch(colLabel) ?? []);
|
|
8215
|
+
const renderDisplayFunction = renderDisplay || defaultRenderDisplay;
|
|
8208
8216
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
8209
8217
|
gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: 'wrap', gap: 1, children: watchEnums.map((enumValue) => {
|
|
8210
8218
|
const item = enumValue;
|
|
8211
8219
|
if (item === undefined) {
|
|
8212
8220
|
return jsx(Fragment, { children: "undefined" });
|
|
8213
8221
|
}
|
|
8214
|
-
return (jsx(Tag, { size: "lg", children:
|
|
8215
|
-
|
|
8216
|
-
: formI18n.t(item) }, item));
|
|
8217
|
-
}) })), !isMultiple && jsx(Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
8222
|
+
return (jsx(Tag, { size: "lg", children: renderDisplayFunction(item) }, item));
|
|
8223
|
+
}) })), !isMultiple && jsx(Text, { children: renderDisplayFunction(watchEnum) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
8218
8224
|
};
|
|
8219
8225
|
|
|
8220
8226
|
const FileViewer = ({ column, schema, prefix }) => {
|
|
@@ -1,57 +1,41 @@
|
|
|
1
|
+
import { CustomJSONSchema7 } from '../components/types/CustomJSONSchema7';
|
|
1
2
|
/**
|
|
2
|
-
* Custom hook for form field labels
|
|
3
|
-
* Automatically handles colLabel construction
|
|
4
|
-
* Uses schema.title
|
|
3
|
+
* Custom hook for form field labels.
|
|
4
|
+
* Automatically handles colLabel construction.
|
|
5
|
+
* Uses schema.title for labels and schema.errorMessages for error messages.
|
|
5
6
|
*
|
|
6
7
|
* @param column - The column name
|
|
7
8
|
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
8
|
-
* @param schema - Required schema object with title
|
|
9
|
+
* @param schema - Required schema object with title and errorMessages properties
|
|
9
10
|
* @returns Object with label helper functions
|
|
10
11
|
*
|
|
11
12
|
* @example
|
|
12
13
|
* ```tsx
|
|
13
14
|
* const formI18n = useFormI18n(column, prefix, schema);
|
|
14
15
|
*
|
|
15
|
-
* // Get field label (
|
|
16
|
+
* // Get field label (from schema.title)
|
|
16
17
|
* <Field label={formI18n.label()} />
|
|
17
18
|
*
|
|
18
|
-
* // Get required error message
|
|
19
|
+
* // Get required error message (from schema.errorMessages?.required)
|
|
19
20
|
* <Text>{formI18n.required()}</Text>
|
|
20
21
|
*
|
|
21
|
-
* // Get custom text
|
|
22
|
-
* <Text>{formI18n.t('add_more')}</Text>
|
|
23
|
-
*
|
|
24
22
|
* // Access the raw colLabel
|
|
25
23
|
* const colLabel = formI18n.colLabel;
|
|
26
24
|
* ```
|
|
27
25
|
*/
|
|
28
|
-
export declare const useFormI18n: (column: string, prefix: string | undefined, schema: {
|
|
29
|
-
title?: string;
|
|
30
|
-
}) => {
|
|
26
|
+
export declare const useFormI18n: (column: string, prefix: string | undefined, schema: CustomJSONSchema7) => {
|
|
31
27
|
/**
|
|
32
28
|
* The constructed column label (prefix + column)
|
|
33
29
|
*/
|
|
34
30
|
colLabel: string;
|
|
35
31
|
/**
|
|
36
|
-
* Get the field label from schema title
|
|
37
|
-
*
|
|
38
|
-
*/
|
|
39
|
-
label: (options?: any) => string;
|
|
40
|
-
/**
|
|
41
|
-
* Get the required error message
|
|
42
|
-
* Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
|
|
43
|
-
*/
|
|
44
|
-
required: (options?: any) => string;
|
|
45
|
-
/**
|
|
46
|
-
* Get text for any custom key relative to the field
|
|
47
|
-
* Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
|
|
48
|
-
*
|
|
49
|
-
* @param key - The key suffix (e.g., 'add_more', 'total', etc.)
|
|
50
|
-
* @param options - Optional options (e.g., defaultValue, interpolation variables)
|
|
32
|
+
* Get the field label from schema title property.
|
|
33
|
+
* Logs a debug message if title is missing.
|
|
51
34
|
*/
|
|
52
|
-
|
|
35
|
+
label: () => string;
|
|
53
36
|
/**
|
|
54
|
-
*
|
|
37
|
+
* Get the required error message from schema.errorMessages?.required.
|
|
38
|
+
* Returns a helpful fallback message if not provided.
|
|
55
39
|
*/
|
|
56
|
-
|
|
40
|
+
required: () => string;
|
|
57
41
|
};
|