@bsol-oss/react-datatable5 13.0.1-beta.13 → 13.0.1-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts
CHANGED
|
@@ -130,8 +130,6 @@ interface TableControlsProps {
|
|
|
130
130
|
children?: ReactNode;
|
|
131
131
|
showGlobalFilter?: boolean;
|
|
132
132
|
showFilter?: boolean;
|
|
133
|
-
showFilterName?: boolean;
|
|
134
|
-
showFilterTags?: boolean;
|
|
135
133
|
showReload?: boolean;
|
|
136
134
|
showPagination?: boolean;
|
|
137
135
|
showPageSizeControl?: boolean;
|
|
@@ -149,7 +147,7 @@ interface TableControlsProps {
|
|
|
149
147
|
hasError?: boolean;
|
|
150
148
|
gridProps?: GridProps;
|
|
151
149
|
}
|
|
152
|
-
declare const TableControls: ({ fitTableWidth, fitTableHeight, children, showGlobalFilter, showFilter,
|
|
150
|
+
declare const TableControls: ({ fitTableWidth, fitTableHeight, children, showGlobalFilter, showFilter, showReload, showPagination, showPageSizeControl, showPageCountText, showView, filterTagsOptions, extraItems, loading, hasError, gridProps, }: TableControlsProps) => react_jsx_runtime.JSX.Element;
|
|
153
151
|
|
|
154
152
|
declare const TableFilter: () => react_jsx_runtime.JSX.Element;
|
|
155
153
|
|
package/dist/index.js
CHANGED
|
@@ -3198,52 +3198,55 @@ const TableSelector = () => {
|
|
|
3198
3198
|
}, "aria-label": 'reset selection', children: jsxRuntime.jsx(md.MdClear, {}) }))] }));
|
|
3199
3199
|
};
|
|
3200
3200
|
|
|
3201
|
+
const Tag = React__namespace.forwardRef(function Tag(props, ref) {
|
|
3202
|
+
const { startElement, endElement, onClose, closable = !!onClose, children, ...rest } = props;
|
|
3203
|
+
return (jsxRuntime.jsxs(react.Tag.Root, { ref: ref, ...rest, children: [startElement && (jsxRuntime.jsx(react.Tag.StartElement, { children: startElement })), jsxRuntime.jsx(react.Tag.Label, { children: children }), endElement && (jsxRuntime.jsx(react.Tag.EndElement, { children: endElement })), closable && (jsxRuntime.jsx(react.Tag.EndElement, { children: jsxRuntime.jsx(react.Tag.CloseTrigger, { onClick: onClose }) }))] }));
|
|
3204
|
+
});
|
|
3205
|
+
|
|
3201
3206
|
const Checkbox = React__namespace.forwardRef(function Checkbox(props, ref) {
|
|
3202
3207
|
const { icon, children, inputProps, rootRef, ...rest } = props;
|
|
3203
3208
|
return (jsxRuntime.jsxs(react.Checkbox.Root, { ref: rootRef, ...rest, children: [jsxRuntime.jsx(react.Checkbox.HiddenInput, { ref: ref, ...inputProps }), jsxRuntime.jsx(react.Checkbox.Control, { children: icon || jsxRuntime.jsx(react.Checkbox.Indicator, {}) }), children != null && (jsxRuntime.jsx(react.Checkbox.Label, { children: children }))] }));
|
|
3204
3209
|
});
|
|
3205
3210
|
|
|
3206
|
-
|
|
3207
|
-
const getColorForColumn = (id) => {
|
|
3208
|
-
const colors = [
|
|
3209
|
-
'blue',
|
|
3210
|
-
'green',
|
|
3211
|
-
'purple',
|
|
3212
|
-
'orange',
|
|
3213
|
-
'pink',
|
|
3214
|
-
'cyan',
|
|
3215
|
-
'teal',
|
|
3216
|
-
'red',
|
|
3217
|
-
];
|
|
3218
|
-
let hash = 0;
|
|
3219
|
-
for (let i = 0; i < id.length; i++) {
|
|
3220
|
-
hash = id.charCodeAt(i) + ((hash << 5) - hash);
|
|
3221
|
-
}
|
|
3222
|
-
return colors[Math.abs(hash) % colors.length];
|
|
3223
|
-
};
|
|
3224
|
-
const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant, colorPalette, }) => {
|
|
3225
|
-
const { table, tableLabel } = useDataTableContext();
|
|
3211
|
+
const ColumnFilterMenu = ({ displayName, filterOptions, filterVariant, colorPalette, value: controlledValue, onChange, labels, open: controlledOpen, onOpenChange, }) => {
|
|
3226
3212
|
const [searchTerm, setSearchTerm] = React.useState('');
|
|
3227
3213
|
const debouncedSearchTerm = usehooks.useDebounce(searchTerm, 300);
|
|
3228
|
-
const [
|
|
3229
|
-
|
|
3230
|
-
const
|
|
3231
|
-
const
|
|
3232
|
-
|
|
3233
|
-
|
|
3214
|
+
const [internalOpen, setInternalOpen] = React.useState(false);
|
|
3215
|
+
// Use controlled open state if provided, otherwise use internal state
|
|
3216
|
+
const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;
|
|
3217
|
+
const handleOpenChange = (details) => {
|
|
3218
|
+
if (onOpenChange) {
|
|
3219
|
+
onOpenChange(details.open);
|
|
3220
|
+
}
|
|
3221
|
+
else {
|
|
3222
|
+
setInternalOpen(details.open);
|
|
3223
|
+
}
|
|
3224
|
+
};
|
|
3225
|
+
const [internalValue, setInternalValue] = React.useState(undefined);
|
|
3226
|
+
// Use controlled value if provided, otherwise use internal state
|
|
3227
|
+
const currentFilterValue = controlledValue !== undefined ? controlledValue : internalValue;
|
|
3234
3228
|
const isArrayFilter = filterVariant === 'tag';
|
|
3235
|
-
//
|
|
3229
|
+
// Default labels
|
|
3230
|
+
const defaultLabels = {
|
|
3231
|
+
filterByLabel: 'Filter by',
|
|
3232
|
+
filterLabelsPlaceholder: 'Filter labels',
|
|
3233
|
+
noFiltersMatchText: 'No filters match your search',
|
|
3234
|
+
};
|
|
3235
|
+
const finalLabels = { ...defaultLabels, ...labels };
|
|
3236
|
+
// Reset search term when menu closes
|
|
3236
3237
|
React.useEffect(() => {
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3238
|
+
if (!isOpen) {
|
|
3239
|
+
setSearchTerm('');
|
|
3240
|
+
}
|
|
3241
|
+
}, [isOpen]);
|
|
3242
|
+
// Filter update function
|
|
3243
|
+
const setFilterValue = (value) => {
|
|
3244
|
+
if (onChange) {
|
|
3245
|
+
onChange(value);
|
|
3246
|
+
}
|
|
3247
|
+
else {
|
|
3248
|
+
setInternalValue(value);
|
|
3249
|
+
}
|
|
3247
3250
|
};
|
|
3248
3251
|
// Get active count for this column
|
|
3249
3252
|
const activeCount = React.useMemo(() => {
|
|
@@ -3262,9 +3265,7 @@ const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant,
|
|
|
3262
3265
|
const searchLower = debouncedSearchTerm.toLowerCase();
|
|
3263
3266
|
return filterOptions.filter((option) => option.label.toLowerCase().includes(searchLower));
|
|
3264
3267
|
}, [filterOptions, debouncedSearchTerm]);
|
|
3265
|
-
|
|
3266
|
-
return null;
|
|
3267
|
-
return (jsxRuntime.jsxs(MenuRoot, { open: isOpen, onOpenChange: (details) => setIsOpen(details.open), children: [jsxRuntime.jsx(MenuTrigger, { asChild: true, children: jsxRuntime.jsxs(react.Button, { variant: "outline", size: "sm", gap: 2, children: [jsxRuntime.jsx(react.Icon, { as: md.MdFilterList }), jsxRuntime.jsxs(react.Text, { children: [displayName, " ", activeCount > 0 && `(${activeCount})`] })] }) }), jsxRuntime.jsx(MenuContent, { maxW: "20rem", minW: "18rem", children: jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 2, p: 2, children: [jsxRuntime.jsxs(react.Heading, { size: "sm", px: 2, children: [tableLabel.filterByLabel, " ", displayName] }), jsxRuntime.jsx(InputGroup, { startElement: jsxRuntime.jsx(react.Icon, { as: md.MdSearch }), children: jsxRuntime.jsx(react.Input, { placeholder: tableLabel.filterLabelsPlaceholder, value: searchTerm, onChange: (e) => setSearchTerm(e.target.value) }) }), jsxRuntime.jsx(react.Box, { maxH: "20rem", overflowY: "auto", css: {
|
|
3268
|
+
return (jsxRuntime.jsxs(MenuRoot, { open: isOpen, onOpenChange: handleOpenChange, children: [jsxRuntime.jsx(MenuTrigger, { asChild: true, children: jsxRuntime.jsxs(react.Button, { variant: "outline", size: "sm", gap: 2, children: [jsxRuntime.jsx(react.Icon, { as: md.MdFilterList }), jsxRuntime.jsxs(react.Text, { children: [displayName, " ", activeCount > 0 && `(${activeCount})`] })] }) }), jsxRuntime.jsx(MenuContent, { maxW: "20rem", minW: "18rem", children: jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 2, p: 2, children: [jsxRuntime.jsxs(react.Heading, { size: "sm", px: 2, children: [finalLabels.filterByLabel, " ", displayName] }), jsxRuntime.jsx(InputGroup, { startElement: jsxRuntime.jsx(react.Icon, { as: md.MdSearch }), children: jsxRuntime.jsx(react.Input, { placeholder: finalLabels.filterLabelsPlaceholder, value: searchTerm, onChange: (e) => setSearchTerm(e.target.value) }) }), jsxRuntime.jsx(react.Box, { maxH: "20rem", overflowY: "auto", css: {
|
|
3268
3269
|
'&::-webkit-scrollbar': {
|
|
3269
3270
|
width: '8px',
|
|
3270
3271
|
},
|
|
@@ -3278,7 +3279,7 @@ const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant,
|
|
|
3278
3279
|
'&::-webkit-scrollbar-thumb:hover': {
|
|
3279
3280
|
background: 'var(--chakra-colors-border-subtle)',
|
|
3280
3281
|
},
|
|
3281
|
-
}, children: jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 1, children: filteredOptions.length === 0 ? (jsxRuntime.jsx(react.Text, { px: 2, py: 4, color: "fg.muted", textAlign: "center", children:
|
|
3282
|
+
}, children: jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 1, children: filteredOptions.length === 0 ? (jsxRuntime.jsx(react.Text, { px: 2, py: 4, color: "fg.muted", textAlign: "center", children: finalLabels.noFiltersMatchText })) : (filteredOptions.map((option) => {
|
|
3282
3283
|
const isActive = isArrayFilter
|
|
3283
3284
|
? currentFilterValue?.includes(option.value) ?? false
|
|
3284
3285
|
: currentFilterValue === option.value;
|
|
@@ -3290,29 +3291,26 @@ const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant,
|
|
|
3290
3291
|
// Remove from filter
|
|
3291
3292
|
const newArray = currentArray.filter((v) => v !== option.value);
|
|
3292
3293
|
if (newArray.length === 0) {
|
|
3293
|
-
|
|
3294
|
+
setFilterValue(undefined);
|
|
3294
3295
|
}
|
|
3295
3296
|
else {
|
|
3296
|
-
|
|
3297
|
+
setFilterValue(newArray);
|
|
3297
3298
|
}
|
|
3298
3299
|
}
|
|
3299
3300
|
else {
|
|
3300
3301
|
// Add to filter
|
|
3301
3302
|
if (!currentArray.includes(option.value)) {
|
|
3302
|
-
|
|
3303
|
-
...currentArray,
|
|
3304
|
-
option.value,
|
|
3305
|
-
]);
|
|
3303
|
+
setFilterValue([...currentArray, option.value]);
|
|
3306
3304
|
}
|
|
3307
3305
|
}
|
|
3308
3306
|
}
|
|
3309
3307
|
else {
|
|
3310
3308
|
// Handle single value filters (select variant)
|
|
3311
3309
|
if (isActive) {
|
|
3312
|
-
|
|
3310
|
+
setFilterValue(undefined);
|
|
3313
3311
|
}
|
|
3314
3312
|
else {
|
|
3315
|
-
|
|
3313
|
+
setFilterValue(option.value);
|
|
3316
3314
|
}
|
|
3317
3315
|
}
|
|
3318
3316
|
};
|
|
@@ -3327,7 +3325,7 @@ const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant,
|
|
|
3327
3325
|
if (details.checked) {
|
|
3328
3326
|
// Add to filter
|
|
3329
3327
|
if (!currentArray.includes(option.value)) {
|
|
3330
|
-
|
|
3328
|
+
setFilterValue([
|
|
3331
3329
|
...currentArray,
|
|
3332
3330
|
option.value,
|
|
3333
3331
|
]);
|
|
@@ -3337,27 +3335,46 @@ const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant,
|
|
|
3337
3335
|
// Remove from filter
|
|
3338
3336
|
const newArray = currentArray.filter((v) => v !== option.value);
|
|
3339
3337
|
if (newArray.length === 0) {
|
|
3340
|
-
|
|
3338
|
+
setFilterValue(undefined);
|
|
3341
3339
|
}
|
|
3342
3340
|
else {
|
|
3343
|
-
|
|
3341
|
+
setFilterValue(newArray);
|
|
3344
3342
|
}
|
|
3345
3343
|
}
|
|
3346
3344
|
}
|
|
3347
3345
|
else {
|
|
3348
3346
|
// Handle single value filters (select variant)
|
|
3349
3347
|
if (details.checked) {
|
|
3350
|
-
|
|
3348
|
+
setFilterValue(option.value);
|
|
3351
3349
|
}
|
|
3352
3350
|
else {
|
|
3353
|
-
|
|
3351
|
+
setFilterValue(undefined);
|
|
3354
3352
|
}
|
|
3355
3353
|
}
|
|
3356
3354
|
} }) }), jsxRuntime.jsx(react.Box, { flex: 1, minW: 0, children: jsxRuntime.jsxs(react.HStack, { gap: 2, align: "center", children: [jsxRuntime.jsx(react.Box, { w: 3, h: 3, borderRadius: "full", bg: `${colorPalette}.500`, flexShrink: 0 }), jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "medium", truncate: true, children: option.label })] }) })] }) }, option.value));
|
|
3357
3355
|
})) }) })] }) })] }));
|
|
3358
3356
|
};
|
|
3357
|
+
|
|
3358
|
+
// Generate a color based on column id for visual distinction
|
|
3359
|
+
const getColorForColumn = (id) => {
|
|
3360
|
+
const colors = [
|
|
3361
|
+
'blue',
|
|
3362
|
+
'green',
|
|
3363
|
+
'purple',
|
|
3364
|
+
'orange',
|
|
3365
|
+
'pink',
|
|
3366
|
+
'cyan',
|
|
3367
|
+
'teal',
|
|
3368
|
+
'red',
|
|
3369
|
+
];
|
|
3370
|
+
let hash = 0;
|
|
3371
|
+
for (let i = 0; i < id.length; i++) {
|
|
3372
|
+
hash = id.charCodeAt(i) + ((hash << 5) - hash);
|
|
3373
|
+
}
|
|
3374
|
+
return colors[Math.abs(hash) % colors.length];
|
|
3375
|
+
};
|
|
3359
3376
|
const TableFilterTags = ({ filterTagsOptions = [], } = {}) => {
|
|
3360
|
-
const { table } = useDataTableContext();
|
|
3377
|
+
const { table, tableLabel } = useDataTableContext();
|
|
3361
3378
|
// Get columns from filterTagsOptions
|
|
3362
3379
|
const columnsWithFilters = React.useMemo(() => {
|
|
3363
3380
|
if (filterTagsOptions.length === 0) {
|
|
@@ -3372,26 +3389,91 @@ const TableFilterTags = ({ filterTagsOptions = [], } = {}) => {
|
|
|
3372
3389
|
const meta = column.columnDef.meta;
|
|
3373
3390
|
const displayName = meta?.displayName ?? column.id;
|
|
3374
3391
|
const filterVariant = meta?.filterVariant;
|
|
3392
|
+
if (!column) {
|
|
3393
|
+
return null;
|
|
3394
|
+
}
|
|
3375
3395
|
return {
|
|
3376
3396
|
columnId: option.column,
|
|
3377
3397
|
displayName,
|
|
3378
3398
|
filterOptions: option.options,
|
|
3379
|
-
filterVariant: filterVariant === 'tag' ? 'tag' : 'select',
|
|
3399
|
+
filterVariant: (filterVariant === 'tag' ? 'tag' : 'select'),
|
|
3380
3400
|
colorPalette: getColorForColumn(option.column),
|
|
3401
|
+
column,
|
|
3381
3402
|
};
|
|
3382
3403
|
})
|
|
3383
|
-
.filter((col) => col !== null);
|
|
3404
|
+
.filter((col) => col !== null && col.column !== null && col.column !== undefined);
|
|
3384
3405
|
}, [table, filterTagsOptions]);
|
|
3385
3406
|
if (columnsWithFilters.length === 0) {
|
|
3386
3407
|
return null;
|
|
3387
3408
|
}
|
|
3388
|
-
return (jsxRuntime.jsx(react.Flex, { gap: 2, flexWrap: "wrap", children: columnsWithFilters.map((column) =>
|
|
3409
|
+
return (jsxRuntime.jsx(react.Flex, { gap: 2, flexWrap: "wrap", children: columnsWithFilters.map((column) => {
|
|
3410
|
+
const filterValue = column.column.getFilterValue();
|
|
3411
|
+
return (jsxRuntime.jsx(ColumnFilterMenu, { displayName: column.displayName, filterOptions: column.filterOptions, filterVariant: column.filterVariant, colorPalette: column.colorPalette, value: filterValue, onChange: (value) => column.column.setFilterValue(value), labels: {
|
|
3412
|
+
filterByLabel: tableLabel.filterByLabel,
|
|
3413
|
+
filterLabelsPlaceholder: tableLabel.filterLabelsPlaceholder,
|
|
3414
|
+
noFiltersMatchText: tableLabel.noFiltersMatchText,
|
|
3415
|
+
} }, column.columnId));
|
|
3416
|
+
}) }));
|
|
3389
3417
|
};
|
|
3390
3418
|
|
|
3391
|
-
const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsxRuntime.jsx(jsxRuntime.Fragment, {}), showGlobalFilter = false, showFilter = false,
|
|
3392
|
-
const { tableLabel, table } = useDataTableContext();
|
|
3419
|
+
const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsxRuntime.jsx(jsxRuntime.Fragment, {}), showGlobalFilter = false, showFilter = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterTagsOptions = [], extraItems = jsxRuntime.jsx(jsxRuntime.Fragment, {}), loading = false, hasError = false, gridProps = {}, }) => {
|
|
3420
|
+
const { tableLabel, table, columnFilters, setColumnFilters } = useDataTableContext();
|
|
3393
3421
|
const { hasErrorText } = tableLabel;
|
|
3394
|
-
|
|
3422
|
+
// Get applied filters with display information
|
|
3423
|
+
const appliedFilters = React.useMemo(() => {
|
|
3424
|
+
return columnFilters
|
|
3425
|
+
.map((filter) => {
|
|
3426
|
+
const column = table.getColumn(filter.id);
|
|
3427
|
+
if (!column)
|
|
3428
|
+
return null;
|
|
3429
|
+
const meta = column.columnDef.meta;
|
|
3430
|
+
const displayName = meta?.displayName ?? filter.id;
|
|
3431
|
+
const filterValue = filter.value;
|
|
3432
|
+
// Handle array values (tag filters)
|
|
3433
|
+
if (Array.isArray(filterValue)) {
|
|
3434
|
+
return {
|
|
3435
|
+
columnId: filter.id,
|
|
3436
|
+
displayName,
|
|
3437
|
+
values: filterValue,
|
|
3438
|
+
isArray: true,
|
|
3439
|
+
};
|
|
3440
|
+
}
|
|
3441
|
+
// Handle single values (select filters)
|
|
3442
|
+
if (filterValue !== undefined &&
|
|
3443
|
+
filterValue !== null &&
|
|
3444
|
+
filterValue !== '') {
|
|
3445
|
+
return {
|
|
3446
|
+
columnId: filter.id,
|
|
3447
|
+
displayName,
|
|
3448
|
+
value: String(filterValue),
|
|
3449
|
+
isArray: false,
|
|
3450
|
+
};
|
|
3451
|
+
}
|
|
3452
|
+
return null;
|
|
3453
|
+
})
|
|
3454
|
+
.filter((filter) => filter !== null);
|
|
3455
|
+
}, [columnFilters, table]);
|
|
3456
|
+
const handleRemoveFilter = (columnId) => {
|
|
3457
|
+
setColumnFilters(columnFilters.filter((f) => f.id !== columnId));
|
|
3458
|
+
};
|
|
3459
|
+
return (jsxRuntime.jsxs(react.Grid, { templateRows: 'auto 1fr', width: fitTableWidth ? 'fit-content' : '100%', height: fitTableHeight ? 'fit-content' : '100%', gap: '0.5rem', p: 1, ...gridProps, children: [jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 2, children: jsxRuntime.jsxs(react.Flex, { justifyContent: 'space-between', children: [jsxRuntime.jsxs(react.Flex, { gap: 2, alignItems: 'center', flexWrap: 'wrap', children: [showView && jsxRuntime.jsx(ViewDialog, { icon: jsxRuntime.jsx(md.MdOutlineViewColumn, {}) }), appliedFilters.length > 0 && (jsxRuntime.jsx(react.Flex, { gap: 1.5, alignItems: 'center', flexWrap: 'wrap', children: appliedFilters.map((filter) => {
|
|
3460
|
+
if (filter.isArray) {
|
|
3461
|
+
return filter.values.map((value, index) => (jsxRuntime.jsxs(Tag, { size: "sm", colorPalette: "blue", onClose: () => {
|
|
3462
|
+
const column = table.getColumn(filter.columnId);
|
|
3463
|
+
if (column) {
|
|
3464
|
+
const currentValue = column.getFilterValue() ?? [];
|
|
3465
|
+
const newValue = currentValue.filter((v) => v !== value);
|
|
3466
|
+
if (newValue.length === 0) {
|
|
3467
|
+
handleRemoveFilter(filter.columnId);
|
|
3468
|
+
}
|
|
3469
|
+
else {
|
|
3470
|
+
column.setFilterValue(newValue);
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
}, children: [filter.displayName, ": ", value] }, `${filter.columnId}-${value}-${index}`)));
|
|
3474
|
+
}
|
|
3475
|
+
return (jsxRuntime.jsxs(Tag, { size: "sm", colorPalette: "blue", onClose: () => handleRemoveFilter(filter.columnId), children: [filter.displayName, ": ", filter.value] }, filter.columnId));
|
|
3476
|
+
}) }))] }), jsxRuntime.jsxs(react.Flex, { gap: '0.5rem', alignItems: 'center', justifySelf: 'end', children: [loading && jsxRuntime.jsx(react.Spinner, { size: 'sm' }), hasError && (jsxRuntime.jsx(Tooltip, { content: hasErrorText, children: jsxRuntime.jsx(react.Icon, { as: bs.BsExclamationCircleFill, color: 'red.400' }) })), showGlobalFilter && jsxRuntime.jsx(GlobalFilter, {}), filterTagsOptions.length > 0 && (jsxRuntime.jsx(TableFilterTags, { filterTagsOptions: filterTagsOptions })), showFilter && jsxRuntime.jsx(FilterDialog, {}), showReload && jsxRuntime.jsx(ReloadButton, {}), extraItems] })] }) }), jsxRuntime.jsx(react.Grid, { children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxRuntime.jsxs(react.Flex, { justifyContent: 'space-between', children: [jsxRuntime.jsxs(react.Flex, { gap: '1rem', alignItems: 'center', children: [showPageSizeControl && jsxRuntime.jsx(PageSizeControl, {}), showPageCountText && jsxRuntime.jsx(RowCountText, {})] }), jsxRuntime.jsx(react.Box, { justifySelf: 'end', children: showPagination && jsxRuntime.jsx(Pagination, {}) })] }))] }));
|
|
3395
3477
|
};
|
|
3396
3478
|
|
|
3397
3479
|
const EmptyState$1 = React__namespace.forwardRef(function EmptyState(props, ref) {
|
|
@@ -3959,11 +4041,6 @@ label, containerProps = {}, textProps = {}, children, }) => {
|
|
|
3959
4041
|
return (jsxRuntime.jsx(react.Box, { textOverflow: "ellipsis", whiteSpace: "nowrap", wordBreak: "break-all", overflow: "auto", display: "flex", alignItems: "center", justifyContent: alignEnd ? 'flex-end' : undefined, height: "100%", textAlign: alignEnd ? 'right' : undefined, children: jsxRuntime.jsx(RenderValue, { text: displayValue, href: href, onClick: onClick, isCopyable: isCopyable, isBadge: isBadge, badgeColor: badgeColor, colorPalette: colorPalette, globalFilter: globalFilter, alignEnd: alignEnd }) }));
|
|
3960
4042
|
};
|
|
3961
4043
|
|
|
3962
|
-
const Tag = React__namespace.forwardRef(function Tag(props, ref) {
|
|
3963
|
-
const { startElement, endElement, onClose, closable = !!onClose, children, ...rest } = props;
|
|
3964
|
-
return (jsxRuntime.jsxs(react.Tag.Root, { ref: ref, ...rest, children: [startElement && (jsxRuntime.jsx(react.Tag.StartElement, { children: startElement })), jsxRuntime.jsx(react.Tag.Label, { children: children }), endElement && (jsxRuntime.jsx(react.Tag.EndElement, { children: endElement })), closable && (jsxRuntime.jsx(react.Tag.EndElement, { children: jsxRuntime.jsx(react.Tag.CloseTrigger, { onClick: onClose }) }))] }));
|
|
3965
|
-
});
|
|
3966
|
-
|
|
3967
4044
|
const CardHeader = ({ row, imageColumnId = undefined, titleColumnId = undefined, tagColumnId = undefined, tagIcon = undefined, showTag = true, imageProps = {}, }) => {
|
|
3968
4045
|
if (!!row.original === false) {
|
|
3969
4046
|
return jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
@@ -6152,15 +6229,29 @@ const defaultRenderDisplay = (item) => {
|
|
|
6152
6229
|
for (const field of displayFields) {
|
|
6153
6230
|
if (obj[field] !== undefined && obj[field] !== null) {
|
|
6154
6231
|
const value = obj[field];
|
|
6155
|
-
// Return the value if it's a string or number
|
|
6232
|
+
// Return the value if it's a string or number
|
|
6156
6233
|
if (typeof value === 'string' || typeof value === 'number') {
|
|
6157
6234
|
return String(value);
|
|
6158
6235
|
}
|
|
6236
|
+
// If the value is an object, show warning and recommend custom renderDisplay
|
|
6237
|
+
if (typeof value === 'object' &&
|
|
6238
|
+
!Array.isArray(value) &&
|
|
6239
|
+
!(value instanceof Date)) {
|
|
6240
|
+
console.warn(`[CustomJSONSchema7] Display field "${field}" contains an object value. Consider providing a custom \`renderDisplay\` function in your schema to properly render this item. Field: ${field}, Value: ${JSON.stringify(value).substring(0, 100)}${JSON.stringify(value).length > 100 ? '...' : ''}`);
|
|
6241
|
+
// Still return the stringified value for now
|
|
6242
|
+
return JSON.stringify(value);
|
|
6243
|
+
}
|
|
6159
6244
|
}
|
|
6160
6245
|
}
|
|
6161
6246
|
// If no display field found, fall back to JSON.stringify
|
|
6162
6247
|
return JSON.stringify(item);
|
|
6163
6248
|
}
|
|
6249
|
+
// For strings that look like JSON, show warning and recommend custom renderDisplay
|
|
6250
|
+
if (typeof item === 'string' &&
|
|
6251
|
+
(item.trim().startsWith('{') || item.trim().startsWith('['))) {
|
|
6252
|
+
console.warn(`[CustomJSONSchema7] Item appears to be a JSON string. Consider providing a custom \`renderDisplay\` function in your schema to properly render this item. Current value: ${item.substring(0, 100)}${item.length > 100 ? '...' : ''}`);
|
|
6253
|
+
return item;
|
|
6254
|
+
}
|
|
6164
6255
|
// For non-objects (primitives, arrays, dates), use JSON.stringify
|
|
6165
6256
|
return JSON.stringify(item);
|
|
6166
6257
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, CheckboxCard as CheckboxCard$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, Tooltip as Tooltip$1, Group, InputElement, Checkbox as Checkbox$1, Icon, VStack, Heading, EmptyState as EmptyState$2, List, Table as Table$1, Card, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Clipboard, Badge, Link,
|
|
2
|
+
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, CheckboxCard as CheckboxCard$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, Tooltip as Tooltip$1, Group, InputElement, Tag as Tag$1, Checkbox as Checkbox$1, Icon, VStack, Heading, EmptyState as EmptyState$2, List, Table as Table$1, Card, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Clipboard, Badge, Link, Image, Alert, Field as Field$1, Popover, useFilter, useListCollection, Combobox, Tabs, useCombobox, Show, Skeleton, NumberInput, RadioCard, CheckboxGroup, Textarea as Textarea$1, InputGroup as InputGroup$1, Select, Center, Stack } from '@chakra-ui/react';
|
|
3
3
|
import { AiOutlineColumnWidth } from 'react-icons/ai';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { createContext, useContext, useState, useMemo, useCallback, useEffect, useRef } from 'react';
|
|
@@ -3178,52 +3178,55 @@ const TableSelector = () => {
|
|
|
3178
3178
|
}, "aria-label": 'reset selection', children: jsx(MdClear, {}) }))] }));
|
|
3179
3179
|
};
|
|
3180
3180
|
|
|
3181
|
+
const Tag = React.forwardRef(function Tag(props, ref) {
|
|
3182
|
+
const { startElement, endElement, onClose, closable = !!onClose, children, ...rest } = props;
|
|
3183
|
+
return (jsxs(Tag$1.Root, { ref: ref, ...rest, children: [startElement && (jsx(Tag$1.StartElement, { children: startElement })), jsx(Tag$1.Label, { children: children }), endElement && (jsx(Tag$1.EndElement, { children: endElement })), closable && (jsx(Tag$1.EndElement, { children: jsx(Tag$1.CloseTrigger, { onClick: onClose }) }))] }));
|
|
3184
|
+
});
|
|
3185
|
+
|
|
3181
3186
|
const Checkbox = React.forwardRef(function Checkbox(props, ref) {
|
|
3182
3187
|
const { icon, children, inputProps, rootRef, ...rest } = props;
|
|
3183
3188
|
return (jsxs(Checkbox$1.Root, { ref: rootRef, ...rest, children: [jsx(Checkbox$1.HiddenInput, { ref: ref, ...inputProps }), jsx(Checkbox$1.Control, { children: icon || jsx(Checkbox$1.Indicator, {}) }), children != null && (jsx(Checkbox$1.Label, { children: children }))] }));
|
|
3184
3189
|
});
|
|
3185
3190
|
|
|
3186
|
-
|
|
3187
|
-
const getColorForColumn = (id) => {
|
|
3188
|
-
const colors = [
|
|
3189
|
-
'blue',
|
|
3190
|
-
'green',
|
|
3191
|
-
'purple',
|
|
3192
|
-
'orange',
|
|
3193
|
-
'pink',
|
|
3194
|
-
'cyan',
|
|
3195
|
-
'teal',
|
|
3196
|
-
'red',
|
|
3197
|
-
];
|
|
3198
|
-
let hash = 0;
|
|
3199
|
-
for (let i = 0; i < id.length; i++) {
|
|
3200
|
-
hash = id.charCodeAt(i) + ((hash << 5) - hash);
|
|
3201
|
-
}
|
|
3202
|
-
return colors[Math.abs(hash) % colors.length];
|
|
3203
|
-
};
|
|
3204
|
-
const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant, colorPalette, }) => {
|
|
3205
|
-
const { table, tableLabel } = useDataTableContext();
|
|
3191
|
+
const ColumnFilterMenu = ({ displayName, filterOptions, filterVariant, colorPalette, value: controlledValue, onChange, labels, open: controlledOpen, onOpenChange, }) => {
|
|
3206
3192
|
const [searchTerm, setSearchTerm] = useState('');
|
|
3207
3193
|
const debouncedSearchTerm = useDebounce(searchTerm, 300);
|
|
3208
|
-
const [
|
|
3209
|
-
|
|
3210
|
-
const
|
|
3211
|
-
const
|
|
3212
|
-
|
|
3213
|
-
|
|
3194
|
+
const [internalOpen, setInternalOpen] = useState(false);
|
|
3195
|
+
// Use controlled open state if provided, otherwise use internal state
|
|
3196
|
+
const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;
|
|
3197
|
+
const handleOpenChange = (details) => {
|
|
3198
|
+
if (onOpenChange) {
|
|
3199
|
+
onOpenChange(details.open);
|
|
3200
|
+
}
|
|
3201
|
+
else {
|
|
3202
|
+
setInternalOpen(details.open);
|
|
3203
|
+
}
|
|
3204
|
+
};
|
|
3205
|
+
const [internalValue, setInternalValue] = useState(undefined);
|
|
3206
|
+
// Use controlled value if provided, otherwise use internal state
|
|
3207
|
+
const currentFilterValue = controlledValue !== undefined ? controlledValue : internalValue;
|
|
3214
3208
|
const isArrayFilter = filterVariant === 'tag';
|
|
3215
|
-
//
|
|
3209
|
+
// Default labels
|
|
3210
|
+
const defaultLabels = {
|
|
3211
|
+
filterByLabel: 'Filter by',
|
|
3212
|
+
filterLabelsPlaceholder: 'Filter labels',
|
|
3213
|
+
noFiltersMatchText: 'No filters match your search',
|
|
3214
|
+
};
|
|
3215
|
+
const finalLabels = { ...defaultLabels, ...labels };
|
|
3216
|
+
// Reset search term when menu closes
|
|
3216
3217
|
useEffect(() => {
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3218
|
+
if (!isOpen) {
|
|
3219
|
+
setSearchTerm('');
|
|
3220
|
+
}
|
|
3221
|
+
}, [isOpen]);
|
|
3222
|
+
// Filter update function
|
|
3223
|
+
const setFilterValue = (value) => {
|
|
3224
|
+
if (onChange) {
|
|
3225
|
+
onChange(value);
|
|
3226
|
+
}
|
|
3227
|
+
else {
|
|
3228
|
+
setInternalValue(value);
|
|
3229
|
+
}
|
|
3227
3230
|
};
|
|
3228
3231
|
// Get active count for this column
|
|
3229
3232
|
const activeCount = useMemo(() => {
|
|
@@ -3242,9 +3245,7 @@ const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant,
|
|
|
3242
3245
|
const searchLower = debouncedSearchTerm.toLowerCase();
|
|
3243
3246
|
return filterOptions.filter((option) => option.label.toLowerCase().includes(searchLower));
|
|
3244
3247
|
}, [filterOptions, debouncedSearchTerm]);
|
|
3245
|
-
|
|
3246
|
-
return null;
|
|
3247
|
-
return (jsxs(MenuRoot, { open: isOpen, onOpenChange: (details) => setIsOpen(details.open), children: [jsx(MenuTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", size: "sm", gap: 2, children: [jsx(Icon, { as: MdFilterList }), jsxs(Text, { children: [displayName, " ", activeCount > 0 && `(${activeCount})`] })] }) }), jsx(MenuContent, { maxW: "20rem", minW: "18rem", children: jsxs(VStack, { align: "stretch", gap: 2, p: 2, children: [jsxs(Heading, { size: "sm", px: 2, children: [tableLabel.filterByLabel, " ", displayName] }), jsx(InputGroup, { startElement: jsx(Icon, { as: MdSearch }), children: jsx(Input, { placeholder: tableLabel.filterLabelsPlaceholder, value: searchTerm, onChange: (e) => setSearchTerm(e.target.value) }) }), jsx(Box, { maxH: "20rem", overflowY: "auto", css: {
|
|
3248
|
+
return (jsxs(MenuRoot, { open: isOpen, onOpenChange: handleOpenChange, children: [jsx(MenuTrigger, { asChild: true, children: jsxs(Button$1, { variant: "outline", size: "sm", gap: 2, children: [jsx(Icon, { as: MdFilterList }), jsxs(Text, { children: [displayName, " ", activeCount > 0 && `(${activeCount})`] })] }) }), jsx(MenuContent, { maxW: "20rem", minW: "18rem", children: jsxs(VStack, { align: "stretch", gap: 2, p: 2, children: [jsxs(Heading, { size: "sm", px: 2, children: [finalLabels.filterByLabel, " ", displayName] }), jsx(InputGroup, { startElement: jsx(Icon, { as: MdSearch }), children: jsx(Input, { placeholder: finalLabels.filterLabelsPlaceholder, value: searchTerm, onChange: (e) => setSearchTerm(e.target.value) }) }), jsx(Box, { maxH: "20rem", overflowY: "auto", css: {
|
|
3248
3249
|
'&::-webkit-scrollbar': {
|
|
3249
3250
|
width: '8px',
|
|
3250
3251
|
},
|
|
@@ -3258,7 +3259,7 @@ const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant,
|
|
|
3258
3259
|
'&::-webkit-scrollbar-thumb:hover': {
|
|
3259
3260
|
background: 'var(--chakra-colors-border-subtle)',
|
|
3260
3261
|
},
|
|
3261
|
-
}, children: jsx(VStack, { align: "stretch", gap: 1, children: filteredOptions.length === 0 ? (jsx(Text, { px: 2, py: 4, color: "fg.muted", textAlign: "center", children:
|
|
3262
|
+
}, children: jsx(VStack, { align: "stretch", gap: 1, children: filteredOptions.length === 0 ? (jsx(Text, { px: 2, py: 4, color: "fg.muted", textAlign: "center", children: finalLabels.noFiltersMatchText })) : (filteredOptions.map((option) => {
|
|
3262
3263
|
const isActive = isArrayFilter
|
|
3263
3264
|
? currentFilterValue?.includes(option.value) ?? false
|
|
3264
3265
|
: currentFilterValue === option.value;
|
|
@@ -3270,29 +3271,26 @@ const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant,
|
|
|
3270
3271
|
// Remove from filter
|
|
3271
3272
|
const newArray = currentArray.filter((v) => v !== option.value);
|
|
3272
3273
|
if (newArray.length === 0) {
|
|
3273
|
-
|
|
3274
|
+
setFilterValue(undefined);
|
|
3274
3275
|
}
|
|
3275
3276
|
else {
|
|
3276
|
-
|
|
3277
|
+
setFilterValue(newArray);
|
|
3277
3278
|
}
|
|
3278
3279
|
}
|
|
3279
3280
|
else {
|
|
3280
3281
|
// Add to filter
|
|
3281
3282
|
if (!currentArray.includes(option.value)) {
|
|
3282
|
-
|
|
3283
|
-
...currentArray,
|
|
3284
|
-
option.value,
|
|
3285
|
-
]);
|
|
3283
|
+
setFilterValue([...currentArray, option.value]);
|
|
3286
3284
|
}
|
|
3287
3285
|
}
|
|
3288
3286
|
}
|
|
3289
3287
|
else {
|
|
3290
3288
|
// Handle single value filters (select variant)
|
|
3291
3289
|
if (isActive) {
|
|
3292
|
-
|
|
3290
|
+
setFilterValue(undefined);
|
|
3293
3291
|
}
|
|
3294
3292
|
else {
|
|
3295
|
-
|
|
3293
|
+
setFilterValue(option.value);
|
|
3296
3294
|
}
|
|
3297
3295
|
}
|
|
3298
3296
|
};
|
|
@@ -3307,7 +3305,7 @@ const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant,
|
|
|
3307
3305
|
if (details.checked) {
|
|
3308
3306
|
// Add to filter
|
|
3309
3307
|
if (!currentArray.includes(option.value)) {
|
|
3310
|
-
|
|
3308
|
+
setFilterValue([
|
|
3311
3309
|
...currentArray,
|
|
3312
3310
|
option.value,
|
|
3313
3311
|
]);
|
|
@@ -3317,27 +3315,46 @@ const ColumnFilterMenu = ({ columnId, displayName, filterOptions, filterVariant,
|
|
|
3317
3315
|
// Remove from filter
|
|
3318
3316
|
const newArray = currentArray.filter((v) => v !== option.value);
|
|
3319
3317
|
if (newArray.length === 0) {
|
|
3320
|
-
|
|
3318
|
+
setFilterValue(undefined);
|
|
3321
3319
|
}
|
|
3322
3320
|
else {
|
|
3323
|
-
|
|
3321
|
+
setFilterValue(newArray);
|
|
3324
3322
|
}
|
|
3325
3323
|
}
|
|
3326
3324
|
}
|
|
3327
3325
|
else {
|
|
3328
3326
|
// Handle single value filters (select variant)
|
|
3329
3327
|
if (details.checked) {
|
|
3330
|
-
|
|
3328
|
+
setFilterValue(option.value);
|
|
3331
3329
|
}
|
|
3332
3330
|
else {
|
|
3333
|
-
|
|
3331
|
+
setFilterValue(undefined);
|
|
3334
3332
|
}
|
|
3335
3333
|
}
|
|
3336
3334
|
} }) }), jsx(Box, { flex: 1, minW: 0, children: jsxs(HStack, { gap: 2, align: "center", children: [jsx(Box, { w: 3, h: 3, borderRadius: "full", bg: `${colorPalette}.500`, flexShrink: 0 }), jsx(Text, { fontSize: "sm", fontWeight: "medium", truncate: true, children: option.label })] }) })] }) }, option.value));
|
|
3337
3335
|
})) }) })] }) })] }));
|
|
3338
3336
|
};
|
|
3337
|
+
|
|
3338
|
+
// Generate a color based on column id for visual distinction
|
|
3339
|
+
const getColorForColumn = (id) => {
|
|
3340
|
+
const colors = [
|
|
3341
|
+
'blue',
|
|
3342
|
+
'green',
|
|
3343
|
+
'purple',
|
|
3344
|
+
'orange',
|
|
3345
|
+
'pink',
|
|
3346
|
+
'cyan',
|
|
3347
|
+
'teal',
|
|
3348
|
+
'red',
|
|
3349
|
+
];
|
|
3350
|
+
let hash = 0;
|
|
3351
|
+
for (let i = 0; i < id.length; i++) {
|
|
3352
|
+
hash = id.charCodeAt(i) + ((hash << 5) - hash);
|
|
3353
|
+
}
|
|
3354
|
+
return colors[Math.abs(hash) % colors.length];
|
|
3355
|
+
};
|
|
3339
3356
|
const TableFilterTags = ({ filterTagsOptions = [], } = {}) => {
|
|
3340
|
-
const { table } = useDataTableContext();
|
|
3357
|
+
const { table, tableLabel } = useDataTableContext();
|
|
3341
3358
|
// Get columns from filterTagsOptions
|
|
3342
3359
|
const columnsWithFilters = useMemo(() => {
|
|
3343
3360
|
if (filterTagsOptions.length === 0) {
|
|
@@ -3352,26 +3369,91 @@ const TableFilterTags = ({ filterTagsOptions = [], } = {}) => {
|
|
|
3352
3369
|
const meta = column.columnDef.meta;
|
|
3353
3370
|
const displayName = meta?.displayName ?? column.id;
|
|
3354
3371
|
const filterVariant = meta?.filterVariant;
|
|
3372
|
+
if (!column) {
|
|
3373
|
+
return null;
|
|
3374
|
+
}
|
|
3355
3375
|
return {
|
|
3356
3376
|
columnId: option.column,
|
|
3357
3377
|
displayName,
|
|
3358
3378
|
filterOptions: option.options,
|
|
3359
|
-
filterVariant: filterVariant === 'tag' ? 'tag' : 'select',
|
|
3379
|
+
filterVariant: (filterVariant === 'tag' ? 'tag' : 'select'),
|
|
3360
3380
|
colorPalette: getColorForColumn(option.column),
|
|
3381
|
+
column,
|
|
3361
3382
|
};
|
|
3362
3383
|
})
|
|
3363
|
-
.filter((col) => col !== null);
|
|
3384
|
+
.filter((col) => col !== null && col.column !== null && col.column !== undefined);
|
|
3364
3385
|
}, [table, filterTagsOptions]);
|
|
3365
3386
|
if (columnsWithFilters.length === 0) {
|
|
3366
3387
|
return null;
|
|
3367
3388
|
}
|
|
3368
|
-
return (jsx(Flex, { gap: 2, flexWrap: "wrap", children: columnsWithFilters.map((column) =>
|
|
3389
|
+
return (jsx(Flex, { gap: 2, flexWrap: "wrap", children: columnsWithFilters.map((column) => {
|
|
3390
|
+
const filterValue = column.column.getFilterValue();
|
|
3391
|
+
return (jsx(ColumnFilterMenu, { displayName: column.displayName, filterOptions: column.filterOptions, filterVariant: column.filterVariant, colorPalette: column.colorPalette, value: filterValue, onChange: (value) => column.column.setFilterValue(value), labels: {
|
|
3392
|
+
filterByLabel: tableLabel.filterByLabel,
|
|
3393
|
+
filterLabelsPlaceholder: tableLabel.filterLabelsPlaceholder,
|
|
3394
|
+
noFiltersMatchText: tableLabel.noFiltersMatchText,
|
|
3395
|
+
} }, column.columnId));
|
|
3396
|
+
}) }));
|
|
3369
3397
|
};
|
|
3370
3398
|
|
|
3371
|
-
const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsx(Fragment, {}), showGlobalFilter = false, showFilter = false,
|
|
3372
|
-
const { tableLabel, table } = useDataTableContext();
|
|
3399
|
+
const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsx(Fragment, {}), showGlobalFilter = false, showFilter = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterTagsOptions = [], extraItems = jsx(Fragment, {}), loading = false, hasError = false, gridProps = {}, }) => {
|
|
3400
|
+
const { tableLabel, table, columnFilters, setColumnFilters } = useDataTableContext();
|
|
3373
3401
|
const { hasErrorText } = tableLabel;
|
|
3374
|
-
|
|
3402
|
+
// Get applied filters with display information
|
|
3403
|
+
const appliedFilters = useMemo(() => {
|
|
3404
|
+
return columnFilters
|
|
3405
|
+
.map((filter) => {
|
|
3406
|
+
const column = table.getColumn(filter.id);
|
|
3407
|
+
if (!column)
|
|
3408
|
+
return null;
|
|
3409
|
+
const meta = column.columnDef.meta;
|
|
3410
|
+
const displayName = meta?.displayName ?? filter.id;
|
|
3411
|
+
const filterValue = filter.value;
|
|
3412
|
+
// Handle array values (tag filters)
|
|
3413
|
+
if (Array.isArray(filterValue)) {
|
|
3414
|
+
return {
|
|
3415
|
+
columnId: filter.id,
|
|
3416
|
+
displayName,
|
|
3417
|
+
values: filterValue,
|
|
3418
|
+
isArray: true,
|
|
3419
|
+
};
|
|
3420
|
+
}
|
|
3421
|
+
// Handle single values (select filters)
|
|
3422
|
+
if (filterValue !== undefined &&
|
|
3423
|
+
filterValue !== null &&
|
|
3424
|
+
filterValue !== '') {
|
|
3425
|
+
return {
|
|
3426
|
+
columnId: filter.id,
|
|
3427
|
+
displayName,
|
|
3428
|
+
value: String(filterValue),
|
|
3429
|
+
isArray: false,
|
|
3430
|
+
};
|
|
3431
|
+
}
|
|
3432
|
+
return null;
|
|
3433
|
+
})
|
|
3434
|
+
.filter((filter) => filter !== null);
|
|
3435
|
+
}, [columnFilters, table]);
|
|
3436
|
+
const handleRemoveFilter = (columnId) => {
|
|
3437
|
+
setColumnFilters(columnFilters.filter((f) => f.id !== columnId));
|
|
3438
|
+
};
|
|
3439
|
+
return (jsxs(Grid, { templateRows: 'auto 1fr', width: fitTableWidth ? 'fit-content' : '100%', height: fitTableHeight ? 'fit-content' : '100%', gap: '0.5rem', p: 1, ...gridProps, children: [jsx(Flex, { flexFlow: 'column', gap: 2, children: jsxs(Flex, { justifyContent: 'space-between', children: [jsxs(Flex, { gap: 2, alignItems: 'center', flexWrap: 'wrap', children: [showView && jsx(ViewDialog, { icon: jsx(MdOutlineViewColumn, {}) }), appliedFilters.length > 0 && (jsx(Flex, { gap: 1.5, alignItems: 'center', flexWrap: 'wrap', children: appliedFilters.map((filter) => {
|
|
3440
|
+
if (filter.isArray) {
|
|
3441
|
+
return filter.values.map((value, index) => (jsxs(Tag, { size: "sm", colorPalette: "blue", onClose: () => {
|
|
3442
|
+
const column = table.getColumn(filter.columnId);
|
|
3443
|
+
if (column) {
|
|
3444
|
+
const currentValue = column.getFilterValue() ?? [];
|
|
3445
|
+
const newValue = currentValue.filter((v) => v !== value);
|
|
3446
|
+
if (newValue.length === 0) {
|
|
3447
|
+
handleRemoveFilter(filter.columnId);
|
|
3448
|
+
}
|
|
3449
|
+
else {
|
|
3450
|
+
column.setFilterValue(newValue);
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
}, children: [filter.displayName, ": ", value] }, `${filter.columnId}-${value}-${index}`)));
|
|
3454
|
+
}
|
|
3455
|
+
return (jsxs(Tag, { size: "sm", colorPalette: "blue", onClose: () => handleRemoveFilter(filter.columnId), children: [filter.displayName, ": ", filter.value] }, filter.columnId));
|
|
3456
|
+
}) }))] }), jsxs(Flex, { gap: '0.5rem', alignItems: 'center', justifySelf: 'end', children: [loading && jsx(Spinner, { size: 'sm' }), hasError && (jsx(Tooltip, { content: hasErrorText, children: jsx(Icon, { as: BsExclamationCircleFill, color: 'red.400' }) })), showGlobalFilter && jsx(GlobalFilter, {}), filterTagsOptions.length > 0 && (jsx(TableFilterTags, { filterTagsOptions: filterTagsOptions })), showFilter && jsx(FilterDialog, {}), showReload && jsx(ReloadButton, {}), extraItems] })] }) }), jsx(Grid, { children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxs(Flex, { justifyContent: 'space-between', children: [jsxs(Flex, { gap: '1rem', alignItems: 'center', children: [showPageSizeControl && jsx(PageSizeControl, {}), showPageCountText && jsx(RowCountText, {})] }), jsx(Box, { justifySelf: 'end', children: showPagination && jsx(Pagination, {}) })] }))] }));
|
|
3375
3457
|
};
|
|
3376
3458
|
|
|
3377
3459
|
const EmptyState$1 = React.forwardRef(function EmptyState(props, ref) {
|
|
@@ -3939,11 +4021,6 @@ label, containerProps = {}, textProps = {}, children, }) => {
|
|
|
3939
4021
|
return (jsx(Box, { textOverflow: "ellipsis", whiteSpace: "nowrap", wordBreak: "break-all", overflow: "auto", display: "flex", alignItems: "center", justifyContent: alignEnd ? 'flex-end' : undefined, height: "100%", textAlign: alignEnd ? 'right' : undefined, children: jsx(RenderValue, { text: displayValue, href: href, onClick: onClick, isCopyable: isCopyable, isBadge: isBadge, badgeColor: badgeColor, colorPalette: colorPalette, globalFilter: globalFilter, alignEnd: alignEnd }) }));
|
|
3940
4022
|
};
|
|
3941
4023
|
|
|
3942
|
-
const Tag = React.forwardRef(function Tag(props, ref) {
|
|
3943
|
-
const { startElement, endElement, onClose, closable = !!onClose, children, ...rest } = props;
|
|
3944
|
-
return (jsxs(Tag$1.Root, { ref: ref, ...rest, children: [startElement && (jsx(Tag$1.StartElement, { children: startElement })), jsx(Tag$1.Label, { children: children }), endElement && (jsx(Tag$1.EndElement, { children: endElement })), closable && (jsx(Tag$1.EndElement, { children: jsx(Tag$1.CloseTrigger, { onClick: onClose }) }))] }));
|
|
3945
|
-
});
|
|
3946
|
-
|
|
3947
4024
|
const CardHeader = ({ row, imageColumnId = undefined, titleColumnId = undefined, tagColumnId = undefined, tagIcon = undefined, showTag = true, imageProps = {}, }) => {
|
|
3948
4025
|
if (!!row.original === false) {
|
|
3949
4026
|
return jsx(Fragment, {});
|
|
@@ -6132,15 +6209,29 @@ const defaultRenderDisplay = (item) => {
|
|
|
6132
6209
|
for (const field of displayFields) {
|
|
6133
6210
|
if (obj[field] !== undefined && obj[field] !== null) {
|
|
6134
6211
|
const value = obj[field];
|
|
6135
|
-
// Return the value if it's a string or number
|
|
6212
|
+
// Return the value if it's a string or number
|
|
6136
6213
|
if (typeof value === 'string' || typeof value === 'number') {
|
|
6137
6214
|
return String(value);
|
|
6138
6215
|
}
|
|
6216
|
+
// If the value is an object, show warning and recommend custom renderDisplay
|
|
6217
|
+
if (typeof value === 'object' &&
|
|
6218
|
+
!Array.isArray(value) &&
|
|
6219
|
+
!(value instanceof Date)) {
|
|
6220
|
+
console.warn(`[CustomJSONSchema7] Display field "${field}" contains an object value. Consider providing a custom \`renderDisplay\` function in your schema to properly render this item. Field: ${field}, Value: ${JSON.stringify(value).substring(0, 100)}${JSON.stringify(value).length > 100 ? '...' : ''}`);
|
|
6221
|
+
// Still return the stringified value for now
|
|
6222
|
+
return JSON.stringify(value);
|
|
6223
|
+
}
|
|
6139
6224
|
}
|
|
6140
6225
|
}
|
|
6141
6226
|
// If no display field found, fall back to JSON.stringify
|
|
6142
6227
|
return JSON.stringify(item);
|
|
6143
6228
|
}
|
|
6229
|
+
// For strings that look like JSON, show warning and recommend custom renderDisplay
|
|
6230
|
+
if (typeof item === 'string' &&
|
|
6231
|
+
(item.trim().startsWith('{') || item.trim().startsWith('['))) {
|
|
6232
|
+
console.warn(`[CustomJSONSchema7] Item appears to be a JSON string. Consider providing a custom \`renderDisplay\` function in your schema to properly render this item. Current value: ${item.substring(0, 100)}${item.length > 100 ? '...' : ''}`);
|
|
6233
|
+
return item;
|
|
6234
|
+
}
|
|
6144
6235
|
// For non-objects (primitives, arrays, dates), use JSON.stringify
|
|
6145
6236
|
return JSON.stringify(item);
|
|
6146
6237
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ColumnFilterMenuLabels {
|
|
2
|
+
filterByLabel?: string;
|
|
3
|
+
filterLabelsPlaceholder?: string;
|
|
4
|
+
noFiltersMatchText?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ColumnFilterMenuProps {
|
|
7
|
+
displayName: string;
|
|
8
|
+
filterOptions: {
|
|
9
|
+
label: string;
|
|
10
|
+
value: string;
|
|
11
|
+
}[];
|
|
12
|
+
filterVariant?: 'select' | 'tag';
|
|
13
|
+
colorPalette: string;
|
|
14
|
+
value?: string[] | string | undefined;
|
|
15
|
+
onChange?: (value: string[] | string | undefined) => void;
|
|
16
|
+
labels?: ColumnFilterMenuLabels;
|
|
17
|
+
open?: boolean;
|
|
18
|
+
onOpenChange?: (open: boolean) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare const ColumnFilterMenu: ({ displayName, filterOptions, filterVariant, colorPalette, value: controlledValue, onChange, labels, open: controlledOpen, onOpenChange, }: ColumnFilterMenuProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -7,8 +7,6 @@ export interface TableControlsProps {
|
|
|
7
7
|
children?: ReactNode;
|
|
8
8
|
showGlobalFilter?: boolean;
|
|
9
9
|
showFilter?: boolean;
|
|
10
|
-
showFilterName?: boolean;
|
|
11
|
-
showFilterTags?: boolean;
|
|
12
10
|
showReload?: boolean;
|
|
13
11
|
showPagination?: boolean;
|
|
14
12
|
showPageSizeControl?: boolean;
|
|
@@ -26,4 +24,4 @@ export interface TableControlsProps {
|
|
|
26
24
|
hasError?: boolean;
|
|
27
25
|
gridProps?: GridProps;
|
|
28
26
|
}
|
|
29
|
-
export declare const TableControls: ({ fitTableWidth, fitTableHeight, children, showGlobalFilter, showFilter,
|
|
27
|
+
export declare const TableControls: ({ fitTableWidth, fitTableHeight, children, showGlobalFilter, showFilter, showReload, showPagination, showPageSizeControl, showPageCountText, showView, filterTagsOptions, extraItems, loading, hasError, gridProps, }: TableControlsProps) => import("react/jsx-runtime").JSX.Element;
|