@dbcdk/react-components 0.0.95 → 0.0.97

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 (226) hide show
  1. package/dist/components/alert/Alert.d.ts +13 -0
  2. package/dist/components/forms/input/Input.d.ts +2 -1
  3. package/dist/components/forms/input-container/InputContainer.d.ts +3 -1
  4. package/dist/components/forms/text-area/Textarea.d.ts +1 -1
  5. package/dist/components/stack/Stack.d.ts +11 -3
  6. package/dist/components/table/Table.d.ts +1 -1
  7. package/dist/components/table/Table.types.d.ts +3 -0
  8. package/dist/components/table/components/TableHeader.d.ts +2 -1
  9. package/dist/index.cjs +12750 -0
  10. package/dist/index.css +7149 -0
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.js +12641 -78
  13. package/dist/tanstack.cjs +2674 -0
  14. package/dist/tanstack.css +1267 -0
  15. package/dist/tanstack.js +2650 -3
  16. package/dist/themes/dbc.css +3 -0
  17. package/dist/themes/forfatterweb.css +2 -0
  18. package/package.json +11 -10
  19. package/dist/assets/logo.js +0 -2
  20. package/dist/components/__stories__/_data/table.d.ts +0 -15
  21. package/dist/components/__stories__/_data/table.js +0 -55
  22. package/dist/components/__stories__/_data/tabs.d.ts +0 -9
  23. package/dist/components/__stories__/_data/tabs.js +0 -31
  24. package/dist/components/__stories__/story-components/Colors.d.ts +0 -11
  25. package/dist/components/__stories__/story-components/Colors.js +0 -96
  26. package/dist/components/__stories__/story-components/Colors.module.css +0 -27
  27. package/dist/components/__stories__/story-components/ComponentSizes.d.ts +0 -2
  28. package/dist/components/__stories__/story-components/ComponentSizes.js +0 -26
  29. package/dist/components/__stories__/story-components/Elevation.d.ts +0 -2
  30. package/dist/components/__stories__/story-components/Elevation.js +0 -49
  31. package/dist/components/__stories__/story-components/Flex.d.ts +0 -2
  32. package/dist/components/__stories__/story-components/Flex.js +0 -177
  33. package/dist/components/__stories__/story-components/Flex.module.css +0 -317
  34. package/dist/components/__stories__/story-components/Spacing.d.ts +0 -6
  35. package/dist/components/__stories__/story-components/Spacing.js +0 -76
  36. package/dist/components/__stories__/story-components/Spacing.module.css +0 -154
  37. package/dist/components/accordion/Accordion.js +0 -70
  38. package/dist/components/accordion/Accordion.module.css +0 -28
  39. package/dist/components/accordion/components/AccordionRow.js +0 -53
  40. package/dist/components/accordion/components/AccordionRow.module.css +0 -90
  41. package/dist/components/app-header/AppHeader.js +0 -5
  42. package/dist/components/app-header/AppHeader.module.css +0 -74
  43. package/dist/components/attribute-chip/AttributeChip.js +0 -5
  44. package/dist/components/attribute-chip/AttributeChip.module.css +0 -65
  45. package/dist/components/avatar/Avatar.js +0 -48
  46. package/dist/components/avatar/Avatar.module.css +0 -91
  47. package/dist/components/breadcrumbs/Breadcrumbs.js +0 -6
  48. package/dist/components/breadcrumbs/Breadcrumbs.module.css +0 -80
  49. package/dist/components/button/Button.js +0 -81
  50. package/dist/components/button/Button.module.css +0 -249
  51. package/dist/components/button-select/ButtonSelect.js +0 -7
  52. package/dist/components/button-select/ButtonSelect.module.css +0 -40
  53. package/dist/components/card/Card.js +0 -71
  54. package/dist/components/card/Card.module.css +0 -160
  55. package/dist/components/card/components/CardMeta.js +0 -26
  56. package/dist/components/card/components/CardMeta.module.css +0 -55
  57. package/dist/components/card-container/CardContainer.js +0 -6
  58. package/dist/components/card-container/CardContainer.module.css +0 -61
  59. package/dist/components/chip/Chip.js +0 -31
  60. package/dist/components/chip/Chip.module.css +0 -236
  61. package/dist/components/circle/Circle.js +0 -5
  62. package/dist/components/circle/Circle.module.css +0 -128
  63. package/dist/components/clear-button/ClearButton.js +0 -13
  64. package/dist/components/clear-button/ClearButton.module.css +0 -26
  65. package/dist/components/code-block/CodeBlock.js +0 -58
  66. package/dist/components/code-block/CodeBlock.module.css +0 -124
  67. package/dist/components/copy-button/CopyButton.js +0 -78
  68. package/dist/components/copy-button/CopyButton.module.css +0 -22
  69. package/dist/components/datetime-picker/DateTimePicker.js +0 -403
  70. package/dist/components/datetime-picker/DateTimePicker.module.css +0 -155
  71. package/dist/components/datetime-picker/dateTimeHelpers.js +0 -248
  72. package/dist/components/divider/Divider.js +0 -12
  73. package/dist/components/filter-field/FilterField.js +0 -191
  74. package/dist/components/filter-field/FilterField.module.css +0 -379
  75. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.js +0 -52
  76. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.module.css +0 -59
  77. package/dist/components/forms/checkbox/Checkbox.js +0 -26
  78. package/dist/components/forms/checkbox/Checkbox.module.css +0 -99
  79. package/dist/components/forms/checkbox-group/CheckboxGroup.js +0 -75
  80. package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +0 -115
  81. package/dist/components/forms/form-select/FormSelect.js +0 -86
  82. package/dist/components/forms/form-select/FormSelect.module.css +0 -236
  83. package/dist/components/forms/input/Input.js +0 -77
  84. package/dist/components/forms/input/Input.module.css +0 -468
  85. package/dist/components/forms/input-container/InputContainer.js +0 -15
  86. package/dist/components/forms/input-container/InputContainer.module.css +0 -56
  87. package/dist/components/forms/multi-select/MultiSelect.js +0 -122
  88. package/dist/components/forms/radio-buttons/RadioButton.js +0 -26
  89. package/dist/components/forms/radio-buttons/RadioButtonGroup.js +0 -19
  90. package/dist/components/forms/radio-buttons/RadioButtons.module.css +0 -118
  91. package/dist/components/forms/select/Select.js +0 -185
  92. package/dist/components/forms/select/Select.module.css +0 -32
  93. package/dist/components/forms/text-area/Textarea.js +0 -47
  94. package/dist/components/forms/text-area/Textarea.module.css +0 -70
  95. package/dist/components/forms/typeahead/Typeahead.js +0 -668
  96. package/dist/components/forms/typeahead/Typeahead.module.css +0 -38
  97. package/dist/components/grid/Grid.js +0 -23
  98. package/dist/components/grid/Grid.module.css +0 -35
  99. package/dist/components/headline/CollapsibleHeadline.js +0 -29
  100. package/dist/components/headline/Headline.js +0 -26
  101. package/dist/components/headline/Headline.module.css +0 -165
  102. package/dist/components/hyperlink/Hyperlink.js +0 -40
  103. package/dist/components/hyperlink/Hyperlink.module.css +0 -107
  104. package/dist/components/icon/Icon.js +0 -14
  105. package/dist/components/icon/Icon.module.css +0 -36
  106. package/dist/components/interval-select/IntervalSelect.js +0 -99
  107. package/dist/components/json-viewer/HighlightedText.js +0 -6
  108. package/dist/components/json-viewer/JsonNode.js +0 -30
  109. package/dist/components/json-viewer/JsonViewer.js +0 -68
  110. package/dist/components/json-viewer/JsonViewer.module.css +0 -346
  111. package/dist/components/json-viewer/types.js +0 -1
  112. package/dist/components/json-viewer/useClipboardStatus.js +0 -11
  113. package/dist/components/json-viewer/utils.js +0 -125
  114. package/dist/components/menu/Menu.js +0 -165
  115. package/dist/components/menu/Menu.module.css +0 -211
  116. package/dist/components/meta-bar/MetaBar.js +0 -9
  117. package/dist/components/meta-bar/MetaBar.module.css +0 -27
  118. package/dist/components/nav-bar/NavBar.js +0 -29
  119. package/dist/components/nav-bar/NavBar.module.css +0 -200
  120. package/dist/components/overlay/fade-overlay/FadeOverlay.js +0 -8
  121. package/dist/components/overlay/fade-overlay/FadeOverlay.module.css +0 -54
  122. package/dist/components/overlay/modal/Modal.js +0 -115
  123. package/dist/components/overlay/modal/Modal.module.css +0 -109
  124. package/dist/components/overlay/modal/provider/ModalProvider.js +0 -73
  125. package/dist/components/overlay/side-panel/SidePanel.js +0 -83
  126. package/dist/components/overlay/side-panel/SidePanel.module.css +0 -177
  127. package/dist/components/overlay/side-panel/useSidePanel.js +0 -11
  128. package/dist/components/overlay/tooltip/Tooltip.js +0 -17
  129. package/dist/components/overlay/tooltip/Tooltip.module.css +0 -104
  130. package/dist/components/overlay/tooltip/TooltipProvider.js +0 -255
  131. package/dist/components/overlay/tooltip/useTooltipTrigger.js +0 -118
  132. package/dist/components/page/Page.js +0 -11
  133. package/dist/components/page/Page.module.css +0 -76
  134. package/dist/components/page-layout/PageLayout.js +0 -76
  135. package/dist/components/page-layout/PageLayout.module.css +0 -236
  136. package/dist/components/page-layout/components/layout-footer/LayoutFooter.js +0 -27
  137. package/dist/components/page-layout/components/layout-footer/LayoutFooter.module.css +0 -89
  138. package/dist/components/page-layout/components/page-layout-hero/PageLayoutHero.js +0 -14
  139. package/dist/components/page-layout/components/page-layout-hero/PageLayoutHero.module.css +0 -84
  140. package/dist/components/pagination/Pagination.js +0 -56
  141. package/dist/components/pagination/Pagination.module.css +0 -25
  142. package/dist/components/panel/Panel.js +0 -7
  143. package/dist/components/panel/Panel.module.css +0 -29
  144. package/dist/components/popover/Popover.js +0 -257
  145. package/dist/components/popover/Popover.module.css +0 -54
  146. package/dist/components/search-box/SearchBox.js +0 -170
  147. package/dist/components/search-box/SearchBox.module.css +0 -21
  148. package/dist/components/segmented-progress-bar/SegmentedProgressBar.js +0 -48
  149. package/dist/components/segmented-progress-bar/SegmentedProgressBar.module.css +0 -167
  150. package/dist/components/sidebar/Sidebar.js +0 -6
  151. package/dist/components/sidebar/components/SidebarItem.js +0 -8
  152. package/dist/components/sidebar/components/SidebarItem.module.css +0 -0
  153. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +0 -63
  154. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.module.css +0 -29
  155. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +0 -153
  156. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +0 -260
  157. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.js +0 -18
  158. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.module.css +0 -106
  159. package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +0 -26
  160. package/dist/components/sidebar/components/sidebar-items/SidebarItems.module.css +0 -20
  161. package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.js +0 -30
  162. package/dist/components/sidebar/providers/SidebarProvider.js +0 -229
  163. package/dist/components/skeleton-loader/SkeletonLoader.js +0 -73
  164. package/dist/components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem.js +0 -13
  165. package/dist/components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem.module.css +0 -51
  166. package/dist/components/split-button/SplitButton.js +0 -10
  167. package/dist/components/split-button/SplitButton.module.css +0 -32
  168. package/dist/components/split-pane/SplitPane.js +0 -107
  169. package/dist/components/split-pane/SplitPane.module.css +0 -111
  170. package/dist/components/split-pane/provider/SplitPaneContext.js +0 -124
  171. package/dist/components/stack/Stack.js +0 -19
  172. package/dist/components/state-page/StatePage.js +0 -20
  173. package/dist/components/state-page/StatePage.module.css +0 -9
  174. package/dist/components/state-page/empty.js +0 -2
  175. package/dist/components/state-page/error.js +0 -2
  176. package/dist/components/state-page/notFound.js +0 -2
  177. package/dist/components/sticky-footer-layout/StickyFooterLayout.js +0 -64
  178. package/dist/components/table/Table.js +0 -50
  179. package/dist/components/table/Table.module.css +0 -536
  180. package/dist/components/table/Table.types.js +0 -1
  181. package/dist/components/table/TanstackTable.js +0 -111
  182. package/dist/components/table/components/TableBody.js +0 -10
  183. package/dist/components/table/components/TableHeader.js +0 -7
  184. package/dist/components/table/components/TableHeaderCell.js +0 -24
  185. package/dist/components/table/components/TableLoadingBody.js +0 -26
  186. package/dist/components/table/components/TablePagination.js +0 -1
  187. package/dist/components/table/components/TableRow.js +0 -54
  188. package/dist/components/table/components/TableSelectionCell.js +0 -16
  189. package/dist/components/table/components/column-resizer/ColumnResizer.js +0 -5
  190. package/dist/components/table/components/column-resizer/ColumnResizer.module.css +0 -22
  191. package/dist/components/table/components/empty-state/EmptyState.js +0 -23
  192. package/dist/components/table/components/empty-state/EmptyState.module.css +0 -4
  193. package/dist/components/table/components/table-settings/TableSettings.js +0 -63
  194. package/dist/components/table/hooks/useTableRowInteractions.js +0 -30
  195. package/dist/components/table/table.classes.js +0 -23
  196. package/dist/components/table/table.utils.js +0 -47
  197. package/dist/components/table/tanstackTable.utils.js +0 -175
  198. package/dist/components/tabs/Tabs.js +0 -125
  199. package/dist/components/tabs/Tabs.module.css +0 -204
  200. package/dist/components/theme-button/ThemeButton.js +0 -23
  201. package/dist/components/toast/Toast.js +0 -20
  202. package/dist/components/toast/Toast.module.css +0 -161
  203. package/dist/components/toast/provider/ToastProvider.js +0 -70
  204. package/dist/components/user-display/UserDisplay.js +0 -6
  205. package/dist/components/user-display/UserDisplay.module.css +0 -25
  206. package/dist/constants/severity.js +0 -24
  207. package/dist/constants/severity.types.js +0 -1
  208. package/dist/constants/sizes.js +0 -7
  209. package/dist/hooks/useDeviceSize.js +0 -32
  210. package/dist/hooks/useListNavigation.js +0 -234
  211. package/dist/hooks/usePagination.js +0 -140
  212. package/dist/hooks/useSorting.js +0 -118
  213. package/dist/hooks/useTableData.js +0 -45
  214. package/dist/hooks/useTableSelection.js +0 -164
  215. package/dist/hooks/useTableSettings.js +0 -71
  216. package/dist/hooks/useTheme.js +0 -66
  217. package/dist/hooks/useTimeDuration.js +0 -68
  218. package/dist/hooks/useViewportFill.js +0 -77
  219. package/dist/styles/animation.js +0 -5
  220. package/dist/styles/themes/types.js +0 -1
  221. package/dist/types/a11y-props.types.js +0 -1
  222. package/dist/types/sizes.types.js +0 -1
  223. package/dist/utils/arrays/nested-filtering.js +0 -48
  224. package/dist/utils/date/formatDate.js +0 -51
  225. package/dist/utils/localStorage.utils.js +0 -78
  226. package/dist/utils/text/get-highlighted-segments.js +0 -46
@@ -1,164 +0,0 @@
1
- 'use client';
2
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- const EMPTY_IDS = new Set();
4
- function safeParseIds(raw) {
5
- if (!raw)
6
- return null;
7
- try {
8
- const parsed = JSON.parse(raw);
9
- if (!Array.isArray(parsed))
10
- return null;
11
- return parsed.filter((v) => typeof v === 'string' || typeof v === 'number');
12
- }
13
- catch {
14
- return null;
15
- }
16
- }
17
- function serializeIds(ids) {
18
- return JSON.stringify(Array.from(ids));
19
- }
20
- function areSetsEqual(a, b) {
21
- if (a.size !== b.size)
22
- return false;
23
- for (const value of a) {
24
- if (!b.has(value))
25
- return false;
26
- }
27
- return true;
28
- }
29
- export function useTableSelection({ storageKey, items, getId, initialSelectedIds, onSelectionChange, selectionMode = 'single', pruneToItems = false, storage = 'session', }) {
30
- const resolvedInitialSelectedIds = initialSelectedIds !== null && initialSelectedIds !== void 0 ? initialSelectedIds : EMPTY_IDS;
31
- const [selectedIds, setSelectedIds] = useState(resolvedInitialSelectedIds);
32
- const [hydrated, setHydrated] = useState(false);
33
- const lastWrittenRef = useRef(null);
34
- const itemsById = useMemo(() => {
35
- const map = new Map();
36
- for (const item of items) {
37
- map.set(getId(item), item);
38
- }
39
- return map;
40
- }, [items, getId]);
41
- useEffect(() => {
42
- if (typeof window === 'undefined')
43
- return;
44
- const storageApi = storage === 'local' ? window.localStorage : window.sessionStorage;
45
- if (!storageKey) {
46
- setSelectedIds(prev => areSetsEqual(prev, resolvedInitialSelectedIds) ? prev : new Set(resolvedInitialSelectedIds));
47
- setHydrated(true);
48
- lastWrittenRef.current = null;
49
- return;
50
- }
51
- const parsed = safeParseIds(storageApi.getItem(storageKey));
52
- const next = new Set(parsed !== null && parsed !== void 0 ? parsed : Array.from(resolvedInitialSelectedIds));
53
- setSelectedIds(prev => (areSetsEqual(prev, next) ? prev : next));
54
- lastWrittenRef.current = serializeIds(next);
55
- setHydrated(true);
56
- }, [storage, storageKey, resolvedInitialSelectedIds]);
57
- useEffect(() => {
58
- if (!pruneToItems)
59
- return;
60
- const visibleIds = new Set(Array.from(itemsById.keys()));
61
- setSelectedIds(prev => {
62
- if (prev.size === 0)
63
- return prev;
64
- if (visibleIds.size === 0)
65
- return prev;
66
- const next = new Set();
67
- for (const id of prev) {
68
- if (visibleIds.has(id))
69
- next.add(id);
70
- }
71
- return areSetsEqual(prev, next) ? prev : next;
72
- });
73
- }, [pruneToItems, itemsById]);
74
- const selectedItemMap = useMemo(() => {
75
- const map = new Map();
76
- for (const id of selectedIds) {
77
- const item = itemsById.get(id);
78
- if (item !== undefined)
79
- map.set(id, item);
80
- }
81
- return map;
82
- }, [selectedIds, itemsById]);
83
- const selectedItems = useMemo(() => Array.from(selectedItemMap.values()), [selectedItemMap]);
84
- const allSelected = useMemo(() => {
85
- if (items.length === 0)
86
- return false;
87
- return items.every(item => selectedIds.has(getId(item)));
88
- }, [items, selectedIds, getId]);
89
- const anySelected = useMemo(() => selectedIds.size > 0, [selectedIds]);
90
- useEffect(() => {
91
- if (!hydrated)
92
- return;
93
- if (typeof window === 'undefined')
94
- return;
95
- if (storageKey) {
96
- const storageApi = storage === 'local' ? window.localStorage : window.sessionStorage;
97
- const nextStr = serializeIds(selectedIds);
98
- if (lastWrittenRef.current !== nextStr) {
99
- storageApi.setItem(storageKey, nextStr);
100
- lastWrittenRef.current = nextStr;
101
- }
102
- }
103
- onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange({ selectedIds, selectedItems });
104
- }, [hydrated, onSelectionChange, selectedIds, selectedItems, storage, storageKey]);
105
- const toggleId = useCallback((id, selected) => {
106
- setSelectedIds(prev => {
107
- const next = new Set(prev);
108
- const isSelected = next.has(id);
109
- const shouldSelect = selected === undefined ? !isSelected : selected;
110
- if (selectionMode === 'single') {
111
- next.clear();
112
- if (shouldSelect)
113
- next.add(id);
114
- return areSetsEqual(prev, next) ? prev : next;
115
- }
116
- if (shouldSelect)
117
- next.add(id);
118
- else
119
- next.delete(id);
120
- return areSetsEqual(prev, next) ? prev : next;
121
- });
122
- }, [selectionMode]);
123
- const toggleItem = useCallback((item) => {
124
- toggleId(getId(item));
125
- }, [toggleId, getId]);
126
- const selectOnly = useCallback((id) => {
127
- setSelectedIds(prev => {
128
- const next = new Set([id]);
129
- return areSetsEqual(prev, next) ? prev : next;
130
- });
131
- }, []);
132
- const clearSelection = useCallback(() => {
133
- setSelectedIds(prev => (prev.size === 0 ? prev : new Set()));
134
- }, []);
135
- const toggleAll = useCallback((selected) => {
136
- if (!selected) {
137
- clearSelection();
138
- return;
139
- }
140
- if (selectionMode === 'single') {
141
- const first = items[0];
142
- const next = first ? new Set([getId(first)]) : new Set();
143
- setSelectedIds(prev => (areSetsEqual(prev, next) ? prev : next));
144
- return;
145
- }
146
- const next = new Set();
147
- for (const item of items) {
148
- next.add(getId(item));
149
- }
150
- setSelectedIds(prev => (areSetsEqual(prev, next) ? prev : next));
151
- }, [clearSelection, getId, items, selectionMode]);
152
- return {
153
- selectedIds,
154
- selectedItems,
155
- selectedItemMap,
156
- toggleItem,
157
- toggleId,
158
- selectOnly,
159
- clearSelection,
160
- allSelected,
161
- anySelected,
162
- toggleAll,
163
- };
164
- }
@@ -1,71 +0,0 @@
1
- 'use client';
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);
34
- useEffect(() => {
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]);
49
- const toggleViewMode = useCallback(() => {
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]);
64
- return {
65
- viewMode: state.viewMode,
66
- toggleViewMode,
67
- setViewMode,
68
- visibleColumnIds: state.visibleColumnIds,
69
- setVisibleColumnIds,
70
- };
71
- }
@@ -1,66 +0,0 @@
1
- 'use client';
2
- import { useCallback, useEffect, useState } from 'react';
3
- const THEME_VARIANTS = ['light', 'dark', 'system'];
4
- const STORAGE_KEY = 'dbc_theme';
5
- function isThemeVariant(x) {
6
- return !!x && THEME_VARIANTS.includes(x);
7
- }
8
- function getCookie(name) {
9
- const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));
10
- return match ? decodeURIComponent(match[1]) : null;
11
- }
12
- function persistTheme(id) {
13
- try {
14
- localStorage.setItem(STORAGE_KEY, id);
15
- }
16
- catch {
17
- console.error('Failed to access localStorage');
18
- }
19
- try {
20
- document.cookie = `${STORAGE_KEY}=${encodeURIComponent(id)}; Path=/; Max-Age=${60 * 60 * 24 * 365}`;
21
- }
22
- catch {
23
- console.error('Failed to set theme cookie');
24
- }
25
- }
26
- function getTheme() {
27
- return document.documentElement.dataset.theme;
28
- }
29
- function applyTheme(id) {
30
- document.documentElement.dataset.theme = id;
31
- }
32
- export function useTheme(initialTheme = 'system') {
33
- const [theme, setTheme] = useState(null);
34
- useEffect(() => {
35
- const themeFromDataAttributes = getTheme();
36
- let resolved = isThemeVariant(themeFromDataAttributes)
37
- ? themeFromDataAttributes
38
- : initialTheme;
39
- // Prefer cookie (SSR + client consistency)
40
- const fromCookie = getCookie(STORAGE_KEY);
41
- if (isThemeVariant(fromCookie)) {
42
- resolved = fromCookie;
43
- }
44
- else {
45
- // fallback to localStorage
46
- try {
47
- const fromStorage = localStorage.getItem(STORAGE_KEY);
48
- if (isThemeVariant(fromStorage))
49
- resolved = fromStorage;
50
- }
51
- catch {
52
- console.error('Failed to access localStorage');
53
- }
54
- }
55
- applyTheme(resolved);
56
- setTheme(resolved);
57
- persistTheme(resolved);
58
- }, [initialTheme]);
59
- const switchTheme = useCallback((id) => {
60
- applyTheme(id);
61
- setTheme(id);
62
- persistTheme(id);
63
- return id;
64
- }, []);
65
- return { theme, switchTheme };
66
- }
@@ -1,68 +0,0 @@
1
- 'use client';
2
- import { useEffect, useMemo, useState } from 'react';
3
- function defaultDuration(ms) {
4
- if (!Number.isFinite(ms) || ms < 0)
5
- return '—';
6
- const sec = Math.floor(ms / 1000) % 60;
7
- const min = Math.floor(ms / (1000 * 60)) % 60;
8
- const hr = Math.floor(ms / (1000 * 60 * 60));
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`;
16
- }
17
- export function useTimeDuration({ start, end, dateFormat = {
18
- year: '2-digit',
19
- month: '2-digit',
20
- day: '2-digit',
21
- hour: '2-digit',
22
- minute: '2-digit',
23
- second: '2-digit',
24
- }, fallback = '—', liveUpdate = false, formatDuration = defaultDuration, }) {
25
- const [hydrated, setHydrated] = useState(false);
26
- const [tick, setTick] = useState(0);
27
- useEffect(() => setHydrated(true), []);
28
- useEffect(() => {
29
- if (!liveUpdate)
30
- return;
31
- if (end && end.getTime() <= Date.now())
32
- return;
33
- const timer = setInterval(() => {
34
- if (end && end.getTime() <= Date.now()) {
35
- clearInterval(timer);
36
- }
37
- setTick(tick => tick + 1);
38
- }, 1000);
39
- return () => clearInterval(timer);
40
- }, [liveUpdate, end]);
41
- const started = useMemo(() => {
42
- if (!start)
43
- return fallback;
44
- if (!hydrated)
45
- return fallback;
46
- return new Intl.DateTimeFormat('da-DK', dateFormat).format(start);
47
- }, [start, hydrated, fallback, dateFormat]);
48
- const ended = useMemo(() => {
49
- if (!end)
50
- return fallback;
51
- if (!hydrated)
52
- return fallback;
53
- return new Intl.DateTimeFormat('da-DK', dateFormat).format(end);
54
- }, [end, hydrated, fallback, dateFormat]);
55
- const duration = useMemo(() => {
56
- if (!start || !hydrated)
57
- return fallback;
58
- const now = Date.now();
59
- if (!end) {
60
- return formatDuration(now - start.getTime());
61
- }
62
- if (end.getTime() > now) {
63
- return formatDuration(end.getTime() - now);
64
- }
65
- return formatDuration(end.getTime() - start.getTime());
66
- }, [start, end, fallback, hydrated, formatDuration, tick]);
67
- return { started, ended, isFinished: !!start && !!end, duration, hydrated };
68
- }
@@ -1,77 +0,0 @@
1
- 'use client';
2
- import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
3
- const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
4
- export function useViewportFill(ref, { bottomOffset = 0, min = 120, includeMarginTop = false, watchRef } = {}) {
5
- const [maxHeight, setMaxHeight] = useState(min);
6
- const raf = useRef(null);
7
- const measure = useCallback(() => {
8
- if (typeof window === 'undefined' || !ref.current)
9
- return;
10
- const el = ref.current;
11
- const rect = el.getBoundingClientRect();
12
- let top = rect.top;
13
- if (includeMarginTop) {
14
- const marginTop = parseFloat(window.getComputedStyle(el).marginTop || '0') || 0;
15
- top -= marginTop;
16
- }
17
- const next = Math.max(min, Math.floor(window.innerHeight - bottomOffset - top));
18
- setMaxHeight(prev => (prev === next ? prev : next));
19
- }, [ref, bottomOffset, min, includeMarginTop]);
20
- const scheduleMeasure = useCallback(() => {
21
- if (typeof window === 'undefined')
22
- return;
23
- if (raf.current != null) {
24
- cancelAnimationFrame(raf.current);
25
- }
26
- raf.current = window.requestAnimationFrame(() => {
27
- raf.current = null;
28
- measure();
29
- });
30
- }, [measure]);
31
- useIsomorphicLayoutEffect(() => {
32
- measure();
33
- }, [measure]);
34
- useEffect(() => {
35
- var _a;
36
- if (typeof window === 'undefined' || !ref.current)
37
- return;
38
- const target = ref.current;
39
- const extra = (_a = watchRef === null || watchRef === void 0 ? void 0 : watchRef.current) !== null && _a !== void 0 ? _a : null;
40
- const parent = target.parentElement;
41
- const onResize = () => scheduleMeasure();
42
- const onTransitionOrAnimationEnd = () => scheduleMeasure();
43
- window.addEventListener('resize', onResize);
44
- document.addEventListener('transitionend', onTransitionOrAnimationEnd, true);
45
- document.addEventListener('animationend', onTransitionOrAnimationEnd, true);
46
- let resizeObserver = null;
47
- if ('ResizeObserver' in window) {
48
- resizeObserver = new ResizeObserver(() => scheduleMeasure());
49
- resizeObserver.observe(target);
50
- if (parent && parent !== target) {
51
- resizeObserver.observe(parent);
52
- }
53
- if (extra && extra !== target && extra !== parent) {
54
- resizeObserver.observe(extra);
55
- }
56
- }
57
- return () => {
58
- window.removeEventListener('resize', onResize);
59
- document.removeEventListener('transitionend', onTransitionOrAnimationEnd, true);
60
- document.removeEventListener('animationend', onTransitionOrAnimationEnd, true);
61
- resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
62
- if (raf.current != null) {
63
- cancelAnimationFrame(raf.current);
64
- raf.current = null;
65
- }
66
- };
67
- }, [ref, watchRef, scheduleMeasure]);
68
- const style = useMemo(() => ({
69
- maxHeight,
70
- overflow: 'auto',
71
- }), [maxHeight]);
72
- return {
73
- maxHeight,
74
- style,
75
- recompute: measure,
76
- };
77
- }
@@ -1,5 +0,0 @@
1
- export const MOTION_MS = {
2
- panelSlide: 300,
3
- modal: 200,
4
- tooltipOpen: 300,
5
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,48 +0,0 @@
1
- const normalize = (s) => s.normalize('NFKC').toLowerCase().trim();
2
- const toTerms = (q) => (Array.isArray(q) ? q : q.split(/\s+/)).map(normalize).filter(Boolean);
3
- const valueToSearchable = (value) => typeof value === 'string'
4
- ? value
5
- : Array.isArray(value) || typeof value === 'object'
6
- ? JSON.stringify(value)
7
- : value == null
8
- ? ''
9
- : String(value);
10
- const itemMatches = (item, keys, terms, mode) => {
11
- if (terms.length === 0)
12
- return true;
13
- const haystack = keys
14
- .map(k => valueToSearchable(item[k]))
15
- .join(' ')
16
- .toString();
17
- const h = normalize(haystack);
18
- const hit = (t) => h.includes(t);
19
- return mode === 'AND' ? terms.every(hit) : terms.some(hit);
20
- };
21
- export function nestedFiltering(items, opts) {
22
- const { keys, query, includeParents = true, childrenKey, mode = 'AND' } = opts;
23
- const ck = (childrenKey !== null && childrenKey !== void 0 ? childrenKey : 'children');
24
- const terms = toTerms(query);
25
- const searchNested = (list) => {
26
- const out = [];
27
- for (const item of list) {
28
- const children = item[ck] || [];
29
- const filteredChildren = searchNested(children);
30
- const matchedSelf = itemMatches(item, keys, terms, mode);
31
- if (matchedSelf) {
32
- const clone = { ...item, [ck]: filteredChildren };
33
- out.push(clone);
34
- }
35
- else if (filteredChildren.length) {
36
- if (includeParents) {
37
- const clone = { ...item, [ck]: filteredChildren };
38
- out.push(clone);
39
- }
40
- else {
41
- out.push(...filteredChildren);
42
- }
43
- }
44
- }
45
- return out;
46
- };
47
- return searchNested(items);
48
- }
@@ -1,51 +0,0 @@
1
- /**
2
- * Formats a Date as "dd/mm/yyyy" or "dd/mm/yyyy hh:mm:ss".
3
- * Optionally returns user-friendly Danish labels like "I dag" or "I går".
4
- *
5
- * Examples:
6
- * - formatDate(new Date(), { userFriendlyLabel: true }) => "I dag"
7
- * - formatDate(new Date(), { userFriendlyLabel: true, showTime: true }) => "I dag, kl. 14:30"
8
- * - formatDate(date, { showTime: true }) => "10.03.2026 14:30"
9
- *
10
- * @param date - The Date or date-parsable value to format
11
- * @param options.showTime - If true, append time "hh:mm" or "hh:mm:ss"
12
- * @param options.showSeconds - If true, append seconds when showTime is enabled
13
- * @param options.userFriendlyLabel - If true, use "I dag" / "I går" when applicable
14
- * @returns A formatted string
15
- */
16
- export function formatDate(date, options = {}) {
17
- const d = date instanceof Date ? date : new Date(date);
18
- if (isNaN(d.getTime()))
19
- return '';
20
- const { showTime = false, showSeconds = false, userFriendlyLabel = false } = options;
21
- const pad = (n) => n.toString().padStart(2, '0');
22
- const formatTime = () => {
23
- const hours = pad(d.getHours());
24
- const minutes = pad(d.getMinutes());
25
- if (!showSeconds)
26
- return `${hours}:${minutes}`;
27
- const seconds = pad(d.getSeconds());
28
- return `${hours}:${minutes}:${seconds}`;
29
- };
30
- const isSameCalendarDay = (a, b) => a.getDate() === b.getDate() &&
31
- a.getMonth() === b.getMonth() &&
32
- a.getFullYear() === b.getFullYear();
33
- if (userFriendlyLabel) {
34
- const now = new Date();
35
- const yesterday = new Date(now);
36
- yesterday.setDate(now.getDate() - 1);
37
- if (isSameCalendarDay(d, now)) {
38
- return showTime ? `I dag, kl. ${formatTime()}` : 'I dag';
39
- }
40
- if (isSameCalendarDay(d, yesterday)) {
41
- return showTime ? `I går, kl. ${formatTime()}` : 'I går';
42
- }
43
- }
44
- const day = pad(d.getDate());
45
- const month = pad(d.getMonth() + 1);
46
- const year = d.getFullYear();
47
- const base = `${day}.${month}.${year}`;
48
- if (!showTime)
49
- return base;
50
- return `${base} ${formatTime()}`;
51
- }
@@ -1,78 +0,0 @@
1
- function isBrowser() {
2
- return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';
3
- }
4
- /**
5
- * Safely read from localStorage.
6
- * - Returns undefined if not in browser
7
- * - Returns parsed JSON if value is JSON
8
- * - Returns plain string if not JSON
9
- * - Never throws
10
- */
11
- export function readLocalStorage(key) {
12
- if (!isBrowser())
13
- return undefined;
14
- try {
15
- const raw = window.localStorage.getItem(key);
16
- if (raw == null)
17
- return undefined;
18
- // Try parse once
19
- try {
20
- const parsed = JSON.parse(raw);
21
- // Handle double-stringified JSON
22
- if (typeof parsed === 'string') {
23
- try {
24
- return JSON.parse(parsed);
25
- }
26
- catch {
27
- return parsed;
28
- }
29
- }
30
- return parsed;
31
- }
32
- catch {
33
- // Not JSON — return as plain string
34
- return raw;
35
- }
36
- }
37
- catch {
38
- return undefined;
39
- }
40
- }
41
- /**
42
- * Safely write to localStorage.
43
- * - Automatically JSON.stringifies objects/arrays
44
- * - Stores plain strings as-is
45
- * - Never throws
46
- */
47
- export function writeLocalStorage(key, value) {
48
- if (!isBrowser())
49
- return;
50
- try {
51
- if (value === undefined) {
52
- window.localStorage.removeItem(key);
53
- return;
54
- }
55
- if (typeof value === 'string') {
56
- window.localStorage.setItem(key, value);
57
- }
58
- else {
59
- window.localStorage.setItem(key, JSON.stringify(value));
60
- }
61
- }
62
- catch {
63
- // ignore quota errors etc.
64
- }
65
- }
66
- /**
67
- * Remove key safely
68
- */
69
- export function removeLocalStorage(key) {
70
- if (!isBrowser())
71
- return;
72
- try {
73
- window.localStorage.removeItem(key);
74
- }
75
- catch {
76
- // ignore
77
- }
78
- }
@@ -1,46 +0,0 @@
1
- function normalizeTerms(query) {
2
- const terms = Array.isArray(query) ? query : [query];
3
- return [...new Set(terms.map(term => term.trim().toLowerCase()).filter(Boolean))].sort((a, b) => b.length - a.length);
4
- }
5
- export function getHighlightedSegments(text, query) {
6
- const terms = normalizeTerms(query);
7
- if (!text || terms.length === 0)
8
- return [{ text, matched: false }];
9
- const lower = text.toLowerCase();
10
- const ranges = [];
11
- for (const term of terms) {
12
- let startIndex = 0;
13
- while (startIndex < lower.length) {
14
- const matchIndex = lower.indexOf(term, startIndex);
15
- if (matchIndex === -1)
16
- break;
17
- ranges.push({ start: matchIndex, end: matchIndex + term.length });
18
- startIndex = matchIndex + term.length;
19
- }
20
- }
21
- if (ranges.length === 0)
22
- return [{ text, matched: false }];
23
- ranges.sort((a, b) => a.start - b.start || a.end - b.end);
24
- const mergedRanges = [];
25
- for (const range of ranges) {
26
- const previous = mergedRanges[mergedRanges.length - 1];
27
- if (!previous || range.start > previous.end) {
28
- mergedRanges.push({ ...range });
29
- continue;
30
- }
31
- previous.end = Math.max(previous.end, range.end);
32
- }
33
- const segments = [];
34
- let cursor = 0;
35
- for (const range of mergedRanges) {
36
- if (range.start > cursor) {
37
- segments.push({ text: text.slice(cursor, range.start), matched: false });
38
- }
39
- segments.push({ text: text.slice(range.start, range.end), matched: true });
40
- cursor = range.end;
41
- }
42
- if (cursor < text.length) {
43
- segments.push({ text: text.slice(cursor), matched: false });
44
- }
45
- return segments.length > 0 ? segments : [{ text, matched: false }];
46
- }