@lmvz-ds/components 0.35.2 → 0.36.1

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 (239) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/assets/icons/calendar.svg +7 -0
  3. package/cjs/{aria-validation-controller-BC0Eaiv4.js → aria-validation-controller-Do0uEK4t.js} +1 -1
  4. package/cjs/aria.constants-DPK5mQEL.js +65 -0
  5. package/cjs/{directional-focus-controller-DBat-oF7.js → directional-focus-controller-8Xd_7MHT.js} +3 -1
  6. package/cjs/{element-activation-controller-BHqCUgQv.js → element-activation-controller-DzTUocEO.js} +1 -1
  7. package/cjs/{element.util-CRS_YJ59.js → element.util-BlhcwmfR.js} +8 -54
  8. package/cjs/{index-TGsVZNDP.js → index-BgvZ4y-3.js} +12 -0
  9. package/cjs/lmvz-action-list.cjs.entry.js +5 -4
  10. package/cjs/lmvz-action.cjs.entry.js +1 -1
  11. package/cjs/lmvz-button-group.cjs.entry.js +3 -2
  12. package/cjs/lmvz-button_2.cjs.entry.js +6 -5
  13. package/cjs/lmvz-card.cjs.entry.js +1 -1
  14. package/cjs/lmvz-checkbox.cjs.entry.js +40 -6
  15. package/cjs/lmvz-chip.cjs.entry.js +2 -2
  16. package/cjs/lmvz-components.cjs.js +2 -2
  17. package/cjs/lmvz-datepicker.cjs.entry.js +2771 -0
  18. package/cjs/lmvz-header_2.cjs.entry.js +7 -6
  19. package/cjs/lmvz-input.cjs.entry.js +71 -15
  20. package/cjs/lmvz-link.cjs.entry.js +2 -2
  21. package/cjs/lmvz-menuitem.cjs.entry.js +6 -5
  22. package/cjs/lmvz-message.cjs.entry.js +2 -2
  23. package/cjs/lmvz-modal.cjs.entry.js +5 -4
  24. package/cjs/lmvz-popover.cjs.entry.js +25 -10
  25. package/cjs/lmvz-radio.cjs.entry.js +63 -5
  26. package/cjs/lmvz-select.cjs.entry.js +425 -18
  27. package/cjs/lmvz-snackbar.cjs.entry.js +2 -2
  28. package/cjs/lmvz-spinner.cjs.entry.js +2 -2
  29. package/cjs/lmvz-tab.cjs.entry.js +2 -2
  30. package/cjs/lmvz-tabs.cjs.entry.js +5 -4
  31. package/cjs/lmvz-toggle.cjs.entry.js +7 -4
  32. package/cjs/loader.cjs.js +2 -2
  33. package/collection/assets/icons/calendar.svg +7 -0
  34. package/collection/collection-manifest.json +1 -0
  35. package/collection/components/lmvz-checkbox/lmvz-checkbox.css +4 -2
  36. package/collection/components/lmvz-checkbox/lmvz-checkbox.js +68 -8
  37. package/collection/components/lmvz-datepicker/lmvz-datepicker.css +161 -0
  38. package/collection/components/lmvz-datepicker/lmvz-datepicker.js +1002 -0
  39. package/collection/components/lmvz-datepicker/lmvz-datepicker.utils.js +189 -0
  40. package/collection/components/lmvz-datepicker/test/lmvz-datepicker.utils.unit.js +300 -0
  41. package/collection/components/lmvz-header/lmvz-header.js +1 -1
  42. package/collection/components/lmvz-icon/lmvz-icon.js +1 -1
  43. package/collection/components/lmvz-input/lmvz-input.css +1 -1
  44. package/collection/components/lmvz-input/lmvz-input.js +85 -12
  45. package/collection/components/lmvz-link/lmvz-link.js +1 -1
  46. package/collection/components/lmvz-menuitem/lmvz-menuitem.js +1 -1
  47. package/collection/components/lmvz-message/lmvz-message.js +1 -1
  48. package/collection/components/lmvz-modal/lmvz-modal.js +1 -1
  49. package/collection/components/lmvz-popover/lmvz-popover.css +1 -1
  50. package/collection/components/lmvz-popover/lmvz-popover.js +50 -6
  51. package/collection/components/lmvz-radio/lmvz-radio.js +77 -9
  52. package/collection/components/lmvz-select/lmvz-select.css +96 -34
  53. package/collection/components/lmvz-select/lmvz-select.js +412 -21
  54. package/collection/components/lmvz-snackbar/lmvz-snackbar.js +1 -1
  55. package/collection/components/lmvz-spinner/lmvz-spinner.js +1 -1
  56. package/collection/components/lmvz-tab/lmvz-tab.js +1 -1
  57. package/collection/components/lmvz-tabs/lmvz-tabs.js +1 -1
  58. package/collection/components/lmvz-toggle/lmvz-toggle.js +21 -1
  59. package/collection/integration/header-integration/header-integration.js +1 -1
  60. package/collection/styles/fragments/_focus-within.css +2 -2
  61. package/collection/utils/aria/aria.constants.js +7 -0
  62. package/collection/utils/aria/directional-focus-controller.js +3 -1
  63. package/collection/utils/aria/listbox-controller.js +154 -0
  64. package/collection/utils/element/element.util.js +5 -0
  65. package/collection/utils/radio/radio-group-controller.js +17 -0
  66. package/components/index.d.ts +2 -0
  67. package/components/index.d.ts.bak +2 -0
  68. package/components/index.js +1 -1
  69. package/components/lmvz-action-list.js +1 -1
  70. package/components/lmvz-action.js +1 -1
  71. package/components/lmvz-button-group.js +1 -1
  72. package/components/lmvz-button.js +1 -1
  73. package/components/lmvz-card.js +1 -1
  74. package/components/lmvz-checkbox.js +1 -1
  75. package/components/lmvz-chip.js +1 -1
  76. package/components/lmvz-datepicker.d.ts +11 -0
  77. package/components/lmvz-datepicker.d.ts.bak +11 -0
  78. package/components/lmvz-datepicker.js +1 -0
  79. package/components/lmvz-header.js +1 -1
  80. package/components/lmvz-icon.js +1 -1
  81. package/components/lmvz-input.js +1 -1
  82. package/components/lmvz-link.js +1 -1
  83. package/components/lmvz-menuitem.js +1 -1
  84. package/components/lmvz-message.js +1 -1
  85. package/components/lmvz-modal.js +1 -1
  86. package/components/lmvz-popover.js +1 -1
  87. package/components/lmvz-radio.js +1 -1
  88. package/components/lmvz-select.js +1 -1
  89. package/components/lmvz-snackbar.js +1 -1
  90. package/components/lmvz-spinner.js +1 -1
  91. package/components/lmvz-tab.js +1 -1
  92. package/components/lmvz-tabs.js +1 -1
  93. package/components/lmvz-toggle.js +1 -1
  94. package/components/{p-Chj7BuUZ.js → p--FDdvoIg.js} +1 -1
  95. package/components/{p-CFTmV4XZ.js → p-BAj4FkUt.js} +1 -1
  96. package/components/p-BApwCp0R.js +1 -0
  97. package/components/{p-CxLd309t.js → p-BLMXiDE0.js} +1 -1
  98. package/components/{p-DGg7OzDl.js → p-BPYBmylI.js} +1 -1
  99. package/components/p-BhALzK62.js +1 -0
  100. package/components/{p-B_rnXUwq.js → p-Bnri3fEI.js} +1 -1
  101. package/components/p-C-pRMuMh.js +1 -0
  102. package/components/p-C5gRiLRR.js +1 -0
  103. package/components/{p-D5FL8n1q.js → p-CrQCHVKL.js} +1 -1
  104. package/components/p-DqdrUt_G.js +1 -0
  105. package/components/{p-CgK6-SEe.js → p-diOze8wI.js} +1 -1
  106. package/esm/{aria-validation-controller-BvOU1BO8.js → aria-validation-controller-Cp6pofER.js} +1 -1
  107. package/esm/aria.constants-DIyiticz.js +62 -0
  108. package/esm/{directional-focus-controller-DgAdCZrG.js → directional-focus-controller-QukTTWBE.js} +3 -1
  109. package/esm/{element-activation-controller-7PNSl6io.js → element-activation-controller-dxJZKMag.js} +1 -1
  110. package/esm/{element.util-BFcYfHYq.js → element.util-3ydVsxUW.js} +7 -54
  111. package/esm/{index-BPeerEwm.js → index-BOXP1Vx0.js} +12 -1
  112. package/esm/lmvz-action-list.entry.js +5 -4
  113. package/esm/lmvz-action.entry.js +1 -1
  114. package/esm/lmvz-button-group.entry.js +3 -2
  115. package/esm/lmvz-button_2.entry.js +6 -5
  116. package/esm/lmvz-card.entry.js +1 -1
  117. package/esm/lmvz-checkbox.entry.js +40 -6
  118. package/esm/lmvz-chip.entry.js +2 -2
  119. package/esm/lmvz-components.js +3 -3
  120. package/esm/lmvz-datepicker.entry.js +2769 -0
  121. package/esm/lmvz-header_2.entry.js +7 -6
  122. package/esm/lmvz-input.entry.js +71 -15
  123. package/esm/lmvz-link.entry.js +2 -2
  124. package/esm/lmvz-menuitem.entry.js +6 -5
  125. package/esm/lmvz-message.entry.js +2 -2
  126. package/esm/lmvz-modal.entry.js +5 -4
  127. package/esm/lmvz-popover.entry.js +25 -10
  128. package/esm/lmvz-radio.entry.js +63 -5
  129. package/esm/lmvz-select.entry.js +425 -18
  130. package/esm/lmvz-snackbar.entry.js +2 -2
  131. package/esm/lmvz-spinner.entry.js +2 -2
  132. package/esm/lmvz-tab.entry.js +2 -2
  133. package/esm/lmvz-tabs.entry.js +5 -4
  134. package/esm/lmvz-toggle.entry.js +7 -4
  135. package/esm/loader.js +3 -3
  136. package/hydrate/index.js +3474 -75
  137. package/hydrate/index.mjs +3474 -75
  138. package/lmvz-components/lmvz-components.esm.js +1 -1
  139. package/lmvz-components/{p-eb62d4af.entry.js → p-0af0211a.entry.js} +1 -1
  140. package/lmvz-components/{p-5bbbcfc0.entry.js → p-0f65d001.entry.js} +1 -1
  141. package/lmvz-components/p-137b1fe1.entry.js +1 -0
  142. package/lmvz-components/p-26dd9684.entry.js +1 -0
  143. package/lmvz-components/p-36f44108.entry.js +1 -0
  144. package/lmvz-components/p-398b5cf4.entry.js +1 -0
  145. package/lmvz-components/p-3a396fc8.entry.js +1 -0
  146. package/lmvz-components/{p-0c05f24b.entry.js → p-3d5867df.entry.js} +1 -1
  147. package/lmvz-components/p-40716828.entry.js +1 -0
  148. package/lmvz-components/{p-a887018d.entry.js → p-492adf21.entry.js} +1 -1
  149. package/lmvz-components/{p-24d13be6.entry.js → p-4fa6e72f.entry.js} +1 -1
  150. package/lmvz-components/p-70f1e31a.entry.js +1 -0
  151. package/lmvz-components/p-71d06d1d.entry.js +1 -0
  152. package/lmvz-components/{p-d45164a8.entry.js → p-7a7aa922.entry.js} +1 -1
  153. package/lmvz-components/p-88661c50.entry.js +1 -0
  154. package/lmvz-components/p-91eb71bb.entry.js +1 -0
  155. package/lmvz-components/p-BA3wizqg.js +1 -0
  156. package/lmvz-components/{p-BPeerEwm.js → p-BOXP1Vx0.js} +2 -2
  157. package/lmvz-components/{p-D9PQIBzA.js → p-BeY96W7m.js} +1 -1
  158. package/lmvz-components/p-CHxiS3ja.js +1 -0
  159. package/lmvz-components/{p-wlMjNjuv.js → p-CPSyM_e-.js} +1 -1
  160. package/lmvz-components/p-DIyiticz.js +1 -0
  161. package/lmvz-components/p-a680a7b2.entry.js +1 -0
  162. package/lmvz-components/{p-c2544495.entry.js → p-a6fe9b61.entry.js} +1 -1
  163. package/lmvz-components/{p-ecbd9e93.entry.js → p-a99acb02.entry.js} +1 -1
  164. package/lmvz-components/p-f16a19fc.entry.js +1 -0
  165. package/lmvz-components/p-f3f0ed49.entry.js +1 -0
  166. package/lmvz-components/p-f516a949.entry.js +1 -0
  167. package/manifest.json +1305 -188
  168. package/package.json +5 -1
  169. package/types/api/ds.constants.d.ts +0 -1
  170. package/types/api/ds.types.d.ts +9 -0
  171. package/types/components/lmvz-action/lmvz-action.d.ts +0 -1
  172. package/types/components/lmvz-action-list/lmvz-action-list.d.ts +0 -1
  173. package/types/components/lmvz-button/lmvz-button.d.ts +0 -1
  174. package/types/components/lmvz-button-group/lmvz-button-group.d.ts +0 -1
  175. package/types/components/lmvz-card/lmvz-card.d.ts +0 -1
  176. package/types/components/lmvz-checkbox/lmvz-checkbox.d.ts +9 -2
  177. package/types/components/lmvz-chip/lmvz-chip.d.ts +0 -1
  178. package/types/components/lmvz-datepicker/lmvz-datepicker.d.ts +77 -0
  179. package/types/components/lmvz-datepicker/lmvz-datepicker.utils.d.ts +22 -0
  180. package/types/components/lmvz-datepicker/test/lmvz-datepicker.utils.unit.d.ts +1 -0
  181. package/types/components/lmvz-header/lmvz-header.d.ts +0 -1
  182. package/types/components/lmvz-icon/lmvz-icon.d.ts +0 -1
  183. package/types/components/lmvz-input/lmvz-input.d.ts +8 -1
  184. package/types/components/lmvz-link/lmvz-link.d.ts +0 -1
  185. package/types/components/lmvz-menuitem/lmvz-menuitem.d.ts +0 -1
  186. package/types/components/lmvz-message/lmvz-message.d.ts +0 -1
  187. package/types/components/lmvz-message/public.d.ts +0 -1
  188. package/types/components/lmvz-modal/lmvz-modal.d.ts +0 -1
  189. package/types/components/lmvz-modal/test/testing.d.ts +0 -1
  190. package/types/components/lmvz-popover/lmvz-popover.d.ts +2 -1
  191. package/types/components/lmvz-radio/lmvz-radio.d.ts +12 -3
  192. package/types/components/lmvz-select/lmvz-select.d.ts +53 -5
  193. package/types/components/lmvz-snackbar/lmvz-snackbar.d.ts +0 -1
  194. package/types/components/lmvz-snackbar/public.d.ts +0 -1
  195. package/types/components/lmvz-snackbar/snackbar-controller.d.ts +0 -1
  196. package/types/components/lmvz-spinner/lmvz-spinner.d.ts +0 -1
  197. package/types/components/lmvz-tab/lmvz-tab.d.ts +0 -1
  198. package/types/components/lmvz-tabs/lmvz-tabs.d.ts +0 -1
  199. package/types/components/lmvz-toggle/lmvz-toggle.d.ts +1 -1
  200. package/types/components.d.ts +312 -12
  201. package/types/index.d.ts +0 -1
  202. package/types/utils/aria/aria-validation-controller.d.ts +0 -1
  203. package/types/utils/aria/aria.constants.d.ts +1 -1
  204. package/types/utils/aria/directional-focus-controller.d.ts +0 -1
  205. package/types/utils/aria/element-activation-controller.d.ts +0 -1
  206. package/types/utils/aria/listbox-controller.d.ts +42 -0
  207. package/types/utils/async/async.util.d.ts +1 -2
  208. package/types/utils/data/event.util.d.ts +0 -1
  209. package/types/utils/data/number.util.d.ts +0 -1
  210. package/types/utils/data/object.util.d.ts +0 -1
  211. package/types/utils/data/time.util.d.ts +0 -1
  212. package/types/utils/element/element.util.d.ts +1 -1
  213. package/types/utils/environment.d.ts +0 -1
  214. package/types/utils/icons/icons-registry.d.ts +0 -1
  215. package/types/utils/icons/icons.d.ts +0 -1
  216. package/types/utils/icons/icons.unit.d.ts +0 -1
  217. package/types/utils/icons/public.d.ts +0 -1
  218. package/types/utils/public.d.ts +0 -1
  219. package/types/utils/radio/radio-group-controller.d.ts +3 -1
  220. package/types/utils/stencil/assets.d.ts +0 -1
  221. package/types/utils/stencil/reactive-controller-host.d.ts +0 -1
  222. package/types/utils/stencil/stencil.util.d.ts +0 -1
  223. package/components/p-DLUsBYJH.js +0 -1
  224. package/components/p-zMWemcoB.js +0 -1
  225. package/lmvz-components/p-194a3af5.entry.js +0 -1
  226. package/lmvz-components/p-46edf36f.entry.js +0 -1
  227. package/lmvz-components/p-5ff55ba9.entry.js +0 -1
  228. package/lmvz-components/p-888e04d7.entry.js +0 -1
  229. package/lmvz-components/p-9dc420e2.entry.js +0 -1
  230. package/lmvz-components/p-BFcYfHYq.js +0 -1
  231. package/lmvz-components/p-BuEA0MWd.js +0 -1
  232. package/lmvz-components/p-aaa7691c.entry.js +0 -1
  233. package/lmvz-components/p-b6dd045b.entry.js +0 -1
  234. package/lmvz-components/p-c3e62aba.entry.js +0 -1
  235. package/lmvz-components/p-d4154a65.entry.js +0 -1
  236. package/lmvz-components/p-e4ce63b3.entry.js +0 -1
  237. package/lmvz-components/p-eb4c5a6f.entry.js +0 -1
  238. package/lmvz-components/p-f42b16e6.entry.js +0 -1
  239. package/lmvz-components/p-fbf066d9.entry.js +0 -1
@@ -0,0 +1,189 @@
1
+ import * as CalendarFns from "temporal-polyfill/fns/Calendar";
2
+ import * as PlainDateFns from "temporal-polyfill/fns/PlainDate";
3
+ import * as PlainYearMonthFns from "temporal-polyfill/fns/PlainYearMonth";
4
+ import { parseIsoDateSafely } from "@lmvz-ds/lib-ts/date/temporal.js";
5
+ export function isSelected(date, value) {
6
+ if (!value)
7
+ return false;
8
+ return PlainDateFns.compare(date, value) === 0;
9
+ }
10
+ export function isDisabled(date, min, max) {
11
+ if (min && PlainDateFns.compare(date, min) < 0)
12
+ return true;
13
+ if (max && PlainDateFns.compare(date, max) > 0)
14
+ return true;
15
+ return false;
16
+ }
17
+ export function buildCalendarGrid(visibleMonth) {
18
+ const firstOfMonth = PlainYearMonthFns.toPlainDate(visibleMonth, { day: 1 });
19
+ const firstDow = PlainDateFns.dayOfWeek(firstOfMonth);
20
+ const offsetToMonday = firstDow - 1;
21
+ const gridStart = PlainDateFns.addDays(firstOfMonth, -offsetToMonday);
22
+ const grid = [];
23
+ for (let i = 0; i < 42; i++) {
24
+ grid.push(PlainDateFns.addDays(gridStart, i));
25
+ }
26
+ if (PlainYearMonthFns.compare(visibleMonth, PlainDateFns.toPlainYearMonth(grid.at(-7))) !== 0) {
27
+ return grid.slice(0, -7);
28
+ }
29
+ return grid;
30
+ }
31
+ export function isInFirstWeekOfMonth(date) {
32
+ return PlainYearMonthFns.compare(PlainDateFns.toPlainYearMonth(PlainDateFns.addDays(date, -7)), PlainDateFns.toPlainYearMonth(date)) !== 0;
33
+ }
34
+ export function isInLastWeekOfMonth(date) {
35
+ return PlainYearMonthFns.compare(PlainDateFns.toPlainYearMonth(PlainDateFns.addDays(date, 7)), PlainDateFns.toPlainYearMonth(date)) !== 0;
36
+ }
37
+ export function firstSelectableDayOfMonth(visibleMonth, min, max) {
38
+ const daysInMonth = PlainYearMonthFns.daysInMonth(visibleMonth);
39
+ for (let d = 1; d <= daysInMonth; d++) {
40
+ const candidate = PlainYearMonthFns.toPlainDate(visibleMonth, { day: d });
41
+ if (!isDisabled(candidate, min, max))
42
+ return candidate;
43
+ }
44
+ return null;
45
+ }
46
+ export function lastSelectableDayOfMonth(visibleMonth, min, max) {
47
+ const daysInMonth = PlainYearMonthFns.daysInMonth(visibleMonth);
48
+ for (let d = daysInMonth; d >= 1; d--) {
49
+ const candidate = PlainYearMonthFns.toPlainDate(visibleMonth, { day: d });
50
+ if (!isDisabled(candidate, min, max))
51
+ return candidate;
52
+ }
53
+ return null;
54
+ }
55
+ const NAV_LABELS = {
56
+ de: { prev: 'Vorheriger Monat', next: 'Nächster Monat' },
57
+ 'de-CH': { prev: 'Vorheriger Monat', next: 'Nächster Monat' },
58
+ 'de-AT': { prev: 'Vorheriger Monat', next: 'Nächster Monat' },
59
+ 'de-DE': { prev: 'Vorheriger Monat', next: 'Nächster Monat' },
60
+ en: { prev: 'Previous month', next: 'Next month' },
61
+ 'en-US': { prev: 'Previous month', next: 'Next month' },
62
+ 'en-GB': { prev: 'Previous month', next: 'Next month' },
63
+ fr: { prev: 'Mois précédent', next: 'Mois suivant' },
64
+ 'fr-CH': { prev: 'Mois précédent', next: 'Mois suivant' },
65
+ it: { prev: 'Mese precedente', next: 'Mese successivo' },
66
+ 'it-CH': { prev: 'Mese precedente', next: 'Mese successivo' },
67
+ };
68
+ export function getNavLabels(locale) {
69
+ const DEFAULT = { prev: 'Vorheriger Monat', next: 'Nächster Monat' };
70
+ const byLocale = NAV_LABELS[locale];
71
+ if (byLocale)
72
+ return byLocale;
73
+ const lang = locale.split('-')[0];
74
+ const byLang = lang !== undefined ? NAV_LABELS[lang] : undefined;
75
+ if (byLang)
76
+ return byLang;
77
+ return DEFAULT;
78
+ }
79
+ const VALIDATION_LABELS = {
80
+ de: { popoverSuffix: '— Kalender', invalidDateMessage: 'Ungültiges Datum' },
81
+ 'de-CH': { popoverSuffix: '— Kalender', invalidDateMessage: 'Ungültiges Datum' },
82
+ 'de-AT': { popoverSuffix: '— Kalender', invalidDateMessage: 'Ungültiges Datum' },
83
+ 'de-DE': { popoverSuffix: '— Kalender', invalidDateMessage: 'Ungültiges Datum' },
84
+ en: { popoverSuffix: '— Calendar', invalidDateMessage: 'Invalid date' },
85
+ 'en-US': { popoverSuffix: '— Calendar', invalidDateMessage: 'Invalid date' },
86
+ 'en-GB': { popoverSuffix: '— Calendar', invalidDateMessage: 'Invalid date' },
87
+ fr: { popoverSuffix: '— Calendrier', invalidDateMessage: 'Date invalide' },
88
+ 'fr-CH': { popoverSuffix: '— Calendrier', invalidDateMessage: 'Date invalide' },
89
+ it: { popoverSuffix: '— Calendario', invalidDateMessage: 'Data non valida' },
90
+ 'it-CH': { popoverSuffix: '— Calendario', invalidDateMessage: 'Data non valida' },
91
+ };
92
+ export function getValidationLabels(locale) {
93
+ const DEFAULT = { popoverSuffix: '— Kalender', invalidDateMessage: 'Ungültiges Datum' };
94
+ const byLocale = VALIDATION_LABELS[locale];
95
+ if (byLocale)
96
+ return byLocale;
97
+ const lang = locale.split('-')[0];
98
+ const byLang = lang !== undefined ? VALIDATION_LABELS[lang] : undefined;
99
+ if (byLang)
100
+ return byLang;
101
+ return DEFAULT;
102
+ }
103
+ const FORMAT_TOKEN_ORDER = ['yyyy', 'MM', 'dd'];
104
+ export function derivePatternFromLocale(locale) {
105
+ const reference = new Date(Date.UTC(2001, 10, 22));
106
+ const parts = new Intl.DateTimeFormat(locale, { year: 'numeric', month: '2-digit', day: '2-digit', timeZone: 'UTC' }).formatToParts(reference);
107
+ return parts
108
+ .map((part) => {
109
+ switch (part.type) {
110
+ case 'year':
111
+ return 'yyyy';
112
+ case 'month':
113
+ return 'MM';
114
+ case 'day':
115
+ return 'dd';
116
+ default:
117
+ return part.value;
118
+ }
119
+ })
120
+ .join('');
121
+ }
122
+ function escapeRegExp(value) {
123
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
124
+ }
125
+ function buildPatternMatcher(pattern) {
126
+ const order = [];
127
+ let regexSource = '';
128
+ let i = 0;
129
+ while (i < pattern.length) {
130
+ const token = FORMAT_TOKEN_ORDER.find((t) => pattern.startsWith(t, i));
131
+ if (token) {
132
+ regexSource += token === 'yyyy' ? '(\\d{4})' : '(\\d{1,2})';
133
+ order.push(token);
134
+ i += token.length;
135
+ }
136
+ else {
137
+ regexSource += escapeRegExp(pattern[i]);
138
+ i += 1;
139
+ }
140
+ }
141
+ return { regex: new RegExp(`^${regexSource}$`), order };
142
+ }
143
+ function isValidCalendarDate(year, month, day) {
144
+ if (!Number.isInteger(year) || year < 1)
145
+ return false;
146
+ if (!Number.isInteger(month) || month < 1 || month > 12)
147
+ return false;
148
+ if (!Number.isInteger(day) || day < 1)
149
+ return false;
150
+ try {
151
+ const ym = PlainYearMonthFns.fromString(`${String(year).padStart(4, '0')}-${String(month).padStart(2, '0')}`, CalendarFns.getBasic);
152
+ return day <= PlainYearMonthFns.daysInMonth(ym);
153
+ }
154
+ catch {
155
+ return false;
156
+ }
157
+ }
158
+ export function formatToDisplay(value, locale, displayFormat) {
159
+ if (!value)
160
+ return '';
161
+ const date = parseIsoDateSafely(value);
162
+ if (!date)
163
+ return '';
164
+ const pattern = displayFormat ?? derivePatternFromLocale(locale);
165
+ const yyyy = String(date.year).padStart(4, '0');
166
+ const MM = String(date.month).padStart(2, '0');
167
+ const dd = String(date.day).padStart(2, '0');
168
+ return pattern.replace(/yyyy/g, yyyy).replace(/MM/g, MM).replace(/dd/g, dd);
169
+ }
170
+ export function parseFromDisplay(text, locale, displayFormat) {
171
+ const trimmed = text.trim();
172
+ if (!trimmed)
173
+ return undefined;
174
+ const pattern = displayFormat ?? derivePatternFromLocale(locale);
175
+ const { regex, order } = buildPatternMatcher(pattern);
176
+ const match = regex.exec(trimmed);
177
+ if (!match)
178
+ return undefined;
179
+ const values = {};
180
+ order.forEach((token, idx) => {
181
+ values[token] = Number(match[idx + 1]);
182
+ });
183
+ const { yyyy, MM, dd } = values;
184
+ if (yyyy === undefined || MM === undefined || dd === undefined)
185
+ return undefined;
186
+ if (!isValidCalendarDate(yyyy, MM, dd))
187
+ return undefined;
188
+ return `${String(yyyy).padStart(4, '0')}-${String(MM).padStart(2, '0')}-${String(dd).padStart(2, '0')}`;
189
+ }
@@ -0,0 +1,300 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import * as CalendarFns from "temporal-polyfill/fns/Calendar";
3
+ import * as PlainDateFns from "temporal-polyfill/fns/PlainDate";
4
+ import * as PlainYearMonthFns from "temporal-polyfill/fns/PlainYearMonth";
5
+ import { toIsoYearMonthString } from "@lmvz-ds/lib-ts/date/temporal.js";
6
+ import { buildCalendarGrid, derivePatternFromLocale, firstSelectableDayOfMonth, formatToDisplay, getNavLabels, getValidationLabels, isDisabled, isInFirstWeekOfMonth, isInLastWeekOfMonth, isSelected, lastSelectableDayOfMonth, parseFromDisplay, } from "../lmvz-datepicker.utils";
7
+ function ym(isoYearMonth) {
8
+ return PlainYearMonthFns.fromString(isoYearMonth, CalendarFns.getBasic);
9
+ }
10
+ function pd(iso) {
11
+ return PlainDateFns.fromString(iso, CalendarFns.getBasic);
12
+ }
13
+ describe('isSelected', () => {
14
+ it('returns true when date matches value', () => {
15
+ expect(isSelected(pd('2024-06-15'), pd('2024-06-15'))).toBe(true);
16
+ });
17
+ it('returns false when date does not match value', () => {
18
+ expect(isSelected(pd('2024-06-15'), pd('2024-06-16'))).toBe(false);
19
+ });
20
+ it('returns false when value is undefined', () => {
21
+ expect(isSelected(pd('2024-06-15'), undefined)).toBe(false);
22
+ });
23
+ });
24
+ describe('isDisabled', () => {
25
+ const date = pd('2024-06-15');
26
+ it('returns false when no bounds', () => {
27
+ expect(isDisabled(date, undefined, undefined)).toBe(false);
28
+ });
29
+ it('returns true when date is before min', () => {
30
+ expect(isDisabled(date, pd('2024-06-20'), undefined)).toBe(true);
31
+ });
32
+ it('returns false when date equals min', () => {
33
+ expect(isDisabled(date, pd('2024-06-15'), undefined)).toBe(false);
34
+ });
35
+ it('returns true when date is after max', () => {
36
+ expect(isDisabled(date, undefined, pd('2024-06-10'))).toBe(true);
37
+ });
38
+ it('returns false when date equals max', () => {
39
+ expect(isDisabled(date, undefined, pd('2024-06-15'))).toBe(false);
40
+ });
41
+ it('returns false when date is within [min, max]', () => {
42
+ expect(isDisabled(date, pd('2024-06-01'), pd('2024-06-30'))).toBe(false);
43
+ });
44
+ });
45
+ describe('buildCalendarGrid', () => {
46
+ it('returns 35 cells when the last padded week is entirely in the next month (2024-06)', () => {
47
+ expect(buildCalendarGrid(ym('2024-06')).length).toBe(35);
48
+ });
49
+ it('returns 42 cells when the last padded week spills into the next month (2024-09)', () => {
50
+ expect(buildCalendarGrid(ym('2024-09')).length).toBe(42);
51
+ });
52
+ it('starts on a Monday', () => {
53
+ const grid = buildCalendarGrid(ym('2024-06'));
54
+ const first = grid[0];
55
+ expect(PlainDateFns.toString(first)).toBe('2024-05-27');
56
+ expect(PlainDateFns.dayOfWeek(first)).toBe(1);
57
+ });
58
+ it('includes all days of the given month', () => {
59
+ const grid = buildCalendarGrid(ym('2024-06'));
60
+ const junedays = grid.filter((d) => d.month === 6 && d.year === 2024);
61
+ expect(junedays.length).toBe(30);
62
+ });
63
+ it('is Monday-first for a month starting on Sunday', () => {
64
+ const grid = buildCalendarGrid(ym('2024-09'));
65
+ const first = grid[0];
66
+ expect(PlainDateFns.dayOfWeek(first)).toBe(1);
67
+ expect(PlainDateFns.toString(first)).toBe('2024-08-26');
68
+ });
69
+ it('is Monday-first for a month starting on Monday', () => {
70
+ const grid = buildCalendarGrid(ym('2024-07'));
71
+ const first = grid[0];
72
+ expect(PlainDateFns.dayOfWeek(first)).toBe(1);
73
+ expect(PlainDateFns.toString(first)).toBe('2024-07-01');
74
+ });
75
+ describe('leap-year February', () => {
76
+ it('returns 35 cells with exactly 29 in-month cells for 2024-02 (leap year)', () => {
77
+ const grid = buildCalendarGrid(ym('2024-02'));
78
+ expect(grid.length).toBe(35);
79
+ const inMonth = grid.filter((d) => d.year === 2024 && d.month === 2);
80
+ expect(inMonth.length).toBe(29);
81
+ });
82
+ it('returns 35 cells with exactly 28 in-month cells for 2023-02 (non-leap year)', () => {
83
+ const grid = buildCalendarGrid(ym('2023-02'));
84
+ expect(grid.length).toBe(35);
85
+ const inMonth = grid.filter((d) => d.year === 2023 && d.month === 2);
86
+ expect(inMonth.length).toBe(28);
87
+ });
88
+ });
89
+ });
90
+ describe('toIsoYearMonthString', () => {
91
+ it('returns a PlainYearMonthFns for a given date', () => {
92
+ const result = toIsoYearMonthString(pd('2024-06-15'));
93
+ expect(result.toString()).toBe('2024-06');
94
+ });
95
+ it('returns the correct year-month for January', () => {
96
+ const result = toIsoYearMonthString(pd('2024-01-01'));
97
+ expect(result.toString()).toBe('2024-01');
98
+ });
99
+ });
100
+ describe('isDisabled — cross-year boundary', () => {
101
+ it('Jan 1 2025 with min 2024-12-30 is not disabled', () => {
102
+ expect(isDisabled(pd('2025-01-01'), pd('2024-12-30'), undefined)).toBe(false);
103
+ });
104
+ it('Dec 31 2024 with max 2024-12-30 is disabled', () => {
105
+ expect(isDisabled(pd('2024-12-31'), undefined, pd('2024-12-30'))).toBe(true);
106
+ });
107
+ });
108
+ describe('getNavLabels', () => {
109
+ it('returns German labels for de-CH', () => {
110
+ const labels = getNavLabels('de-CH');
111
+ expect(labels.prev).toBe('Vorheriger Monat');
112
+ expect(labels.next).toBe('Nächster Monat');
113
+ });
114
+ it('returns German labels for de (language prefix fallback)', () => {
115
+ const labels = getNavLabels('de-UNKNOWN');
116
+ expect(labels.prev).toBe('Vorheriger Monat');
117
+ });
118
+ it('returns English labels for en-US', () => {
119
+ const labels = getNavLabels('en-US');
120
+ expect(labels.prev).toBe('Previous month');
121
+ expect(labels.next).toBe('Next month');
122
+ });
123
+ it('falls back to German for completely unknown locale', () => {
124
+ const labels = getNavLabels('zh-TW');
125
+ expect(labels.prev).toBe('Vorheriger Monat');
126
+ });
127
+ });
128
+ describe('getValidationLabels', () => {
129
+ it('returns German popover suffix for de', () => {
130
+ const labels = getValidationLabels('de');
131
+ expect(labels.popoverSuffix).toBe('— Kalender');
132
+ expect(labels.invalidDateMessage).toBe('Ungültiges Datum');
133
+ });
134
+ it('returns German popover suffix for de-CH', () => {
135
+ const labels = getValidationLabels('de-CH');
136
+ expect(labels.popoverSuffix).toBe('— Kalender');
137
+ expect(labels.invalidDateMessage).toBe('Ungültiges Datum');
138
+ });
139
+ it('returns English popover suffix for en', () => {
140
+ const labels = getValidationLabels('en');
141
+ expect(labels.popoverSuffix).toBe('— Calendar');
142
+ expect(labels.invalidDateMessage).toBe('Invalid date');
143
+ });
144
+ it('returns English popover suffix for en-US', () => {
145
+ const labels = getValidationLabels('en-US');
146
+ expect(labels.popoverSuffix).toBe('— Calendar');
147
+ expect(labels.invalidDateMessage).toBe('Invalid date');
148
+ });
149
+ it('returns French popover suffix for fr', () => {
150
+ const labels = getValidationLabels('fr');
151
+ expect(labels.popoverSuffix).toBe('— Calendrier');
152
+ expect(labels.invalidDateMessage).toBe('Date invalide');
153
+ });
154
+ it('returns French popover suffix for fr-CH', () => {
155
+ const labels = getValidationLabels('fr-CH');
156
+ expect(labels.popoverSuffix).toBe('— Calendrier');
157
+ expect(labels.invalidDateMessage).toBe('Date invalide');
158
+ });
159
+ it('returns Italian popover suffix for it', () => {
160
+ const labels = getValidationLabels('it');
161
+ expect(labels.popoverSuffix).toBe('— Calendario');
162
+ expect(labels.invalidDateMessage).toBe('Data non valida');
163
+ });
164
+ it('returns Italian popover suffix for it-CH', () => {
165
+ const labels = getValidationLabels('it-CH');
166
+ expect(labels.popoverSuffix).toBe('— Calendario');
167
+ expect(labels.invalidDateMessage).toBe('Data non valida');
168
+ });
169
+ it('returns German labels for completely unknown locale (fallback)', () => {
170
+ const labels = getValidationLabels('zh-TW');
171
+ expect(labels.popoverSuffix).toBe('— Kalender');
172
+ expect(labels.invalidDateMessage).toBe('Ungültiges Datum');
173
+ });
174
+ });
175
+ describe('isInFirstWeekOfMonth', () => {
176
+ it('returns true when going back 7 days crosses into the previous month', () => {
177
+ expect(isInFirstWeekOfMonth(pd('2024-06-03'))).toBe(true);
178
+ expect(isInFirstWeekOfMonth(pd('2024-06-01'))).toBe(true);
179
+ expect(isInFirstWeekOfMonth(pd('2024-06-07'))).toBe(true);
180
+ });
181
+ it('returns false when going back 7 days stays in the same month', () => {
182
+ expect(isInFirstWeekOfMonth(pd('2024-06-08'))).toBe(false);
183
+ expect(isInFirstWeekOfMonth(pd('2024-06-15'))).toBe(false);
184
+ });
185
+ });
186
+ describe('isInLastWeekOfMonth', () => {
187
+ it('returns true when going forward 7 days crosses into the next month', () => {
188
+ expect(isInLastWeekOfMonth(pd('2024-06-25'))).toBe(true);
189
+ expect(isInLastWeekOfMonth(pd('2024-06-30'))).toBe(true);
190
+ expect(isInLastWeekOfMonth(pd('2024-06-24'))).toBe(true);
191
+ });
192
+ it('returns false when going forward 7 days stays in the same month', () => {
193
+ expect(isInLastWeekOfMonth(pd('2024-06-23'))).toBe(false);
194
+ expect(isInLastWeekOfMonth(pd('2024-06-15'))).toBe(false);
195
+ });
196
+ });
197
+ describe('firstSelectableDayOfMonth', () => {
198
+ it('returns the 1st when no min/max restrictions', () => {
199
+ const result = firstSelectableDayOfMonth(ym('2024-06'), undefined, undefined);
200
+ expect(result).not.toBeNull();
201
+ expect(result.day).toBe(1);
202
+ });
203
+ it('skips disabled days and returns first enabled day when min is set', () => {
204
+ const result = firstSelectableDayOfMonth(ym('2024-06'), pd('2024-06-10'), undefined);
205
+ expect(result).not.toBeNull();
206
+ expect(result.day).toBe(10);
207
+ });
208
+ it('returns null when the entire month is disabled (min > last day)', () => {
209
+ const result = firstSelectableDayOfMonth(ym('2024-06'), pd('2024-07-01'), undefined);
210
+ expect(result).toBeNull();
211
+ });
212
+ });
213
+ describe('lastSelectableDayOfMonth', () => {
214
+ it('returns the last day of the month when no min/max restrictions', () => {
215
+ const result = lastSelectableDayOfMonth(ym('2024-06'), undefined, undefined);
216
+ expect(result).not.toBeNull();
217
+ expect(result.day).toBe(30);
218
+ });
219
+ it('skips disabled days and returns last enabled day when max is set', () => {
220
+ const result = lastSelectableDayOfMonth(ym('2024-06'), undefined, pd('2024-06-20'));
221
+ expect(result).not.toBeNull();
222
+ expect(result.day).toBe(20);
223
+ });
224
+ it('returns null when the entire month is disabled (max < first day)', () => {
225
+ const result = lastSelectableDayOfMonth(ym('2024-06'), undefined, pd('2024-05-31'));
226
+ expect(result).toBeNull();
227
+ });
228
+ });
229
+ describe('formatToDisplay', () => {
230
+ it('returns an empty string for undefined', () => {
231
+ expect(formatToDisplay(undefined, 'de-CH')).toBe('');
232
+ });
233
+ it('formats a date using the de-CH locale pattern (dd.MM.yyyy)', () => {
234
+ expect(formatToDisplay('2024-06-05', 'de-CH')).toBe('05.06.2024');
235
+ });
236
+ it('formats a date using the en-US locale pattern (MM/dd/yyyy)', () => {
237
+ expect(formatToDisplay('2024-06-05', 'en-US')).toBe('06/05/2024');
238
+ });
239
+ it('uses an explicit displayFormat override regardless of locale', () => {
240
+ expect(formatToDisplay('2024-06-05', 'en-US', 'yyyy-MM-dd')).toBe('2024-06-05');
241
+ });
242
+ it('returns an empty string for an unparseable ISO value', () => {
243
+ expect(formatToDisplay('not-a-date', 'de-CH')).toBe('');
244
+ });
245
+ });
246
+ describe('parseFromDisplay', () => {
247
+ it('returns undefined for empty text', () => {
248
+ expect(parseFromDisplay('', 'de-CH')).toBeUndefined();
249
+ });
250
+ it('returns undefined for whitespace-only text', () => {
251
+ expect(parseFromDisplay(' ', 'de-CH')).toBeUndefined();
252
+ });
253
+ it('parses a complete valid de-CH date (dd.MM.yyyy)', () => {
254
+ expect(parseFromDisplay('05.06.2024', 'de-CH')).toBe('2024-06-05');
255
+ });
256
+ it('parses a complete valid en-US date (MM/dd/yyyy)', () => {
257
+ expect(parseFromDisplay('06/05/2024', 'en-US')).toBe('2024-06-05');
258
+ });
259
+ it('returns undefined for incomplete/partial input (mid-keystroke)', () => {
260
+ expect(parseFromDisplay('05.06.202', 'de-CH')).toBeUndefined();
261
+ expect(parseFromDisplay('05.06.', 'de-CH')).toBeUndefined();
262
+ expect(parseFromDisplay('05', 'de-CH')).toBeUndefined();
263
+ });
264
+ it('returns undefined for a non-existent calendar date (e.g. Feb 30)', () => {
265
+ expect(parseFromDisplay('30.02.2024', 'de-CH')).toBeUndefined();
266
+ });
267
+ it('returns undefined for a syntactically invalid string', () => {
268
+ expect(parseFromDisplay('not a date', 'de-CH')).toBeUndefined();
269
+ });
270
+ it('respects an explicit displayFormat override regardless of locale', () => {
271
+ expect(parseFromDisplay('2024-06-05', 'en-US', 'yyyy-MM-dd')).toBe('2024-06-05');
272
+ });
273
+ it('round-trips format -> parse -> format for de-CH', () => {
274
+ const iso = '2024-06-05';
275
+ const displayed = formatToDisplay(iso, 'de-CH');
276
+ const parsed = parseFromDisplay(displayed, 'de-CH');
277
+ expect(parsed).toBe(iso);
278
+ expect(formatToDisplay(parsed, 'de-CH')).toBe(displayed);
279
+ });
280
+ it('round-trips format -> parse -> format for en-US (different token ordering)', () => {
281
+ const iso = '2024-06-05';
282
+ const displayed = formatToDisplay(iso, 'en-US');
283
+ expect(displayed).toBe('06/05/2024');
284
+ const parsed = parseFromDisplay(displayed, 'en-US');
285
+ expect(parsed).toBe(iso);
286
+ expect(formatToDisplay(parsed, 'en-US')).toBe(displayed);
287
+ });
288
+ it('honors locale-specific token ordering (de-CH day-first vs en-US month-first)', () => {
289
+ expect(parseFromDisplay('05.06.2024', 'de-CH')).toBe('2024-06-05');
290
+ expect(parseFromDisplay('05/06/2024', 'en-US')).toBe('2024-05-06');
291
+ });
292
+ });
293
+ describe('derivePatternFromLocale', () => {
294
+ it('derives dd.MM.yyyy for de-CH', () => {
295
+ expect(derivePatternFromLocale('de-CH')).toBe('dd.MM.yyyy');
296
+ });
297
+ it('derives MM/dd/yyyy for en-US', () => {
298
+ expect(derivePatternFromLocale('en-US')).toBe('MM/dd/yyyy');
299
+ });
300
+ });
@@ -87,7 +87,7 @@ export class LmvzHeader extends ReactiveControllerHost {
87
87
  }
88
88
  }
89
89
  render() {
90
- return (h(Host, { key: 'ce4b8cf9f7687e4af97d45908e2f0e484b90684f', onFocus: this.delegateFocus.bind(this) }, h("div", { key: 'a2213d8038d126e47262c4ec18071dd4302152db', class: "brand" }, h("slot", { key: '68a0a1e2b21859d78d2f9a7d3f5c86020c52c225', name: "brand" }, h("img", { key: 'd0a878bc4c9f7a3460e857fb5aa52f1d942a0423', id: "fallback-logo-lmvz", src: logo, alt: "Lehrmittelverlag Z\u00FCrich" }))), h("nav", { key: '687791624d6ced477bc0cce73ce97b26c7d03af0', "aria-label": "Hauptnavigation" }, h("div", { key: 'a9e8fa4a57e619a3d3b1056bfc0d5df74e89f630', role: "menubar", class: "primary-menubar" }, h("slot", { key: 'f75f0a3bed2267aff902490f1905c67ad1b7e6be', name: "nav-primary", ref: (el) => (this.primarySlot = el) }), h("div", { key: '3cf2d099bed99e4ba7b32a2f3171c69663785012', role: "menu", id: "nav-secondary", class: "secondary-menubar", hidden: !this.lmvzActiveNav, ref: (el) => (this.secondaryNav = el) }, h("slot", { key: '85dbe77ea8ab62aa400640495e11e2d174ca5210', name: this.secondarySlotName, ref: (el) => (this.secondarySlot = el) })))), h("div", { key: 'cf5d135a5b969af6a2bbb5432a10f8e1b9af1dca', class: "actions" }, h("slot", { key: '1a0323668942151c071a24238039c7a216358363', name: "actions" }))));
90
+ return (h(Host, { key: '77744fd74160551232eb0347e9ebb01eb3b9bec0', onFocus: this.delegateFocus.bind(this) }, h("div", { key: 'dfd78b2a2ab06b010d9f29dd61f57aced82243fe', class: "brand" }, h("slot", { key: 'c6d29bbdbcbe581a8a170fbeb3d6ab1e31d27dcd', name: "brand" }, h("img", { key: '80cea3b254d153411864d52c2ba300e0eb3c57a7', id: "fallback-logo-lmvz", src: logo, alt: "Lehrmittelverlag Z\u00FCrich" }))), h("nav", { key: '71c53ae0300b61291d0763cdb23f1f645a83928a', "aria-label": "Hauptnavigation" }, h("div", { key: '09949b77a66c54a10c4c141de846fd5697b9d445', role: "menubar", class: "primary-menubar" }, h("slot", { key: 'acec0cf7e13325c49d1e0929b90b056ad1cbbe64', name: "nav-primary", ref: (el) => (this.primarySlot = el) }), h("div", { key: 'd35860c71ad5e28ee2e3aaafb157acbeff41d83e', role: "menu", id: "nav-secondary", class: "secondary-menubar", hidden: !this.lmvzActiveNav, ref: (el) => (this.secondaryNav = el) }, h("slot", { key: 'a4c3a1ad1b1de5bd903b54ed6bd1616ce6517bbb', name: this.secondarySlotName, ref: (el) => (this.secondarySlot = el) })))), h("div", { key: 'ff50045d9ab28bf66a619a48d9ea1f0ed2f5f952', class: "actions" }, h("slot", { key: '6ead0b7a54bf93bb06f0eab2aa8159bd6e96e8f5', name: "actions" }))));
91
91
  }
92
92
  static get is() { return "lmvz-header"; }
93
93
  static get encapsulation() { return "shadow"; }
@@ -57,7 +57,7 @@ export class LmvzIcon extends ReactiveControllerHost {
57
57
  super.componentDidRender();
58
58
  }
59
59
  render() {
60
- return h(Host, { key: '4fba217d573d968951819f12af24d775c8ac62dc', role: "img", "aria-hidden": `${this.ariaHidden}`, innerHTML: this.iconData });
60
+ return h(Host, { key: 'be6032d11399289c3baddd63ebc7d9e1fb98b773', role: "img", "aria-hidden": `${this.ariaHidden}`, innerHTML: this.iconData });
61
61
  }
62
62
  waitUntilVisible(callback, rootMargin = 50) {
63
63
  if (!Build.isBrowser || typeof window === 'undefined' || !window.IntersectionObserver) {
@@ -107,7 +107,7 @@
107
107
  cursor: not-allowed;
108
108
  pointer-events: none;
109
109
  }
110
- .input-container:focus-within .input-wrapper {
110
+ :host:has(:focus-visible) .input-wrapper {
111
111
  border-color: var(--input-border-color-focus);
112
112
  outline: var(--lmvz-ds-outline, 1px solid #0e7ab4);
113
113
  outline-offset: var(--lmvz-ds-outline-offset, clamp(0.25rem, 0.19rem + 0.26vw, 0.5rem));