@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.
- package/dist/components/table/Table.d.ts +1 -1
- package/dist/components/table/Table.types.d.ts +3 -0
- package/dist/components/table/components/TableHeader.d.ts +2 -1
- package/dist/index.cjs +12750 -0
- package/dist/index.css +7149 -0
- package/dist/index.js +12641 -79
- package/dist/tanstack.cjs +2674 -0
- package/dist/tanstack.css +1267 -0
- package/dist/tanstack.js +2650 -3
- package/dist/themes/dbc.css +3 -0
- package/dist/themes/forfatterweb.css +2 -0
- package/package.json +11 -10
- package/dist/assets/logo.js +0 -2
- package/dist/components/__stories__/_data/table.d.ts +0 -15
- package/dist/components/__stories__/_data/table.js +0 -55
- package/dist/components/__stories__/_data/tabs.d.ts +0 -9
- package/dist/components/__stories__/_data/tabs.js +0 -31
- package/dist/components/__stories__/story-components/Colors.d.ts +0 -11
- package/dist/components/__stories__/story-components/Colors.js +0 -96
- package/dist/components/__stories__/story-components/Colors.module.css +0 -27
- package/dist/components/__stories__/story-components/ComponentSizes.d.ts +0 -2
- package/dist/components/__stories__/story-components/ComponentSizes.js +0 -26
- package/dist/components/__stories__/story-components/Elevation.d.ts +0 -2
- package/dist/components/__stories__/story-components/Elevation.js +0 -49
- package/dist/components/__stories__/story-components/Flex.d.ts +0 -2
- package/dist/components/__stories__/story-components/Flex.js +0 -177
- package/dist/components/__stories__/story-components/Flex.module.css +0 -317
- package/dist/components/__stories__/story-components/Spacing.d.ts +0 -6
- package/dist/components/__stories__/story-components/Spacing.js +0 -76
- package/dist/components/__stories__/story-components/Spacing.module.css +0 -154
- package/dist/components/accordion/Accordion.js +0 -70
- package/dist/components/accordion/Accordion.module.css +0 -28
- package/dist/components/accordion/components/AccordionRow.js +0 -53
- package/dist/components/accordion/components/AccordionRow.module.css +0 -90
- package/dist/components/alert/Alert.js +0 -17
- package/dist/components/alert/Alert.module.css +0 -98
- package/dist/components/app-header/AppHeader.js +0 -5
- package/dist/components/app-header/AppHeader.module.css +0 -74
- package/dist/components/attribute-chip/AttributeChip.js +0 -5
- package/dist/components/attribute-chip/AttributeChip.module.css +0 -65
- package/dist/components/avatar/Avatar.js +0 -48
- package/dist/components/avatar/Avatar.module.css +0 -91
- package/dist/components/breadcrumbs/Breadcrumbs.js +0 -6
- package/dist/components/breadcrumbs/Breadcrumbs.module.css +0 -80
- package/dist/components/button/Button.js +0 -81
- package/dist/components/button/Button.module.css +0 -249
- package/dist/components/button-select/ButtonSelect.js +0 -7
- package/dist/components/button-select/ButtonSelect.module.css +0 -40
- package/dist/components/card/Card.js +0 -71
- package/dist/components/card/Card.module.css +0 -160
- package/dist/components/card/components/CardMeta.js +0 -26
- package/dist/components/card/components/CardMeta.module.css +0 -55
- package/dist/components/card-container/CardContainer.js +0 -6
- package/dist/components/card-container/CardContainer.module.css +0 -61
- package/dist/components/chip/Chip.js +0 -31
- package/dist/components/chip/Chip.module.css +0 -236
- package/dist/components/circle/Circle.js +0 -5
- package/dist/components/circle/Circle.module.css +0 -128
- package/dist/components/clear-button/ClearButton.js +0 -13
- package/dist/components/clear-button/ClearButton.module.css +0 -26
- package/dist/components/code-block/CodeBlock.js +0 -58
- package/dist/components/code-block/CodeBlock.module.css +0 -124
- package/dist/components/copy-button/CopyButton.js +0 -78
- package/dist/components/copy-button/CopyButton.module.css +0 -22
- package/dist/components/datetime-picker/DateTimePicker.js +0 -403
- package/dist/components/datetime-picker/DateTimePicker.module.css +0 -155
- package/dist/components/datetime-picker/dateTimeHelpers.js +0 -248
- package/dist/components/divider/Divider.js +0 -12
- package/dist/components/filter-field/FilterField.js +0 -191
- package/dist/components/filter-field/FilterField.module.css +0 -379
- package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.js +0 -52
- package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.module.css +0 -59
- package/dist/components/forms/checkbox/Checkbox.js +0 -28
- package/dist/components/forms/checkbox/Checkbox.module.css +0 -103
- package/dist/components/forms/checkbox-group/CheckboxGroup.js +0 -75
- package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +0 -115
- package/dist/components/forms/form-select/FormSelect.js +0 -86
- package/dist/components/forms/form-select/FormSelect.module.css +0 -236
- package/dist/components/forms/input/Input.js +0 -77
- package/dist/components/forms/input/Input.module.css +0 -468
- package/dist/components/forms/input-container/InputContainer.js +0 -15
- package/dist/components/forms/input-container/InputContainer.module.css +0 -60
- package/dist/components/forms/multi-select/MultiSelect.js +0 -122
- package/dist/components/forms/radio-buttons/RadioButton.js +0 -26
- package/dist/components/forms/radio-buttons/RadioButtonGroup.js +0 -19
- package/dist/components/forms/radio-buttons/RadioButtons.module.css +0 -118
- package/dist/components/forms/select/Select.js +0 -185
- package/dist/components/forms/select/Select.module.css +0 -32
- package/dist/components/forms/text-area/Textarea.js +0 -47
- package/dist/components/forms/text-area/Textarea.module.css +0 -70
- package/dist/components/forms/typeahead/Typeahead.js +0 -668
- package/dist/components/forms/typeahead/Typeahead.module.css +0 -38
- package/dist/components/grid/Grid.js +0 -23
- package/dist/components/grid/Grid.module.css +0 -35
- package/dist/components/headline/CollapsibleHeadline.js +0 -29
- package/dist/components/headline/Headline.js +0 -26
- package/dist/components/headline/Headline.module.css +0 -185
- package/dist/components/hyperlink/Hyperlink.js +0 -40
- package/dist/components/hyperlink/Hyperlink.module.css +0 -107
- package/dist/components/icon/Icon.js +0 -14
- package/dist/components/icon/Icon.module.css +0 -36
- package/dist/components/interval-select/IntervalSelect.js +0 -99
- package/dist/components/json-viewer/HighlightedText.js +0 -6
- package/dist/components/json-viewer/JsonNode.js +0 -30
- package/dist/components/json-viewer/JsonViewer.js +0 -68
- package/dist/components/json-viewer/JsonViewer.module.css +0 -346
- package/dist/components/json-viewer/types.js +0 -1
- package/dist/components/json-viewer/useClipboardStatus.js +0 -11
- package/dist/components/json-viewer/utils.js +0 -125
- package/dist/components/menu/Menu.js +0 -165
- package/dist/components/menu/Menu.module.css +0 -220
- package/dist/components/meta-bar/MetaBar.js +0 -9
- package/dist/components/meta-bar/MetaBar.module.css +0 -27
- package/dist/components/nav-bar/NavBar.js +0 -29
- package/dist/components/nav-bar/NavBar.module.css +0 -221
- package/dist/components/overlay/fade-overlay/FadeOverlay.js +0 -8
- package/dist/components/overlay/fade-overlay/FadeOverlay.module.css +0 -54
- package/dist/components/overlay/modal/Modal.js +0 -115
- package/dist/components/overlay/modal/Modal.module.css +0 -109
- package/dist/components/overlay/modal/provider/ModalProvider.js +0 -73
- package/dist/components/overlay/side-panel/SidePanel.js +0 -83
- package/dist/components/overlay/side-panel/SidePanel.module.css +0 -177
- package/dist/components/overlay/side-panel/useSidePanel.js +0 -11
- package/dist/components/overlay/tooltip/Tooltip.js +0 -17
- package/dist/components/overlay/tooltip/Tooltip.module.css +0 -104
- package/dist/components/overlay/tooltip/TooltipProvider.js +0 -255
- package/dist/components/overlay/tooltip/useTooltipTrigger.js +0 -118
- package/dist/components/page/Page.js +0 -11
- package/dist/components/page/Page.module.css +0 -89
- package/dist/components/page-layout/PageLayout.js +0 -76
- package/dist/components/page-layout/PageLayout.module.css +0 -236
- package/dist/components/page-layout/components/layout-footer/LayoutFooter.js +0 -27
- package/dist/components/page-layout/components/layout-footer/LayoutFooter.module.css +0 -89
- package/dist/components/page-layout/components/page-layout-hero/PageLayoutHero.js +0 -14
- package/dist/components/page-layout/components/page-layout-hero/PageLayoutHero.module.css +0 -84
- package/dist/components/pagination/Pagination.js +0 -56
- package/dist/components/pagination/Pagination.module.css +0 -25
- package/dist/components/panel/Panel.js +0 -7
- package/dist/components/panel/Panel.module.css +0 -29
- package/dist/components/popover/Popover.js +0 -257
- package/dist/components/popover/Popover.module.css +0 -54
- package/dist/components/search-box/SearchBox.js +0 -170
- package/dist/components/search-box/SearchBox.module.css +0 -21
- package/dist/components/segmented-progress-bar/SegmentedProgressBar.js +0 -48
- package/dist/components/segmented-progress-bar/SegmentedProgressBar.module.css +0 -167
- package/dist/components/sidebar/Sidebar.js +0 -6
- package/dist/components/sidebar/components/SidebarItem.js +0 -8
- package/dist/components/sidebar/components/SidebarItem.module.css +0 -0
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +0 -63
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.module.css +0 -29
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +0 -153
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +0 -260
- package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.js +0 -18
- package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.module.css +0 -106
- package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +0 -26
- package/dist/components/sidebar/components/sidebar-items/SidebarItems.module.css +0 -20
- package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.js +0 -30
- package/dist/components/sidebar/providers/SidebarProvider.js +0 -229
- package/dist/components/skeleton-loader/SkeletonLoader.js +0 -73
- package/dist/components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem.js +0 -13
- package/dist/components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem.module.css +0 -51
- package/dist/components/split-button/SplitButton.js +0 -10
- package/dist/components/split-button/SplitButton.module.css +0 -32
- package/dist/components/split-pane/SplitPane.js +0 -107
- package/dist/components/split-pane/SplitPane.module.css +0 -111
- package/dist/components/split-pane/provider/SplitPaneContext.js +0 -124
- package/dist/components/stack/Stack.js +0 -33
- package/dist/components/stack/Stack.module.css +0 -61
- package/dist/components/state-page/StatePage.js +0 -20
- package/dist/components/state-page/StatePage.module.css +0 -9
- package/dist/components/state-page/empty.js +0 -2
- package/dist/components/state-page/error.js +0 -2
- package/dist/components/state-page/notFound.js +0 -2
- package/dist/components/sticky-footer-layout/StickyFooterLayout.js +0 -64
- package/dist/components/table/Table.js +0 -50
- package/dist/components/table/Table.module.css +0 -536
- package/dist/components/table/Table.types.js +0 -1
- package/dist/components/table/TanstackTable.js +0 -111
- package/dist/components/table/components/TableBody.js +0 -10
- package/dist/components/table/components/TableHeader.js +0 -7
- package/dist/components/table/components/TableHeaderCell.js +0 -24
- package/dist/components/table/components/TableLoadingBody.js +0 -26
- package/dist/components/table/components/TablePagination.js +0 -1
- package/dist/components/table/components/TableRow.js +0 -54
- package/dist/components/table/components/TableSelectionCell.js +0 -16
- package/dist/components/table/components/column-resizer/ColumnResizer.js +0 -5
- package/dist/components/table/components/column-resizer/ColumnResizer.module.css +0 -22
- package/dist/components/table/components/empty-state/EmptyState.js +0 -23
- package/dist/components/table/components/empty-state/EmptyState.module.css +0 -4
- package/dist/components/table/components/table-settings/TableSettings.js +0 -63
- package/dist/components/table/hooks/useTableRowInteractions.js +0 -30
- package/dist/components/table/table.classes.js +0 -23
- package/dist/components/table/table.utils.js +0 -47
- package/dist/components/table/tanstackTable.utils.js +0 -175
- package/dist/components/tabs/Tabs.js +0 -125
- package/dist/components/tabs/Tabs.module.css +0 -233
- package/dist/components/theme-button/ThemeButton.js +0 -23
- package/dist/components/toast/Toast.js +0 -20
- package/dist/components/toast/Toast.module.css +0 -161
- package/dist/components/toast/provider/ToastProvider.js +0 -70
- package/dist/components/user-display/UserDisplay.js +0 -6
- package/dist/components/user-display/UserDisplay.module.css +0 -25
- package/dist/constants/severity.js +0 -24
- package/dist/constants/severity.types.js +0 -1
- package/dist/constants/sizes.js +0 -7
- package/dist/hooks/useDeviceSize.js +0 -32
- package/dist/hooks/useListNavigation.js +0 -234
- package/dist/hooks/usePagination.js +0 -140
- package/dist/hooks/useSorting.js +0 -118
- package/dist/hooks/useTableData.js +0 -45
- package/dist/hooks/useTableSelection.js +0 -164
- package/dist/hooks/useTableSettings.js +0 -71
- package/dist/hooks/useTheme.js +0 -66
- package/dist/hooks/useTimeDuration.js +0 -68
- package/dist/hooks/useViewportFill.js +0 -77
- package/dist/styles/animation.js +0 -5
- package/dist/styles/themes/types.js +0 -1
- package/dist/types/a11y-props.types.js +0 -1
- package/dist/types/sizes.types.js +0 -1
- package/dist/utils/arrays/nested-filtering.js +0 -48
- package/dist/utils/date/formatDate.js +0 -51
- package/dist/utils/localStorage.utils.js +0 -78
- 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
|
-
}
|
package/dist/hooks/useSorting.js
DELETED
|
@@ -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
|
-
}
|
package/dist/hooks/useTheme.js
DELETED
|
@@ -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
|
-
}
|