@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
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useReactTable, getCoreRowModel, getSortedRowModel, getFilteredRowModel, } from '@tanstack/react-table';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import ColumnResizer from './components/column-resizer/ColumnResizer';
|
|
6
5
|
import { Table } from './Table';
|
|
6
|
+
import ColumnResizer from './components/column-resizer/ColumnResizer';
|
|
7
7
|
function getColumnId(def, index) {
|
|
8
8
|
const d = def;
|
|
9
9
|
if (d.id != null && String(d.id).length)
|
|
@@ -12,9 +12,20 @@ function getColumnId(def, index) {
|
|
|
12
12
|
return String(d.accessorKey);
|
|
13
13
|
return `col_${index}`;
|
|
14
14
|
}
|
|
15
|
-
function
|
|
15
|
+
function buildDefaultVisibleIdsFromDefs(defs) {
|
|
16
|
+
const ids = [];
|
|
17
|
+
defs.forEach((def, idx) => {
|
|
18
|
+
var _a;
|
|
19
|
+
const id = getColumnId(def, idx);
|
|
20
|
+
const hiddenByMeta = Boolean((_a = def.meta) === null || _a === void 0 ? void 0 : _a.hidden);
|
|
21
|
+
if (!hiddenByMeta)
|
|
22
|
+
ids.push(id);
|
|
23
|
+
});
|
|
24
|
+
return ids;
|
|
25
|
+
}
|
|
26
|
+
function mapDefsToColumnItems(defs, columnVisibility) {
|
|
16
27
|
return defs.map((def, index) => {
|
|
17
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r
|
|
28
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
18
29
|
const id = getColumnId(def, index);
|
|
19
30
|
const accessorKey = def.accessorKey;
|
|
20
31
|
const accessorFn = def.accessorFn;
|
|
@@ -39,41 +50,62 @@ function mapDefsToColumnItems(defs) {
|
|
|
39
50
|
else {
|
|
40
51
|
render = () => null;
|
|
41
52
|
}
|
|
53
|
+
const isVisible = (_a = columnVisibility[id]) !== null && _a !== void 0 ? _a : true;
|
|
42
54
|
return {
|
|
43
55
|
id,
|
|
44
56
|
header: def.header,
|
|
45
57
|
accessor: accessorKey,
|
|
46
|
-
sortable: (
|
|
58
|
+
sortable: (_b = def.enableSorting) !== null && _b !== void 0 ? _b : !!accessorKey,
|
|
47
59
|
render,
|
|
48
|
-
hidden:
|
|
49
|
-
align: (
|
|
50
|
-
verticalAlign: (
|
|
51
|
-
fitContent: (
|
|
52
|
-
emptyPlaceholder: (
|
|
53
|
-
allowWrap: (
|
|
54
|
-
fillWidth: (
|
|
55
|
-
severity: (
|
|
60
|
+
hidden: !isVisible,
|
|
61
|
+
align: (_d = (_c = def.meta) === null || _c === void 0 ? void 0 : _c.align) !== null && _d !== void 0 ? _d : undefined,
|
|
62
|
+
verticalAlign: (_f = (_e = def.meta) === null || _e === void 0 ? void 0 : _e.verticalAlign) !== null && _f !== void 0 ? _f : undefined,
|
|
63
|
+
fitContent: (_h = (_g = def.meta) === null || _g === void 0 ? void 0 : _g.fitContent) !== null && _h !== void 0 ? _h : false,
|
|
64
|
+
emptyPlaceholder: (_k = (_j = def.meta) === null || _j === void 0 ? void 0 : _j.emptyPlaceholder) !== null && _k !== void 0 ? _k : '-',
|
|
65
|
+
allowWrap: (_m = (_l = def.meta) === null || _l === void 0 ? void 0 : _l.allowWrap) !== null && _m !== void 0 ? _m : false,
|
|
66
|
+
fillWidth: (_p = (_o = def.meta) === null || _o === void 0 ? void 0 : _o.fillWidth) !== null && _p !== void 0 ? _p : false,
|
|
67
|
+
severity: (_r = (_q = def.meta) === null || _q === void 0 ? void 0 : _q.severity) !== null && _r !== void 0 ? _r : undefined,
|
|
56
68
|
};
|
|
57
69
|
});
|
|
58
70
|
}
|
|
59
71
|
export function TanstackTable(props) {
|
|
60
72
|
var _a, _b;
|
|
61
|
-
const { data, dataKey, columns, filterable = [], onSortingChange, ...tableProps } = props;
|
|
73
|
+
const { data, dataKey, columns, filterable = [], onSortingChange, initialSortBy, initialSortDirection, visibleColumnIds, ...tableProps } = props;
|
|
62
74
|
const [sorting, setSorting] = React.useState([]);
|
|
63
75
|
const [columnFilters, setColumnFilters] = React.useState([]);
|
|
64
76
|
const [columnSizing, setColumnSizing] = React.useState({});
|
|
77
|
+
// IDs in the same order as defs
|
|
78
|
+
const allColumnIds = React.useMemo(() => columns.map((def, i) => getColumnId(def, i)), [columns]);
|
|
79
|
+
// Defaults derived from ColumnDef meta.hidden
|
|
80
|
+
const defaultVisibleIds = React.useMemo(() => buildDefaultVisibleIdsFromDefs(columns), [columns]);
|
|
81
|
+
// Treat [] as "unset" and fall back to defaults
|
|
82
|
+
const effectiveVisibleIds = React.useMemo(() => {
|
|
83
|
+
if (visibleColumnIds && visibleColumnIds.length > 0)
|
|
84
|
+
return visibleColumnIds;
|
|
85
|
+
return defaultVisibleIds;
|
|
86
|
+
}, [visibleColumnIds, defaultVisibleIds]);
|
|
87
|
+
// TanStack visibility state
|
|
88
|
+
const [columnVisibility, setColumnVisibility] = React.useState(() => {
|
|
89
|
+
const visible = new Set(effectiveVisibleIds);
|
|
90
|
+
const next = {};
|
|
91
|
+
for (const id of allColumnIds)
|
|
92
|
+
next[id] = visible.has(id);
|
|
93
|
+
return next;
|
|
94
|
+
});
|
|
65
95
|
const table = useReactTable({
|
|
66
96
|
data,
|
|
67
97
|
columns: columns,
|
|
68
|
-
state: { sorting, columnFilters, columnSizing },
|
|
98
|
+
state: { sorting, columnFilters, columnSizing, columnVisibility },
|
|
69
99
|
onSortingChange: setSorting,
|
|
70
100
|
onColumnFiltersChange: setColumnFilters,
|
|
71
101
|
onColumnSizingChange: setColumnSizing,
|
|
102
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
72
103
|
getCoreRowModel: getCoreRowModel(),
|
|
73
104
|
getSortedRowModel: getSortedRowModel(),
|
|
74
105
|
getFilteredRowModel: getFilteredRowModel(),
|
|
75
106
|
enableColumnResizing: true,
|
|
76
107
|
columnResizeMode: 'onChange',
|
|
108
|
+
initialState: {},
|
|
77
109
|
defaultColumn: {
|
|
78
110
|
enableResizing: true,
|
|
79
111
|
minSize: 80,
|
|
@@ -81,7 +113,28 @@ export function TanstackTable(props) {
|
|
|
81
113
|
maxSize: 800,
|
|
82
114
|
},
|
|
83
115
|
});
|
|
84
|
-
|
|
116
|
+
// Apply external "visibleColumnIds" -> TanStack column visibility using toggleVisibility,
|
|
117
|
+
// as requested (no selector UI here).
|
|
118
|
+
React.useEffect(() => {
|
|
119
|
+
const desired = new Set(effectiveVisibleIds);
|
|
120
|
+
for (const id of allColumnIds) {
|
|
121
|
+
const col = table.getColumn(id);
|
|
122
|
+
if (!col)
|
|
123
|
+
continue;
|
|
124
|
+
const shouldBeVisible = desired.has(id);
|
|
125
|
+
if (col.getIsVisible() !== shouldBeVisible) {
|
|
126
|
+
col.toggleVisibility(shouldBeVisible);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}, [table, allColumnIds, effectiveVisibleIds]);
|
|
130
|
+
React.useEffect(() => {
|
|
131
|
+
if (initialSortDirection !== 'asc' && initialSortDirection !== 'desc')
|
|
132
|
+
return table.setSorting([]);
|
|
133
|
+
table.setSorting(() => initialSortBy && initialSortDirection
|
|
134
|
+
? [{ id: initialSortBy, desc: initialSortDirection === 'desc' }]
|
|
135
|
+
: []);
|
|
136
|
+
}, [initialSortBy, initialSortDirection, table]);
|
|
137
|
+
const columnItems = React.useMemo(() => mapDefsToColumnItems(columns, columnVisibility), [columns, columnVisibility]);
|
|
85
138
|
const visibleData = table.getRowModel().rows.map(r => r.original);
|
|
86
139
|
const s = (_a = table.getState().sorting) === null || _a === void 0 ? void 0 : _a[0];
|
|
87
140
|
const sortById = (_b = s === null || s === void 0 ? void 0 : s.id) !== null && _b !== void 0 ? _b : undefined;
|
|
@@ -149,14 +202,13 @@ export function TanstackTable(props) {
|
|
|
149
202
|
}) }));
|
|
150
203
|
}, [columnItems, filterable, table, gridTemplateColumns]);
|
|
151
204
|
return (_jsx(Table, { ...tableProps, dataKey: dataKey, data: visibleData, columns: columnItems, sortById: sortById, sortDirection: sortDirection, onSortChange: (col, dir) => {
|
|
152
|
-
var _a
|
|
153
|
-
|
|
154
|
-
if (!id)
|
|
155
|
-
return;
|
|
156
|
-
if (!dir)
|
|
205
|
+
var _a;
|
|
206
|
+
if (dir == null) {
|
|
157
207
|
table.setSorting([]);
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
208
|
+
onSortingChange === null || onSortingChange === void 0 ? void 0 : onSortingChange(null, null);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
table.setSorting([{ id: col.id, desc: dir === 'desc' }]);
|
|
212
|
+
onSortingChange === null || onSortingChange === void 0 ? void 0 : onSortingChange((_a = col.id) !== null && _a !== void 0 ? _a : null, dir);
|
|
161
213
|
}, headerExtras: headerExtras, columnStyles: columnStyles, headerBelowRow: headerBelowRow }));
|
|
162
214
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Toast.tsx
|
|
2
3
|
import { X } from 'lucide-react';
|
|
3
4
|
import styles from './Toast.module.css';
|
|
4
5
|
import { Button } from '../button/Button';
|
|
5
6
|
import { Headline } from '../headline/Headline';
|
|
6
7
|
export function Toast({ title, message, severity = 'info', action, onClose, }) {
|
|
7
|
-
|
|
8
|
+
const showHeader = Boolean(title);
|
|
9
|
+
const showMessage = Boolean(message);
|
|
10
|
+
const CloseButton = onClose ? (_jsx(Button, { type: "button", variant: "inline", className: styles.closeButton, "aria-label": "Dismiss notification", onClick: onClose, children: _jsx(X, { className: styles.closeIcon, "aria-hidden": "true" }) })) : null;
|
|
11
|
+
return (_jsxs("div", { className: `${styles.toast} ${styles[severity]}`, role: "status", children: [_jsxs("div", { className: styles.content, children: [showHeader && (_jsxs("div", { className: styles.row, children: [_jsx(Headline, { size: 4, severity: severity, disableMargin: true, children: title }), CloseButton] })), showMessage && (_jsxs("div", { className: styles.row, children: [_jsx("div", { className: styles.message, children: message }), !showHeader && CloseButton] }))] }), action && (_jsx("div", { className: styles.actions, children: _jsx(Button, { type: "button", variant: "primary", onClick: action.onClick, children: action.label }) }))] }));
|
|
8
12
|
}
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
border-left-width: var(--border-width-thick);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/* Severity accents */
|
|
35
36
|
.info {
|
|
36
37
|
border-left-color: var(--color-status-info-border);
|
|
37
38
|
}
|
|
@@ -48,40 +49,58 @@
|
|
|
48
49
|
border-left-color: var(--color-status-error-border);
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
display: inline-flex;
|
|
53
|
-
align-items: center;
|
|
54
|
-
justify-content: center;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.icon {
|
|
58
|
-
width: var(--icon-size-md);
|
|
59
|
-
height: var(--icon-size-md);
|
|
60
|
-
}
|
|
61
|
-
|
|
52
|
+
/* Layout */
|
|
62
53
|
.content {
|
|
63
54
|
flex: 1;
|
|
64
55
|
min-width: 0;
|
|
65
56
|
display: flex;
|
|
66
57
|
flex-direction: column;
|
|
58
|
+
gap: var(--spacing-xxs);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.row {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
67
64
|
gap: var(--spacing-xs);
|
|
65
|
+
min-width: 0;
|
|
68
66
|
}
|
|
69
67
|
|
|
68
|
+
/* Long-text handling suitable for toasts */
|
|
69
|
+
.title,
|
|
70
|
+
.message {
|
|
71
|
+
min-width: 0;
|
|
72
|
+
overflow-wrap: anywhere;
|
|
73
|
+
word-break: break-word;
|
|
74
|
+
white-space: normal;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Optional: clamp to avoid giant toasts */
|
|
70
78
|
.title {
|
|
71
79
|
font-size: var(--font-size-sm);
|
|
72
80
|
font-weight: var(--font-weight-semibold);
|
|
73
81
|
line-height: var(--line-height-tight);
|
|
82
|
+
|
|
83
|
+
display: -webkit-box;
|
|
84
|
+
-webkit-box-orient: vertical;
|
|
85
|
+
-webkit-line-clamp: 2;
|
|
86
|
+
overflow: hidden;
|
|
74
87
|
}
|
|
75
88
|
|
|
76
89
|
.message {
|
|
77
90
|
font-size: var(--font-size-sm);
|
|
78
91
|
line-height: var(--line-height-normal);
|
|
92
|
+
|
|
93
|
+
display: -webkit-box;
|
|
94
|
+
-webkit-box-orient: vertical;
|
|
95
|
+
-webkit-line-clamp: 4;
|
|
96
|
+
overflow: hidden;
|
|
79
97
|
}
|
|
80
98
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
99
|
+
/* Close button stays aligned at the end of the row */
|
|
100
|
+
.closeButton {
|
|
101
|
+
margin-inline-start: auto;
|
|
102
|
+
flex: 0 0 auto;
|
|
103
|
+
align-self: flex-start;
|
|
85
104
|
}
|
|
86
105
|
|
|
87
106
|
.closeIcon {
|
|
@@ -89,6 +108,12 @@
|
|
|
89
108
|
height: var(--icon-size-sm);
|
|
90
109
|
}
|
|
91
110
|
|
|
111
|
+
.actions {
|
|
112
|
+
display: flex;
|
|
113
|
+
justify-content: flex-end;
|
|
114
|
+
gap: var(--spacing-xs);
|
|
115
|
+
}
|
|
116
|
+
|
|
92
117
|
/* Simple enter animation */
|
|
93
118
|
@keyframes toast-enter {
|
|
94
119
|
from {
|
|
@@ -1,7 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { ColumnDef } from '@tanstack/react-table';
|
|
2
|
+
export type ViewMode = 'compact' | 'wrapped';
|
|
3
|
+
export type TableSettingsState = {
|
|
3
4
|
viewMode: ViewMode;
|
|
4
|
-
|
|
5
|
+
visibleColumnIds: string[];
|
|
6
|
+
};
|
|
7
|
+
export type TableSettingsStorage = {
|
|
8
|
+
get: (key: string) => TableSettingsState | undefined;
|
|
9
|
+
set: (key: string, next: TableSettingsState) => void;
|
|
10
|
+
};
|
|
11
|
+
export declare const localStorageTableSettingsStorage: TableSettingsStorage;
|
|
12
|
+
interface UseTableSettingsOptions {
|
|
13
|
+
storageKey: string;
|
|
14
|
+
tableColumns?: ColumnDef<any>[];
|
|
15
|
+
defaultViewMode?: ViewMode;
|
|
16
|
+
defaultVisibleColumnIds?: string[];
|
|
17
|
+
storage?: TableSettingsStorage;
|
|
5
18
|
}
|
|
6
|
-
export declare function useTableSettings(storageKey
|
|
19
|
+
export declare function useTableSettings({ storageKey, tableColumns, defaultViewMode, defaultVisibleColumnIds, storage, }: UseTableSettingsOptions): {
|
|
20
|
+
viewMode: ViewMode;
|
|
21
|
+
toggleViewMode: () => void;
|
|
22
|
+
setViewMode: (mode: ViewMode) => void;
|
|
23
|
+
visibleColumnIds: string[];
|
|
24
|
+
setVisibleColumnIds: (ids: string[]) => void;
|
|
25
|
+
};
|
|
7
26
|
export {};
|
|
@@ -1,24 +1,71 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { readLocalStorage, writeLocalStorage } from '../utils/localStorage.utils';
|
|
4
|
+
function getDefaultVisibleIds(tableColumns) {
|
|
5
|
+
var _a;
|
|
6
|
+
return ((_a = tableColumns === null || tableColumns === void 0 ? void 0 : tableColumns.filter(c => { var _a; return !((_a = c.meta) === null || _a === void 0 ? void 0 : _a.hidden); }).map(c => c.id).filter(Boolean)) !== null && _a !== void 0 ? _a : []);
|
|
7
|
+
}
|
|
8
|
+
function mergeDefaults(stored, defaults) {
|
|
9
|
+
const viewMode = (stored === null || stored === void 0 ? void 0 : stored.viewMode) === 'compact' || (stored === null || stored === void 0 ? void 0 : stored.viewMode) === 'wrapped'
|
|
10
|
+
? stored.viewMode
|
|
11
|
+
: defaults.viewMode;
|
|
12
|
+
const visibleColumnIds = Array.isArray(stored === null || stored === void 0 ? void 0 : stored.visibleColumnIds) && stored.visibleColumnIds.length > 0
|
|
13
|
+
? stored.visibleColumnIds
|
|
14
|
+
: defaults.visibleColumnIds;
|
|
15
|
+
return { viewMode, visibleColumnIds };
|
|
16
|
+
}
|
|
17
|
+
export const localStorageTableSettingsStorage = {
|
|
18
|
+
get: key => {
|
|
19
|
+
const v = readLocalStorage(key);
|
|
20
|
+
return v && typeof v === 'object' ? v : undefined;
|
|
21
|
+
},
|
|
22
|
+
set: (key, next) => {
|
|
23
|
+
writeLocalStorage(key, next);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
export function useTableSettings({ storageKey, tableColumns, defaultViewMode = 'compact', defaultVisibleColumnIds, storage = localStorageTableSettingsStorage, }) {
|
|
27
|
+
const defaults = useMemo(() => {
|
|
28
|
+
return {
|
|
29
|
+
viewMode: defaultViewMode,
|
|
30
|
+
visibleColumnIds: defaultVisibleColumnIds !== null && defaultVisibleColumnIds !== void 0 ? defaultVisibleColumnIds : getDefaultVisibleIds(tableColumns),
|
|
31
|
+
};
|
|
32
|
+
}, [defaultViewMode, defaultVisibleColumnIds, tableColumns]);
|
|
33
|
+
const [state, setState] = useState(defaults);
|
|
5
34
|
useEffect(() => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
35
|
+
const stored = storage.get(storageKey);
|
|
36
|
+
const next = mergeDefaults(stored, defaults);
|
|
37
|
+
setState(next);
|
|
38
|
+
}, [storageKey, storage, defaults]);
|
|
39
|
+
const persist = useCallback((next) => storage.set(storageKey, next), [storage, storageKey]);
|
|
40
|
+
const setViewMode = useCallback((mode) => {
|
|
41
|
+
setState(prev => {
|
|
42
|
+
if (prev.viewMode === mode)
|
|
43
|
+
return prev;
|
|
44
|
+
const next = { ...prev, viewMode: mode };
|
|
45
|
+
persist(next);
|
|
46
|
+
return next;
|
|
47
|
+
});
|
|
48
|
+
}, [persist]);
|
|
13
49
|
const toggleViewMode = useCallback(() => {
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
50
|
+
setState(prev => {
|
|
51
|
+
const nextMode = prev.viewMode === 'wrapped' ? 'compact' : 'wrapped';
|
|
52
|
+
const next = { ...prev, viewMode: nextMode };
|
|
53
|
+
persist(next);
|
|
54
|
+
return next;
|
|
55
|
+
});
|
|
56
|
+
}, [persist]);
|
|
57
|
+
const setVisibleColumnIds = useCallback((ids) => {
|
|
58
|
+
setState(prev => {
|
|
59
|
+
const next = { ...prev, visibleColumnIds: ids };
|
|
60
|
+
persist(next);
|
|
61
|
+
return next;
|
|
62
|
+
});
|
|
63
|
+
}, [persist]);
|
|
20
64
|
return {
|
|
21
|
-
viewMode,
|
|
65
|
+
viewMode: state.viewMode,
|
|
22
66
|
toggleViewMode,
|
|
67
|
+
setViewMode,
|
|
68
|
+
visibleColumnIds: state.visibleColumnIds,
|
|
69
|
+
setVisibleColumnIds,
|
|
23
70
|
};
|
|
24
71
|
}
|
|
@@ -6,7 +6,13 @@ function defaultDuration(ms) {
|
|
|
6
6
|
const sec = Math.floor(ms / 1000) % 60;
|
|
7
7
|
const min = Math.floor(ms / (1000 * 60)) % 60;
|
|
8
8
|
const hr = Math.floor(ms / (1000 * 60 * 60));
|
|
9
|
-
|
|
9
|
+
if (hr > 0) {
|
|
10
|
+
return `${hr}t ${min}m ${sec}s`;
|
|
11
|
+
}
|
|
12
|
+
if (min > 0) {
|
|
13
|
+
return `${min}m ${sec}s`;
|
|
14
|
+
}
|
|
15
|
+
return `${sec}s`;
|
|
10
16
|
}
|
|
11
17
|
export function useTimeDuration({ start, end, dateFormat = { dateStyle: 'short', timeStyle: 'medium' }, fallback = '—', formatDuration = defaultDuration, }) {
|
|
12
18
|
const [hydrated, setHydrated] = useState(false);
|
|
@@ -16,14 +22,14 @@ export function useTimeDuration({ start, end, dateFormat = { dateStyle: 'short',
|
|
|
16
22
|
return fallback;
|
|
17
23
|
if (!hydrated)
|
|
18
24
|
return fallback;
|
|
19
|
-
return new Intl.DateTimeFormat(
|
|
25
|
+
return new Intl.DateTimeFormat('da-DK', dateFormat).format(start);
|
|
20
26
|
}, [start, hydrated, fallback, dateFormat]);
|
|
21
27
|
const ended = useMemo(() => {
|
|
22
28
|
if (!end)
|
|
23
29
|
return fallback;
|
|
24
30
|
if (!hydrated)
|
|
25
31
|
return fallback;
|
|
26
|
-
return new Intl.DateTimeFormat(
|
|
32
|
+
return new Intl.DateTimeFormat('da-DK', dateFormat).format(end);
|
|
27
33
|
}, [end, hydrated, fallback, dateFormat]);
|
|
28
34
|
const duration = useMemo(() => {
|
|
29
35
|
if (!start || !end)
|
package/dist/index.d.ts
CHANGED
|
@@ -61,3 +61,9 @@ export * from './components/hyperlink/Hyperlink';
|
|
|
61
61
|
export * from './components/overlay/tooltip/Tooltip';
|
|
62
62
|
export * from './components/overlay/tooltip/TooltipProvider';
|
|
63
63
|
export * from './components/overlay/tooltip/useTooltipTrigger';
|
|
64
|
+
export * from './components/forms/radio-buttons/RadioButton';
|
|
65
|
+
export * from './components/forms/radio-buttons/RadioButtonGroup';
|
|
66
|
+
export * from './components/interval-select/IntervalSelect';
|
|
67
|
+
export * from './components/accordion/Accordion';
|
|
68
|
+
export * from './components/state-page/StatePage';
|
|
69
|
+
export * from './components/sticky-footer-layout/StickyFooterLayout';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
'use client';
|
|
2
1
|
export * from './components/button/Button';
|
|
3
2
|
export * from './components/nav-bar/NavBar';
|
|
4
3
|
export * from './components/avatar/Avatar';
|
|
@@ -62,3 +61,9 @@ export * from './components/hyperlink/Hyperlink';
|
|
|
62
61
|
export * from './components/overlay/tooltip/Tooltip';
|
|
63
62
|
export * from './components/overlay/tooltip/TooltipProvider';
|
|
64
63
|
export * from './components/overlay/tooltip/useTooltipTrigger';
|
|
64
|
+
export * from './components/forms/radio-buttons/RadioButton';
|
|
65
|
+
export * from './components/forms/radio-buttons/RadioButtonGroup';
|
|
66
|
+
export * from './components/interval-select/IntervalSelect';
|
|
67
|
+
export * from './components/accordion/Accordion';
|
|
68
|
+
export * from './components/state-page/StatePage';
|
|
69
|
+
export * from './components/sticky-footer-layout/StickyFooterLayout';
|
|
@@ -30,6 +30,8 @@ body {
|
|
|
30
30
|
color: var(--color-fg-default);
|
|
31
31
|
background-color: var(--color-bg-page);
|
|
32
32
|
--density: var(--density-comfortable);
|
|
33
|
+
font-size: var(--font-size-sm);
|
|
34
|
+
margin: 0;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
h1 {
|
|
@@ -45,7 +47,7 @@ h3 {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
h4 {
|
|
48
|
-
font-size: var(--font-size-
|
|
50
|
+
font-size: var(--font-size-sm);
|
|
49
51
|
font-weight: var(--font-weight-medium);
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -53,46 +55,79 @@ body.dbc-app {
|
|
|
53
55
|
max-width: 1600px;
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
.dbc-font-mono {
|
|
59
|
+
font-family: monospace;
|
|
60
|
+
}
|
|
61
|
+
|
|
56
62
|
.dbc-table {
|
|
57
63
|
--card-label-width: 260px;
|
|
64
|
+
|
|
58
65
|
border-collapse: collapse;
|
|
59
66
|
font-size: var(--font-size-sm);
|
|
60
67
|
line-height: var(--line-height-normal);
|
|
61
|
-
|
|
62
|
-
tr + tr td {
|
|
63
|
-
padding-block: var(--spacing-xxs);
|
|
64
|
-
}
|
|
68
|
+
}
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
padding-right: var(--spacing-lg);
|
|
71
|
-
vertical-align: top;
|
|
72
|
-
text-align: left;
|
|
73
|
-
}
|
|
70
|
+
.dbc-table tr + tr th,
|
|
71
|
+
.dbc-table tr + tr td {
|
|
72
|
+
padding-block: var(--spacing-xxs);
|
|
73
|
+
}
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
/* LABELS (th) → match .metaLabel */
|
|
76
|
+
.dbc-table th {
|
|
77
|
+
white-space: nowrap;
|
|
78
|
+
text-align: left;
|
|
79
|
+
vertical-align: top;
|
|
80
|
+
max-width: var(--card-label-width);
|
|
81
|
+
overflow: hidden;
|
|
82
|
+
text-overflow: ellipsis;
|
|
83
|
+
font-size: var(--font-size-xs);
|
|
84
|
+
color: var(--color-fg-subtle);
|
|
85
|
+
letter-spacing: var(--letter-spacing-wide);
|
|
86
|
+
text-transform: uppercase;
|
|
87
|
+
font-weight: var(--font-weight-default);
|
|
88
|
+
padding-right: var(--spacing-lg);
|
|
89
|
+
}
|
|
80
90
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
91
|
+
/* VALUES (td) → match .metaValue */
|
|
92
|
+
.dbc-table td {
|
|
93
|
+
vertical-align: top;
|
|
94
|
+
min-width: 0;
|
|
95
|
+
|
|
96
|
+
margin: 0; /* harmless on td, keeps parity with metaValue */
|
|
97
|
+
font-size: var(--font-size-sm);
|
|
98
|
+
color: var(--color-fg-default);
|
|
99
|
+
font-weight: var(--font-weight-medium);
|
|
100
|
+
|
|
101
|
+
word-break: break-word;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Optional: baseline alignment closer to metaRow */
|
|
105
|
+
.dbc-table th,
|
|
106
|
+
.dbc-table td {
|
|
107
|
+
vertical-align: baseline;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.dbc-full-width {
|
|
111
|
+
width: 100%;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.dbc-highlight {
|
|
115
|
+
background-color: var(--color-status-warning-bg);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.dbc-muted-text {
|
|
119
|
+
color: var(--color-fg-subtle);
|
|
86
120
|
}
|
|
87
121
|
|
|
88
122
|
.dbc-table--bordered {
|
|
89
123
|
width: auto;
|
|
90
|
-
border:
|
|
124
|
+
border: var(--border-width-thin) solid var(--color-border-default);
|
|
125
|
+
border-collapse: collapse;
|
|
91
126
|
}
|
|
92
127
|
|
|
93
128
|
.dbc-table--bordered th,
|
|
94
129
|
.dbc-table--bordered td {
|
|
95
|
-
border:
|
|
130
|
+
border: var(--border-width-thin) solid var(--color-border-default);
|
|
96
131
|
padding: var(--spacing-xs) var(--spacing-sm);
|
|
97
132
|
}
|
|
98
133
|
|