@dbcdk/react-components 0.0.5 → 0.0.7

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 (276) hide show
  1. package/dist/assets/logo.js +2 -85
  2. package/dist/components/__stories__/_data/table.d.ts +15 -0
  3. package/dist/components/__stories__/_data/table.js +49 -0
  4. package/dist/components/__stories__/story-components/Colors.d.ts +2 -1
  5. package/dist/components/__stories__/story-components/Colors.js +87 -142
  6. package/dist/components/__stories__/story-components/Spacing.d.ts +1 -0
  7. package/dist/components/__stories__/story-components/Spacing.js +58 -166
  8. package/dist/components/app-header/AppHeader.d.ts +4 -3
  9. package/dist/components/app-header/AppHeader.js +3 -6
  10. package/dist/components/attribute-chip/AttributeChip.d.ts +1 -0
  11. package/dist/components/attribute-chip/AttributeChip.js +3 -14
  12. package/dist/components/avatar/Avatar.d.ts +2 -2
  13. package/dist/components/avatar/Avatar.js +37 -71
  14. package/dist/components/breadcrumbs/Breadcrumbs.d.ts +4 -4
  15. package/dist/components/breadcrumbs/Breadcrumbs.js +4 -13
  16. package/dist/components/button/Button.d.ts +3 -2
  17. package/dist/components/button/Button.js +54 -56
  18. package/dist/components/button/Button.module.css +1 -1
  19. package/dist/components/card/Card.d.ts +8 -7
  20. package/dist/components/card/Card.js +19 -60
  21. package/dist/components/card-container/CardContainer.d.ts +3 -3
  22. package/dist/components/card-container/CardContainer.js +4 -16
  23. package/dist/components/chip/Chip.d.ts +6 -5
  24. package/dist/components/chip/Chip.js +14 -38
  25. package/dist/components/chip/Chip.module.css +9 -1
  26. package/dist/components/circle/Circle.d.ts +3 -2
  27. package/dist/components/circle/Circle.js +3 -10
  28. package/dist/components/clear-button/ClearButton.d.ts +2 -1
  29. package/dist/components/clear-button/ClearButton.js +6 -17
  30. package/dist/components/code-block/CodeBlock.d.ts +1 -0
  31. package/dist/components/code-block/CodeBlock.js +4 -10
  32. package/dist/components/copy-button/CopyButton.d.ts +4 -3
  33. package/dist/components/copy-button/CopyButton.js +19 -26
  34. package/dist/components/datetime-picker/DateTimePicker.d.ts +8 -5
  35. package/dist/components/datetime-picker/DateTimePicker.js +262 -475
  36. package/dist/components/datetime-picker/dateTimeHelpers.d.ts +13 -0
  37. package/dist/components/datetime-picker/dateTimeHelpers.js +119 -0
  38. package/dist/components/filter-field/FilterField.d.ts +5 -2
  39. package/dist/components/filter-field/FilterField.js +130 -173
  40. package/dist/components/filter-field/FilterField.module.css +21 -5
  41. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.d.ts +36 -0
  42. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.js +53 -0
  43. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.module.css +60 -0
  44. package/dist/components/forms/checkbox/Checkbox.d.ts +31 -0
  45. package/dist/components/forms/checkbox/Checkbox.js +27 -0
  46. package/dist/components/{checkbox → forms/checkbox}/Checkbox.module.css +0 -1
  47. package/dist/components/forms/checkbox-group/CheckboxGroup.d.ts +47 -0
  48. package/dist/components/forms/checkbox-group/CheckboxGroup.js +75 -0
  49. package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +115 -0
  50. package/dist/components/{input → forms/input}/Input.d.ts +9 -5
  51. package/dist/components/forms/input/Input.js +70 -0
  52. package/dist/components/{input → forms/input}/Input.module.css +1 -0
  53. package/dist/components/forms/input-container/InputContainer.d.ts +15 -0
  54. package/dist/components/forms/input-container/InputContainer.js +15 -0
  55. package/dist/components/forms/input-container/InputContainer.module.css +34 -0
  56. package/dist/components/forms/multi-select/MultiSelect.d.ts +20 -0
  57. package/dist/components/forms/multi-select/MultiSelect.js +19 -0
  58. package/dist/components/forms/select/Select.d.ts +21 -0
  59. package/dist/components/forms/select/Select.js +94 -0
  60. package/dist/components/forms/text-area/Textarea.d.ts +17 -0
  61. package/dist/components/forms/text-area/Textarea.js +33 -0
  62. package/dist/components/forms/text-area/Textarea.module.css +26 -0
  63. package/dist/components/headline/Headline.js +18 -43
  64. package/dist/components/{link/Link.d.ts → hyperlink/Hyperlink.d.ts} +2 -2
  65. package/dist/components/hyperlink/Hyperlink.js +11 -0
  66. package/dist/components/{link/Link.module.css → hyperlink/Hyperlink.module.css} +5 -14
  67. package/dist/components/icon/Icon.d.ts +4 -3
  68. package/dist/components/icon/Icon.js +11 -17
  69. package/dist/components/interval-select/IntervalSelect.d.ts +30 -0
  70. package/dist/components/interval-select/IntervalSelect.js +82 -0
  71. package/dist/components/menu/Menu.js +25 -67
  72. package/dist/components/meta-bar/MetaBar.d.ts +4 -4
  73. package/dist/components/meta-bar/MetaBar.js +7 -20
  74. package/dist/components/nav-bar/NavBar.d.ts +5 -5
  75. package/dist/components/nav-bar/NavBar.js +15 -45
  76. package/dist/components/{modal → overlay/modal}/Modal.d.ts +4 -2
  77. package/dist/components/overlay/modal/Modal.js +92 -0
  78. package/dist/components/{modal → overlay/modal}/provider/ModalProvider.d.ts +0 -1
  79. package/dist/components/overlay/modal/provider/ModalProvider.js +70 -0
  80. package/dist/components/overlay/side-panel/SidePanel.d.ts +16 -0
  81. package/dist/components/overlay/side-panel/SidePanel.js +10 -0
  82. package/dist/components/overlay/side-panel/SidePanel.module.css +56 -0
  83. package/dist/components/overlay/side-panel/useSidePanel.d.ts +5 -0
  84. package/dist/components/overlay/side-panel/useSidePanel.js +11 -0
  85. package/dist/components/overlay/tooltip/Tooltip.d.ts +13 -0
  86. package/dist/components/overlay/tooltip/Tooltip.js +17 -0
  87. package/dist/components/overlay/tooltip/Tooltip.module.css +106 -0
  88. package/dist/components/overlay/tooltip/TooltipProvider.d.ts +20 -0
  89. package/dist/components/overlay/tooltip/TooltipProvider.js +244 -0
  90. package/dist/components/overlay/tooltip/useTooltipTrigger.d.ts +24 -0
  91. package/dist/components/overlay/tooltip/useTooltipTrigger.js +108 -0
  92. package/dist/components/page/Page.d.ts +7 -6
  93. package/dist/components/page/Page.js +4 -21
  94. package/dist/components/page-layout/PageLayout.d.ts +11 -12
  95. package/dist/components/page-layout/PageLayout.js +35 -71
  96. package/dist/components/page-layout/components/page-layout-hero/PageLayoutHero.js +4 -22
  97. package/dist/components/pagination/Pagination.d.ts +2 -1
  98. package/dist/components/pagination/Pagination.js +38 -121
  99. package/dist/components/panel/Panel.d.ts +4 -3
  100. package/dist/components/panel/Panel.js +5 -10
  101. package/dist/components/popover/Popover.d.ts +1 -0
  102. package/dist/components/popover/Popover.js +116 -141
  103. package/dist/components/search-box/SearchBox.d.ts +2 -2
  104. package/dist/components/search-box/SearchBox.js +112 -162
  105. package/dist/components/segmented-progress-bar/SegmentedProgressBar.d.ts +1 -1
  106. package/dist/components/segmented-progress-bar/SegmentedProgressBar.js +47 -94
  107. package/dist/components/sidebar/Sidebar.d.ts +1 -0
  108. package/dist/components/sidebar/Sidebar.js +5 -7
  109. package/dist/components/sidebar/components/SidebarItem.js +6 -14
  110. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.d.ts +1 -1
  111. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +48 -88
  112. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.d.ts +3 -2
  113. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +11 -41
  114. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.d.ts +1 -0
  115. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.js +4 -25
  116. package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +9 -23
  117. package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.js +19 -40
  118. package/dist/components/sidebar/providers/SidebarProvider.d.ts +2 -1
  119. package/dist/components/sidebar/providers/SidebarProvider.js +182 -165
  120. package/dist/components/skeleton-loader/SkeletonLoader.js +68 -266
  121. package/dist/components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem.js +11 -34
  122. package/dist/components/split-button/SplitButton.d.ts +7 -5
  123. package/dist/components/split-button/SplitButton.js +4 -27
  124. package/dist/components/split-pane/SplitPane.js +69 -105
  125. package/dist/components/split-pane/provider/SplitPaneContext.js +77 -71
  126. package/dist/components/table/Table.d.ts +9 -7
  127. package/dist/components/table/Table.js +115 -238
  128. package/dist/components/table/Table.module.css +5 -1
  129. package/dist/components/table/components/column-resizer/ColumnResizer.js +4 -15
  130. package/dist/components/table/components/empty-state/EmptyState.d.ts +6 -5
  131. package/dist/components/table/components/empty-state/EmptyState.js +22 -41
  132. package/dist/components/table/components/table-settings/TableSettings.d.ts +2 -1
  133. package/dist/components/table/components/table-settings/TableSettings.js +9 -27
  134. package/dist/components/table/tanstack.d.ts +1 -1
  135. package/dist/components/table/tanstack.js +154 -160
  136. package/dist/components/tabs/Tabs.d.ts +1 -0
  137. package/dist/components/tabs/Tabs.js +32 -81
  138. package/dist/components/toast/Toast.d.ts +1 -1
  139. package/dist/components/toast/Toast.js +4 -37
  140. package/dist/components/toast/Toast.module.css +1 -0
  141. package/dist/components/toast/provider/ToastProvider.d.ts +1 -1
  142. package/dist/components/toast/provider/ToastProvider.js +60 -87
  143. package/dist/components/user-display/UserDisplay.d.ts +2 -1
  144. package/dist/components/user-display/UserDisplay.js +4 -20
  145. package/dist/constants/severity.d.ts +1 -1
  146. package/dist/constants/severity.js +14 -16
  147. package/dist/constants/severity.types.d.ts +1 -1
  148. package/dist/constants/severity.types.js +1 -1
  149. package/dist/constants/sizes.js +6 -8
  150. package/dist/hooks/usePagination.d.ts +1 -1
  151. package/dist/hooks/usePagination.js +75 -82
  152. package/dist/hooks/useSorting.js +112 -110
  153. package/dist/hooks/useTableData.d.ts +1 -1
  154. package/dist/hooks/useTableData.js +42 -47
  155. package/dist/hooks/useTableSelection.js +121 -121
  156. package/dist/hooks/useTableSettings.js +23 -25
  157. package/dist/hooks/useTheme.d.ts +3 -7
  158. package/dist/hooks/useTheme.js +52 -47
  159. package/dist/hooks/useTimeDuration.d.ts +2 -2
  160. package/dist/hooks/useTimeDuration.js +33 -34
  161. package/dist/hooks/useViewportFill.d.ts +3 -2
  162. package/dist/hooks/useViewportFill.js +55 -48
  163. package/dist/index.d.ts +17 -8
  164. package/dist/index.js +18 -8
  165. package/dist/src/styles/styles.css +3 -3
  166. package/dist/styles/css-helper-classes/flex.css +4 -0
  167. package/dist/styles/styles.css +3 -3
  168. package/dist/styles/themes/dbc/dark.css +1 -1
  169. package/dist/styles/themes/dbc/light.css +2 -1
  170. package/dist/styles/themes/forfatterweb/light.css +1 -1
  171. package/dist/styles/themes/types.js +1 -1
  172. package/dist/types/a11y-props.types.d.ts +5 -5
  173. package/dist/types/a11y-props.types.js +1 -1
  174. package/dist/types/sizes.types.js +1 -1
  175. package/dist/utils/arrays/nested-filtering.js +43 -33
  176. package/dist/utils/date/formatDate.js +25 -16
  177. package/package.json +18 -9
  178. package/dist/assets/logo.cjs +0 -87
  179. package/dist/components/__stories__/story-components/Colors.cjs +0 -159
  180. package/dist/components/__stories__/story-components/Spacing.cjs +0 -190
  181. package/dist/components/app-header/AppHeader.cjs +0 -14
  182. package/dist/components/attribute-chip/AttributeChip.cjs +0 -22
  183. package/dist/components/avatar/Avatar.cjs +0 -101
  184. package/dist/components/breadcrumbs/Breadcrumbs.cjs +0 -22
  185. package/dist/components/button/Button.cjs +0 -87
  186. package/dist/components/card/Card.cjs +0 -69
  187. package/dist/components/card-container/CardContainer.cjs +0 -24
  188. package/dist/components/checkbox/Checkbox.cjs +0 -42
  189. package/dist/components/checkbox/Checkbox.d.ts +0 -12
  190. package/dist/components/checkbox/Checkbox.js +0 -36
  191. package/dist/components/chip/Chip.cjs +0 -50
  192. package/dist/components/circle/Circle.cjs +0 -18
  193. package/dist/components/clear-button/ClearButton.cjs +0 -26
  194. package/dist/components/code-block/CodeBlock.cjs +0 -18
  195. package/dist/components/copy-button/CopyButton.cjs +0 -35
  196. package/dist/components/datetime-picker/DateTimePicker.cjs +0 -504
  197. package/dist/components/filter-field/FilterField.cjs +0 -189
  198. package/dist/components/headline/Headline.cjs +0 -53
  199. package/dist/components/icon/Icon.cjs +0 -27
  200. package/dist/components/input/Input.cjs +0 -89
  201. package/dist/components/input/Input.js +0 -83
  202. package/dist/components/link/Link.cjs +0 -46
  203. package/dist/components/link/Link.js +0 -21
  204. package/dist/components/menu/Menu.cjs +0 -96
  205. package/dist/components/meta-bar/MetaBar.cjs +0 -29
  206. package/dist/components/modal/Modal.cjs +0 -134
  207. package/dist/components/modal/Modal.js +0 -128
  208. package/dist/components/modal/provider/ModalProvider.cjs +0 -80
  209. package/dist/components/modal/provider/ModalProvider.js +0 -77
  210. package/dist/components/multi-select/MultiSelect.cjs +0 -59
  211. package/dist/components/multi-select/MultiSelect.d.ts +0 -18
  212. package/dist/components/multi-select/MultiSelect.js +0 -57
  213. package/dist/components/nav-bar/NavBar.cjs +0 -55
  214. package/dist/components/page/Page.cjs +0 -30
  215. package/dist/components/page-layout/PageLayout.cjs +0 -84
  216. package/dist/components/page-layout/components/page-layout-hero/PageLayoutHero.cjs +0 -32
  217. package/dist/components/pagination/Pagination.cjs +0 -133
  218. package/dist/components/panel/Panel.cjs +0 -18
  219. package/dist/components/popover/Popover.cjs +0 -149
  220. package/dist/components/search-box/SearchBox.cjs +0 -175
  221. package/dist/components/segmented-progress-bar/SegmentedProgressBar.cjs +0 -103
  222. package/dist/components/select/Select.cjs +0 -121
  223. package/dist/components/select/Select.d.ts +0 -12
  224. package/dist/components/select/Select.js +0 -119
  225. package/dist/components/sidebar/Sidebar.cjs +0 -11
  226. package/dist/components/sidebar/components/SidebarItem.cjs +0 -18
  227. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.cjs +0 -100
  228. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.cjs +0 -50
  229. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.cjs +0 -34
  230. package/dist/components/sidebar/components/sidebar-items/SidebarItems.cjs +0 -29
  231. package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.cjs +0 -52
  232. package/dist/components/sidebar/providers/SidebarProvider.cjs +0 -179
  233. package/dist/components/skeleton-loader/SkeletonLoader.cjs +0 -270
  234. package/dist/components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem.cjs +0 -42
  235. package/dist/components/split-button/SplitButton.cjs +0 -37
  236. package/dist/components/split-pane/SplitPane.cjs +0 -123
  237. package/dist/components/split-pane/provider/SplitPaneContext.cjs +0 -87
  238. package/dist/components/table/Table.cjs +0 -249
  239. package/dist/components/table/components/column-resizer/ColumnResizer.cjs +0 -22
  240. package/dist/components/table/components/empty-state/EmptyState.cjs +0 -52
  241. package/dist/components/table/components/table-settings/TableSettings.cjs +0 -32
  242. package/dist/components/table/tanstack.cjs +0 -193
  243. package/dist/components/tabs/Tabs.cjs +0 -90
  244. package/dist/components/text-area/Textarea.cjs +0 -62
  245. package/dist/components/text-area/Textarea.d.ts +0 -14
  246. package/dist/components/text-area/Textarea.js +0 -56
  247. package/dist/components/text-area/Textarea.module.css +0 -3
  248. package/dist/components/toast/Toast.cjs +0 -47
  249. package/dist/components/toast/provider/ToastProvider.cjs +0 -98
  250. package/dist/components/tooltip/Tooltip.cjs +0 -183
  251. package/dist/components/tooltip/Tooltip.d.ts +0 -11
  252. package/dist/components/tooltip/Tooltip.js +0 -177
  253. package/dist/components/tooltip/Tooltip.module.css +0 -66
  254. package/dist/components/user-display/UserDisplay.cjs +0 -28
  255. package/dist/constants/severity.cjs +0 -21
  256. package/dist/constants/severity.types.cjs +0 -2
  257. package/dist/constants/sizes.cjs +0 -11
  258. package/dist/hooks/usePagination.cjs +0 -88
  259. package/dist/hooks/useSorting.cjs +0 -118
  260. package/dist/hooks/useTableData.cjs +0 -52
  261. package/dist/hooks/useTableSelection.cjs +0 -130
  262. package/dist/hooks/useTableSettings.cjs +0 -28
  263. package/dist/hooks/useTheme.cjs +0 -58
  264. package/dist/hooks/useTimeDuration.cjs +0 -39
  265. package/dist/hooks/useViewportFill.cjs +0 -52
  266. package/dist/index.cjs +0 -383
  267. package/dist/styles/themes/types.cjs +0 -2
  268. package/dist/types/a11y-props.types.cjs +0 -2
  269. package/dist/types/assets.d.cjs +0 -2
  270. package/dist/types/assets.d.js +0 -1
  271. package/dist/types/css.d.cjs +0 -2
  272. package/dist/types/css.d.js +0 -1
  273. package/dist/types/sizes.types.cjs +0 -2
  274. package/dist/utils/arrays/nested-filtering.cjs +0 -40
  275. package/dist/utils/date/formatDate.cjs +0 -19
  276. /package/dist/components/{modal → overlay/modal}/Modal.module.css +0 -0
@@ -0,0 +1,13 @@
1
+ export declare const digits: (s: string) => string;
2
+ export declare function maskDateEU(text: string): string;
3
+ export declare function maskTimeHM(text: string): string;
4
+ export declare function maskSingle(text: string, enableTime: boolean): string;
5
+ export declare function maskRange(text: string, enableTime: boolean): string;
6
+ export declare const pad2: (n: number) => string;
7
+ export declare function toMaskedFromDate(d: Date, enableTime: boolean): string;
8
+ export declare function toMaskedRange(start: Date | null, end: Date | null, enableTime: boolean): string;
9
+ export declare function parseLooseDateOrDateTime(input: string): Date | null;
10
+ export declare function parseLooseRange(input: string): {
11
+ start: Date;
12
+ end: Date;
13
+ } | null;
@@ -0,0 +1,119 @@
1
+ /* ---------- Mask helpers (no deps) ---------- */
2
+ // Pull only 0-9
3
+ export const digits = (s) => (s.match(/\d/g) || []).join('');
4
+ // DD-MM-YYYY
5
+ export function maskDateEU(text) {
6
+ const d = digits(text).slice(0, 8);
7
+ const dd = d.slice(0, 2);
8
+ const mm = d.slice(2, 4);
9
+ const yyyy = d.slice(4, 8);
10
+ let out = dd;
11
+ if (mm.length)
12
+ out += (out ? '-' : '') + mm;
13
+ if (yyyy.length)
14
+ out += (out ? '-' : '') + yyyy;
15
+ return out;
16
+ }
17
+ // HH:mm (24h)
18
+ export function maskTimeHM(text) {
19
+ const d = digits(text).slice(0, 4);
20
+ const hh = d.slice(0, 2);
21
+ const mm = d.slice(2, 4);
22
+ return mm.length ? `${hh}:${mm}` : hh;
23
+ }
24
+ // Single: "DD-MM-YYYY" or "DD-MM-YYYY HH:mm"
25
+ export function maskSingle(text, enableTime) {
26
+ let t = text.trim().replace(/\s+/g, ' ');
27
+ if (!enableTime)
28
+ return maskDateEU(t);
29
+ // split date + time by first space or 'T'
30
+ const m = /^(.*?)[ T](.*)$/.exec(t);
31
+ if (!m)
32
+ return maskDateEU(t);
33
+ const datePart = maskDateEU(m[1]);
34
+ const timePart = maskTimeHM(m[2]);
35
+ return timePart ? `${datePart} ${timePart}` : datePart;
36
+ }
37
+ // Range: mask both sides around common separators (–, -, to, til)
38
+ export function maskRange(text, enableTime) {
39
+ const sepRe = /\s*(?:–|-|to|til)\s*/i;
40
+ const parts = text.split(sepRe);
41
+ if (parts.length === 1) {
42
+ // user typing first side
43
+ return maskSingle(parts[0], enableTime);
44
+ }
45
+ const a = maskSingle(parts[0], enableTime);
46
+ const b = maskSingle(parts.slice(1).join(' '), enableTime); // everything after first sep
47
+ return `${a} – ${b}`.trim();
48
+ }
49
+ // Pad helper
50
+ export const pad2 = (n) => String(n).padStart(2, '0');
51
+ // From Date → "DD-MM-YYYY" or "DD-MM-YYYY HH:mm" (local time)
52
+ export function toMaskedFromDate(d, enableTime) {
53
+ const dd = pad2(d.getDate());
54
+ const mm = pad2(d.getMonth() + 1);
55
+ const yyyy = String(d.getFullYear());
56
+ let out = `${dd}-${mm}-${yyyy}`;
57
+ if (enableTime)
58
+ out += ` ${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
59
+ return out;
60
+ }
61
+ // From start/end → "DD-MM-YYYY – DD-MM-YYYY" (+ optional time)
62
+ export function toMaskedRange(start, end, enableTime) {
63
+ if (start && end)
64
+ return `${toMaskedFromDate(start, enableTime)} – ${toMaskedFromDate(end, enableTime)}`;
65
+ if (start)
66
+ return `${toMaskedFromDate(start, enableTime)} –`;
67
+ if (end)
68
+ return `– ${toMaskedFromDate(end, enableTime)}`;
69
+ return '';
70
+ }
71
+ /* ---------- Parsing helpers (no deps) ---------- */
72
+ // Accepts: YYYY-MM-DD, DD-MM-YYYY, DD/MM/YYYY, DD.MM.YYYY (+ optional HH:mm)
73
+ export function parseLooseDateOrDateTime(input) {
74
+ const txt = input.trim().replace(/\s+/g, ' ');
75
+ const dateTimeMatch = /^(?<date>[\d./-]{8,10})(?:[ T](?<hh>\d{1,2}):(?<mm>\d{2}))?$/i.exec(txt);
76
+ if (!(dateTimeMatch === null || dateTimeMatch === void 0 ? void 0 : dateTimeMatch.groups))
77
+ return null;
78
+ const raw = dateTimeMatch.groups.date;
79
+ const hh = dateTimeMatch.groups.hh ? parseInt(dateTimeMatch.groups.hh, 10) : 0;
80
+ const mm = dateTimeMatch.groups.mm ? parseInt(dateTimeMatch.groups.mm, 10) : 0;
81
+ if (hh < 0 || hh > 23 || mm < 0 || mm > 59)
82
+ return null;
83
+ // Try YYYY-MM-DD first
84
+ let y, m, d;
85
+ const mIso = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(raw);
86
+ if (mIso) {
87
+ y = +mIso[1];
88
+ m = +mIso[2] - 1;
89
+ d = +mIso[3];
90
+ }
91
+ else {
92
+ // Try DD-MM-YYYY or DD/MM/YYYY or DD.MM.YYYY
93
+ const mEu = /^(\d{1,2})[./-](\d{1,2})[./-](\d{4})$/.exec(raw);
94
+ if (!mEu)
95
+ return null;
96
+ d = +mEu[1];
97
+ m = +mEu[2] - 1;
98
+ y = +mEu[3];
99
+ }
100
+ const local = new Date(y, m, d, hh, mm, 0, 0);
101
+ if (Number.isNaN(local.getTime()))
102
+ return null;
103
+ // Guard: JS autocorrects invalid dates; re-validate exact Y/M/D
104
+ if (local.getFullYear() !== y || local.getMonth() !== m || local.getDate() !== d)
105
+ return null;
106
+ return local;
107
+ }
108
+ // Parse a range string with separators: "–", "-", "to", "til"
109
+ export function parseLooseRange(input) {
110
+ const sep = /\s*(?:–|-|to|til)\s*/i;
111
+ const [a, b] = input.split(sep);
112
+ if (!a || !b)
113
+ return null;
114
+ const s = parseLooseDateOrDateTime(a);
115
+ const e = parseLooseDateOrDateTime(b);
116
+ if (!s || !e)
117
+ return null;
118
+ return s <= e ? { start: s, end: e } : { start: e, end: s };
119
+ }
@@ -5,7 +5,7 @@ export interface FilterEvent {
5
5
  operator: Operator;
6
6
  value: string | string[] | null;
7
7
  }
8
- export interface MultiselectOption {
8
+ interface MultiselectOption {
9
9
  label: string;
10
10
  value: string;
11
11
  icon?: React.ReactNode;
@@ -25,4 +25,7 @@ export interface FilterFieldProps extends Omit<React.InputHTMLAttributes<HTMLInp
25
25
  disabled?: boolean;
26
26
  }
27
27
  export declare const NUMBER_OPERATORS: Operator[];
28
- export declare function FilterField({ field, control, operator, value, onChange, operators, options, single, size, label, placeholder, disabled, ...inputProps }: FilterFieldProps): React.ReactElement;
28
+ export declare function FilterField({ field, control, operator, value, onChange, operators, options, single, size, label, placeholder, disabled, 'data-cy': dataCy, ...inputProps }: FilterFieldProps & {
29
+ 'data-cy'?: string;
30
+ }): React.ReactElement;
31
+ export {};
@@ -1,182 +1,139 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { useState, useMemo, useEffect, useRef } from 'react';
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Check } from 'lucide-react';
4
- import { Popover } from '../popover/Popover';
5
- import { Input } from '../input/Input';
6
- import { Menu } from '../menu/Menu';
7
- import { MultiSelect } from '../multi-select/MultiSelect';
8
- import { Select } from '../select/Select';
4
+ import { useMemo, useRef, useState, useEffect } from 'react';
5
+ import { Input } from '../../components/forms/input/Input';
6
+ import { MultiSelect } from '../../components/forms/multi-select/MultiSelect';
9
7
  import styles from './FilterField.module.css';
10
-
8
+ import { Select } from '../forms/select/Select';
9
+ import { Menu } from '../menu/Menu';
10
+ import { Popover } from '../popover/Popover';
11
11
  const LABELS = {
12
- is: "is",
13
- isNot: "not",
14
- contains: "contains",
15
- notContains: "not contain",
16
- startsWith: "starts with",
17
- endsWith: "ends with",
18
- gt: ">",
19
- lt: "<",
20
- gte: "\u2265",
21
- lte: "\u2264",
22
- in: "",
23
- notIn: "not in",
24
- isEmpty: "empty",
25
- isNotEmpty: "not empty"
12
+ is: 'is',
13
+ isNot: 'not',
14
+ contains: 'contains',
15
+ notContains: 'not contain',
16
+ startsWith: 'starts with',
17
+ endsWith: 'ends with',
18
+ gt: '>',
19
+ lt: '<',
20
+ gte: '≥',
21
+ lte: '≤',
22
+ in: '',
23
+ notIn: 'not in',
24
+ isEmpty: 'empty',
25
+ isNotEmpty: 'not empty',
26
26
  };
27
27
  const DEFAULT_TEXT_OPERATORS = [
28
- "is",
29
- "isNot",
30
- "contains",
31
- "notContains",
32
- "startsWith",
33
- "endsWith",
34
- "isEmpty",
35
- "isNotEmpty"
28
+ 'is',
29
+ 'isNot',
30
+ 'contains',
31
+ 'notContains',
32
+ 'startsWith',
33
+ 'endsWith',
34
+ 'isEmpty',
35
+ 'isNotEmpty',
36
36
  ];
37
- const NUMBER_OPERATORS = [
38
- "is",
39
- "isNot",
40
- "gt",
41
- "lt",
42
- "gte",
43
- "lte",
44
- "isEmpty",
45
- "isNotEmpty"
37
+ export const NUMBER_OPERATORS = [
38
+ 'is',
39
+ 'isNot',
40
+ 'gt',
41
+ 'lt',
42
+ 'gte',
43
+ 'lte',
44
+ 'isEmpty',
45
+ 'isNotEmpty',
46
46
  ];
47
- function OperatorDropdown({
48
- value,
49
- onChange,
50
- operators,
51
- size = "sm",
52
- disabled
53
- }) {
54
- const popRef = useRef(null);
55
- const [activeIndex, setActiveIndex] = useState(() => Math.max(0, operators.indexOf(value)));
56
- useEffect(() => {
57
- setActiveIndex(Math.max(0, operators.indexOf(value)));
58
- }, [operators, value]);
59
- const handleSelect = (op) => {
60
- var _a;
61
- onChange(op);
62
- setActiveIndex(operators.indexOf(op));
63
- (_a = popRef.current) == null ? void 0 : _a.close();
64
- };
65
- return /* @__PURE__ */ jsx(
66
- Popover,
67
- {
68
- ref: popRef,
69
- minWidth: "220px",
70
- trigger: (toggle, icon) => /* @__PURE__ */ jsxs(
71
- "button",
72
- {
73
- type: "button",
74
- onClick: toggle,
75
- disabled,
76
- "aria-label": "Change operator",
77
- className: `${styles.operatorTrigger} ${styles[size]}`,
78
- children: [
79
- /* @__PURE__ */ jsx("span", { className: styles.operatorText, children: LABELS[value] }),
80
- icon
81
- ]
82
- }
83
- ),
84
- children: /* @__PURE__ */ jsx(Menu, { children: operators.map((op) => {
85
- const selected = op === value;
86
- return /* @__PURE__ */ jsx(Menu.Item, { active: selected, children: /* @__PURE__ */ jsxs("button", { onClick: () => handleSelect(op), children: [
87
- /* @__PURE__ */ jsx("span", { style: { width: 16, display: "inline-flex", justifyContent: "center" }, children: selected ? /* @__PURE__ */ jsx(Check, { size: 16 }) : null }),
88
- LABELS[op]
89
- ] }) }, op);
90
- }) })
91
- }
92
- );
47
+ function OperatorDropdown({ value, onChange, operators, size = 'sm', disabled, }) {
48
+ const popRef = useRef(null);
49
+ const [activeIndex, setActiveIndex] = useState(() => Math.max(0, operators.indexOf(value)));
50
+ useEffect(() => {
51
+ setActiveIndex(Math.max(0, operators.indexOf(value)));
52
+ }, [operators, value]);
53
+ const handleSelect = (op) => {
54
+ var _a;
55
+ onChange(op);
56
+ setActiveIndex(operators.indexOf(op));
57
+ (_a = popRef.current) === null || _a === void 0 ? void 0 : _a.close();
58
+ };
59
+ return (_jsx(Popover, { ref: popRef, minWidth: "220px", trigger: (toggle, icon) => (_jsxs("button", { type: "button", onClick: toggle, disabled: disabled, "aria-label": "Change operator", className: `${styles.operatorTrigger} ${styles[size]}`, children: [_jsx("span", { className: styles.operatorText, children: LABELS[value] }), icon] })), children: _jsx(Menu, { children: operators.map(op => {
60
+ const selected = op === value;
61
+ return (_jsx(Menu.Item, { active: selected, children: _jsxs("button", { type: "button", onClick: () => handleSelect(op), disabled: disabled, children: [_jsx("span", { style: { width: 16, display: 'inline-flex', justifyContent: 'center' }, children: selected ? _jsx(Check, { size: 16 }) : null }), LABELS[op]] }) }, op));
62
+ }) }) }));
93
63
  }
94
- function FilterField({
95
- field,
96
- control,
97
- operator,
98
- value,
99
- onChange,
100
- operators,
101
- options = [],
102
- single = true,
103
- size = "md",
104
- label,
105
- placeholder = "Type value\u2026",
106
- disabled,
107
- ...inputProps
108
- }) {
109
- const [selectedOperator, setSelectedOperator] = useState(operator);
110
- const ops = useMemo(() => operators != null ? operators : DEFAULT_TEXT_OPERATORS, [operators]);
111
- useEffect(() => {
112
- }, [operator]);
113
- useEffect(() => {
114
- if (ops.includes(operator)) {
115
- setSelectedOperator(operator);
116
- }
117
- }, [operator]);
118
- const emit = (next) => {
119
- var _a, _b, _c;
120
- setSelectedOperator((_a = next.operator) != null ? _a : selectedOperator);
121
- onChange({
122
- field,
123
- operator: (_b = next.operator) != null ? _b : selectedOperator,
124
- value: (_c = next.value) != null ? _c : value
125
- });
126
- };
127
- return /* @__PURE__ */ jsxs("div", { className: ` ${styles.filterField} ${styles[size]}`, children: [
128
- label ? /* @__PURE__ */ jsx("span", { className: `${styles.label} ${styles[size]}`, children: label }) : null,
129
- /* @__PURE__ */ jsx(
130
- OperatorDropdown,
131
- {
132
- value: selectedOperator,
133
- onChange: (op) => emit({ operator: op }),
134
- operators: ops,
135
- size,
136
- disabled
137
- }
138
- ),
139
- /* @__PURE__ */ jsx("div", { className: `${control === "input" ? "" : styles.valueWrapper}`, children: control === "input" ? /* @__PURE__ */ jsx(
140
- Input,
141
- {
142
- ...inputProps,
143
- value: value != null ? value : "",
144
- onChange: (e) => emit({ value: e.currentTarget.value }),
145
- inputSize: size,
146
- placeholder,
147
- fullWidth: true,
148
- minWidth: "120px",
149
- disabled,
150
- onClear: () => emit({ value: "" })
151
- }
152
- ) : single ? /* @__PURE__ */ jsx(
153
- Select,
154
- {
155
- options,
156
- selectedValue: value != null ? value : null,
157
- onChange: (v) => emit({ value: v }),
158
- placeholder,
159
- size,
160
- variant: "inline",
161
- onClear: () => emit({ value: "" })
162
- }
163
- ) : /* @__PURE__ */ jsx(
164
- MultiSelect,
165
- {
166
- options,
167
- size,
168
- variant: "inline",
169
- selectedValues: Array.isArray(value) ? value : [],
170
- onChange: (v) => {
171
- const current = new Set(Array.isArray(value) ? value : []);
172
- current.has(v) ? current.delete(v) : current.add(v);
173
- emit({ value: Array.from(current) });
174
- },
175
- onClear: () => emit({ value: [] }),
176
- children: placeholder
177
- }
178
- ) })
179
- ] });
64
+ export function FilterField({ field, control, operator, value, onChange, operators, options = [], single = true, size = 'md', label, placeholder = 'Type value…', disabled, 'data-cy': dataCy, ...inputProps }) {
65
+ var _a, _b;
66
+ const [selectedOperator, setSelectedOperator] = useState(operator);
67
+ const ops = useMemo(() => operators !== null && operators !== void 0 ? operators : DEFAULT_TEXT_OPERATORS, [operators]);
68
+ // Local state ONLY for input control (to avoid URL->props lag)
69
+ const [localValue, setLocalValue] = useState((_a = value) !== null && _a !== void 0 ? _a : '');
70
+ const debounceRef = useRef(null);
71
+ const isTypingRef = useRef(false);
72
+ useEffect(() => {
73
+ if (ops.includes(operator)) {
74
+ setSelectedOperator(operator);
75
+ }
76
+ }, [operator, ops]);
77
+ const emit = (next) => {
78
+ var _a, _b;
79
+ const nextOperator = (_a = next.operator) !== null && _a !== void 0 ? _a : selectedOperator;
80
+ const nextValue = (_b = next.value) !== null && _b !== void 0 ? _b : value;
81
+ if (next.operator)
82
+ setSelectedOperator(nextOperator);
83
+ onChange({
84
+ field,
85
+ operator: nextOperator,
86
+ value: nextValue,
87
+ });
88
+ };
89
+ const scheduleEmitValue = (nextVal) => {
90
+ if (debounceRef.current)
91
+ clearTimeout(debounceRef.current);
92
+ debounceRef.current = setTimeout(() => {
93
+ isTypingRef.current = false;
94
+ emit({ value: nextVal });
95
+ }, 250); // tweak debounce as needed
96
+ };
97
+ // Sync internal value when parent value changes (e.g. URL updates)
98
+ useEffect(() => {
99
+ var _a;
100
+ if (control !== 'input')
101
+ return;
102
+ const incoming = (_a = value) !== null && _a !== void 0 ? _a : '';
103
+ // don't fight the user mid-typing; once parent catches up, we allow sync again
104
+ if (!isTypingRef.current && incoming !== localValue) {
105
+ setLocalValue(incoming);
106
+ }
107
+ if (incoming === localValue) {
108
+ isTypingRef.current = false;
109
+ }
110
+ }, [value, control, localValue]);
111
+ // Cleanup debounce on unmount
112
+ useEffect(() => {
113
+ return () => {
114
+ if (debounceRef.current)
115
+ clearTimeout(debounceRef.current);
116
+ };
117
+ }, []);
118
+ return (_jsxs("div", { ...(dataCy ? { 'data-cy': dataCy } : {}), className: ` ${styles.filterField} ${styles[size]} ${value ? styles.active : ''}`, children: [label ? _jsx("span", { className: `${styles.label} ${styles[size]}`, children: label }) : null, _jsx(OperatorDropdown, { value: selectedOperator, onChange: op => emit({ operator: op }), operators: ops, size: size, disabled: disabled }), _jsx("div", { className: `${control === 'input' ? 'dbc-flex' : styles.valueWrapper}`, children: control === 'input' ? (_jsx(Input, { ...inputProps, value: localValue, onChange: e => {
119
+ const next = e.currentTarget.value;
120
+ isTypingRef.current = true;
121
+ setLocalValue(next); // immediate UI update
122
+ scheduleEmitValue(next); // debounced parent update
123
+ }, inputSize: size, placeholder: placeholder, width: "160px", minWidth: "120px", disabled: disabled, onClear: () => {
124
+ isTypingRef.current = false;
125
+ if (debounceRef.current)
126
+ clearTimeout(debounceRef.current);
127
+ setLocalValue('');
128
+ emit({ value: '' }); // clear should be immediate
129
+ } })) : single ? (_jsx(Select, { options: options, selectedValue: (_b = value) !== null && _b !== void 0 ? _b : null, onChange: v => emit({ value: v }), placeholder: placeholder, size: size, variant: "inline", onClear: () => emit({ value: '' }) })) : (_jsx(MultiSelect, { options: options, size: size, variant: "inline", selectedValues: (Array.isArray(value) ? value : []), onChange: v => {
130
+ const current = new Set((Array.isArray(value) ? value : []));
131
+ if (current.has(v)) {
132
+ current.delete(v);
133
+ }
134
+ else {
135
+ current.add(v);
136
+ }
137
+ emit({ value: Array.from(current) });
138
+ }, onClear: () => emit({ value: [] }), children: placeholder })) })] }));
180
139
  }
181
-
182
- export { FilterField, NUMBER_OPERATORS };
@@ -16,10 +16,10 @@
16
16
  background-color var(--transition-fast) var(--ease-standard);
17
17
  }
18
18
 
19
- .filterField:focus-within {
19
+ /* .filterField.active {
20
20
  border-color: var(--color-border-selected);
21
- box-shadow: var(--focus-ring);
22
- }
21
+ background: var(--color-bg-selected);
22
+ } */
23
23
 
24
24
  .filterField.sm {
25
25
  block-size: calc(var(--component-size-sm) + var(--density));
@@ -76,9 +76,21 @@
76
76
  .filterField .valueWrapper {
77
77
  display: inline-flex;
78
78
  align-items: center;
79
+ padding: 0;
80
+ height: 100%;
81
+ }
79
82
 
80
- padding-block: calc(var(--spacing-2xs) + var(--density));
81
- padding-inline: var(--spacing-sm);
83
+ .valueWrapper > * {
84
+ height: 100%;
85
+ & > * {
86
+ height: 100% !important;
87
+ }
88
+ }
89
+
90
+ .valueWrapper button {
91
+ height: 100% !important;
92
+ border: 0 !important;
93
+ padding-inline: var(--spacing-sm) !important;
82
94
  }
83
95
 
84
96
  .filterField input {
@@ -93,6 +105,10 @@
93
105
  block-size: 100%;
94
106
  }
95
107
 
108
+ .filterField button {
109
+ border-radius: 0;
110
+ }
111
+
96
112
  .filterField input::placeholder {
97
113
  color: var(--color-fg-muted);
98
114
  }
@@ -0,0 +1,36 @@
1
+ import type { JSX } from 'react';
2
+ import React from 'react';
3
+ interface ChipToggleOption {
4
+ label: string;
5
+ value: string;
6
+ icon?: React.ReactNode;
7
+ }
8
+ interface ChipMultiToggleProps {
9
+ /** Optional group label (e.g. "Fejlede i") */
10
+ label?: string;
11
+ options: ChipToggleOption[];
12
+ selectedValues: string[];
13
+ onChange: (nextSelectedValues: string[]) => void;
14
+ onToggle?: (toggledValue: string, isSelected: boolean) => void;
15
+ size?: 'sm' | 'md' | 'lg';
16
+ selectedSeverity: 'neutral' | 'info' | 'success' | 'warning' | 'danger';
17
+ unselectedSeverity?: 'neutral' | 'info' | 'success' | 'warning' | 'danger' | null;
18
+ fullWidth?: boolean;
19
+ disabled?: boolean;
20
+ showAllOption?: boolean;
21
+ allLabel?: string;
22
+ allIcon?: React.ReactNode;
23
+ /**
24
+ * ✅ If true, clicking "All" toggles between:
25
+ * - All (no filtering) => []
26
+ * - None (match nothing) => [noneValue]
27
+ */
28
+ allTogglesNone?: boolean;
29
+ /**
30
+ * Sentinel stored in selectedValues to represent "none selected".
31
+ * Must not collide with any real option.value.
32
+ */
33
+ noneValue?: string;
34
+ }
35
+ export declare function ChipMultiToggle({ label, options, selectedValues, onChange, onToggle, size, selectedSeverity, unselectedSeverity, fullWidth, disabled, showAllOption, allLabel, allIcon, allTogglesNone, noneValue, }: ChipMultiToggleProps): JSX.Element;
36
+ export {};
@@ -0,0 +1,53 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React from 'react';
4
+ import { Chip } from '../../../components/chip/Chip';
5
+ import styles from './ChipMultiToggle.module.css';
6
+ export function ChipMultiToggle({ label, options, selectedValues = [], onChange, onToggle, size = 'sm', selectedSeverity = 'info', unselectedSeverity = null, fullWidth = false, disabled = false, showAllOption = false, allLabel = 'Alle', allIcon, allTogglesNone = false, noneValue = '__none__', }) {
7
+ const selectedSet = React.useMemo(() => new Set(selectedValues), [selectedValues]);
8
+ const isNoneSelected = allTogglesNone && selectedSet.has(noneValue);
9
+ const isAllSelected = showAllOption && !isNoneSelected && selectedSet.size === 0;
10
+ const toggleValue = (value) => {
11
+ if (disabled)
12
+ return;
13
+ // If we're in "none" state, selecting any option should exit none state
14
+ const next = new Set(selectedSet);
15
+ if (isNoneSelected)
16
+ next.delete(noneValue);
17
+ const willSelect = !next.has(value);
18
+ if (willSelect)
19
+ next.add(value);
20
+ else
21
+ next.delete(value);
22
+ const nextArr = Array.from(next);
23
+ onChange(nextArr);
24
+ onToggle === null || onToggle === void 0 ? void 0 : onToggle(value, willSelect);
25
+ };
26
+ const toggleAll = () => {
27
+ if (disabled)
28
+ return;
29
+ if (!allTogglesNone) {
30
+ // Classic "All" = clear selection
31
+ onChange([]);
32
+ return;
33
+ }
34
+ // Toggle between All <-> None
35
+ if (isAllSelected) {
36
+ onChange([noneValue]);
37
+ onToggle === null || onToggle === void 0 ? void 0 : onToggle(noneValue, true);
38
+ }
39
+ else if (isNoneSelected) {
40
+ onChange([]);
41
+ onToggle === null || onToggle === void 0 ? void 0 : onToggle(noneValue, false);
42
+ }
43
+ else {
44
+ // If some are selected, clicking All goes to All (clear)
45
+ onChange([]);
46
+ }
47
+ };
48
+ return (_jsxs("div", { className: `${styles.wrapper} ${fullWidth ? styles.fullWidth : ''}`, children: [label && _jsx("span", { className: styles.label, children: label }), _jsxs("div", { className: styles.container, children: [showAllOption && (_jsx("button", { type: "button", className: styles.chipButton, onClick: toggleAll, "aria-pressed": isAllSelected || isNoneSelected, disabled: disabled, children: _jsx(Chip, { size: size, severity: (isAllSelected || isNoneSelected ? selectedSeverity : unselectedSeverity), customIcon: allIcon, type: unselectedSeverity === null ? 'outlined' : 'rounded', children: isNoneSelected ? `${allLabel} (ingen)` : allLabel }) }, "__all__")), options.map(opt => {
49
+ // If none-state is active, everything else should look unselected
50
+ const isSelected = !isNoneSelected && selectedSet.has(opt.value);
51
+ return (_jsx("button", { type: "button", className: styles.chipButton, onClick: () => toggleValue(opt.value), "aria-pressed": isSelected, disabled: disabled, children: _jsx(Chip, { size: size, severity: (isSelected ? selectedSeverity : unselectedSeverity), customIcon: opt.icon, type: unselectedSeverity === null ? 'outlined' : 'rounded', children: opt.label }) }, opt.value));
52
+ })] })] }));
53
+ }