@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,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
- }