@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.
Files changed (113) hide show
  1. package/dist/components/accordion/Accordion.d.ts +27 -0
  2. package/dist/components/accordion/Accordion.js +66 -0
  3. package/dist/components/accordion/Accordion.module.css +87 -0
  4. package/dist/components/button/Button.module.css +1 -0
  5. package/dist/components/card/Card.d.ts +21 -3
  6. package/dist/components/card/Card.js +17 -2
  7. package/dist/components/card/Card.module.css +59 -0
  8. package/dist/components/circle/Circle.d.ts +5 -1
  9. package/dist/components/circle/Circle.js +2 -2
  10. package/dist/components/circle/Circle.module.css +60 -4
  11. package/dist/components/code-block/CodeBlock.js +1 -1
  12. package/dist/components/code-block/CodeBlock.module.css +30 -17
  13. package/dist/components/copy-button/CopyButton.d.ts +1 -0
  14. package/dist/components/copy-button/CopyButton.js +10 -2
  15. package/dist/components/datetime-picker/DateTimePicker.d.ts +4 -8
  16. package/dist/components/datetime-picker/DateTimePicker.js +72 -92
  17. package/dist/components/datetime-picker/dateTimeHelpers.d.ts +14 -12
  18. package/dist/components/datetime-picker/dateTimeHelpers.js +25 -45
  19. package/dist/components/filter-field/FilterField.js +16 -11
  20. package/dist/components/filter-field/FilterField.module.css +133 -12
  21. package/dist/components/forms/checkbox/Checkbox.d.ts +4 -10
  22. package/dist/components/forms/checkbox/Checkbox.js +3 -5
  23. package/dist/components/forms/checkbox-group/CheckboxGroup.js +1 -1
  24. package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +1 -1
  25. package/dist/components/forms/input/Input.d.ts +1 -0
  26. package/dist/components/forms/input/Input.js +2 -4
  27. package/dist/components/forms/input/Input.module.css +10 -11
  28. package/dist/components/forms/input-container/InputContainer.d.ts +2 -1
  29. package/dist/components/forms/input-container/InputContainer.js +3 -3
  30. package/dist/components/forms/input-container/InputContainer.module.css +65 -0
  31. package/dist/components/forms/radio-buttons/RadioButton.d.ts +36 -0
  32. package/dist/components/forms/radio-buttons/RadioButton.js +26 -0
  33. package/dist/components/forms/radio-buttons/RadioButtonGroup.d.ts +25 -0
  34. package/dist/components/forms/radio-buttons/RadioButtonGroup.js +19 -0
  35. package/dist/components/forms/radio-buttons/RadioButtons.module.css +117 -0
  36. package/dist/components/forms/select/Select.d.ts +1 -1
  37. package/dist/components/forms/select/Select.js +3 -3
  38. package/dist/components/forms/text-area/Textarea.js +3 -3
  39. package/dist/components/forms/text-area/Textarea.module.css +8 -1
  40. package/dist/components/headline/Headline.d.ts +2 -7
  41. package/dist/components/headline/Headline.js +5 -2
  42. package/dist/components/headline/Headline.module.css +61 -2
  43. package/dist/components/hyperlink/Hyperlink.d.ts +19 -6
  44. package/dist/components/hyperlink/Hyperlink.js +35 -7
  45. package/dist/components/hyperlink/Hyperlink.module.css +50 -2
  46. package/dist/components/icon/Icon.module.css +1 -0
  47. package/dist/components/interval-select/IntervalSelect.js +1 -1
  48. package/dist/components/menu/Menu.d.ts +32 -0
  49. package/dist/components/menu/Menu.js +73 -13
  50. package/dist/components/menu/Menu.module.css +72 -4
  51. package/dist/components/nav-bar/NavBar.d.ts +24 -6
  52. package/dist/components/overlay/modal/Modal.module.css +2 -2
  53. package/dist/components/overlay/side-panel/SidePanel.d.ts +12 -4
  54. package/dist/components/overlay/side-panel/SidePanel.js +77 -4
  55. package/dist/components/overlay/side-panel/SidePanel.module.css +149 -28
  56. package/dist/components/overlay/side-panel/useSidePanel.d.ts +1 -1
  57. package/dist/components/overlay/side-panel/useSidePanel.js +2 -2
  58. package/dist/components/overlay/tooltip/useTooltipTrigger.js +4 -2
  59. package/dist/components/page-layout/PageLayout.js +0 -2
  60. package/dist/components/popover/Popover.js +1 -1
  61. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.d.ts +5 -5
  62. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +36 -24
  63. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.module.css +0 -3
  64. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.d.ts +3 -1
  65. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +4 -3
  66. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +109 -79
  67. package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +16 -3
  68. package/dist/components/sidebar/components/sidebar-items/SidebarItems.module.css +20 -0
  69. package/dist/components/sidebar/providers/SidebarProvider.d.ts +4 -1
  70. package/dist/components/sidebar/providers/SidebarProvider.js +85 -58
  71. package/dist/components/skeleton-loader/SkeletonLoader.d.ts +1 -1
  72. package/dist/components/skeleton-loader/SkeletonLoader.js +15 -12
  73. package/dist/components/split-button/SplitButton.d.ts +1 -1
  74. package/dist/components/split-button/SplitButton.js +3 -1
  75. package/dist/components/split-button/SplitButton.module.css +4 -4
  76. package/dist/components/state-page/StatePage.d.ts +9 -0
  77. package/dist/components/state-page/StatePage.js +20 -0
  78. package/dist/components/state-page/StatePage.module.css +9 -0
  79. package/dist/components/state-page/empty.d.ts +2 -0
  80. package/dist/components/state-page/empty.js +2 -0
  81. package/dist/components/state-page/error.d.ts +2 -0
  82. package/dist/components/state-page/error.js +2 -0
  83. package/dist/components/state-page/notFound.d.ts +2 -0
  84. package/dist/components/state-page/notFound.js +2 -0
  85. package/dist/components/sticky-footer-layout/StickyFooterLayout.d.ts +19 -0
  86. package/dist/components/sticky-footer-layout/StickyFooterLayout.js +27 -0
  87. package/dist/components/table/Table.d.ts +9 -4
  88. package/dist/components/table/Table.js +6 -9
  89. package/dist/components/table/Table.module.css +180 -59
  90. package/dist/components/table/components/empty-state/EmptyState.d.ts +1 -1
  91. package/dist/components/table/components/empty-state/EmptyState.js +6 -7
  92. package/dist/components/table/components/table-settings/TableSettings.d.ts +13 -3
  93. package/dist/components/table/components/table-settings/TableSettings.js +55 -4
  94. package/dist/components/table/tanstack.d.ts +12 -1
  95. package/dist/components/table/tanstack.js +75 -23
  96. package/dist/components/toast/Toast.js +5 -1
  97. package/dist/components/toast/Toast.module.css +40 -15
  98. package/dist/components/toast/provider/ToastProvider.js +1 -0
  99. package/dist/hooks/useTableSettings.d.ts +23 -4
  100. package/dist/hooks/useTableSettings.js +64 -17
  101. package/dist/hooks/useTimeDuration.js +9 -3
  102. package/dist/hooks/useViewportFill.js +1 -0
  103. package/dist/index.d.ts +6 -0
  104. package/dist/index.js +6 -1
  105. package/dist/src/styles/styles.css +60 -25
  106. package/dist/styles/animation.d.ts +5 -0
  107. package/dist/styles/animation.js +5 -0
  108. package/dist/styles/styles.css +60 -25
  109. package/dist/styles/themes/dbc/dark.css +1 -1
  110. package/dist/styles/themes/dbc/light.css +2 -1
  111. package/dist/utils/localStorage.utils.d.ts +19 -0
  112. package/dist/utils/localStorage.utils.js +78 -0
  113. 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 mapDefsToColumnItems(defs) {
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, _s;
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: (_a = def.enableSorting) !== null && _a !== void 0 ? _a : !!accessorKey,
58
+ sortable: (_b = def.enableSorting) !== null && _b !== void 0 ? _b : !!accessorKey,
47
59
  render,
48
- hidden: (_c = (_b = def.meta) === null || _b === void 0 ? void 0 : _b.hidden) !== null && _c !== void 0 ? _c : false,
49
- align: (_e = (_d = def.meta) === null || _d === void 0 ? void 0 : _d.align) !== null && _e !== void 0 ? _e : undefined,
50
- verticalAlign: (_g = (_f = def.meta) === null || _f === void 0 ? void 0 : _f.verticalAlign) !== null && _g !== void 0 ? _g : undefined,
51
- fitContent: (_j = (_h = def.meta) === null || _h === void 0 ? void 0 : _h.fitContent) !== null && _j !== void 0 ? _j : false,
52
- emptyPlaceholder: (_l = (_k = def.meta) === null || _k === void 0 ? void 0 : _k.emptyPlaceholder) !== null && _l !== void 0 ? _l : '-',
53
- allowWrap: (_o = (_m = def.meta) === null || _m === void 0 ? void 0 : _m.allowWrap) !== null && _o !== void 0 ? _o : false,
54
- fillWidth: (_q = (_p = def.meta) === null || _p === void 0 ? void 0 : _p.fillWidth) !== null && _q !== void 0 ? _q : false,
55
- severity: (_s = (_r = def.meta) === null || _r === void 0 ? void 0 : _r.severity) !== null && _s !== void 0 ? _s : undefined,
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
- const columnItems = React.useMemo(() => mapDefsToColumnItems(columns), [columns]);
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, _b, _c;
153
- const id = String(col.id);
154
- if (!id)
155
- return;
156
- if (!dir)
205
+ var _a;
206
+ if (dir == null) {
157
207
  table.setSorting([]);
158
- else
159
- table.setSorting([{ id, desc: dir === 'desc' }]);
160
- onSortingChange === null || onSortingChange === void 0 ? void 0 : onSortingChange((_c = (_b = (_a = table.getState().sorting) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : null, dir);
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
- return (_jsxs("div", { className: `${styles.toast} ${styles[severity]}`, role: "status", children: [_jsxs("div", { className: styles.content, children: [_jsx(Headline, { size: 4, severity: title ? severity : undefined, disableMargin: true, addition: onClose && (_jsx("div", { style: { marginLeft: 'auto' }, children: _jsx(Button, { type: "button", variant: "inline", "aria-label": "Dismiss notification", onClick: onClose, children: _jsx(X, { className: styles.closeIcon, "aria-hidden": "true" }) }) })), children: title }), message && _jsx("div", { className: styles.message, children: message })] }), _jsx("div", { className: styles.actions, children: action && (_jsx(Button, { type: "button", variant: "primary", onClick: action.onClick, children: action.label })) })] }));
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
- .iconContainer {
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
- .actions {
82
- display: flex;
83
- justify-content: flex-end;
84
- gap: var(--spacing-xs);
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,3 +1,4 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import { createContext, useCallback, useContext, useState, useRef, useEffect, } from 'react';
3
4
  import { Toast } from '../Toast';
@@ -1,7 +1,26 @@
1
- export type ViewMode = 'compact' | 'comfortable';
2
- interface TableSettings {
1
+ import { ColumnDef } from '@tanstack/react-table';
2
+ export type ViewMode = 'compact' | 'wrapped';
3
+ export type TableSettingsState = {
3
4
  viewMode: ViewMode;
4
- toggleViewMode: () => void;
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?: string): TableSettings;
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
- export function useTableSettings(storageKey) {
4
- const [viewMode, setViewMode] = useState('compact');
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
- if (typeof window !== 'undefined' && storageKey) {
7
- const storedMode = window.localStorage.getItem(`dbc-table-settings:${storageKey}`);
8
- if (storedMode === 'compact' || storedMode === 'comfortable') {
9
- setViewMode(storedMode);
10
- }
11
- }
12
- }, [storageKey]);
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
- if (typeof window !== 'undefined' && storageKey) {
15
- const newMode = viewMode === 'comfortable' ? 'compact' : 'comfortable';
16
- window.localStorage.setItem(`dbc-table-settings:${storageKey}`, newMode);
17
- }
18
- setViewMode(prevMode => (prevMode === 'comfortable' ? 'compact' : 'comfortable'));
19
- }, [storageKey, viewMode]);
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
- return hr > 0 ? `${hr}t ${min}m ${sec}s` : `${min}m ${sec}s`;
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(undefined, dateFormat).format(start);
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(undefined, dateFormat).format(end);
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)
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import { useCallback, useEffect, useLayoutEffect, useRef, useState, } from 'react';
2
3
  const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
3
4
  /**
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-md);
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
- tr + tr th,
62
- tr + tr td {
63
- padding-block: var(--spacing-xxs);
64
- }
68
+ }
65
69
 
66
- th {
67
- white-space: nowrap;
68
- color: var(--color-fg-subtle);
69
- font-weight: var(--font-weight-default);
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
- td {
76
- color: var(--color-fg-default);
77
- vertical-align: top;
78
- min-width: 0;
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
- th {
82
- max-width: var(--card-label-width);
83
- overflow: hidden;
84
- text-overflow: ellipsis;
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: 1px solid var(--color-border-default);
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: 1px solid var(--color-border-default);
130
+ border: var(--border-width-thin) solid var(--color-border-default);
96
131
  padding: var(--spacing-xs) var(--spacing-sm);
97
132
  }
98
133
 
@@ -0,0 +1,5 @@
1
+ export declare const MOTION_MS: {
2
+ readonly panelSlide: 300;
3
+ readonly modal: 200;
4
+ readonly tooltipOpen: 300;
5
+ };
@@ -0,0 +1,5 @@
1
+ export const MOTION_MS = {
2
+ panelSlide: 300,
3
+ modal: 200,
4
+ tooltipOpen: 300,
5
+ };