@dbcdk/react-components 0.0.5 → 0.0.6

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 (272) 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 +364 -459
  36. package/dist/components/filter-field/FilterField.d.ts +5 -2
  37. package/dist/components/filter-field/FilterField.js +130 -173
  38. package/dist/components/filter-field/FilterField.module.css +21 -5
  39. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.d.ts +36 -0
  40. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.js +53 -0
  41. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.module.css +60 -0
  42. package/dist/components/forms/checkbox/Checkbox.d.ts +31 -0
  43. package/dist/components/forms/checkbox/Checkbox.js +27 -0
  44. package/dist/components/{checkbox → forms/checkbox}/Checkbox.module.css +0 -1
  45. package/dist/components/forms/checkbox-group/CheckboxGroup.d.ts +47 -0
  46. package/dist/components/forms/checkbox-group/CheckboxGroup.js +75 -0
  47. package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +115 -0
  48. package/dist/components/{input → forms/input}/Input.d.ts +9 -5
  49. package/dist/components/forms/input/Input.js +70 -0
  50. package/dist/components/{input → forms/input}/Input.module.css +1 -0
  51. package/dist/components/forms/input-container/InputContainer.d.ts +15 -0
  52. package/dist/components/forms/input-container/InputContainer.js +15 -0
  53. package/dist/components/forms/input-container/InputContainer.module.css +34 -0
  54. package/dist/components/forms/multi-select/MultiSelect.d.ts +20 -0
  55. package/dist/components/forms/multi-select/MultiSelect.js +19 -0
  56. package/dist/components/forms/select/Select.d.ts +21 -0
  57. package/dist/components/forms/select/Select.js +94 -0
  58. package/dist/components/forms/text-area/Textarea.d.ts +17 -0
  59. package/dist/components/forms/text-area/Textarea.js +33 -0
  60. package/dist/components/forms/text-area/Textarea.module.css +26 -0
  61. package/dist/components/headline/Headline.js +18 -43
  62. package/dist/components/{link/Link.d.ts → hyperlink/Hyperlink.d.ts} +2 -2
  63. package/dist/components/hyperlink/Hyperlink.js +11 -0
  64. package/dist/components/{link/Link.module.css → hyperlink/Hyperlink.module.css} +5 -14
  65. package/dist/components/icon/Icon.d.ts +4 -3
  66. package/dist/components/icon/Icon.js +11 -17
  67. package/dist/components/menu/Menu.js +25 -67
  68. package/dist/components/meta-bar/MetaBar.d.ts +4 -4
  69. package/dist/components/meta-bar/MetaBar.js +7 -20
  70. package/dist/components/nav-bar/NavBar.d.ts +5 -5
  71. package/dist/components/nav-bar/NavBar.js +15 -45
  72. package/dist/components/{modal → overlay/modal}/Modal.d.ts +4 -2
  73. package/dist/components/overlay/modal/Modal.js +92 -0
  74. package/dist/components/{modal → overlay/modal}/provider/ModalProvider.d.ts +0 -1
  75. package/dist/components/overlay/modal/provider/ModalProvider.js +70 -0
  76. package/dist/components/overlay/side-panel/SidePanel.d.ts +16 -0
  77. package/dist/components/overlay/side-panel/SidePanel.js +10 -0
  78. package/dist/components/overlay/side-panel/SidePanel.module.css +56 -0
  79. package/dist/components/overlay/side-panel/useSidePanel.d.ts +5 -0
  80. package/dist/components/overlay/side-panel/useSidePanel.js +11 -0
  81. package/dist/components/overlay/tooltip/Tooltip.d.ts +13 -0
  82. package/dist/components/overlay/tooltip/Tooltip.js +17 -0
  83. package/dist/components/overlay/tooltip/Tooltip.module.css +106 -0
  84. package/dist/components/overlay/tooltip/TooltipProvider.d.ts +20 -0
  85. package/dist/components/overlay/tooltip/TooltipProvider.js +244 -0
  86. package/dist/components/overlay/tooltip/useTooltipTrigger.d.ts +24 -0
  87. package/dist/components/overlay/tooltip/useTooltipTrigger.js +108 -0
  88. package/dist/components/page/Page.d.ts +7 -6
  89. package/dist/components/page/Page.js +4 -21
  90. package/dist/components/page-layout/PageLayout.d.ts +11 -12
  91. package/dist/components/page-layout/PageLayout.js +35 -71
  92. package/dist/components/page-layout/components/page-layout-hero/PageLayoutHero.js +4 -22
  93. package/dist/components/pagination/Pagination.d.ts +2 -1
  94. package/dist/components/pagination/Pagination.js +38 -121
  95. package/dist/components/panel/Panel.d.ts +4 -3
  96. package/dist/components/panel/Panel.js +5 -10
  97. package/dist/components/popover/Popover.d.ts +1 -0
  98. package/dist/components/popover/Popover.js +116 -141
  99. package/dist/components/search-box/SearchBox.d.ts +2 -2
  100. package/dist/components/search-box/SearchBox.js +112 -162
  101. package/dist/components/segmented-progress-bar/SegmentedProgressBar.d.ts +1 -1
  102. package/dist/components/segmented-progress-bar/SegmentedProgressBar.js +47 -94
  103. package/dist/components/sidebar/Sidebar.d.ts +1 -0
  104. package/dist/components/sidebar/Sidebar.js +5 -7
  105. package/dist/components/sidebar/components/SidebarItem.js +6 -14
  106. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.d.ts +1 -1
  107. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +48 -88
  108. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.d.ts +3 -2
  109. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +11 -41
  110. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.d.ts +1 -0
  111. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.js +4 -25
  112. package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +9 -23
  113. package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.js +19 -40
  114. package/dist/components/sidebar/providers/SidebarProvider.d.ts +2 -1
  115. package/dist/components/sidebar/providers/SidebarProvider.js +182 -165
  116. package/dist/components/skeleton-loader/SkeletonLoader.js +68 -266
  117. package/dist/components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem.js +11 -34
  118. package/dist/components/split-button/SplitButton.d.ts +7 -5
  119. package/dist/components/split-button/SplitButton.js +4 -27
  120. package/dist/components/split-pane/SplitPane.js +69 -105
  121. package/dist/components/split-pane/provider/SplitPaneContext.js +77 -71
  122. package/dist/components/table/Table.d.ts +9 -7
  123. package/dist/components/table/Table.js +115 -238
  124. package/dist/components/table/Table.module.css +5 -1
  125. package/dist/components/table/components/column-resizer/ColumnResizer.js +4 -15
  126. package/dist/components/table/components/empty-state/EmptyState.d.ts +6 -5
  127. package/dist/components/table/components/empty-state/EmptyState.js +22 -41
  128. package/dist/components/table/components/table-settings/TableSettings.d.ts +2 -1
  129. package/dist/components/table/components/table-settings/TableSettings.js +9 -27
  130. package/dist/components/table/tanstack.d.ts +1 -1
  131. package/dist/components/table/tanstack.js +154 -160
  132. package/dist/components/tabs/Tabs.d.ts +1 -0
  133. package/dist/components/tabs/Tabs.js +32 -81
  134. package/dist/components/toast/Toast.d.ts +1 -1
  135. package/dist/components/toast/Toast.js +4 -37
  136. package/dist/components/toast/Toast.module.css +1 -0
  137. package/dist/components/toast/provider/ToastProvider.d.ts +1 -1
  138. package/dist/components/toast/provider/ToastProvider.js +60 -87
  139. package/dist/components/user-display/UserDisplay.d.ts +2 -1
  140. package/dist/components/user-display/UserDisplay.js +4 -20
  141. package/dist/constants/severity.d.ts +1 -1
  142. package/dist/constants/severity.js +14 -16
  143. package/dist/constants/severity.types.d.ts +1 -1
  144. package/dist/constants/severity.types.js +1 -1
  145. package/dist/constants/sizes.js +6 -8
  146. package/dist/hooks/usePagination.d.ts +1 -1
  147. package/dist/hooks/usePagination.js +75 -82
  148. package/dist/hooks/useSorting.js +112 -110
  149. package/dist/hooks/useTableData.d.ts +1 -1
  150. package/dist/hooks/useTableData.js +42 -47
  151. package/dist/hooks/useTableSelection.js +121 -121
  152. package/dist/hooks/useTableSettings.js +23 -25
  153. package/dist/hooks/useTheme.d.ts +3 -7
  154. package/dist/hooks/useTheme.js +52 -47
  155. package/dist/hooks/useTimeDuration.d.ts +2 -2
  156. package/dist/hooks/useTimeDuration.js +33 -34
  157. package/dist/hooks/useViewportFill.d.ts +3 -2
  158. package/dist/hooks/useViewportFill.js +55 -48
  159. package/dist/index.d.ts +17 -8
  160. package/dist/index.js +18 -8
  161. package/dist/src/styles/styles.css +3 -3
  162. package/dist/styles/css-helper-classes/flex.css +4 -0
  163. package/dist/styles/styles.css +3 -3
  164. package/dist/styles/themes/dbc/dark.css +1 -1
  165. package/dist/styles/themes/dbc/light.css +2 -1
  166. package/dist/styles/themes/forfatterweb/light.css +1 -1
  167. package/dist/styles/themes/types.js +1 -1
  168. package/dist/types/a11y-props.types.d.ts +5 -5
  169. package/dist/types/a11y-props.types.js +1 -1
  170. package/dist/types/sizes.types.js +1 -1
  171. package/dist/utils/arrays/nested-filtering.js +43 -33
  172. package/dist/utils/date/formatDate.js +25 -16
  173. package/package.json +18 -9
  174. package/dist/assets/logo.cjs +0 -87
  175. package/dist/components/__stories__/story-components/Colors.cjs +0 -159
  176. package/dist/components/__stories__/story-components/Spacing.cjs +0 -190
  177. package/dist/components/app-header/AppHeader.cjs +0 -14
  178. package/dist/components/attribute-chip/AttributeChip.cjs +0 -22
  179. package/dist/components/avatar/Avatar.cjs +0 -101
  180. package/dist/components/breadcrumbs/Breadcrumbs.cjs +0 -22
  181. package/dist/components/button/Button.cjs +0 -87
  182. package/dist/components/card/Card.cjs +0 -69
  183. package/dist/components/card-container/CardContainer.cjs +0 -24
  184. package/dist/components/checkbox/Checkbox.cjs +0 -42
  185. package/dist/components/checkbox/Checkbox.d.ts +0 -12
  186. package/dist/components/checkbox/Checkbox.js +0 -36
  187. package/dist/components/chip/Chip.cjs +0 -50
  188. package/dist/components/circle/Circle.cjs +0 -18
  189. package/dist/components/clear-button/ClearButton.cjs +0 -26
  190. package/dist/components/code-block/CodeBlock.cjs +0 -18
  191. package/dist/components/copy-button/CopyButton.cjs +0 -35
  192. package/dist/components/datetime-picker/DateTimePicker.cjs +0 -504
  193. package/dist/components/filter-field/FilterField.cjs +0 -189
  194. package/dist/components/headline/Headline.cjs +0 -53
  195. package/dist/components/icon/Icon.cjs +0 -27
  196. package/dist/components/input/Input.cjs +0 -89
  197. package/dist/components/input/Input.js +0 -83
  198. package/dist/components/link/Link.cjs +0 -46
  199. package/dist/components/link/Link.js +0 -21
  200. package/dist/components/menu/Menu.cjs +0 -96
  201. package/dist/components/meta-bar/MetaBar.cjs +0 -29
  202. package/dist/components/modal/Modal.cjs +0 -134
  203. package/dist/components/modal/Modal.js +0 -128
  204. package/dist/components/modal/provider/ModalProvider.cjs +0 -80
  205. package/dist/components/modal/provider/ModalProvider.js +0 -77
  206. package/dist/components/multi-select/MultiSelect.cjs +0 -59
  207. package/dist/components/multi-select/MultiSelect.d.ts +0 -18
  208. package/dist/components/multi-select/MultiSelect.js +0 -57
  209. package/dist/components/nav-bar/NavBar.cjs +0 -55
  210. package/dist/components/page/Page.cjs +0 -30
  211. package/dist/components/page-layout/PageLayout.cjs +0 -84
  212. package/dist/components/page-layout/components/page-layout-hero/PageLayoutHero.cjs +0 -32
  213. package/dist/components/pagination/Pagination.cjs +0 -133
  214. package/dist/components/panel/Panel.cjs +0 -18
  215. package/dist/components/popover/Popover.cjs +0 -149
  216. package/dist/components/search-box/SearchBox.cjs +0 -175
  217. package/dist/components/segmented-progress-bar/SegmentedProgressBar.cjs +0 -103
  218. package/dist/components/select/Select.cjs +0 -121
  219. package/dist/components/select/Select.d.ts +0 -12
  220. package/dist/components/select/Select.js +0 -119
  221. package/dist/components/sidebar/Sidebar.cjs +0 -11
  222. package/dist/components/sidebar/components/SidebarItem.cjs +0 -18
  223. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.cjs +0 -100
  224. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.cjs +0 -50
  225. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.cjs +0 -34
  226. package/dist/components/sidebar/components/sidebar-items/SidebarItems.cjs +0 -29
  227. package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.cjs +0 -52
  228. package/dist/components/sidebar/providers/SidebarProvider.cjs +0 -179
  229. package/dist/components/skeleton-loader/SkeletonLoader.cjs +0 -270
  230. package/dist/components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem.cjs +0 -42
  231. package/dist/components/split-button/SplitButton.cjs +0 -37
  232. package/dist/components/split-pane/SplitPane.cjs +0 -123
  233. package/dist/components/split-pane/provider/SplitPaneContext.cjs +0 -87
  234. package/dist/components/table/Table.cjs +0 -249
  235. package/dist/components/table/components/column-resizer/ColumnResizer.cjs +0 -22
  236. package/dist/components/table/components/empty-state/EmptyState.cjs +0 -52
  237. package/dist/components/table/components/table-settings/TableSettings.cjs +0 -32
  238. package/dist/components/table/tanstack.cjs +0 -193
  239. package/dist/components/tabs/Tabs.cjs +0 -90
  240. package/dist/components/text-area/Textarea.cjs +0 -62
  241. package/dist/components/text-area/Textarea.d.ts +0 -14
  242. package/dist/components/text-area/Textarea.js +0 -56
  243. package/dist/components/text-area/Textarea.module.css +0 -3
  244. package/dist/components/toast/Toast.cjs +0 -47
  245. package/dist/components/toast/provider/ToastProvider.cjs +0 -98
  246. package/dist/components/tooltip/Tooltip.cjs +0 -183
  247. package/dist/components/tooltip/Tooltip.d.ts +0 -11
  248. package/dist/components/tooltip/Tooltip.js +0 -177
  249. package/dist/components/tooltip/Tooltip.module.css +0 -66
  250. package/dist/components/user-display/UserDisplay.cjs +0 -28
  251. package/dist/constants/severity.cjs +0 -21
  252. package/dist/constants/severity.types.cjs +0 -2
  253. package/dist/constants/sizes.cjs +0 -11
  254. package/dist/hooks/usePagination.cjs +0 -88
  255. package/dist/hooks/useSorting.cjs +0 -118
  256. package/dist/hooks/useTableData.cjs +0 -52
  257. package/dist/hooks/useTableSelection.cjs +0 -130
  258. package/dist/hooks/useTableSettings.cjs +0 -28
  259. package/dist/hooks/useTheme.cjs +0 -58
  260. package/dist/hooks/useTimeDuration.cjs +0 -39
  261. package/dist/hooks/useViewportFill.cjs +0 -52
  262. package/dist/index.cjs +0 -383
  263. package/dist/styles/themes/types.cjs +0 -2
  264. package/dist/types/a11y-props.types.cjs +0 -2
  265. package/dist/types/assets.d.cjs +0 -2
  266. package/dist/types/assets.d.js +0 -1
  267. package/dist/types/css.d.cjs +0 -2
  268. package/dist/types/css.d.js +0 -1
  269. package/dist/types/sizes.types.cjs +0 -2
  270. package/dist/utils/arrays/nested-filtering.cjs +0 -40
  271. package/dist/utils/date/formatDate.cjs +0 -19
  272. /package/dist/components/{modal → overlay/modal}/Modal.module.css +0 -0
@@ -1,498 +1,403 @@
1
- import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { forwardRef, useRef, useMemo, useState, useCallback, useEffect } from 'react';
3
- import { X, ChevronLeft, ChevronRight, Clock, Calendar } from 'lucide-react';
4
- import { Popover } from '../popover/Popover';
5
- import { Input } from '../input/Input';
6
- import { Button } from '../button/Button';
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Calendar, ChevronLeft, ChevronRight, Clock, X } from 'lucide-react';
4
+ import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import { Button } from '../../components/button/Button';
6
+ import { Input } from '../../components/forms/input/Input';
7
+ import { Popover } from '../../components/popover/Popover';
7
8
  import styles from './DateTimePicker.module.css';
8
-
9
- const digits = (s) => (s.match(/\d/g) || []).join("");
9
+ /* ---------- Mask helpers (no deps) ---------- */
10
+ // Pull only 0-9
11
+ const digits = (s) => (s.match(/\d/g) || []).join('');
12
+ // DD-MM-YYYY
10
13
  function maskDateEU(text) {
11
- const d = digits(text).slice(0, 8);
12
- const dd = d.slice(0, 2);
13
- const mm = d.slice(2, 4);
14
- const yyyy = d.slice(4, 8);
15
- let out = dd;
16
- if (mm.length) out += (out ? "-" : "") + mm;
17
- if (yyyy.length) out += (out ? "-" : "") + yyyy;
18
- return out;
14
+ const d = digits(text).slice(0, 8);
15
+ const dd = d.slice(0, 2);
16
+ const mm = d.slice(2, 4);
17
+ const yyyy = d.slice(4, 8);
18
+ let out = dd;
19
+ if (mm.length)
20
+ out += (out ? '-' : '') + mm;
21
+ if (yyyy.length)
22
+ out += (out ? '-' : '') + yyyy;
23
+ return out;
19
24
  }
25
+ // HH:mm (24h)
20
26
  function maskTimeHM(text) {
21
- const d = digits(text).slice(0, 4);
22
- const hh = d.slice(0, 2);
23
- const mm = d.slice(2, 4);
24
- return mm.length ? `${hh}:${mm}` : hh;
27
+ const d = digits(text).slice(0, 4);
28
+ const hh = d.slice(0, 2);
29
+ const mm = d.slice(2, 4);
30
+ return mm.length ? `${hh}:${mm}` : hh;
25
31
  }
32
+ // Single: "DD-MM-YYYY" or "DD-MM-YYYY HH:mm"
26
33
  function maskSingle(text, enableTime) {
27
- let t = text.trim().replace(/\s+/g, " ");
28
- if (!enableTime) return maskDateEU(t);
29
- const m = /^(.*?)[ T](.*)$/.exec(t);
30
- if (!m) return maskDateEU(t);
31
- const datePart = maskDateEU(m[1]);
32
- const timePart = maskTimeHM(m[2]);
33
- return timePart ? `${datePart} ${timePart}` : datePart;
34
+ let t = text.trim().replace(/\s+/g, ' ');
35
+ if (!enableTime)
36
+ return maskDateEU(t);
37
+ // split date + time by first space or 'T'
38
+ const m = /^(.*?)[ T](.*)$/.exec(t);
39
+ if (!m)
40
+ return maskDateEU(t);
41
+ const datePart = maskDateEU(m[1]);
42
+ const timePart = maskTimeHM(m[2]);
43
+ return timePart ? `${datePart} ${timePart}` : datePart;
34
44
  }
45
+ // Range: mask both sides around common separators (–, -, to, til)
35
46
  function maskRange(text, enableTime) {
36
- const sepRe = /\s*(?:–|-|to|til)\s*/i;
37
- const parts = text.split(sepRe);
38
- if (parts.length === 1) {
39
- return maskSingle(parts[0], enableTime);
40
- }
41
- const a = maskSingle(parts[0], enableTime);
42
- const b = maskSingle(parts.slice(1).join(" "), enableTime);
43
- return `${a} \u2013 ${b}`.trim();
47
+ const sepRe = /\s*(?:–|-|to|til)\s*/i;
48
+ const parts = text.split(sepRe);
49
+ if (parts.length === 1) {
50
+ // user typing first side
51
+ return maskSingle(parts[0], enableTime);
52
+ }
53
+ const a = maskSingle(parts[0], enableTime);
54
+ const b = maskSingle(parts.slice(1).join(' '), enableTime); // everything after first sep
55
+ return `${a} – ${b}`.trim();
44
56
  }
45
- const pad2 = (n) => String(n).padStart(2, "0");
57
+ // Pad helper
58
+ const pad2 = (n) => String(n).padStart(2, '0');
59
+ // From Date → "DD-MM-YYYY" or "DD-MM-YYYY HH:mm" (local time)
46
60
  function toMaskedFromDate(d, enableTime) {
47
- const dd = pad2(d.getDate());
48
- const mm = pad2(d.getMonth() + 1);
49
- const yyyy = String(d.getFullYear());
50
- let out = `${dd}-${mm}-${yyyy}`;
51
- if (enableTime) out += ` ${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
52
- return out;
61
+ const dd = pad2(d.getDate());
62
+ const mm = pad2(d.getMonth() + 1);
63
+ const yyyy = String(d.getFullYear());
64
+ let out = `${dd}-${mm}-${yyyy}`;
65
+ if (enableTime)
66
+ out += ` ${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
67
+ return out;
53
68
  }
69
+ // From start/end → "DD-MM-YYYY – DD-MM-YYYY" (+ optional time)
54
70
  function toMaskedRange(start, end, enableTime) {
55
- if (start && end)
56
- return `${toMaskedFromDate(start, enableTime)} \u2013 ${toMaskedFromDate(end, enableTime)}`;
57
- if (start) return `${toMaskedFromDate(start, enableTime)} \u2013`;
58
- if (end) return `\u2013 ${toMaskedFromDate(end, enableTime)}`;
59
- return "";
71
+ if (start && end)
72
+ return `${toMaskedFromDate(start, enableTime)} ${toMaskedFromDate(end, enableTime)}`;
73
+ if (start)
74
+ return `${toMaskedFromDate(start, enableTime)} –`;
75
+ if (end)
76
+ return `– ${toMaskedFromDate(end, enableTime)}`;
77
+ return '';
60
78
  }
79
+ /* ---------- Parsing helpers (no deps) ---------- */
80
+ // Accepts: YYYY-MM-DD, DD-MM-YYYY, DD/MM/YYYY, DD.MM.YYYY (+ optional HH:mm)
61
81
  function parseLooseDateOrDateTime(input) {
62
- const txt = input.trim().replace(/\s+/g, " ");
63
- const dateTimeMatch = /^(?<date>[\d./-]{8,10})(?:[ T](?<hh>\d{1,2}):(?<mm>\d{2}))?$/i.exec(txt);
64
- if (!(dateTimeMatch == null ? void 0 : dateTimeMatch.groups)) return null;
65
- const raw = dateTimeMatch.groups.date;
66
- const hh = dateTimeMatch.groups.hh ? parseInt(dateTimeMatch.groups.hh, 10) : 0;
67
- const mm = dateTimeMatch.groups.mm ? parseInt(dateTimeMatch.groups.mm, 10) : 0;
68
- if (hh < 0 || hh > 23 || mm < 0 || mm > 59) return null;
69
- let y, m, d;
70
- let mIso = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(raw);
71
- if (mIso) {
72
- y = +mIso[1];
73
- m = +mIso[2] - 1;
74
- d = +mIso[3];
75
- } else {
76
- let mEu = /^(\d{1,2})[./-](\d{1,2})[./-](\d{4})$/.exec(raw);
77
- if (!mEu) return null;
78
- d = +mEu[1];
79
- m = +mEu[2] - 1;
80
- y = +mEu[3];
81
- }
82
- const local = new Date(y, m, d, hh, mm, 0, 0);
83
- if (Number.isNaN(local.getTime())) return null;
84
- if (local.getFullYear() !== y || local.getMonth() !== m || local.getDate() !== d) return null;
85
- return local;
82
+ const txt = input.trim().replace(/\s+/g, ' ');
83
+ const dateTimeMatch = /^(?<date>[\d./-]{8,10})(?:[ T](?<hh>\d{1,2}):(?<mm>\d{2}))?$/i.exec(txt);
84
+ if (!(dateTimeMatch === null || dateTimeMatch === void 0 ? void 0 : dateTimeMatch.groups))
85
+ return null;
86
+ const raw = dateTimeMatch.groups.date;
87
+ const hh = dateTimeMatch.groups.hh ? parseInt(dateTimeMatch.groups.hh, 10) : 0;
88
+ const mm = dateTimeMatch.groups.mm ? parseInt(dateTimeMatch.groups.mm, 10) : 0;
89
+ if (hh < 0 || hh > 23 || mm < 0 || mm > 59)
90
+ return null;
91
+ // Try YYYY-MM-DD first
92
+ let y, m, d;
93
+ const mIso = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(raw);
94
+ if (mIso) {
95
+ y = +mIso[1];
96
+ m = +mIso[2] - 1;
97
+ d = +mIso[3];
98
+ }
99
+ else {
100
+ // Try DD-MM-YYYY or DD/MM/YYYY or DD.MM.YYYY
101
+ const mEu = /^(\d{1,2})[./-](\d{1,2})[./-](\d{4})$/.exec(raw);
102
+ if (!mEu)
103
+ return null;
104
+ d = +mEu[1];
105
+ m = +mEu[2] - 1;
106
+ y = +mEu[3];
107
+ }
108
+ const local = new Date(y, m, d, hh, mm, 0, 0);
109
+ if (Number.isNaN(local.getTime()))
110
+ return null;
111
+ // Guard: JS autocorrects invalid dates; re-validate exact Y/M/D
112
+ if (local.getFullYear() !== y || local.getMonth() !== m || local.getDate() !== d)
113
+ return null;
114
+ return local;
86
115
  }
116
+ // Parse a range string with separators: "–", "-", "to", "til"
87
117
  function parseLooseRange(input) {
88
- const sep = /\s*(?:–|-|to|til)\s*/i;
89
- const [a, b] = input.split(sep);
90
- if (!a || !b) return null;
91
- const s = parseLooseDateOrDateTime(a);
92
- const e = parseLooseDateOrDateTime(b);
93
- if (!s || !e) return null;
94
- return s <= e ? { start: s, end: e } : { start: e, end: s };
118
+ const sep = /\s*(?:–|-|to|til)\s*/i;
119
+ const [a, b] = input.split(sep);
120
+ if (!a || !b)
121
+ return null;
122
+ const s = parseLooseDateOrDateTime(a);
123
+ const e = parseLooseDateOrDateTime(b);
124
+ if (!s || !e)
125
+ return null;
126
+ return s <= e ? { start: s, end: e } : { start: e, end: s };
95
127
  }
128
+ /* ---------- Date grid helpers (UTC) ---------- */
96
129
  const dUTC = (y, m, day) => new Date(Date.UTC(y, m, day));
97
130
  const addDaysUTC = (utcDate, n) => dUTC(utcDate.getUTCFullYear(), utcDate.getUTCMonth(), utcDate.getUTCDate() + n);
98
131
  const startOfMonthUTC = (utcDate) => dUTC(utcDate.getUTCFullYear(), utcDate.getUTCMonth(), 1);
99
132
  const endOfMonthUTC = (utcDate) => dUTC(utcDate.getUTCFullYear(), utcDate.getUTCMonth() + 1, 0);
100
- const sameDayUTC = (a, b) => a.getUTCFullYear() === b.getUTCFullYear() && a.getUTCMonth() === b.getUTCMonth() && a.getUTCDate() === b.getUTCDate();
133
+ const sameDayUTC = (a, b) => a.getUTCFullYear() === b.getUTCFullYear() &&
134
+ a.getUTCMonth() === b.getUTCMonth() &&
135
+ a.getUTCDate() === b.getUTCDate();
101
136
  const toUTCDateOnly = (local) => dUTC(local.getFullYear(), local.getMonth(), local.getDate());
102
137
  const startOfWeekUTC = (utcDate, weekStartsOn) => {
103
- const dow = utcDate.getUTCDay();
104
- const diff = (dow - weekStartsOn + 7) % 7;
105
- return addDaysUTC(utcDate, -diff);
138
+ const dow = utcDate.getUTCDay();
139
+ const diff = (dow - weekStartsOn + 7) % 7;
140
+ return addDaysUTC(utcDate, -diff);
106
141
  };
107
142
  function buildMonthGrid(anchorLocalDate, weekStartsOn) {
108
- const anchorUTC = toUTCDateOnly(anchorLocalDate);
109
- const firstUTC = startOfWeekUTC(startOfMonthUTC(anchorUTC), weekStartsOn);
110
- const cells = [];
111
- for (let i = 0; i < 42; i++) cells.push(addDaysUTC(firstUTC, i));
112
- return cells;
143
+ const anchorUTC = toUTCDateOnly(anchorLocalDate);
144
+ const firstUTC = startOfWeekUTC(startOfMonthUTC(anchorUTC), weekStartsOn);
145
+ const cells = [];
146
+ for (let i = 0; i < 42; i++)
147
+ cells.push(addDaysUTC(firstUTC, i));
148
+ return cells;
113
149
  }
114
150
  const isBetweenUTC = (d, a, b) => {
115
- const t = +d, s = +a, e = +b;
116
- return t >= Math.min(s, e) && t <= Math.max(s, e);
151
+ const t = +d, s = +a, e = +b;
152
+ return t >= Math.min(s, e) && t <= Math.max(s, e);
117
153
  };
118
154
  function composeLocalDateTimeISO(utcDateOnly, hh, mm) {
119
- const y = utcDateOnly.getUTCFullYear();
120
- const m = utcDateOnly.getUTCMonth();
121
- const d = utcDateOnly.getUTCDate();
122
- const local = new Date(y, m, d, hh, mm, 0, 0);
123
- return local.toISOString();
155
+ const y = utcDateOnly.getUTCFullYear();
156
+ const m = utcDateOnly.getUTCMonth();
157
+ const d = utcDateOnly.getUTCDate();
158
+ const local = new Date(y, m, d, hh, mm, 0, 0);
159
+ return local.toISOString();
124
160
  }
161
+ /* ---------- Formatting (exposed but input uses mask) ---------- */
125
162
  function defaultFormatDate(d, { locale, enableTime }) {
126
- const opts = enableTime ? { year: "numeric", month: "short", day: "2-digit", hour: "2-digit", minute: "2-digit" } : { year: "numeric", month: "short", day: "2-digit" };
127
- return new Intl.DateTimeFormat(locale || void 0, opts).format(d);
163
+ const opts = enableTime
164
+ ? { year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }
165
+ : { year: 'numeric', month: 'short', day: '2-digit' };
166
+ return new Intl.DateTimeFormat(locale || undefined, opts).format(d);
128
167
  }
129
168
  function defaultFormatRange(s, e, opts) {
130
- if (s && e) return `${defaultFormatDate(s, opts)} \u2013 ${defaultFormatDate(e, opts)}`;
131
- if (s) return `${defaultFormatDate(s, opts)} \u2013`;
132
- if (e) return `\u2013 ${defaultFormatDate(e, opts)}`;
133
- return "";
169
+ if (s && e)
170
+ return `${defaultFormatDate(s, opts)} ${defaultFormatDate(e, opts)}`;
171
+ if (s)
172
+ return `${defaultFormatDate(s, opts)} –`;
173
+ if (e)
174
+ return `– ${defaultFormatDate(e, opts)}`;
175
+ return '';
134
176
  }
135
- const cx = (...classes) => classes.filter(Boolean).join(" ");
136
- const DateTimePicker = forwardRef(function DateTimePicker2({
137
- mode = "single",
138
- value,
139
- onChange,
140
- enableTime = false,
141
- timeStep = 15,
142
- min,
143
- max,
144
- locale = typeof navigator !== "undefined" ? navigator.language : "da-DK",
145
- weekStartsOn = 1,
146
- presets,
147
- placeholder,
148
- inputSize = "md",
149
- disabled,
150
- id,
151
- formatDate = defaultFormatDate,
152
- // still exposed, not used for input text
153
- formatRange = defaultFormatRange
154
- // still exposed, not used for input text
155
- }, _ref) {
156
- const popRef = useRef(null);
157
- const todayLocal = useMemo(() => /* @__PURE__ */ new Date(), []);
158
- const initialAnchor = useMemo(() => {
159
- if (mode === "single" && value instanceof Date && value) return value;
160
- if (mode === "range" && value && typeof value === "object" && "start" in value && value.start)
161
- return value.start;
162
- return todayLocal;
163
- }, [mode, value, todayLocal]);
164
- const [monthAnchor, setMonthAnchor] = useState(initialAnchor);
165
- const [timeHH, setTimeHH] = useState(todayLocal.getHours());
166
- const [timeMM, setTimeMM] = useState(
167
- Math.floor(todayLocal.getMinutes() / timeStep) * timeStep
168
- );
169
- const [hoverUTC, setHoverUTC] = useState(null);
170
- const cellsUTC = useMemo(
171
- () => buildMonthGrid(monthAnchor, weekStartsOn),
172
- [monthAnchor, weekStartsOn]
173
- );
174
- const monthStartUTC = useMemo(() => startOfMonthUTC(toUTCDateOnly(monthAnchor)), [monthAnchor]);
175
- const monthEndUTC = useMemo(() => endOfMonthUTC(toUTCDateOnly(monthAnchor)), [monthAnchor]);
176
- const weekdayFmt = useMemo(() => new Intl.DateTimeFormat(locale, { weekday: "short" }), [locale]);
177
- const monthFmt = useMemo(
178
- () => new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }),
179
- [locale]
180
- );
181
- const selectedUTC_single = mode === "single" && value instanceof Date && value ? toUTCDateOnly(value) : null;
182
- const selectedUTC_start = mode === "range" && value && typeof value === "object" && "start" in value && value.start ? toUTCDateOnly(value.start) : null;
183
- const selectedUTC_end = mode === "range" && value && typeof value === "object" && "end" in value && value.end ? toUTCDateOnly(value.end) : null;
184
- const isDisabledUTC = useCallback(
185
- (utcDay) => {
186
- if (min && utcDay < toUTCDateOnly(min)) return true;
187
- if (max && utcDay > toUTCDateOnly(max)) return true;
188
- return false;
189
- },
190
- [min, max]
191
- );
192
- const selectDay = (utcDay) => {
193
- var _a, _b;
194
- if (isDisabledUTC(utcDay)) return;
195
- if (mode === "single") {
196
- if (enableTime) {
197
- const iso = composeLocalDateTimeISO(utcDay, timeHH, timeMM);
198
- onChange(new Date(iso));
199
- } else {
200
- onChange(new Date(utcDay.getTime()));
201
- }
202
- (_a = popRef.current) == null ? void 0 : _a.close();
203
- return;
204
- }
205
- const curr = value && typeof value === "object" && "start" in value ? value : { start: null, end: null };
206
- if (!curr.start || curr.start && curr.end) {
207
- onChange({ start: new Date(utcDay.getTime()), end: null });
208
- } else {
209
- const startUTC = toUTCDateOnly(curr.start);
210
- const endUTC = utcDay;
211
- const s = new Date(Math.min(+startUTC, +endUTC));
212
- const e = new Date(Math.max(+startUTC, +endUTC));
213
- onChange({ start: s, end: e });
214
- (_b = popRef.current) == null ? void 0 : _b.close();
215
- }
216
- };
217
- const gridRef = useRef(null);
218
- useEffect(() => {
219
- const el = gridRef.current;
220
- if (!el) return;
221
- const onKey = (e) => {
222
- var _a;
223
- if (!((_a = popRef.current) == null ? void 0 : _a.isOpen())) return;
224
- if ([
225
- "ArrowLeft",
226
- "ArrowRight",
227
- "ArrowUp",
228
- "ArrowDown",
229
- "PageUp",
230
- "PageDown",
231
- "Home",
232
- "End"
233
- ].includes(e.key)) {
234
- e.preventDefault();
235
- }
236
- const anchor = toUTCDateOnly(monthAnchor);
237
- const move = (days) => setMonthAnchor((prev) => addDaysLocal(prev, days));
238
- switch (e.key) {
239
- case "ArrowLeft":
240
- move(-1);
241
- break;
242
- case "ArrowRight":
243
- move(1);
244
- break;
245
- case "ArrowUp":
246
- move(-7);
247
- break;
248
- case "ArrowDown":
249
- move(7);
250
- break;
251
- case "PageUp":
252
- setMonthAnchor(addMonthsLocal(monthAnchor, -1));
253
- break;
254
- case "PageDown":
255
- setMonthAnchor(addMonthsLocal(monthAnchor, 1));
256
- break;
257
- case "Home":
258
- setMonthAnchor(new Date(anchor.getUTCFullYear(), anchor.getUTCMonth(), 1));
259
- break;
260
- case "End":
261
- setMonthAnchor(new Date(anchor.getUTCFullYear(), anchor.getUTCMonth() + 1, 0));
262
- break;
263
- }
177
+ const cx = (...classes) => classes.filter(Boolean).join(' ');
178
+ export const DateTimePicker = forwardRef(function DateTimePicker({ mode = 'single', value, onChange, enableTime = false, timeStep = 15, min, max, locale = typeof navigator !== 'undefined' ? navigator.language : 'da-DK', weekStartsOn = 1, presets, inputProps, formatDate = defaultFormatDate, // still exposed, not used for input text
179
+ formatRange = defaultFormatRange, // still exposed, not used for input text
180
+ }, _ref) {
181
+ void formatDate;
182
+ void formatRange;
183
+ const popRef = useRef(null);
184
+ const todayLocal = useMemo(() => new Date(), []);
185
+ const initialAnchor = useMemo(() => {
186
+ if (mode === 'single' && value instanceof Date && value)
187
+ return value;
188
+ if (mode === 'range' && value && typeof value === 'object' && 'start' in value && value.start)
189
+ return value.start;
190
+ return todayLocal;
191
+ }, [mode, value, todayLocal]);
192
+ const [monthAnchor, setMonthAnchor] = useState(initialAnchor);
193
+ const [timeHH, setTimeHH] = useState(todayLocal.getHours());
194
+ const [timeMM, setTimeMM] = useState(Math.floor(todayLocal.getMinutes() / timeStep) * timeStep);
195
+ const [hoverUTC, setHoverUTC] = useState(null);
196
+ const cellsUTC = useMemo(() => buildMonthGrid(monthAnchor, weekStartsOn), [monthAnchor, weekStartsOn]);
197
+ const monthStartUTC = useMemo(() => startOfMonthUTC(toUTCDateOnly(monthAnchor)), [monthAnchor]);
198
+ const monthEndUTC = useMemo(() => endOfMonthUTC(toUTCDateOnly(monthAnchor)), [monthAnchor]);
199
+ const weekdayFmt = useMemo(() => new Intl.DateTimeFormat(locale, { weekday: 'short' }), [locale]);
200
+ const monthFmt = useMemo(() => new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric' }), [locale]);
201
+ const selectedUTC_single = mode === 'single' && value instanceof Date && value ? toUTCDateOnly(value) : null;
202
+ const selectedUTC_start = mode === 'range' && value && typeof value === 'object' && 'start' in value && value.start
203
+ ? toUTCDateOnly(value.start)
204
+ : null;
205
+ const selectedUTC_end = mode === 'range' && value && typeof value === 'object' && 'end' in value && value.end
206
+ ? toUTCDateOnly(value.end)
207
+ : null;
208
+ const isDisabledUTC = useCallback((utcDay) => {
209
+ if (min && utcDay < toUTCDateOnly(min))
210
+ return true;
211
+ if (max && utcDay > toUTCDateOnly(max))
212
+ return true;
213
+ return false;
214
+ }, [min, max]);
215
+ const selectDay = (utcDay) => {
216
+ var _a, _b;
217
+ if (isDisabledUTC(utcDay))
218
+ return;
219
+ if (mode === 'single') {
220
+ if (enableTime) {
221
+ const iso = composeLocalDateTimeISO(utcDay, timeHH, timeMM);
222
+ onChange(new Date(iso));
223
+ }
224
+ else {
225
+ onChange(new Date(utcDay.getTime()));
226
+ }
227
+ (_a = popRef.current) === null || _a === void 0 ? void 0 : _a.close();
228
+ return;
229
+ }
230
+ const curr = value && typeof value === 'object' && 'start' in value ? value : { start: null, end: null };
231
+ if (!curr.start || (curr.start && curr.end)) {
232
+ onChange({ start: new Date(utcDay.getTime()), end: null });
233
+ }
234
+ else {
235
+ const startUTC = toUTCDateOnly(curr.start);
236
+ const endUTC = utcDay;
237
+ const s = new Date(Math.min(+startUTC, +endUTC));
238
+ const e = new Date(Math.max(+startUTC, +endUTC));
239
+ onChange({ start: s, end: e });
240
+ (_b = popRef.current) === null || _b === void 0 ? void 0 : _b.close();
241
+ }
264
242
  };
265
- el.addEventListener("keydown", onKey);
266
- return () => el.removeEventListener("keydown", onKey);
267
- }, [monthAnchor]);
268
- const hours = useMemo(() => Array.from({ length: 24 }, (_, i) => i), []);
269
- const minutes = useMemo(
270
- () => Array.from({ length: Math.floor(60 / (timeStep || 1)) }, (_, i) => i * (timeStep || 1)),
271
- [timeStep]
272
- );
273
- const formatted = useMemo(() => {
274
- var _a, _b;
275
- if (mode === "single") {
276
- return value instanceof Date && value ? toMaskedFromDate(value, enableTime) : "";
277
- }
278
- const v = value;
279
- return toMaskedRange((_a = v == null ? void 0 : v.start) != null ? _a : null, (_b = v == null ? void 0 : v.end) != null ? _b : null, enableTime);
280
- }, [mode, value, enableTime]);
281
- const [text, setText] = useState(formatted);
282
- const [dirty, setDirty] = useState(false);
283
- useEffect(() => {
284
- if (!dirty) setText(formatted);
285
- }, [formatted, dirty]);
286
- const commitTypedValue = useCallback(() => {
287
- if (!text.trim()) {
288
- if (mode === "single") onChange(null);
289
- else onChange({ start: null, end: null });
290
- setDirty(false);
291
- return;
292
- }
293
- if (mode === "single") {
294
- const dLocal = parseLooseDateOrDateTime(text);
295
- if (dLocal) {
296
- onChange(dLocal);
297
- setMonthAnchor(dLocal);
298
- setDirty(false);
299
- }
300
- return;
301
- }
302
- const r = parseLooseRange(text);
303
- if (r) {
304
- onChange({ start: r.start, end: r.end });
305
- setMonthAnchor(r.start);
306
- setDirty(false);
307
- }
308
- }, [text, mode, onChange]);
309
- const clear = useCallback(() => {
310
- if (mode === "single") onChange(null);
311
- else onChange({ start: null, end: null });
312
- setDirty(false);
313
- setText("");
314
- }, [mode, onChange]);
315
- function addMonthsLocal(dt, n) {
316
- const y = dt.getFullYear(), m = dt.getMonth();
317
- return new Date(y, m + n, 1);
318
- }
319
- function addDaysLocal(dt, n) {
320
- const d = new Date(dt);
321
- d.setDate(d.getDate() + n);
322
- return d;
323
- }
324
- return /* @__PURE__ */ jsx(
325
- Popover,
326
- {
327
- ref: popRef,
328
- trigger: (toggle) => {
329
- var _a;
330
- return /* @__PURE__ */ jsx("div", { onClick: toggle, className: styles.triggerWrap, children: /* @__PURE__ */ jsx(
331
- Input,
332
- {
333
- id,
334
- placeholder: placeholder || (mode === "single" ? "V\xE6lg dato" : "V\xE6lg interval"),
335
- value: dirty ? text : formatted,
336
- onInput: (e) => {
337
- setDirty(true);
338
- const raw = e.target.value;
339
- const masked = mode === "single" ? maskSingle(raw, enableTime) : maskRange(raw, enableTime);
340
- setText(masked);
341
- },
342
- onBlur: commitTypedValue,
343
- onKeyDown: (e) => {
344
- if (e.key === "Enter") {
243
+ const gridRef = useRef(null);
244
+ useEffect(() => {
245
+ const el = gridRef.current;
246
+ if (!el)
247
+ return;
248
+ const onKey = (e) => {
249
+ var _a;
250
+ if (!((_a = popRef.current) === null || _a === void 0 ? void 0 : _a.isOpen()))
251
+ return;
252
+ if ([
253
+ 'ArrowLeft',
254
+ 'ArrowRight',
255
+ 'ArrowUp',
256
+ 'ArrowDown',
257
+ 'PageUp',
258
+ 'PageDown',
259
+ 'Home',
260
+ 'End',
261
+ ].includes(e.key)) {
345
262
  e.preventDefault();
346
- commitTypedValue();
347
- }
348
- },
349
- inputSize,
350
- icon: /* @__PURE__ */ jsx(Calendar, { size: 16 }),
351
- onClear: formatted || text ? clear : void 0,
352
- "aria-haspopup": "dialog",
353
- "aria-expanded": ((_a = popRef.current) == null ? void 0 : _a.isOpen()) ? true : false,
354
- disabled
355
- }
356
- ) });
357
- },
358
- minWidth: "320px",
359
- viewportPadding: 8,
360
- children: /* @__PURE__ */ jsxs("div", { className: cx(styles.panel, !!(presets == null ? void 0 : presets.length) && styles.panelWithPresets), children: [
361
- (presets == null ? void 0 : presets.length) ? /* @__PURE__ */ jsxs("div", { className: styles.presetsCol, children: [
362
- /* @__PURE__ */ jsx("div", { className: styles.presetsLabel, children: "Forvalg" }),
363
- /* @__PURE__ */ jsxs("div", { className: styles.presetsList, children: [
364
- presets.map((p) => /* @__PURE__ */ jsx(
365
- Button,
366
- {
367
- variant: "outlined",
368
- size: "sm",
369
- onClick: () => {
370
- var _a;
371
- const r = p.getRange();
372
- onChange({ start: r.start, end: r.end });
373
- setDirty(false);
374
- setText(toMaskedRange(r.start, r.end, enableTime));
375
- setMonthAnchor(r.start);
376
- (_a = popRef.current) == null ? void 0 : _a.close();
377
- },
378
- children: p.label
379
- },
380
- p.label
381
- )),
382
- mode === "range" && /* @__PURE__ */ jsx(Button, { variant: "danger", size: "sm", onClick: clear, icon: /* @__PURE__ */ jsx(X, { size: 14 }), children: "Ryd" })
383
- ] })
384
- ] }) : null,
385
- /* @__PURE__ */ jsxs("div", { className: styles.calendarArea, children: [
386
- /* @__PURE__ */ jsxs("div", { className: styles.header, children: [
387
- /* @__PURE__ */ jsx(
388
- Button,
389
- {
390
- variant: "outlined",
391
- size: "sm",
392
- "aria-label": "Forrige m\xE5ned",
393
- icon: /* @__PURE__ */ jsx(ChevronLeft, { size: 16 }),
394
- onClick: () => setMonthAnchor(addMonthsLocal(monthAnchor, -1))
395
- }
396
- ),
397
- /* @__PURE__ */ jsx("div", { "aria-live": "polite", className: styles.headerTitle, children: monthFmt.format(monthAnchor) }),
398
- /* @__PURE__ */ jsx(
399
- Button,
400
- {
401
- variant: "outlined",
402
- size: "sm",
403
- "aria-label": "N\xE6ste m\xE5ned",
404
- icon: /* @__PURE__ */ jsx(ChevronRight, { size: 16 }),
405
- onClick: () => setMonthAnchor(addMonthsLocal(monthAnchor, 1))
406
- }
407
- )
408
- ] }),
409
- /* @__PURE__ */ jsx("div", { className: styles.weekRow, "aria-hidden": true, children: Array.from({ length: 7 }, (_, i) => (i + weekStartsOn) % 7).map((dow) => /* @__PURE__ */ jsx("div", { className: styles.weekCell, children: weekdayFmt.format(dUTC(2024, 8, dow + 1)).slice(0, 2) }, dow)) }),
410
- /* @__PURE__ */ jsx(
411
- "div",
412
- {
413
- ref: gridRef,
414
- role: "grid",
415
- "aria-label": "Kalender",
416
- tabIndex: 0,
417
- className: styles.grid,
418
- onMouseLeave: () => setHoverUTC(null),
419
- children: cellsUTC.map((utcDay, idx) => {
420
- const inThisMonth = utcDay >= monthStartUTC && utcDay <= monthEndUTC;
421
- const isToday = sameDayUTC(utcDay, toUTCDateOnly(todayLocal));
422
- const disabledDay = isDisabledUTC(utcDay);
423
- let selected = false;
424
- let inRange = false;
425
- if (mode === "single" && selectedUTC_single)
426
- selected = sameDayUTC(utcDay, selectedUTC_single);
427
- if (mode === "range" && selectedUTC_start && selectedUTC_end) {
428
- inRange = isBetweenUTC(utcDay, selectedUTC_start, selectedUTC_end);
429
- selected = sameDayUTC(utcDay, selectedUTC_start) || sameDayUTC(utcDay, selectedUTC_end);
430
- }
431
- if (mode === "range" && selectedUTC_start && !selectedUTC_end && hoverUTC) {
432
- inRange = isBetweenUTC(utcDay, selectedUTC_start, hoverUTC);
433
- selected = sameDayUTC(utcDay, selectedUTC_start);
434
- }
435
- const dayNum = utcDay.getUTCDate();
436
- return /* @__PURE__ */ jsx(
437
- "button",
438
- {
439
- role: "gridcell",
440
- "aria-selected": selected,
441
- "aria-disabled": disabledDay,
442
- onMouseEnter: () => setHoverUTC(utcDay),
443
- onClick: () => selectDay(utcDay),
444
- disabled: disabledDay,
445
- className: cx(
446
- styles.dayCell,
447
- inThisMonth ? styles.dayInMonth : styles.dayOutside,
448
- selected && styles.daySelected,
449
- inRange && styles.dayInRange,
450
- isToday && !selected && styles.dayToday,
451
- disabledDay && styles.dayDisabled
452
- ),
453
- title: new Date(utcDay).toLocaleDateString(locale),
454
- children: dayNum
455
- },
456
- idx
457
- );
458
- })
459
263
  }
460
- ),
461
- enableTime && mode === "single" && /* @__PURE__ */ jsxs("div", { className: styles.timeRow, children: [
462
- /* @__PURE__ */ jsxs("div", { className: styles.timeLabel, children: [
463
- /* @__PURE__ */ jsx(Clock, { size: 14 }),
464
- " Tid"
465
- ] }),
466
- /* @__PURE__ */ jsx(
467
- "select",
468
- {
469
- value: timeHH,
470
- onChange: (e) => setTimeHH(parseInt(e.target.value, 10)),
471
- className: styles.timeSelect,
472
- children: hours.map((h) => /* @__PURE__ */ jsx("option", { value: h, children: String(h).padStart(2, "0") }, h))
473
- }
474
- ),
475
- /* @__PURE__ */ jsx(
476
- "select",
477
- {
478
- value: timeMM,
479
- onChange: (e) => setTimeMM(parseInt(e.target.value, 10)),
480
- className: styles.timeSelect,
481
- children: minutes.map((m) => /* @__PURE__ */ jsx("option", { value: m, children: String(m).padStart(2, "0") }, m))
482
- }
483
- )
484
- ] }),
485
- mode === "range" && /* @__PURE__ */ jsxs("div", { className: styles.footer, children: [
486
- /* @__PURE__ */ jsx(Button, { variant: "outlined", size: "sm", onClick: clear, icon: /* @__PURE__ */ jsx(X, { size: 14 }), children: "Ryd" }),
487
- /* @__PURE__ */ jsx(Button, { variant: "primary", size: "sm", onClick: () => {
488
- var _a;
489
- return (_a = popRef.current) == null ? void 0 : _a.close();
490
- }, children: "OK" })
491
- ] })
492
- ] })
493
- ] })
264
+ const anchor = toUTCDateOnly(monthAnchor);
265
+ const move = (days) => setMonthAnchor(prev => addDaysLocal(prev, days));
266
+ switch (e.key) {
267
+ case 'ArrowLeft':
268
+ move(-1);
269
+ break;
270
+ case 'ArrowRight':
271
+ move(1);
272
+ break;
273
+ case 'ArrowUp':
274
+ move(-7);
275
+ break;
276
+ case 'ArrowDown':
277
+ move(7);
278
+ break;
279
+ case 'PageUp':
280
+ setMonthAnchor(addMonthsLocal(monthAnchor, -1));
281
+ break;
282
+ case 'PageDown':
283
+ setMonthAnchor(addMonthsLocal(monthAnchor, 1));
284
+ break;
285
+ case 'Home':
286
+ setMonthAnchor(new Date(anchor.getUTCFullYear(), anchor.getUTCMonth(), 1));
287
+ break;
288
+ case 'End':
289
+ setMonthAnchor(new Date(anchor.getUTCFullYear(), anchor.getUTCMonth() + 1, 0));
290
+ break;
291
+ }
292
+ };
293
+ el.addEventListener('keydown', onKey);
294
+ return () => el.removeEventListener('keydown', onKey);
295
+ }, [monthAnchor]);
296
+ const hours = useMemo(() => Array.from({ length: 24 }, (_, i) => i), []);
297
+ const minutes = useMemo(() => Array.from({ length: Math.floor(60 / (timeStep || 1)) }, (_, i) => i * (timeStep || 1)), [timeStep]);
298
+ // ---- Input display: follow mask format (not Intl) ----
299
+ const formatted = useMemo(() => {
300
+ var _a, _b;
301
+ if (mode === 'single') {
302
+ return value instanceof Date && value ? toMaskedFromDate(value, enableTime) : '';
303
+ }
304
+ const v = value;
305
+ return toMaskedRange((_a = v === null || v === void 0 ? void 0 : v.start) !== null && _a !== void 0 ? _a : null, (_b = v === null || v === void 0 ? void 0 : v.end) !== null && _b !== void 0 ? _b : null, enableTime);
306
+ }, [mode, value, enableTime]);
307
+ const [text, setText] = useState(formatted);
308
+ const [dirty, setDirty] = useState(false); // while user is typing
309
+ useEffect(() => {
310
+ if (!dirty)
311
+ setText(formatted); // keep in sync when external value changes
312
+ }, [formatted, dirty]);
313
+ const commitTypedValue = useCallback(() => {
314
+ if (!text.trim()) {
315
+ if (mode === 'single')
316
+ onChange(null);
317
+ else
318
+ onChange({ start: null, end: null });
319
+ setDirty(false);
320
+ return;
321
+ }
322
+ if (mode === 'single') {
323
+ const dLocal = parseLooseDateOrDateTime(text);
324
+ if (dLocal) {
325
+ onChange(dLocal);
326
+ setMonthAnchor(dLocal);
327
+ setDirty(false);
328
+ }
329
+ return;
330
+ }
331
+ const r = parseLooseRange(text);
332
+ if (r) {
333
+ onChange({ start: r.start, end: r.end });
334
+ setMonthAnchor(r.start);
335
+ setDirty(false);
336
+ }
337
+ }, [text, mode, onChange]);
338
+ const clear = useCallback(() => {
339
+ if (mode === 'single')
340
+ onChange(null);
341
+ else
342
+ onChange({ start: null, end: null });
343
+ setDirty(false);
344
+ setText('');
345
+ }, [mode, onChange]);
346
+ function addMonthsLocal(dt, n) {
347
+ const y = dt.getFullYear();
348
+ const m = dt.getMonth();
349
+ return new Date(y, m + n, 1);
350
+ }
351
+ function addDaysLocal(dt, n) {
352
+ const d = new Date(dt);
353
+ d.setDate(d.getDate() + n);
354
+ return d;
494
355
  }
495
- );
356
+ const fallbackPlaceholder = mode === 'single' ? 'Vælg dato' : 'Vælg interval';
357
+ return (_jsx(Popover, { ref: popRef, trigger: toggle => {
358
+ var _a, _b;
359
+ return (_jsx("div", { onClick: toggle, className: styles.triggerWrap, children: _jsx(Input, { ...inputProps, placeholder: (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.placeholder) !== null && _a !== void 0 ? _a : fallbackPlaceholder, value: dirty ? text : formatted, onInput: e => {
360
+ setDirty(true);
361
+ const raw = e.target.value;
362
+ const masked = mode === 'single' ? maskSingle(raw, enableTime) : maskRange(raw, enableTime);
363
+ setText(masked);
364
+ }, onBlur: commitTypedValue, onKeyDown: e => {
365
+ var _a;
366
+ (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
367
+ if (e.defaultPrevented)
368
+ return;
369
+ if (e.key === 'Enter') {
370
+ e.preventDefault();
371
+ commitTypedValue();
372
+ }
373
+ }, icon: _jsx(Calendar, { size: 16 }), onClear: formatted || text ? clear : undefined, "aria-haspopup": "dialog", "aria-expanded": ((_b = popRef.current) === null || _b === void 0 ? void 0 : _b.isOpen()) ? true : false, disabled: inputProps === null || inputProps === void 0 ? void 0 : inputProps.disabled, error: inputProps === null || inputProps === void 0 ? void 0 : inputProps.error }) }));
374
+ }, viewportPadding: 8, children: _jsxs("div", { className: cx(styles.panel, !!(presets === null || presets === void 0 ? void 0 : presets.length) && styles.panelWithPresets), children: [(presets === null || presets === void 0 ? void 0 : presets.length) ? (_jsxs("div", { className: styles.presetsCol, children: [_jsx("div", { className: styles.presetsLabel, children: "Forvalg" }), _jsxs("div", { className: styles.presetsList, children: [presets.map(p => (_jsx(Button, { variant: "outlined", size: "sm", onClick: () => {
375
+ var _a;
376
+ const r = p.getRange();
377
+ onChange({ start: r.start, end: r.end });
378
+ setDirty(false);
379
+ setText(toMaskedRange(r.start, r.end, enableTime));
380
+ setMonthAnchor(r.start);
381
+ (_a = popRef.current) === null || _a === void 0 ? void 0 : _a.close();
382
+ }, children: p.label }, p.label))), mode === 'range' && (_jsx(Button, { variant: "danger", size: "sm", onClick: clear, icon: _jsx(X, { size: 14 }), children: "Ryd" }))] })] })) : null, _jsxs("div", { className: styles.calendarArea, children: [_jsxs("div", { className: styles.header, children: [_jsx(Button, { variant: "outlined", size: "sm", "aria-label": "Forrige m\u00E5ned", icon: _jsx(ChevronLeft, { size: 16 }), onClick: () => setMonthAnchor(addMonthsLocal(monthAnchor, -1)) }), _jsx("div", { "aria-live": "polite", className: styles.headerTitle, children: monthFmt.format(monthAnchor) }), _jsx(Button, { variant: "outlined", size: "sm", "aria-label": "N\u00E6ste m\u00E5ned", icon: _jsx(ChevronRight, { size: 16 }), onClick: () => setMonthAnchor(addMonthsLocal(monthAnchor, 1)) })] }), _jsx("div", { className: styles.weekRow, "aria-hidden": true, children: Array.from({ length: 7 }, (_, i) => (i + weekStartsOn) % 7).map(dow => (_jsx("div", { className: styles.weekCell, children: weekdayFmt.format(dUTC(2024, 8, dow + 1)).slice(0, 2) }, dow))) }), _jsx("div", { ref: gridRef, role: "grid", "aria-label": "Kalender", tabIndex: 0, className: styles.grid, onMouseLeave: () => setHoverUTC(null), children: cellsUTC.map((utcDay, idx) => {
383
+ const inThisMonth = utcDay >= monthStartUTC && utcDay <= monthEndUTC;
384
+ const isToday = sameDayUTC(utcDay, toUTCDateOnly(todayLocal));
385
+ const disabledDay = isDisabledUTC(utcDay);
386
+ let selected = false;
387
+ let inRange = false;
388
+ if (mode === 'single' && selectedUTC_single)
389
+ selected = sameDayUTC(utcDay, selectedUTC_single);
390
+ if (mode === 'range' && selectedUTC_start && selectedUTC_end) {
391
+ inRange = isBetweenUTC(utcDay, selectedUTC_start, selectedUTC_end);
392
+ selected =
393
+ sameDayUTC(utcDay, selectedUTC_start) || sameDayUTC(utcDay, selectedUTC_end);
394
+ }
395
+ if (mode === 'range' && selectedUTC_start && !selectedUTC_end && hoverUTC) {
396
+ inRange = isBetweenUTC(utcDay, selectedUTC_start, hoverUTC);
397
+ selected = sameDayUTC(utcDay, selectedUTC_start);
398
+ }
399
+ const dayNum = utcDay.getUTCDate();
400
+ return (_jsx("button", { role: "gridcell", "aria-selected": selected, "aria-disabled": disabledDay, onMouseEnter: () => setHoverUTC(utcDay), onClick: () => selectDay(utcDay), disabled: disabledDay, className: cx(styles.dayCell, inThisMonth ? styles.dayInMonth : styles.dayOutside, selected && styles.daySelected, inRange && styles.dayInRange, isToday && !selected && styles.dayToday, disabledDay && styles.dayDisabled), title: new Date(utcDay).toLocaleDateString(locale), children: dayNum }, idx));
401
+ }) }), enableTime && mode === 'single' && (_jsxs("div", { className: styles.timeRow, children: [_jsxs("div", { className: styles.timeLabel, children: [_jsx(Clock, { size: 14 }), " Tid"] }), _jsx("select", { value: timeHH, onChange: e => setTimeHH(parseInt(e.target.value, 10)), className: styles.timeSelect, children: hours.map(h => (_jsx("option", { value: h, children: String(h).padStart(2, '0') }, h))) }), _jsx("select", { value: timeMM, onChange: e => setTimeMM(parseInt(e.target.value, 10)), className: styles.timeSelect, children: minutes.map(m => (_jsx("option", { value: m, children: String(m).padStart(2, '0') }, m))) })] })), mode === 'range' && (_jsxs("div", { className: styles.footer, children: [_jsx(Button, { variant: "outlined", size: "sm", onClick: clear, icon: _jsx(X, { size: 14 }), children: "Ryd" }), _jsx(Button, { variant: "primary", size: "sm", onClick: () => { var _a; return (_a = popRef.current) === null || _a === void 0 ? void 0 : _a.close(); }, children: "OK" })] }))] })] }) }));
496
402
  });
497
-
498
- export { DateTimePicker };
403
+ DateTimePicker.displayName = 'DateTimePicker';