@dbcdk/react-components 0.0.96 → 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 (223) hide show
  1. package/dist/components/table/Table.d.ts +1 -1
  2. package/dist/components/table/Table.types.d.ts +3 -0
  3. package/dist/components/table/components/TableHeader.d.ts +2 -1
  4. package/dist/index.cjs +12750 -0
  5. package/dist/index.css +7149 -0
  6. package/dist/index.js +12641 -79
  7. package/dist/tanstack.cjs +2674 -0
  8. package/dist/tanstack.css +1267 -0
  9. package/dist/tanstack.js +2650 -3
  10. package/dist/themes/dbc.css +3 -0
  11. package/dist/themes/forfatterweb.css +2 -0
  12. package/package.json +11 -10
  13. package/dist/assets/logo.js +0 -2
  14. package/dist/components/__stories__/_data/table.d.ts +0 -15
  15. package/dist/components/__stories__/_data/table.js +0 -55
  16. package/dist/components/__stories__/_data/tabs.d.ts +0 -9
  17. package/dist/components/__stories__/_data/tabs.js +0 -31
  18. package/dist/components/__stories__/story-components/Colors.d.ts +0 -11
  19. package/dist/components/__stories__/story-components/Colors.js +0 -96
  20. package/dist/components/__stories__/story-components/Colors.module.css +0 -27
  21. package/dist/components/__stories__/story-components/ComponentSizes.d.ts +0 -2
  22. package/dist/components/__stories__/story-components/ComponentSizes.js +0 -26
  23. package/dist/components/__stories__/story-components/Elevation.d.ts +0 -2
  24. package/dist/components/__stories__/story-components/Elevation.js +0 -49
  25. package/dist/components/__stories__/story-components/Flex.d.ts +0 -2
  26. package/dist/components/__stories__/story-components/Flex.js +0 -177
  27. package/dist/components/__stories__/story-components/Flex.module.css +0 -317
  28. package/dist/components/__stories__/story-components/Spacing.d.ts +0 -6
  29. package/dist/components/__stories__/story-components/Spacing.js +0 -76
  30. package/dist/components/__stories__/story-components/Spacing.module.css +0 -154
  31. package/dist/components/accordion/Accordion.js +0 -70
  32. package/dist/components/accordion/Accordion.module.css +0 -28
  33. package/dist/components/accordion/components/AccordionRow.js +0 -53
  34. package/dist/components/accordion/components/AccordionRow.module.css +0 -90
  35. package/dist/components/alert/Alert.js +0 -17
  36. package/dist/components/alert/Alert.module.css +0 -98
  37. package/dist/components/app-header/AppHeader.js +0 -5
  38. package/dist/components/app-header/AppHeader.module.css +0 -74
  39. package/dist/components/attribute-chip/AttributeChip.js +0 -5
  40. package/dist/components/attribute-chip/AttributeChip.module.css +0 -65
  41. package/dist/components/avatar/Avatar.js +0 -48
  42. package/dist/components/avatar/Avatar.module.css +0 -91
  43. package/dist/components/breadcrumbs/Breadcrumbs.js +0 -6
  44. package/dist/components/breadcrumbs/Breadcrumbs.module.css +0 -80
  45. package/dist/components/button/Button.js +0 -81
  46. package/dist/components/button/Button.module.css +0 -249
  47. package/dist/components/button-select/ButtonSelect.js +0 -7
  48. package/dist/components/button-select/ButtonSelect.module.css +0 -40
  49. package/dist/components/card/Card.js +0 -71
  50. package/dist/components/card/Card.module.css +0 -160
  51. package/dist/components/card/components/CardMeta.js +0 -26
  52. package/dist/components/card/components/CardMeta.module.css +0 -55
  53. package/dist/components/card-container/CardContainer.js +0 -6
  54. package/dist/components/card-container/CardContainer.module.css +0 -61
  55. package/dist/components/chip/Chip.js +0 -31
  56. package/dist/components/chip/Chip.module.css +0 -236
  57. package/dist/components/circle/Circle.js +0 -5
  58. package/dist/components/circle/Circle.module.css +0 -128
  59. package/dist/components/clear-button/ClearButton.js +0 -13
  60. package/dist/components/clear-button/ClearButton.module.css +0 -26
  61. package/dist/components/code-block/CodeBlock.js +0 -58
  62. package/dist/components/code-block/CodeBlock.module.css +0 -124
  63. package/dist/components/copy-button/CopyButton.js +0 -78
  64. package/dist/components/copy-button/CopyButton.module.css +0 -22
  65. package/dist/components/datetime-picker/DateTimePicker.js +0 -403
  66. package/dist/components/datetime-picker/DateTimePicker.module.css +0 -155
  67. package/dist/components/datetime-picker/dateTimeHelpers.js +0 -248
  68. package/dist/components/divider/Divider.js +0 -12
  69. package/dist/components/filter-field/FilterField.js +0 -191
  70. package/dist/components/filter-field/FilterField.module.css +0 -379
  71. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.js +0 -52
  72. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.module.css +0 -59
  73. package/dist/components/forms/checkbox/Checkbox.js +0 -28
  74. package/dist/components/forms/checkbox/Checkbox.module.css +0 -103
  75. package/dist/components/forms/checkbox-group/CheckboxGroup.js +0 -75
  76. package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +0 -115
  77. package/dist/components/forms/form-select/FormSelect.js +0 -86
  78. package/dist/components/forms/form-select/FormSelect.module.css +0 -236
  79. package/dist/components/forms/input/Input.js +0 -77
  80. package/dist/components/forms/input/Input.module.css +0 -468
  81. package/dist/components/forms/input-container/InputContainer.js +0 -15
  82. package/dist/components/forms/input-container/InputContainer.module.css +0 -60
  83. package/dist/components/forms/multi-select/MultiSelect.js +0 -122
  84. package/dist/components/forms/radio-buttons/RadioButton.js +0 -26
  85. package/dist/components/forms/radio-buttons/RadioButtonGroup.js +0 -19
  86. package/dist/components/forms/radio-buttons/RadioButtons.module.css +0 -118
  87. package/dist/components/forms/select/Select.js +0 -185
  88. package/dist/components/forms/select/Select.module.css +0 -32
  89. package/dist/components/forms/text-area/Textarea.js +0 -47
  90. package/dist/components/forms/text-area/Textarea.module.css +0 -70
  91. package/dist/components/forms/typeahead/Typeahead.js +0 -668
  92. package/dist/components/forms/typeahead/Typeahead.module.css +0 -38
  93. package/dist/components/grid/Grid.js +0 -23
  94. package/dist/components/grid/Grid.module.css +0 -35
  95. package/dist/components/headline/CollapsibleHeadline.js +0 -29
  96. package/dist/components/headline/Headline.js +0 -26
  97. package/dist/components/headline/Headline.module.css +0 -185
  98. package/dist/components/hyperlink/Hyperlink.js +0 -40
  99. package/dist/components/hyperlink/Hyperlink.module.css +0 -107
  100. package/dist/components/icon/Icon.js +0 -14
  101. package/dist/components/icon/Icon.module.css +0 -36
  102. package/dist/components/interval-select/IntervalSelect.js +0 -99
  103. package/dist/components/json-viewer/HighlightedText.js +0 -6
  104. package/dist/components/json-viewer/JsonNode.js +0 -30
  105. package/dist/components/json-viewer/JsonViewer.js +0 -68
  106. package/dist/components/json-viewer/JsonViewer.module.css +0 -346
  107. package/dist/components/json-viewer/types.js +0 -1
  108. package/dist/components/json-viewer/useClipboardStatus.js +0 -11
  109. package/dist/components/json-viewer/utils.js +0 -125
  110. package/dist/components/menu/Menu.js +0 -165
  111. package/dist/components/menu/Menu.module.css +0 -220
  112. package/dist/components/meta-bar/MetaBar.js +0 -9
  113. package/dist/components/meta-bar/MetaBar.module.css +0 -27
  114. package/dist/components/nav-bar/NavBar.js +0 -29
  115. package/dist/components/nav-bar/NavBar.module.css +0 -221
  116. package/dist/components/overlay/fade-overlay/FadeOverlay.js +0 -8
  117. package/dist/components/overlay/fade-overlay/FadeOverlay.module.css +0 -54
  118. package/dist/components/overlay/modal/Modal.js +0 -115
  119. package/dist/components/overlay/modal/Modal.module.css +0 -109
  120. package/dist/components/overlay/modal/provider/ModalProvider.js +0 -73
  121. package/dist/components/overlay/side-panel/SidePanel.js +0 -83
  122. package/dist/components/overlay/side-panel/SidePanel.module.css +0 -177
  123. package/dist/components/overlay/side-panel/useSidePanel.js +0 -11
  124. package/dist/components/overlay/tooltip/Tooltip.js +0 -17
  125. package/dist/components/overlay/tooltip/Tooltip.module.css +0 -104
  126. package/dist/components/overlay/tooltip/TooltipProvider.js +0 -255
  127. package/dist/components/overlay/tooltip/useTooltipTrigger.js +0 -118
  128. package/dist/components/page/Page.js +0 -11
  129. package/dist/components/page/Page.module.css +0 -89
  130. package/dist/components/page-layout/PageLayout.js +0 -76
  131. package/dist/components/page-layout/PageLayout.module.css +0 -236
  132. package/dist/components/page-layout/components/layout-footer/LayoutFooter.js +0 -27
  133. package/dist/components/page-layout/components/layout-footer/LayoutFooter.module.css +0 -89
  134. package/dist/components/page-layout/components/page-layout-hero/PageLayoutHero.js +0 -14
  135. package/dist/components/page-layout/components/page-layout-hero/PageLayoutHero.module.css +0 -84
  136. package/dist/components/pagination/Pagination.js +0 -56
  137. package/dist/components/pagination/Pagination.module.css +0 -25
  138. package/dist/components/panel/Panel.js +0 -7
  139. package/dist/components/panel/Panel.module.css +0 -29
  140. package/dist/components/popover/Popover.js +0 -257
  141. package/dist/components/popover/Popover.module.css +0 -54
  142. package/dist/components/search-box/SearchBox.js +0 -170
  143. package/dist/components/search-box/SearchBox.module.css +0 -21
  144. package/dist/components/segmented-progress-bar/SegmentedProgressBar.js +0 -48
  145. package/dist/components/segmented-progress-bar/SegmentedProgressBar.module.css +0 -167
  146. package/dist/components/sidebar/Sidebar.js +0 -6
  147. package/dist/components/sidebar/components/SidebarItem.js +0 -8
  148. package/dist/components/sidebar/components/SidebarItem.module.css +0 -0
  149. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +0 -63
  150. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.module.css +0 -29
  151. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +0 -153
  152. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +0 -260
  153. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.js +0 -18
  154. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.module.css +0 -106
  155. package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +0 -26
  156. package/dist/components/sidebar/components/sidebar-items/SidebarItems.module.css +0 -20
  157. package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.js +0 -30
  158. package/dist/components/sidebar/providers/SidebarProvider.js +0 -229
  159. package/dist/components/skeleton-loader/SkeletonLoader.js +0 -73
  160. package/dist/components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem.js +0 -13
  161. package/dist/components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem.module.css +0 -51
  162. package/dist/components/split-button/SplitButton.js +0 -10
  163. package/dist/components/split-button/SplitButton.module.css +0 -32
  164. package/dist/components/split-pane/SplitPane.js +0 -107
  165. package/dist/components/split-pane/SplitPane.module.css +0 -111
  166. package/dist/components/split-pane/provider/SplitPaneContext.js +0 -124
  167. package/dist/components/stack/Stack.js +0 -33
  168. package/dist/components/stack/Stack.module.css +0 -61
  169. package/dist/components/state-page/StatePage.js +0 -20
  170. package/dist/components/state-page/StatePage.module.css +0 -9
  171. package/dist/components/state-page/empty.js +0 -2
  172. package/dist/components/state-page/error.js +0 -2
  173. package/dist/components/state-page/notFound.js +0 -2
  174. package/dist/components/sticky-footer-layout/StickyFooterLayout.js +0 -64
  175. package/dist/components/table/Table.js +0 -50
  176. package/dist/components/table/Table.module.css +0 -536
  177. package/dist/components/table/Table.types.js +0 -1
  178. package/dist/components/table/TanstackTable.js +0 -111
  179. package/dist/components/table/components/TableBody.js +0 -10
  180. package/dist/components/table/components/TableHeader.js +0 -7
  181. package/dist/components/table/components/TableHeaderCell.js +0 -24
  182. package/dist/components/table/components/TableLoadingBody.js +0 -26
  183. package/dist/components/table/components/TablePagination.js +0 -1
  184. package/dist/components/table/components/TableRow.js +0 -54
  185. package/dist/components/table/components/TableSelectionCell.js +0 -16
  186. package/dist/components/table/components/column-resizer/ColumnResizer.js +0 -5
  187. package/dist/components/table/components/column-resizer/ColumnResizer.module.css +0 -22
  188. package/dist/components/table/components/empty-state/EmptyState.js +0 -23
  189. package/dist/components/table/components/empty-state/EmptyState.module.css +0 -4
  190. package/dist/components/table/components/table-settings/TableSettings.js +0 -63
  191. package/dist/components/table/hooks/useTableRowInteractions.js +0 -30
  192. package/dist/components/table/table.classes.js +0 -23
  193. package/dist/components/table/table.utils.js +0 -47
  194. package/dist/components/table/tanstackTable.utils.js +0 -175
  195. package/dist/components/tabs/Tabs.js +0 -125
  196. package/dist/components/tabs/Tabs.module.css +0 -233
  197. package/dist/components/theme-button/ThemeButton.js +0 -23
  198. package/dist/components/toast/Toast.js +0 -20
  199. package/dist/components/toast/Toast.module.css +0 -161
  200. package/dist/components/toast/provider/ToastProvider.js +0 -70
  201. package/dist/components/user-display/UserDisplay.js +0 -6
  202. package/dist/components/user-display/UserDisplay.module.css +0 -25
  203. package/dist/constants/severity.js +0 -24
  204. package/dist/constants/severity.types.js +0 -1
  205. package/dist/constants/sizes.js +0 -7
  206. package/dist/hooks/useDeviceSize.js +0 -32
  207. package/dist/hooks/useListNavigation.js +0 -234
  208. package/dist/hooks/usePagination.js +0 -140
  209. package/dist/hooks/useSorting.js +0 -118
  210. package/dist/hooks/useTableData.js +0 -45
  211. package/dist/hooks/useTableSelection.js +0 -164
  212. package/dist/hooks/useTableSettings.js +0 -71
  213. package/dist/hooks/useTheme.js +0 -66
  214. package/dist/hooks/useTimeDuration.js +0 -68
  215. package/dist/hooks/useViewportFill.js +0 -77
  216. package/dist/styles/animation.js +0 -5
  217. package/dist/styles/themes/types.js +0 -1
  218. package/dist/types/a11y-props.types.js +0 -1
  219. package/dist/types/sizes.types.js +0 -1
  220. package/dist/utils/arrays/nested-filtering.js +0 -48
  221. package/dist/utils/date/formatDate.js +0 -51
  222. package/dist/utils/localStorage.utils.js +0 -78
  223. package/dist/utils/text/get-highlighted-segments.js +0 -46
@@ -1,140 +0,0 @@
1
- 'use client';
2
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- function clamp(n, min, max) {
4
- return Math.max(min, Math.min(max, n));
5
- }
6
- function normalizePaginationState(next) {
7
- return {
8
- skip: Math.max(0, next.skip),
9
- take: Math.max(1, next.take),
10
- };
11
- }
12
- function safeParsePaginationState(raw) {
13
- if (!raw)
14
- return null;
15
- try {
16
- const parsed = JSON.parse(raw);
17
- if (typeof parsed !== 'object' ||
18
- parsed == null ||
19
- typeof parsed.skip !== 'number' ||
20
- typeof parsed.take !== 'number') {
21
- return null;
22
- }
23
- return normalizePaginationState({
24
- skip: parsed.skip,
25
- take: parsed.take,
26
- });
27
- }
28
- catch {
29
- return null;
30
- }
31
- }
32
- export function usePagination({ data = [], skip = 0, take = 10, state, onStateChange, resetOnDataChange = false, storageKey, }) {
33
- const isControlled = state != null;
34
- const [hydrated, setHydrated] = useState(() => !storageKey || isControlled);
35
- const [uncontrolled, setUncontrolled] = useState(() => {
36
- var _a;
37
- const initial = normalizePaginationState({
38
- skip,
39
- take,
40
- });
41
- if (typeof window === 'undefined' || !storageKey || isControlled) {
42
- return initial;
43
- }
44
- return (_a = safeParsePaginationState(window.localStorage.getItem(storageKey))) !== null && _a !== void 0 ? _a : initial;
45
- });
46
- // Hydrate from localStorage when key changes.
47
- useEffect(() => {
48
- if (typeof window === 'undefined')
49
- return;
50
- if (isControlled || !storageKey) {
51
- setHydrated(true);
52
- return;
53
- }
54
- const fallback = normalizePaginationState({ skip, take });
55
- const stored = safeParsePaginationState(window.localStorage.getItem(storageKey));
56
- setUncontrolled(stored !== null && stored !== void 0 ? stored : fallback);
57
- setHydrated(true);
58
- }, [isControlled, storageKey, skip, take]);
59
- // Keep initial props in sync ONLY for uncontrolled if props change.
60
- // Do not overwrite localStorage-hydrated state when storageKey is provided.
61
- const didInitRef = useRef(false);
62
- useEffect(() => {
63
- if (isControlled)
64
- return;
65
- if (storageKey)
66
- return;
67
- if (!didInitRef.current) {
68
- didInitRef.current = true;
69
- return;
70
- }
71
- setUncontrolled(prev => ({
72
- skip: prev.skip,
73
- take: Math.max(1, take),
74
- }));
75
- }, [isControlled, storageKey, take]);
76
- const paginationState = (isControlled ? state : uncontrolled);
77
- const totalCount = data.length;
78
- const safeTake = Math.max(1, paginationState.take);
79
- const maxSkip = Math.max(0, totalCount === 0 ? 0 : Math.floor((totalCount - 1) / safeTake) * safeTake);
80
- const safeSkip = clamp(Math.max(0, paginationState.skip), 0, maxSkip);
81
- const setPagination = useCallback((next) => {
82
- const normalized = normalizePaginationState(next);
83
- if (isControlled) {
84
- onStateChange === null || onStateChange === void 0 ? void 0 : onStateChange(normalized);
85
- return;
86
- }
87
- setUncontrolled(normalized);
88
- }, [isControlled, onStateChange]);
89
- const onPageChange = useCallback((pageEvent) => {
90
- const nextTake = Math.max(1, pageEvent.take);
91
- const nextSkip = Math.max(0, (pageEvent.page - 1) * nextTake);
92
- setPagination({ skip: nextSkip, take: nextTake });
93
- }, [setPagination]);
94
- const resetPage = useCallback(() => {
95
- setPagination({ skip: 0, take: safeTake });
96
- }, [setPagination, safeTake]);
97
- // Optional: reset page when data reference changes (after sort/filter).
98
- useEffect(() => {
99
- if (!resetOnDataChange)
100
- return;
101
- if (!hydrated)
102
- return;
103
- resetPage();
104
- // eslint-disable-next-line react-hooks/exhaustive-deps
105
- }, [resetOnDataChange, data, hydrated]);
106
- const paginatedData = useMemo(() => {
107
- return data.slice(safeSkip, safeSkip + safeTake);
108
- }, [data, safeSkip, safeTake]);
109
- const page = useMemo(() => Math.floor(safeSkip / safeTake) + 1, [safeSkip, safeTake]);
110
- // If uncontrolled and data shrinks such that skip becomes invalid, clamp it once.
111
- useEffect(() => {
112
- if (isControlled)
113
- return;
114
- if (safeSkip !== paginationState.skip) {
115
- setUncontrolled(prev => ({ ...prev, skip: safeSkip }));
116
- }
117
- }, [isControlled, safeSkip, paginationState.skip]);
118
- // Persist uncontrolled state to localStorage when enabled.
119
- useEffect(() => {
120
- if (typeof window === 'undefined')
121
- return;
122
- if (isControlled || !storageKey)
123
- return;
124
- if (!hydrated)
125
- return;
126
- window.localStorage.setItem(storageKey, JSON.stringify({
127
- skip: paginationState.skip,
128
- take: paginationState.take,
129
- }));
130
- }, [hydrated, isControlled, paginationState.skip, paginationState.take, storageKey]);
131
- return {
132
- paginatedData,
133
- paginationState: { skip: safeSkip, take: safeTake },
134
- onPageChange,
135
- setPagination,
136
- resetPage,
137
- page,
138
- totalCount,
139
- };
140
- }
@@ -1,118 +0,0 @@
1
- 'use client';
2
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- function defaultCompare(a, b, dir, nulls) {
4
- const aNull = a == null;
5
- const bNull = b == null;
6
- if (aNull || bNull) {
7
- if (aNull && bNull)
8
- return 0;
9
- const order = nulls === 'first' ? -1 : 1;
10
- return aNull ? order : -order;
11
- }
12
- // Dates
13
- if (a instanceof Date && b instanceof Date) {
14
- const diff = a.getTime() - b.getTime();
15
- return dir === 'asc' ? diff : -diff;
16
- }
17
- // Numbers
18
- if (typeof a === 'number' && typeof b === 'number') {
19
- const diff = a - b;
20
- return dir === 'asc' ? diff : -diff;
21
- }
22
- // Booleans
23
- if (typeof a === 'boolean' && typeof b === 'boolean') {
24
- const diff = Number(a) - Number(b);
25
- return dir === 'asc' ? diff : -diff;
26
- }
27
- // Strings (locale-aware-ish)
28
- const aStr = String(a);
29
- const bStr = String(b);
30
- const diff = aStr.localeCompare(bStr, undefined, { numeric: true, sensitivity: 'base' });
31
- return dir === 'asc' ? diff : -diff;
32
- }
33
- // Stable sort (decorate-sort-undecorate)
34
- function stableSort(arr, cmp) {
35
- return arr
36
- .map((item, idx) => ({ item, idx }))
37
- .sort((x, y) => {
38
- const c = cmp(x.item, y.item);
39
- return c !== 0 ? c : x.idx - y.idx;
40
- })
41
- .map(x => x.item);
42
- }
43
- export function useSorting({ data = [], sortBy = null, sortDirection = 'asc', state, onStateChange, columnComparators = {}, nulls = 'last', allowUnsort = true, resetOnDataChange = false, }) {
44
- const isControlled = state != null;
45
- const [uncontrolled, setUncontrolled] = useState(() => ({
46
- sortBy,
47
- sortDirection,
48
- }));
49
- const sortState = (isControlled ? state : uncontrolled);
50
- const setSort = useCallback((next) => {
51
- var _a, _b;
52
- const normalized = {
53
- sortBy: (_a = next.sortBy) !== null && _a !== void 0 ? _a : null,
54
- sortDirection: (_b = next.sortDirection) !== null && _b !== void 0 ? _b : null,
55
- };
56
- if (isControlled)
57
- onStateChange === null || onStateChange === void 0 ? void 0 : onStateChange(normalized);
58
- else
59
- setUncontrolled(normalized);
60
- }, [isControlled, onStateChange]);
61
- const clearSort = useCallback(() => setSort({ sortBy: null, sortDirection: null }), [setSort]);
62
- const onSortChange = useCallback((e) => {
63
- var _a, _b;
64
- const nextSortBy = ((_a = e.sortBy) !== null && _a !== void 0 ? _a : null);
65
- setSort(sortState);
66
- const current = sortState;
67
- if (nextSortBy == null) {
68
- return clearSort();
69
- }
70
- // Same column toggling
71
- if (current.sortBy === nextSortBy) {
72
- const nextDir = current.sortDirection === 'asc' ? 'desc' : allowUnsort ? null : 'asc';
73
- return setSort({ sortBy: nextSortBy, sortDirection: nextDir });
74
- }
75
- // New column: default to provided direction or asc
76
- return setSort({
77
- sortBy: nextSortBy,
78
- sortDirection: (_b = e.sortDirection) !== null && _b !== void 0 ? _b : 'asc',
79
- });
80
- }, [allowUnsort, clearSort, setSort, sortState]);
81
- // Optional reset on data ref change
82
- const didInitRef = useRef(false);
83
- useEffect(() => {
84
- if (!resetOnDataChange)
85
- return;
86
- if (!didInitRef.current) {
87
- didInitRef.current = true;
88
- return;
89
- }
90
- clearSort();
91
- // eslint-disable-next-line react-hooks/exhaustive-deps
92
- }, [resetOnDataChange, data]);
93
- const sortedData = useMemo(() => {
94
- const { sortBy: sb, sortDirection: dir } = sortState;
95
- if (!sb || !dir)
96
- return data;
97
- const custom = columnComparators[sb];
98
- const cmp = (a, b) => {
99
- if (custom)
100
- return custom(a, b, dir);
101
- const av = a[sb];
102
- const bv = b[sb];
103
- return defaultCompare(av, bv, dir, nulls);
104
- };
105
- // Don’t mutate input
106
- return stableSort(data, cmp);
107
- }, [data, sortState, columnComparators, nulls]);
108
- // Helper: support functional updates in uncontrolled mode (optional nicety)
109
- const setSortRef = useRef(setSort);
110
- setSortRef.current = setSort;
111
- return {
112
- sortedData,
113
- sortState,
114
- onSortChange,
115
- setSort,
116
- clearSort,
117
- };
118
- }
@@ -1,45 +0,0 @@
1
- 'use client';
2
- import { useEffect, useMemo } from 'react';
3
- import { usePagination } from './usePagination';
4
- import { useSorting, } from './useSorting';
5
- export function useTableData({ data = [], pagination, sorting, resetPageOnSortChange = true, }) {
6
- var _a, _b, _c, _d, _e, _f;
7
- const s = useSorting({
8
- data,
9
- sortBy: (_a = sorting === null || sorting === void 0 ? void 0 : sorting.sortBy) !== null && _a !== void 0 ? _a : null,
10
- sortDirection: (_b = sorting === null || sorting === void 0 ? void 0 : sorting.direction) !== null && _b !== void 0 ? _b : null,
11
- state: sorting === null || sorting === void 0 ? void 0 : sorting.state,
12
- onStateChange: sorting === null || sorting === void 0 ? void 0 : sorting.onStateChange,
13
- columnComparators: sorting === null || sorting === void 0 ? void 0 : sorting.columnComparators,
14
- nulls: (_c = sorting === null || sorting === void 0 ? void 0 : sorting.nulls) !== null && _c !== void 0 ? _c : 'last',
15
- allowUnsort: (_d = sorting === null || sorting === void 0 ? void 0 : sorting.allowUnsort) !== null && _d !== void 0 ? _d : true,
16
- });
17
- const p = usePagination({
18
- data: s.sortedData,
19
- skip: (_e = pagination === null || pagination === void 0 ? void 0 : pagination.skip) !== null && _e !== void 0 ? _e : 0,
20
- take: (_f = pagination === null || pagination === void 0 ? void 0 : pagination.take) !== null && _f !== void 0 ? _f : 10,
21
- state: pagination === null || pagination === void 0 ? void 0 : pagination.state,
22
- onStateChange: pagination === null || pagination === void 0 ? void 0 : pagination.onStateChange,
23
- });
24
- useEffect(() => {
25
- if (!resetPageOnSortChange)
26
- return;
27
- p.resetPage();
28
- // eslint-disable-next-line react-hooks/exhaustive-deps
29
- }, [resetPageOnSortChange, s.sortState.sortBy, s.sortState.sortDirection]);
30
- const rows = useMemo(() => p.paginatedData, [p.paginatedData]);
31
- return {
32
- rows,
33
- totalCount: s.sortedData.length,
34
- pagination: {
35
- state: p.paginationState,
36
- onPageChange: p.onPageChange,
37
- resetPage: p.resetPage,
38
- },
39
- sorting: {
40
- state: s.sortState,
41
- onSortChange: s.onSortChange,
42
- clearSort: s.clearSort,
43
- },
44
- };
45
- }
@@ -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
- }