@dbcdk/react-components 0.0.9 → 0.0.12
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/components/accordion/Accordion.d.ts +27 -0
- package/dist/components/accordion/Accordion.js +66 -0
- package/dist/components/accordion/Accordion.module.css +87 -0
- package/dist/components/button/Button.module.css +1 -0
- package/dist/components/card/Card.d.ts +21 -3
- package/dist/components/card/Card.js +17 -2
- package/dist/components/card/Card.module.css +59 -0
- package/dist/components/circle/Circle.d.ts +5 -1
- package/dist/components/circle/Circle.js +2 -2
- package/dist/components/circle/Circle.module.css +60 -4
- package/dist/components/code-block/CodeBlock.js +1 -1
- package/dist/components/code-block/CodeBlock.module.css +30 -17
- package/dist/components/copy-button/CopyButton.d.ts +1 -0
- package/dist/components/copy-button/CopyButton.js +10 -2
- package/dist/components/datetime-picker/DateTimePicker.d.ts +4 -8
- package/dist/components/datetime-picker/DateTimePicker.js +72 -92
- package/dist/components/datetime-picker/dateTimeHelpers.d.ts +14 -12
- package/dist/components/datetime-picker/dateTimeHelpers.js +25 -45
- package/dist/components/filter-field/FilterField.js +16 -11
- package/dist/components/filter-field/FilterField.module.css +133 -12
- package/dist/components/forms/checkbox/Checkbox.d.ts +4 -10
- package/dist/components/forms/checkbox/Checkbox.js +3 -5
- package/dist/components/forms/checkbox-group/CheckboxGroup.js +1 -1
- package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +1 -1
- package/dist/components/forms/input/Input.d.ts +1 -0
- package/dist/components/forms/input/Input.js +2 -4
- package/dist/components/forms/input/Input.module.css +10 -11
- package/dist/components/forms/input-container/InputContainer.d.ts +2 -1
- package/dist/components/forms/input-container/InputContainer.js +3 -3
- package/dist/components/forms/input-container/InputContainer.module.css +65 -0
- package/dist/components/forms/radio-buttons/RadioButton.d.ts +36 -0
- package/dist/components/forms/radio-buttons/RadioButton.js +26 -0
- package/dist/components/forms/radio-buttons/RadioButtonGroup.d.ts +25 -0
- package/dist/components/forms/radio-buttons/RadioButtonGroup.js +19 -0
- package/dist/components/forms/radio-buttons/RadioButtons.module.css +117 -0
- package/dist/components/forms/select/Select.d.ts +1 -1
- package/dist/components/forms/select/Select.js +3 -3
- package/dist/components/forms/text-area/Textarea.js +3 -3
- package/dist/components/forms/text-area/Textarea.module.css +8 -1
- package/dist/components/headline/Headline.d.ts +2 -7
- package/dist/components/headline/Headline.js +5 -2
- package/dist/components/headline/Headline.module.css +61 -2
- package/dist/components/hyperlink/Hyperlink.d.ts +19 -6
- package/dist/components/hyperlink/Hyperlink.js +35 -7
- package/dist/components/hyperlink/Hyperlink.module.css +50 -2
- package/dist/components/icon/Icon.module.css +1 -0
- package/dist/components/interval-select/IntervalSelect.js +1 -1
- package/dist/components/menu/Menu.d.ts +32 -0
- package/dist/components/menu/Menu.js +73 -13
- package/dist/components/menu/Menu.module.css +72 -4
- package/dist/components/nav-bar/NavBar.d.ts +24 -6
- package/dist/components/overlay/modal/Modal.module.css +2 -2
- package/dist/components/overlay/side-panel/SidePanel.d.ts +12 -4
- package/dist/components/overlay/side-panel/SidePanel.js +77 -4
- package/dist/components/overlay/side-panel/SidePanel.module.css +149 -28
- package/dist/components/overlay/side-panel/useSidePanel.d.ts +1 -1
- package/dist/components/overlay/side-panel/useSidePanel.js +2 -2
- package/dist/components/overlay/tooltip/useTooltipTrigger.js +4 -2
- package/dist/components/page-layout/PageLayout.js +0 -2
- package/dist/components/popover/Popover.js +1 -1
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.d.ts +5 -5
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +36 -24
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.module.css +0 -3
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.d.ts +3 -1
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +4 -3
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +109 -79
- package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +16 -3
- package/dist/components/sidebar/components/sidebar-items/SidebarItems.module.css +20 -0
- package/dist/components/sidebar/providers/SidebarProvider.d.ts +4 -1
- package/dist/components/sidebar/providers/SidebarProvider.js +85 -58
- package/dist/components/skeleton-loader/SkeletonLoader.d.ts +1 -1
- package/dist/components/skeleton-loader/SkeletonLoader.js +15 -12
- package/dist/components/split-button/SplitButton.d.ts +1 -1
- package/dist/components/split-button/SplitButton.js +3 -1
- package/dist/components/split-button/SplitButton.module.css +4 -4
- package/dist/components/state-page/StatePage.d.ts +9 -0
- package/dist/components/state-page/StatePage.js +20 -0
- package/dist/components/state-page/StatePage.module.css +9 -0
- package/dist/components/state-page/empty.d.ts +2 -0
- package/dist/components/state-page/empty.js +2 -0
- package/dist/components/state-page/error.d.ts +2 -0
- package/dist/components/state-page/error.js +2 -0
- package/dist/components/state-page/notFound.d.ts +2 -0
- package/dist/components/state-page/notFound.js +2 -0
- package/dist/components/sticky-footer-layout/StickyFooterLayout.d.ts +19 -0
- package/dist/components/sticky-footer-layout/StickyFooterLayout.js +27 -0
- package/dist/components/table/Table.d.ts +9 -4
- package/dist/components/table/Table.js +6 -9
- package/dist/components/table/Table.module.css +180 -59
- package/dist/components/table/components/empty-state/EmptyState.d.ts +1 -1
- package/dist/components/table/components/empty-state/EmptyState.js +6 -7
- package/dist/components/table/components/table-settings/TableSettings.d.ts +13 -3
- package/dist/components/table/components/table-settings/TableSettings.js +55 -4
- package/dist/components/table/tanstack.d.ts +12 -1
- package/dist/components/table/tanstack.js +75 -23
- package/dist/components/toast/Toast.js +5 -1
- package/dist/components/toast/Toast.module.css +40 -15
- package/dist/components/toast/provider/ToastProvider.js +1 -0
- package/dist/hooks/useTableSettings.d.ts +23 -4
- package/dist/hooks/useTableSettings.js +64 -17
- package/dist/hooks/useTimeDuration.js +9 -3
- package/dist/hooks/useViewportFill.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -1
- package/dist/src/styles/styles.css +60 -25
- package/dist/styles/animation.d.ts +5 -0
- package/dist/styles/animation.js +5 -0
- package/dist/styles/styles.css +60 -25
- package/dist/styles/themes/dbc/dark.css +1 -1
- package/dist/styles/themes/dbc/light.css +2 -1
- package/dist/utils/localStorage.utils.d.ts +19 -0
- package/dist/utils/localStorage.utils.js +78 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { JSX, ReactNode } from 'react';
|
|
2
|
+
import type { HTMLAttributes, JSX, ReactNode } from 'react';
|
|
3
3
|
import { Severity } from '../../constants/severity.types';
|
|
4
4
|
import { PageChangeEvent } from '../../components/pagination/Pagination';
|
|
5
5
|
import { ViewMode } from '../../hooks/useTableSettings';
|
|
@@ -19,13 +19,14 @@ export interface ColumnItem<T> {
|
|
|
19
19
|
allowWrap?: boolean;
|
|
20
20
|
emptyPlaceholder?: ReactNode;
|
|
21
21
|
width?: number | string;
|
|
22
|
+
canHide?: boolean;
|
|
22
23
|
}
|
|
23
24
|
type HeaderExtrasArgs<T> = {
|
|
24
25
|
column: ColumnItem<T>;
|
|
25
26
|
index: number;
|
|
26
27
|
};
|
|
27
28
|
export type TableVariant = 'primary' | 'embedded';
|
|
28
|
-
export
|
|
29
|
+
export type TableProps<T extends Record<string, any>> = Omit<HTMLAttributes<HTMLTableElement>, 'onClick'> & {
|
|
29
30
|
data: T[];
|
|
30
31
|
dataKey: keyof T;
|
|
31
32
|
columns: ColumnItem<T>[];
|
|
@@ -42,6 +43,10 @@ export interface TableProps<T extends Record<string, any>> {
|
|
|
42
43
|
headerExtras?: (args: HeaderExtrasArgs<T>) => ReactNode;
|
|
43
44
|
columnStyles?: Partial<Record<string, React.CSSProperties>>;
|
|
44
45
|
headerBelowRow?: ReactNode;
|
|
46
|
+
/**
|
|
47
|
+
* NEW: optional toolbar area above the table (right now used for column selector)
|
|
48
|
+
*/
|
|
49
|
+
toolbar?: ReactNode;
|
|
45
50
|
striped?: boolean;
|
|
46
51
|
fillViewport?: boolean;
|
|
47
52
|
viewportBottomOffset?: number;
|
|
@@ -58,6 +63,6 @@ export interface TableProps<T extends Record<string, any>> {
|
|
|
58
63
|
showFirstLast?: boolean;
|
|
59
64
|
viewMode?: ViewMode;
|
|
60
65
|
emptyConfig?: TableEmptyConfig;
|
|
61
|
-
}
|
|
62
|
-
export declare function Table<T extends Record<string, any>>({ data, columns, selectedRows, onRowSelect, selectionMode, onSortChange, onRowClick, sortById, sortDirection, dataKey, headerExtras, columnStyles, headerBelowRow, striped, fillViewport, viewportBottomOffset, viewportMin, viewportIncludeMarginTop, take, skip, paginationPlacement, totalItemsCount, onPageChange, loading, variant, size, getRowSeverity, showFirstLast, allRowsSelected, onSelectAllRows, viewMode, emptyConfig, }: TableProps<T>): JSX.Element;
|
|
66
|
+
} & Omit<HTMLAttributes<HTMLTableElement>, 'onClick'>;
|
|
67
|
+
export declare function Table<T extends Record<string, any>>({ data, columns, selectedRows, onRowSelect, selectionMode, onSortChange, onRowClick, sortById, sortDirection, dataKey, headerExtras, columnStyles, headerBelowRow, toolbar, striped, fillViewport, viewportBottomOffset, viewportMin, viewportIncludeMarginTop, take, skip, paginationPlacement, totalItemsCount, onPageChange, loading, variant, size, getRowSeverity, showFirstLast, allRowsSelected, onSelectAllRows, viewMode, emptyConfig, ...rest }: TableProps<T>): JSX.Element;
|
|
63
68
|
export {};
|
|
@@ -9,7 +9,7 @@ import { Pagination } from '../../components/pagination/Pagination';
|
|
|
9
9
|
import { SkeletonLoaderItem } from '../../components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem';
|
|
10
10
|
import { TableEmptyState } from './components/empty-state/EmptyState';
|
|
11
11
|
import styles from './Table.module.css';
|
|
12
|
-
export function Table({ data, columns, selectedRows, onRowSelect, selectionMode = 'single', onSortChange, onRowClick, sortById, sortDirection, dataKey, headerExtras, columnStyles, headerBelowRow, striped, fillViewport = false, viewportBottomOffset = 0, viewportMin = 120, viewportIncludeMarginTop = false, take, skip, paginationPlacement = 'bottom', totalItemsCount, onPageChange, loading, variant = 'primary', size = 'md', getRowSeverity, showFirstLast = false, allRowsSelected, onSelectAllRows, viewMode, emptyConfig, }) {
|
|
12
|
+
export function Table({ data, columns, selectedRows, onRowSelect, selectionMode = 'single', onSortChange, onRowClick, sortById, sortDirection, dataKey, headerExtras, columnStyles, headerBelowRow, toolbar, striped, fillViewport = false, viewportBottomOffset = 0, viewportMin = 120, viewportIncludeMarginTop = false, take, skip, paginationPlacement = 'bottom', totalItemsCount, onPageChange, loading, variant = 'primary', size = 'md', getRowSeverity, showFirstLast = false, allRowsSelected, onSelectAllRows, viewMode, emptyConfig, ...rest }) {
|
|
13
13
|
const filteredColumns = useMemo(() => columns.filter(c => !c.hidden), [columns]);
|
|
14
14
|
const handlePageChange = useCallback((e) => {
|
|
15
15
|
onPageChange === null || onPageChange === void 0 ? void 0 : onPageChange(e);
|
|
@@ -31,7 +31,7 @@ export function Table({ data, columns, selectedRows, onRowSelect, selectionMode
|
|
|
31
31
|
min: viewportMin,
|
|
32
32
|
includeMarginTop: viewportIncludeMarginTop,
|
|
33
33
|
});
|
|
34
|
-
const tableEl = (_jsxs(_Fragment, { children: [_jsxs("table", { className: `${styles.table} ${styles[variant]} ${styles[size]}`, children: [_jsxs("thead", { children: [_jsxs("tr", { children: [selectedRows && onRowSelect && dataKey && (_jsx("th", { className: `${styles.fitContent} ${styles.th}
|
|
34
|
+
const tableEl = (_jsxs(_Fragment, { children: [toolbar ? _jsx("div", { style: { marginBottom: 12 }, children: toolbar }) : null, _jsxs("table", { ...rest, className: `${styles.table} ${styles[variant]} ${styles[size]} ${getRowSeverity ? styles.severityTable : ''}`, children: [_jsxs("thead", { children: [_jsxs("tr", { children: [selectedRows && onRowSelect && dataKey && (_jsx("th", { className: `${styles.fitContent} ${styles.th} $`, children: selectionMode === 'multiple' ? (_jsx(Checkbox, { size: "sm", variant: "primary", checked: allRowsSelected, onChange: checked => onSelectAllRows === null || onSelectAllRows === void 0 ? void 0 : onSelectAllRows(checked) })) : null })), filteredColumns.map((column, index) => {
|
|
35
35
|
const isActiveSort = sortById === column.id;
|
|
36
36
|
const ariaSort = column.sortable && isActiveSort
|
|
37
37
|
? sortDirection === 'asc'
|
|
@@ -73,12 +73,9 @@ export function Table({ data, columns, selectedRows, onRowSelect, selectionMode
|
|
|
73
73
|
e.stopPropagation();
|
|
74
74
|
const isSelected = selectedRows.has(rowId);
|
|
75
75
|
if (selectionMode === 'single') {
|
|
76
|
-
// In single mode, treat modifier-click as "select this row"
|
|
77
|
-
// (toggle if already selected)
|
|
78
76
|
onRowSelect(rowId, !isSelected);
|
|
79
77
|
}
|
|
80
78
|
else {
|
|
81
|
-
// multiple mode: toggle selection
|
|
82
79
|
onRowSelect(rowId, !isSelected);
|
|
83
80
|
}
|
|
84
81
|
return;
|
|
@@ -88,11 +85,11 @@ export function Table({ data, columns, selectedRows, onRowSelect, selectionMode
|
|
|
88
85
|
['--row-severity-color']: rowSeverity
|
|
89
86
|
? SeverityBgColor[rowSeverity]
|
|
90
87
|
: undefined,
|
|
91
|
-
}, className: `${onRowClick ? styles.clickableRow : ''} ${(selectedRows === null || selectedRows === void 0 ? void 0 : selectedRows.has(row[dataKey])) ? styles.selectedRow : ''} ${rowSeverity ? styles.severity : ''}`, children: [selectedRows && onRowSelect && dataKey && (_jsx("td", { className:
|
|
88
|
+
}, className: `${onRowClick ? styles.clickableRow : ''} ${(selectedRows === null || selectedRows === void 0 ? void 0 : selectedRows.has(row[dataKey])) ? styles.selectedRow : ''} ${rowSeverity ? styles.severity : ''}`, children: [selectedRows && onRowSelect && dataKey && (_jsx("td", { className: `fitContent ${styles.selectionCell}`, onClick: e => e.stopPropagation(), children: _jsx(Checkbox, { variant: "primary", checked: selectedRows.has(row[dataKey]), size: "sm", onChange: () => onRowSelect === null || onRowSelect === void 0 ? void 0 : onRowSelect(row[dataKey], !selectedRows.has(row[dataKey])) }) })), filteredColumns.map(column => {
|
|
92
89
|
var _a, _b;
|
|
93
90
|
return (_jsx("td", { style: getColStyle(column.id, column.align, column.verticalAlign, column.width), className: `${styles.tableCell} ${column.fitContent ? 'fitContent' : ''} ${column.allowWrap ||
|
|
94
91
|
(selectedRows === null || selectedRows === void 0 ? void 0 : selectedRows.has(row[dataKey])) ||
|
|
95
|
-
viewMode === '
|
|
92
|
+
viewMode === 'wrapped'
|
|
96
93
|
? styles.allowWrap
|
|
97
94
|
: styles.nowrap} `, children: column.render
|
|
98
95
|
? column.render(row) || ((_a = column.emptyPlaceholder) !== null && _a !== void 0 ? _a : '')
|
|
@@ -108,7 +105,7 @@ export function Table({ data, columns, selectedRows, onRowSelect, selectionMode
|
|
|
108
105
|
gap: '20px',
|
|
109
106
|
flexFlow: paginationPlacement === 'top' ? 'column-reverse' : 'column',
|
|
110
107
|
position: 'relative',
|
|
111
|
-
}, children: [_jsx("div", { ref: scrollRef, style: viewportStyle, className: styles.tableScroll, children: tableEl }), onPageChange && (_jsx(Pagination, { itemsCount: totalItemsCount, take: take, skip: skip, onPageChange: handlePageChange, showFirstLast: showFirstLast }))] }));
|
|
108
|
+
}, children: [_jsx("div", { ref: scrollRef, style: viewportStyle, className: styles.tableScroll, children: tableEl }), onPageChange && data.length > 0 && (_jsx(Pagination, { itemsCount: totalItemsCount, take: take, skip: skip, onPageChange: handlePageChange, showFirstLast: showFirstLast }))] }));
|
|
112
109
|
}
|
|
113
110
|
return (_jsxs("div", { style: {
|
|
114
111
|
display: 'flex',
|
|
@@ -116,5 +113,5 @@ export function Table({ data, columns, selectedRows, onRowSelect, selectionMode
|
|
|
116
113
|
gap: '20px',
|
|
117
114
|
flexFlow: paginationPlacement === 'top' ? 'column-reverse' : 'column',
|
|
118
115
|
position: 'relative',
|
|
119
|
-
}, children: [tableEl, onPageChange && (_jsx(Pagination, { itemsCount: totalItemsCount, take: take, skip: skip, onPageChange: handlePageChange }))] }));
|
|
116
|
+
}, children: [tableEl, onPageChange && data.length > 0 && (_jsx(Pagination, { itemsCount: totalItemsCount, take: take, skip: skip, onPageChange: handlePageChange }))] }));
|
|
120
117
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/* =========================
|
|
2
|
+
Base table
|
|
3
|
+
========================= */
|
|
4
|
+
|
|
1
5
|
.table {
|
|
2
6
|
inline-size: 100%;
|
|
3
7
|
max-inline-size: 100%;
|
|
@@ -9,68 +13,64 @@
|
|
|
9
13
|
background: var(--color-bg-surface);
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
.tableScroll {
|
|
17
|
+
position: relative;
|
|
18
|
+
overflow: auto;
|
|
19
|
+
max-inline-size: 100%;
|
|
20
|
+
-webkit-overflow-scrolling: touch;
|
|
16
21
|
}
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
/* =========================
|
|
24
|
+
Header
|
|
25
|
+
========================= */
|
|
21
26
|
|
|
22
27
|
.table thead {
|
|
23
28
|
position: sticky;
|
|
24
29
|
inset-block-start: 0;
|
|
25
|
-
background-color: var(--color-bg-surface);
|
|
26
30
|
z-index: 10;
|
|
31
|
+
background-color: var(--color-bg-surface);
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
.table.primary thead {
|
|
30
35
|
box-shadow: var(--shadow-md);
|
|
31
36
|
}
|
|
32
37
|
|
|
33
|
-
.
|
|
34
|
-
|
|
35
|
-
}
|
|
38
|
+
.table .th {
|
|
39
|
+
position: relative;
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
+
padding-block: var(--spacing-xs);
|
|
42
|
+
padding-inline: var(--spacing-md);
|
|
43
|
+
padding-right: var(--spacing-lg);
|
|
41
44
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
+
text-align: left;
|
|
46
|
+
vertical-align: middle;
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
background-color: var(--color-bg-selected);
|
|
48
|
-
}
|
|
49
|
-
.selectedRow:hover {
|
|
50
|
-
background-color: var(--color-bg-selected-hover);
|
|
51
|
-
}
|
|
48
|
+
background: inherit;
|
|
52
49
|
|
|
53
|
-
|
|
50
|
+
/* Typography */
|
|
51
|
+
font-size: var(--font-size-xs);
|
|
52
|
+
font-weight: var(--font-weight-normal);
|
|
53
|
+
letter-spacing: var(--letter-spacing-wide);
|
|
54
|
+
text-transform: uppercase;
|
|
55
|
+
|
|
56
|
+
color: var(--color-fg-subtle);
|
|
57
|
+
|
|
58
|
+
/* Truncation */
|
|
54
59
|
white-space: nowrap;
|
|
55
60
|
overflow: hidden;
|
|
56
61
|
text-overflow: ellipsis;
|
|
62
|
+
|
|
63
|
+
/* Width control */
|
|
64
|
+
min-width: 0;
|
|
65
|
+
max-width: var(--card-label-width);
|
|
57
66
|
}
|
|
58
67
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
font-size: var(--font-size-xs);
|
|
62
|
-
font-weight: var(--font-weight-medium);
|
|
63
|
-
position: relative;
|
|
64
|
-
padding-block: var(--spacing-xs);
|
|
68
|
+
/* Small variant: header padding */
|
|
69
|
+
.table.sm .th {
|
|
65
70
|
padding-inline: var(--spacing-md);
|
|
66
|
-
text-align: start;
|
|
67
|
-
background: inherit;
|
|
68
|
-
white-space: nowrap;
|
|
69
|
-
min-width: unset;
|
|
70
|
-
max-width: unset;
|
|
71
|
-
vertical-align: middle;
|
|
72
71
|
}
|
|
73
72
|
|
|
73
|
+
/* Sortable header behavior */
|
|
74
74
|
.th.sortable {
|
|
75
75
|
cursor: pointer;
|
|
76
76
|
user-select: none;
|
|
@@ -78,10 +78,12 @@
|
|
|
78
78
|
background-color var(--transition-fast) var(--ease-standard),
|
|
79
79
|
color var(--transition-fast) var(--ease-standard);
|
|
80
80
|
}
|
|
81
|
+
|
|
81
82
|
.th.sortable:hover,
|
|
82
83
|
th.sortable:hover {
|
|
83
84
|
background-color: var(--color-bg-contextual);
|
|
84
85
|
}
|
|
86
|
+
|
|
85
87
|
.th.sortable:focus-visible,
|
|
86
88
|
th.sortable:focus-visible {
|
|
87
89
|
outline: none;
|
|
@@ -95,6 +97,7 @@ th.sortable:focus-visible {
|
|
|
95
97
|
.sortIndicator {
|
|
96
98
|
display: flex;
|
|
97
99
|
}
|
|
100
|
+
|
|
98
101
|
.sortIndicator svg {
|
|
99
102
|
inline-size: var(--icon-size-sm);
|
|
100
103
|
block-size: var(--icon-size-sm);
|
|
@@ -103,6 +106,7 @@ th.sortable:focus-visible {
|
|
|
103
106
|
.th > .thInner {
|
|
104
107
|
display: inline-block;
|
|
105
108
|
}
|
|
109
|
+
|
|
106
110
|
.th > .thInner > span {
|
|
107
111
|
display: inline-flex;
|
|
108
112
|
align-items: center;
|
|
@@ -110,53 +114,120 @@ th.sortable:focus-visible {
|
|
|
110
114
|
inline-size: 100%;
|
|
111
115
|
}
|
|
112
116
|
|
|
117
|
+
/* =========================
|
|
118
|
+
Body + cells
|
|
119
|
+
========================= */
|
|
120
|
+
|
|
113
121
|
.tBody::before {
|
|
114
122
|
content: '';
|
|
115
123
|
height: var(--spacing-xs);
|
|
116
124
|
display: block;
|
|
117
125
|
}
|
|
118
126
|
|
|
119
|
-
.tBody tr td
|
|
120
|
-
.tbody tr td {
|
|
127
|
+
.tBody tr td {
|
|
121
128
|
position: relative;
|
|
122
129
|
padding-block: var(--spacing-xs);
|
|
123
130
|
padding-inline: var(--spacing-sm);
|
|
131
|
+
|
|
124
132
|
border-block-end: var(--border-width-thin) solid var(--color-border-default);
|
|
133
|
+
|
|
125
134
|
text-align: start;
|
|
126
135
|
vertical-align: top;
|
|
136
|
+
|
|
127
137
|
overflow-wrap: break-word;
|
|
128
138
|
word-break: normal;
|
|
129
139
|
}
|
|
130
140
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
/* Small variant applies to all cells by default */
|
|
142
|
+
.table.sm .tBody tr td {
|
|
143
|
+
padding-block: var(--spacing-xxs);
|
|
144
|
+
padding-inline: var(--spacing-md);
|
|
145
|
+
font-size: var(--font-size-xs);
|
|
146
|
+
line-height: var(--line-height-normal);
|
|
136
147
|
}
|
|
137
148
|
|
|
138
|
-
|
|
139
|
-
|
|
149
|
+
/* =========================
|
|
150
|
+
Selection column
|
|
151
|
+
========================= */
|
|
152
|
+
|
|
153
|
+
/*
|
|
154
|
+
Default (no severity rails):
|
|
155
|
+
Remove ALL inline padding for selection/checkbox cells in both header + body.
|
|
156
|
+
|
|
157
|
+
We deliberately use padding-inline (shorthand) so it reliably beats other
|
|
158
|
+
padding-inline shorthands (like .table.sm .tBody tr td).
|
|
159
|
+
*/
|
|
160
|
+
|
|
161
|
+
/* Body selection cells (covers td with .selectionCell even if markup differs) */
|
|
162
|
+
.tBody tr td.selectionCell,
|
|
163
|
+
.table .tBody tr td.selectionCell,
|
|
164
|
+
.table td.selectionCell {
|
|
165
|
+
padding-inline: var(--spacing-xxs);
|
|
140
166
|
}
|
|
141
167
|
|
|
142
|
-
|
|
143
|
-
|
|
168
|
+
/* Header selection cells:
|
|
169
|
+
- covers your .th class
|
|
170
|
+
- AND real <th> elements that might not have the .th class */
|
|
171
|
+
.table .th.selectionCell,
|
|
172
|
+
.table th.selectionCell,
|
|
173
|
+
th.selectionCell {
|
|
174
|
+
padding-inline: var(--spacing-xxs);
|
|
144
175
|
}
|
|
145
|
-
|
|
146
|
-
|
|
176
|
+
|
|
177
|
+
/* Override the .table.sm .tBody tr td padding-inline (must be as-specific or more) */
|
|
178
|
+
.table.sm .tBody tr td.selectionCell,
|
|
179
|
+
.table.table.sm .tBody tr td.selectionCell {
|
|
180
|
+
padding-inline: var(--spacing-xxs);
|
|
147
181
|
}
|
|
148
182
|
|
|
149
|
-
|
|
150
|
-
|
|
183
|
+
/* If severity rails are enabled, reserve a left gutter (still no right padding) */
|
|
184
|
+
.table.severityTable .tBody tr td.selectionCell,
|
|
185
|
+
.table.severityTable td.selectionCell,
|
|
186
|
+
.table.severityTable .th.selectionCell,
|
|
187
|
+
.table.severityTable th.selectionCell {
|
|
188
|
+
padding-inline: var(--spacing-xxs);
|
|
189
|
+
padding-inline-start: 14px;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Ensure severityTable also wins in sm */
|
|
193
|
+
.table.sm.severityTable .tBody tr td.selectionCell,
|
|
194
|
+
.table.table.sm.severityTable .tBody tr td.selectionCell,
|
|
195
|
+
.table.sm.severityTable .th.selectionCell,
|
|
196
|
+
.table.table.sm.severityTable .th.selectionCell,
|
|
197
|
+
.table.sm.severityTable th.selectionCell {
|
|
198
|
+
padding-inline: var(--spacing-xxs);
|
|
199
|
+
padding-inline-start: 14px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* =========================
|
|
203
|
+
Rows (interaction + states)
|
|
204
|
+
========================= */
|
|
205
|
+
|
|
206
|
+
.clickableRow {
|
|
207
|
+
cursor: pointer;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.clickableRow:hover {
|
|
211
|
+
background-color: var(--color-bg-contextual);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.selectedRow {
|
|
215
|
+
background-color: var(--color-bg-selected);
|
|
151
216
|
}
|
|
217
|
+
|
|
218
|
+
.selectedRow:hover {
|
|
219
|
+
background-color: var(--color-bg-selected-hover);
|
|
220
|
+
}
|
|
221
|
+
|
|
152
222
|
.tr--hover:hover {
|
|
153
223
|
background-color: var(--color-bg-contextual);
|
|
154
224
|
}
|
|
155
225
|
|
|
156
|
-
.
|
|
157
|
-
|
|
158
|
-
box-shadow: none;
|
|
226
|
+
.striped tr:nth-child(even):not(.selectedRow):not(:hover) {
|
|
227
|
+
background-color: var(--color-bg-surface-subtle);
|
|
159
228
|
}
|
|
229
|
+
|
|
230
|
+
/* Focus ring */
|
|
160
231
|
.table .tbody tr:focus-within {
|
|
161
232
|
outline: none;
|
|
162
233
|
box-shadow:
|
|
@@ -166,9 +237,59 @@ th.sortable:focus-visible {
|
|
|
166
237
|
inset 0 -2px 0 var(--color-brand);
|
|
167
238
|
}
|
|
168
239
|
|
|
169
|
-
|
|
240
|
+
/* =========================
|
|
241
|
+
Content utilities
|
|
242
|
+
========================= */
|
|
243
|
+
|
|
244
|
+
.nowrap {
|
|
245
|
+
white-space: nowrap;
|
|
246
|
+
overflow: hidden;
|
|
247
|
+
text-overflow: ellipsis;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.allowWrap {
|
|
251
|
+
word-break: break-all !important;
|
|
252
|
+
overflow-wrap: anywhere !important;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.td--numeric {
|
|
256
|
+
text-align: end;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.td--muted {
|
|
260
|
+
color: var(--color-fg-muted);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.td .error {
|
|
264
|
+
color: var(--color-danger);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* =========================
|
|
268
|
+
Severity rail
|
|
269
|
+
========================= */
|
|
270
|
+
|
|
271
|
+
.tBody tr.severity td:first-child {
|
|
170
272
|
position: relative;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* Only render the rail when the table actually uses severity rails */
|
|
276
|
+
.table.severityTable .tBody tr.severity td:first-child::before {
|
|
277
|
+
content: '';
|
|
278
|
+
position: absolute;
|
|
279
|
+
|
|
280
|
+
left: 4px;
|
|
281
|
+
top: 4px;
|
|
282
|
+
bottom: 4px;
|
|
283
|
+
width: 5px;
|
|
284
|
+
|
|
285
|
+
background-color: var(--row-severity-color);
|
|
286
|
+
border-radius: 3px;
|
|
287
|
+
|
|
288
|
+
z-index: 0;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* keep checkbox/content above the rail */
|
|
292
|
+
.table.severityTable .tBody tr.severity td:first-child > * {
|
|
293
|
+
position: relative;
|
|
294
|
+
z-index: 1;
|
|
174
295
|
}
|
|
@@ -8,7 +8,7 @@ export type TableEmptyConfig = {
|
|
|
8
8
|
/**
|
|
9
9
|
* Title + description text (defaults are your current Danish copy)
|
|
10
10
|
*/
|
|
11
|
-
title?:
|
|
11
|
+
title?: string;
|
|
12
12
|
description?: ReactNode;
|
|
13
13
|
/**
|
|
14
14
|
* Optional custom actions area. If provided, it will be rendered first.
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ArrowLeft
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import { Headline } from '../../../headline/Headline';
|
|
2
|
+
import { ArrowLeft } from 'lucide-react';
|
|
3
|
+
import { Button } from '../../../../components/button/Button';
|
|
4
|
+
import { StatePage } from '../../../../components/state-page/StatePage';
|
|
6
5
|
const defaultEmptyConfig = {
|
|
7
6
|
enabled: true,
|
|
8
|
-
title:
|
|
7
|
+
title: 'Ingen resultater',
|
|
9
8
|
description: _jsx("span", { children: "Pr\u00F8v at \u00E6ndre dine filtre eller tilf\u00F8je data." }),
|
|
10
9
|
showBack: true,
|
|
11
10
|
showRefresh: true,
|
|
12
11
|
backLabel: (_jsxs(_Fragment, { children: [_jsx(ArrowLeft, {}), "Tilbage"] })),
|
|
13
|
-
refreshLabel: (
|
|
12
|
+
refreshLabel: _jsx(_Fragment, { children: "Indl\u00E6s igen" }),
|
|
14
13
|
className: 'dbc-flex dbc-flex-column dbc-justify-center dbc-items-center dbc-flex-grow ',
|
|
15
14
|
};
|
|
16
15
|
export function TableEmptyState({ config }) {
|
|
@@ -23,5 +22,5 @@ export function TableEmptyState({ config }) {
|
|
|
23
22
|
const showBack = merged.showBack && typeof merged.onBack === 'function';
|
|
24
23
|
const showRefresh = merged.showRefresh && typeof merged.onRefresh === 'function';
|
|
25
24
|
const hasAnyActions = Boolean(merged.actions) || showBack || showRefresh;
|
|
26
|
-
return (
|
|
25
|
+
return (_jsx(StatePage, { type: "empty", header: merged.title, actions: _jsxs("div", { children: [hasAnyActions && (_jsxs("div", { className: "dbc-flex dbc-gap-sm", children: [showBack && (_jsx(Button, { type: "button", onClick: merged.onBack, children: merged.backLabel })), showRefresh && (_jsx(Button, { type: "button", onClick: merged.onRefresh, children: merged.refreshLabel }))] })), merged.actions] }), children: merged.description }));
|
|
27
26
|
}
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ColumnDef } from '@tanstack/react-table';
|
|
2
|
+
import type { JSX, ReactNode } from 'react';
|
|
2
3
|
import { ViewMode } from '../../../../hooks/useTableSettings';
|
|
3
|
-
|
|
4
|
+
import { ButtonSize } from '../../../button/Button';
|
|
5
|
+
interface TableSettingsProps<T extends Record<string, any>> {
|
|
4
6
|
handleChangeViewMode: (mode: ViewMode) => void;
|
|
5
7
|
viewMode: ViewMode;
|
|
8
|
+
columns?: ColumnDef<T>[];
|
|
9
|
+
visibleColumnIds?: string[];
|
|
10
|
+
onVisibleColumnIdsChange?: (nextVisibleIds: string[]) => void;
|
|
11
|
+
columnsLabel?: string;
|
|
12
|
+
allPresetLabel?: string;
|
|
13
|
+
standardPresetLabel?: string;
|
|
14
|
+
buttonSize?: ButtonSize;
|
|
15
|
+
additionalSettings?: (close?: () => void) => ReactNode;
|
|
6
16
|
}
|
|
7
|
-
export declare function TableSettings({ viewMode, handleChangeViewMode }: TableSettingsProps): JSX.Element;
|
|
17
|
+
export declare function TableSettings<T extends Record<string, any>>({ viewMode, handleChangeViewMode, columns, visibleColumnIds, onVisibleColumnIdsChange, columnsLabel, allPresetLabel, standardPresetLabel, buttonSize, additionalSettings, }: TableSettingsProps<T>): JSX.Element;
|
|
8
18
|
export {};
|
|
@@ -1,12 +1,63 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
3
|
import { ListChevronsDownUp, Settings } from 'lucide-react';
|
|
4
|
+
import { useMemo } from 'react';
|
|
3
5
|
import { Button } from '../../../button/Button';
|
|
4
6
|
import { Menu } from '../../../menu/Menu';
|
|
5
7
|
import { Popover } from '../../../popover/Popover';
|
|
6
|
-
export function TableSettings({ viewMode, handleChangeViewMode }) {
|
|
8
|
+
export function TableSettings({ viewMode, handleChangeViewMode, columns = [], visibleColumnIds = [], onVisibleColumnIdsChange, columnsLabel = 'Kolonner', allPresetLabel = 'Alle', standardPresetLabel = 'Standard', buttonSize = 'sm', additionalSettings, }) {
|
|
7
9
|
const handleViewModeChange = (mode, close) => {
|
|
8
|
-
handleChangeViewMode(mode === '
|
|
10
|
+
handleChangeViewMode(mode === 'wrapped' ? 'compact' : 'wrapped');
|
|
9
11
|
close === null || close === void 0 ? void 0 : close();
|
|
10
12
|
};
|
|
11
|
-
|
|
13
|
+
const hideableColumns = useMemo(() => columns.filter(c => c.enableHiding !== false), [columns]);
|
|
14
|
+
const allPresetIds = useMemo(() => hideableColumns.map(c => c.id), [hideableColumns]);
|
|
15
|
+
const standardPresetIds = useMemo(() => hideableColumns.filter(c => { var _a; return ((_a = c.meta) === null || _a === void 0 ? void 0 : _a.hidden) !== true; }).map(c => c.id), [hideableColumns]);
|
|
16
|
+
const visibleSet = useMemo(() => new Set(visibleColumnIds), [visibleColumnIds]);
|
|
17
|
+
const visibleCount = useMemo(() => {
|
|
18
|
+
return hideableColumns.reduce((acc, c) => { var _a; return acc + (visibleSet.has((_a = c.id) !== null && _a !== void 0 ? _a : '') ? 1 : 0); }, 0);
|
|
19
|
+
}, [hideableColumns, visibleSet]);
|
|
20
|
+
const setVisibleIds = (nextIds) => {
|
|
21
|
+
if (!onVisibleColumnIdsChange)
|
|
22
|
+
return;
|
|
23
|
+
const safe = nextIds.length > 0 ? nextIds : standardPresetIds.length > 0 ? standardPresetIds : allPresetIds;
|
|
24
|
+
onVisibleColumnIdsChange(safe.filter((id) => typeof id === 'string' && Boolean(id)));
|
|
25
|
+
};
|
|
26
|
+
const toggleColumn = (id, nextVisible) => {
|
|
27
|
+
const next = new Set(visibleColumnIds);
|
|
28
|
+
if (nextVisible)
|
|
29
|
+
next.add(id);
|
|
30
|
+
else
|
|
31
|
+
next.delete(id);
|
|
32
|
+
setVisibleIds(Array.from(next));
|
|
33
|
+
};
|
|
34
|
+
const isAllActive = useMemo(() => {
|
|
35
|
+
if (!hideableColumns.length)
|
|
36
|
+
return false;
|
|
37
|
+
return hideableColumns.every(c => c.id && visibleSet.has(c.id));
|
|
38
|
+
}, [hideableColumns, visibleSet]);
|
|
39
|
+
const isStandardActive = useMemo(() => {
|
|
40
|
+
if (!hideableColumns.length)
|
|
41
|
+
return false;
|
|
42
|
+
const std = new Set(standardPresetIds);
|
|
43
|
+
return hideableColumns.every(c => c.id && visibleSet.has(c.id) === std.has(c.id));
|
|
44
|
+
}, [hideableColumns, visibleSet, standardPresetIds]);
|
|
45
|
+
// Required by your RadioButton component
|
|
46
|
+
const presetRadioName = 'table-columns-preset';
|
|
47
|
+
return (_jsx(Popover, { trigger: (onClick, icon) => (_jsxs(Button, { size: buttonSize, onClick: onClick, type: "button", children: [_jsx(Settings, {}), icon] })), children: close => (_jsxs(Menu, { children: [additionalSettings === null || additionalSettings === void 0 ? void 0 : additionalSettings(close), _jsx(Menu.Item, { active: viewMode === 'wrapped', children: _jsxs("button", { type: "button", onClick: () => handleViewModeChange(viewMode, close), children: [_jsx(ListChevronsDownUp, {}), "Ombryd tekst"] }) }), hideableColumns.length > 0 && onVisibleColumnIdsChange ? (_jsxs(_Fragment, { children: [_jsx(Menu.Separator, {}), _jsx("div", { style: { padding: '6px 10px', fontSize: 12, opacity: 0.7 }, children: columnsLabel }), _jsx(Menu.RadioItem, { name: presetRadioName, value: "all", checked: isAllActive, label: allPresetLabel, onValueChange: () => {
|
|
48
|
+
setVisibleIds(allPresetIds.filter((id) => typeof id === 'string' && Boolean(id)));
|
|
49
|
+
close === null || close === void 0 ? void 0 : close();
|
|
50
|
+
} }), _jsx(Menu.RadioItem, { name: presetRadioName, value: "standard", checked: isStandardActive, label: standardPresetLabel, onValueChange: () => {
|
|
51
|
+
setVisibleIds(standardPresetIds.filter((id) => typeof id === 'string' && Boolean(id)));
|
|
52
|
+
close === null || close === void 0 ? void 0 : close();
|
|
53
|
+
} }), _jsx(Menu.Separator, {}), hideableColumns.map(col => {
|
|
54
|
+
const isVisible = col.id ? visibleSet.has(col.id) : false;
|
|
55
|
+
const disableUncheckingLast = isVisible && visibleCount <= 1;
|
|
56
|
+
const label = col.header;
|
|
57
|
+
return (_jsx(Menu.CheckItem, { checked: isVisible, disabled: disableUncheckingLast, label: label, onCheckedChange: nextChecked => {
|
|
58
|
+
if (disableUncheckingLast)
|
|
59
|
+
return;
|
|
60
|
+
toggleColumn(col.id, nextChecked);
|
|
61
|
+
} }, col.id));
|
|
62
|
+
})] })) : null] })) }));
|
|
12
63
|
}
|
|
@@ -3,12 +3,23 @@ import * as React from 'react';
|
|
|
3
3
|
import { type TableProps, type TableVariant } from './Table';
|
|
4
4
|
import { ViewMode } from '../../hooks/useTableSettings';
|
|
5
5
|
type Filterable<T> = Array<keyof T>;
|
|
6
|
-
export type TanstackTableProps<T extends Record<string, any>> = Omit<TableProps<T>, 'columns' | 'onSortChange' | 'sortById' | 'sortDirection' | 'headerBelowRow' | 'headerExtras' | 'columnStyles'> & {
|
|
6
|
+
export type TanstackTableProps<T extends Record<string, any>> = Omit<TableProps<T>, 'columns' | 'onSortChange' | 'sortById' | 'sortDirection' | 'headerBelowRow' | 'headerExtras' | 'columnStyles' | 'toolbar'> & {
|
|
7
7
|
columns: ReadonlyArray<ColumnDef<T, any>>;
|
|
8
8
|
filterable?: Filterable<T>;
|
|
9
9
|
onSortingChange?: (sortBy: string | number | symbol | null, direction: 'asc' | 'desc' | null) => void;
|
|
10
|
+
initialSortBy?: string;
|
|
11
|
+
initialSortDirection?: 'asc' | 'desc';
|
|
10
12
|
variant?: TableVariant;
|
|
11
13
|
viewMode?: ViewMode;
|
|
14
|
+
/**
|
|
15
|
+
* TanStack-agnostic column visibility input.
|
|
16
|
+
*
|
|
17
|
+
* If provided, this list is the single source of truth for which columns are visible.
|
|
18
|
+
* If not provided (or empty), defaults are derived from ColumnDef meta.hidden.
|
|
19
|
+
*
|
|
20
|
+
* NOTE: Passing [] is treated as "unset" and will fall back to defaults.
|
|
21
|
+
*/
|
|
22
|
+
visibleColumnIds?: string[];
|
|
12
23
|
};
|
|
13
24
|
export declare function TanstackTable<T extends Record<string, any>>(props: TanstackTableProps<T>): React.ReactNode;
|
|
14
25
|
export {};
|