ngwr 10.1.0 → 10.2.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 (172) hide show
  1. package/alert/styles/_index.scss +7 -3
  2. package/breadcrumbs/styles/_index.scss +1 -1
  3. package/dialog/styles/_index.scss +31 -0
  4. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  5. package/fesm2022/ngwr-affix.mjs +3 -3
  6. package/fesm2022/ngwr-alert.mjs +3 -3
  7. package/fesm2022/ngwr-anchor.mjs +3 -3
  8. package/fesm2022/ngwr-aurora.mjs +3 -3
  9. package/fesm2022/ngwr-avatar.mjs +3 -3
  10. package/fesm2022/ngwr-back-top.mjs +3 -3
  11. package/fesm2022/ngwr-badge.mjs +6 -6
  12. package/fesm2022/ngwr-bar-chart.mjs +3 -3
  13. package/fesm2022/ngwr-blur-text.mjs +3 -3
  14. package/fesm2022/ngwr-border-glow.mjs +4 -4
  15. package/fesm2022/ngwr-breadcrumbs.mjs +9 -8
  16. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  17. package/fesm2022/ngwr-burger.mjs +3 -3
  18. package/fesm2022/ngwr-button.mjs +59 -11
  19. package/fesm2022/ngwr-button.mjs.map +1 -1
  20. package/fesm2022/ngwr-calendar-heatmap.mjs +3 -3
  21. package/fesm2022/ngwr-calendar.mjs +88 -8
  22. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  23. package/fesm2022/ngwr-card.mjs +10 -10
  24. package/fesm2022/ngwr-carousel.mjs +6 -6
  25. package/fesm2022/ngwr-cascader.mjs +4 -4
  26. package/fesm2022/ngwr-checkbox.mjs +6 -6
  27. package/fesm2022/ngwr-circular-text.mjs +4 -4
  28. package/fesm2022/ngwr-click-spark.mjs +3 -3
  29. package/fesm2022/ngwr-clipboard.mjs +18 -4
  30. package/fesm2022/ngwr-clipboard.mjs.map +1 -1
  31. package/fesm2022/ngwr-collapse.mjs +9 -9
  32. package/fesm2022/ngwr-color-picker.mjs +6 -6
  33. package/fesm2022/ngwr-command-palette.mjs +3 -3
  34. package/fesm2022/ngwr-compare.mjs +3 -3
  35. package/fesm2022/ngwr-confetti.mjs +3 -3
  36. package/fesm2022/ngwr-context-menu.mjs +12 -12
  37. package/fesm2022/ngwr-cookie.mjs +3 -3
  38. package/fesm2022/ngwr-counter.mjs +6 -6
  39. package/fesm2022/ngwr-date-adapter-fns.mjs +3 -3
  40. package/fesm2022/ngwr-date-adapter-luxon.mjs +3 -3
  41. package/fesm2022/ngwr-date-adapter.mjs +3 -3
  42. package/fesm2022/ngwr-date-picker.mjs +336 -54
  43. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  44. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  45. package/fesm2022/ngwr-density.mjs +6 -6
  46. package/fesm2022/ngwr-descriptions.mjs +6 -6
  47. package/fesm2022/ngwr-dialog.mjs +33 -17
  48. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  49. package/fesm2022/ngwr-directives.mjs +12 -12
  50. package/fesm2022/ngwr-divider.mjs +3 -3
  51. package/fesm2022/ngwr-donut-chart.mjs +3 -3
  52. package/fesm2022/ngwr-drag-drop.mjs +7 -7
  53. package/fesm2022/ngwr-drawer.mjs +37 -19
  54. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  55. package/fesm2022/ngwr-dropdown.mjs +9 -9
  56. package/fesm2022/ngwr-empty.mjs +3 -3
  57. package/fesm2022/ngwr-event-calendar.mjs +6 -6
  58. package/fesm2022/ngwr-falling-text.mjs +4 -4
  59. package/fesm2022/ngwr-file-upload.mjs +3 -3
  60. package/fesm2022/ngwr-form.mjs +9 -9
  61. package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
  62. package/fesm2022/ngwr-gauge.mjs +3 -3
  63. package/fesm2022/ngwr-glitch-text.mjs +4 -4
  64. package/fesm2022/ngwr-gradient-text.mjs +4 -4
  65. package/fesm2022/ngwr-hotkey.mjs +31 -10
  66. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  67. package/fesm2022/ngwr-i18n-en.mjs +11 -0
  68. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  69. package/fesm2022/ngwr-i18n-ru.mjs +11 -0
  70. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  71. package/fesm2022/ngwr-i18n.mjs +9 -9
  72. package/fesm2022/ngwr-icon.mjs +6 -6
  73. package/fesm2022/ngwr-image-cropper.mjs +3 -3
  74. package/fesm2022/ngwr-input-number.mjs +3 -3
  75. package/fesm2022/ngwr-input-otp.mjs +3 -3
  76. package/fesm2022/ngwr-input.mjs +15 -15
  77. package/fesm2022/ngwr-keyboard.mjs +3 -3
  78. package/fesm2022/ngwr-knob.mjs +3 -3
  79. package/fesm2022/ngwr-layout.mjs +15 -15
  80. package/fesm2022/ngwr-lightbox.mjs +4 -4
  81. package/fesm2022/ngwr-line-chart.mjs +3 -3
  82. package/fesm2022/ngwr-list.mjs +14 -9
  83. package/fesm2022/ngwr-list.mjs.map +1 -1
  84. package/fesm2022/ngwr-loading-bar.mjs +71 -31
  85. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  86. package/fesm2022/ngwr-marquee.mjs +4 -4
  87. package/fesm2022/ngwr-media.mjs +3 -3
  88. package/fesm2022/ngwr-mention.mjs +6 -6
  89. package/fesm2022/ngwr-meta.mjs +6 -6
  90. package/fesm2022/ngwr-meter-group.mjs +3 -3
  91. package/fesm2022/ngwr-overlay.mjs +16 -7
  92. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  93. package/fesm2022/ngwr-page-header.mjs +3 -3
  94. package/fesm2022/ngwr-pagination.mjs +13 -9
  95. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  96. package/fesm2022/ngwr-pipes.mjs +21 -21
  97. package/fesm2022/ngwr-platform.mjs +9 -9
  98. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  99. package/fesm2022/ngwr-popover.mjs +28 -8
  100. package/fesm2022/ngwr-popover.mjs.map +1 -1
  101. package/fesm2022/ngwr-progress.mjs +3 -3
  102. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  103. package/fesm2022/ngwr-qr.mjs +3 -3
  104. package/fesm2022/ngwr-radio.mjs +6 -6
  105. package/fesm2022/ngwr-rating.mjs +3 -3
  106. package/fesm2022/ngwr-result.mjs +12 -12
  107. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  108. package/fesm2022/ngwr-scroll.mjs +3 -3
  109. package/fesm2022/ngwr-segmented.mjs +3 -3
  110. package/fesm2022/ngwr-select.mjs +9 -9
  111. package/fesm2022/ngwr-shiny-text.mjs +7 -7
  112. package/fesm2022/ngwr-sidebar.mjs +3 -3
  113. package/fesm2022/ngwr-skeleton.mjs +3 -3
  114. package/fesm2022/ngwr-slider.mjs +3 -3
  115. package/fesm2022/ngwr-sparkline.mjs +3 -3
  116. package/fesm2022/ngwr-speed-dial.mjs +3 -3
  117. package/fesm2022/ngwr-spinner.mjs +3 -3
  118. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  119. package/fesm2022/ngwr-split-text.mjs +3 -3
  120. package/fesm2022/ngwr-splitter.mjs +3 -3
  121. package/fesm2022/ngwr-spotlight-card.mjs +7 -7
  122. package/fesm2022/ngwr-squircle.mjs +6 -6
  123. package/fesm2022/ngwr-star-border.mjs +4 -4
  124. package/fesm2022/ngwr-statistic.mjs +9 -9
  125. package/fesm2022/ngwr-stepper.mjs +6 -6
  126. package/fesm2022/ngwr-storage.mjs +27 -17
  127. package/fesm2022/ngwr-storage.mjs.map +1 -1
  128. package/fesm2022/ngwr-switch.mjs +3 -3
  129. package/fesm2022/ngwr-table.mjs +19 -31
  130. package/fesm2022/ngwr-table.mjs.map +1 -1
  131. package/fesm2022/ngwr-tabs.mjs +6 -6
  132. package/fesm2022/ngwr-textarea.mjs +3 -3
  133. package/fesm2022/ngwr-theme.mjs +3 -3
  134. package/fesm2022/ngwr-tilt-card.mjs +7 -7
  135. package/fesm2022/ngwr-timeline.mjs +6 -6
  136. package/fesm2022/ngwr-toast.mjs +54 -20
  137. package/fesm2022/ngwr-toast.mjs.map +1 -1
  138. package/fesm2022/ngwr-toolbar.mjs +3 -3
  139. package/fesm2022/ngwr-tour.mjs +6 -6
  140. package/fesm2022/ngwr-transfer.mjs +3 -3
  141. package/fesm2022/ngwr-tree.mjs +3 -3
  142. package/fesm2022/ngwr-typewriter.mjs +4 -4
  143. package/fesm2022/ngwr-typography.mjs +3 -3
  144. package/fesm2022/ngwr-version.mjs +1 -1
  145. package/fesm2022/ngwr-version.mjs.map +1 -1
  146. package/fesm2022/ngwr-virtual-scroll.mjs +4 -4
  147. package/fesm2022/ngwr-waves.mjs +4 -4
  148. package/fesm2022/ngwr-window.mjs +80 -18
  149. package/fesm2022/ngwr-window.mjs.map +1 -1
  150. package/i18n/en.json +8 -0
  151. package/i18n/ru.json +8 -0
  152. package/package.json +1 -1
  153. package/sidebar/styles/_index.scss +3 -3
  154. package/stepper/styles/_index.scss +3 -3
  155. package/tabs/styles/_index.scss +1 -1
  156. package/theme/styles/_colors.scss +29 -8
  157. package/types/ngwr-button.d.ts +32 -0
  158. package/types/ngwr-calendar.d.ts +27 -1
  159. package/types/ngwr-clipboard.d.ts +8 -1
  160. package/types/ngwr-date-picker.d.ts +124 -8
  161. package/types/ngwr-dialog.d.ts +13 -0
  162. package/types/ngwr-drawer.d.ts +15 -0
  163. package/types/ngwr-hotkey.d.ts +2 -0
  164. package/types/ngwr-list.d.ts +7 -2
  165. package/types/ngwr-loading-bar.d.ts +4 -7
  166. package/types/ngwr-pagination.d.ts +6 -1
  167. package/types/ngwr-popover.d.ts +10 -2
  168. package/types/ngwr-storage.d.ts +10 -1
  169. package/types/ngwr-toast.d.ts +19 -4
  170. package/types/ngwr-version.d.ts +1 -1
  171. package/types/ngwr-window.d.ts +23 -2
  172. package/typography/styles/_index.scss +2 -2
@@ -2,15 +2,13 @@ import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coerci
2
2
  import { ScrollStrategyOptions } from '@angular/cdk/overlay';
3
3
  import { ComponentPortal } from '@angular/cdk/portal';
4
4
  import * as i0 from '@angular/core';
5
- import { input, inject, model, output, signal, computed, effect, untracked, ViewEncapsulation, Component, ElementRef, DestroyRef, viewChild } from '@angular/core';
5
+ import { input, inject, ElementRef, model, output, signal, computed, afterNextRender, effect, untracked, ViewEncapsulation, Component, DestroyRef, viewChild } from '@angular/core';
6
6
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
7
7
  import { WrCalendar } from 'ngwr/calendar';
8
8
  import { WrDateAdapter, WR_DATE_LOCALE } from 'ngwr/date-adapter';
9
9
  import { readI18nText, useI18nText } from 'ngwr/i18n';
10
10
  import { WrInput, WrInputGroup, WrInputSuffix } from 'ngwr/input';
11
11
  import { WR_OVERLAY, WrOutsideClick } from 'ngwr/overlay';
12
- import * as i1 from '@angular/forms';
13
- import { FormsModule } from '@angular/forms';
14
12
  import { clamp } from 'ngwr/utils';
15
13
 
16
14
  /**
@@ -54,7 +52,13 @@ class WrTimePanel {
54
52
  disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
55
53
  /** Read-only — values cannot be changed. @default false */
56
54
  readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
55
+ /**
56
+ * Move focus onto the hours field once the panel is on screen. Off by
57
+ * default — see `WrCalendar.autoFocus` for why. @default false
58
+ */
59
+ autoFocus = input(false, { ...(ngDevMode ? { debugName: "autoFocus" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
57
60
  adapter = inject(WrDateAdapter);
61
+ host = inject(ElementRef);
58
62
  locale = inject(WR_DATE_LOCALE);
59
63
  /**
60
64
  * Form value — the selected time as a `Date` (its date portion is preserved).
@@ -78,6 +82,14 @@ class WrTimePanel {
78
82
  effectiveDisabled = computed(() => this.disabled(), /* @ts-ignore */
79
83
  ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
80
84
  constructor() {
85
+ // The hours field, not the increment button: a stepper is a shortcut, the
86
+ // number is the control. Deferred because the inputs are not in the DOM
87
+ // until the panel's first change-detection pass.
88
+ afterNextRender(() => {
89
+ if (!this.autoFocus())
90
+ return;
91
+ this.host.nativeElement.querySelector('.wr-time-picker__input')?.focus();
92
+ });
81
93
  // Mirror an external `value` write into the internal h/m/s state (the old
82
94
  // `writeValue` body). Guarded against the echo of our own `emit()` so a live
83
95
  // edit is never clobbered by re-deriving it.
@@ -207,13 +219,13 @@ class WrTimePanel {
207
219
  this.lastEmitted = next;
208
220
  this.value.set(next);
209
221
  }
210
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTimePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
211
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrTimePanel, isStandalone: true, selector: "wr-time-picker", inputs: { format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Hours\"\n [value]=\"hoursDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onHoursInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n<span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Minutes\"\n [value]=\"minutesDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onMinutesInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n@if (showSeconds()) {\n <span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n <div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Seconds\"\n [value]=\"secondsDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onSecondsInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n\n@if (is12h()) {\n <div class=\"wr-time-picker__col wr-time-picker__col--ampm\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <span class=\"wr-time-picker__label\" aria-live=\"polite\">{{ amPmLabel() }}</span>\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n", encapsulation: i0.ViewEncapsulation.None });
222
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrTimePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
223
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrTimePanel, isStandalone: true, selector: "wr-time-picker", inputs: { format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Hours\"\n [value]=\"hoursDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onHoursInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n<span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Minutes\"\n [value]=\"minutesDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onMinutesInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n@if (showSeconds()) {\n <span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n <div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Seconds\"\n [value]=\"secondsDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onSecondsInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n\n@if (is12h()) {\n <div class=\"wr-time-picker__col wr-time-picker__col--ampm\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <span class=\"wr-time-picker__label\" aria-live=\"polite\">{{ amPmLabel() }}</span>\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n", encapsulation: i0.ViewEncapsulation.None });
212
224
  }
213
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTimePanel, decorators: [{
225
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrTimePanel, decorators: [{
214
226
  type: Component,
215
227
  args: [{ selector: 'wr-time-picker', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Hours\"\n [value]=\"hoursDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onHoursInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n<span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Minutes\"\n [value]=\"minutesDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onMinutesInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n@if (showSeconds()) {\n <span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n <div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Seconds\"\n [value]=\"secondsDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onSecondsInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n\n@if (is12h()) {\n <div class=\"wr-time-picker__col wr-time-picker__col--ampm\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <span class=\"wr-time-picker__label\" aria-live=\"polite\">{{ amPmLabel() }}</span>\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n" }]
216
- }], ctorParameters: () => [], propDecorators: { format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
228
+ }], ctorParameters: () => [], propDecorators: { format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
217
229
 
218
230
  /**
219
231
  * @license
@@ -243,6 +255,13 @@ class WrDateTimePanel {
243
255
  ...(ngDevMode ? [{ debugName: "showSeconds" }] : /* istanbul ignore next */ []));
244
256
  step = input(1, /* @ts-ignore */
245
257
  ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
258
+ /**
259
+ * Forwarded to the calendar only: a datetime panel opened from the keyboard
260
+ * lands on the day grid, never on the hours field. Picking the date first is
261
+ * the order the panel is laid out in, and the time fields are one Tab away.
262
+ */
263
+ autoFocus = input(false, /* @ts-ignore */
264
+ ...(ngDevMode ? [{ debugName: "autoFocus" }] : /* istanbul ignore next */ []));
246
265
  changed = output();
247
266
  adapter = inject(WrDateAdapter);
248
267
  /** Date portion used by the calendar — falls back to today when value is null. */
@@ -265,13 +284,13 @@ class WrDateTimePanel {
265
284
  const combined = this.adapter.setTime(this.adapter.createDate(this.adapter.getYear(base), this.adapter.getMonth(base), this.adapter.getDate(base)), this.adapter.getHours(time), this.adapter.getMinutes(time), this.adapter.getSeconds(time));
266
285
  this.changed.emit(combined);
267
286
  }
268
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateTimePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
269
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: WrDateTimePanel, isStandalone: true, selector: "wr-date-time-panel", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { classAttribute: "wr-date-time-panel" }, ngImport: i0, template: "<wr-calendar\n [date]=\"calendarValue()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n (dateChange)=\"onCalendarSelect($event)\"\n/>\n\n<div class=\"wr-date-time-panel__time\">\n <wr-time-picker\n [ngModel]=\"timeValue()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onTimeChange($event)\"\n />\n</div>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: WrCalendar, selector: "wr-calendar", inputs: ["mode", "date", "range", "min", "max", "dateFilter", "disabled"], outputs: ["dateChange", "rangeChange"] }, { kind: "component", type: WrTimePanel, selector: "wr-time-picker", inputs: ["format", "showSeconds", "step", "disabled", "readonly", "value"], outputs: ["valueChange", "touch"] }], encapsulation: i0.ViewEncapsulation.None });
287
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateTimePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
288
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: WrDateTimePanel, isStandalone: true, selector: "wr-date-time-panel", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { classAttribute: "wr-date-time-panel" }, ngImport: i0, template: "<wr-calendar\n [date]=\"calendarValue()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n [autoFocus]=\"autoFocus()\"\n (dateChange)=\"onCalendarSelect($event)\"\n/>\n\n<div class=\"wr-date-time-panel__time\">\n <wr-time-picker\n [value]=\"timeValue()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onTimeChange($event)\"\n />\n</div>\n", dependencies: [{ kind: "component", type: WrCalendar, selector: "wr-calendar", inputs: ["mode", "date", "range", "min", "max", "dateFilter", "autoFocus", "disabled"], outputs: ["dateChange", "rangeChange"] }, { kind: "component", type: WrTimePanel, selector: "wr-time-picker", inputs: ["format", "showSeconds", "step", "disabled", "readonly", "autoFocus", "value"], outputs: ["valueChange", "touch"] }], encapsulation: i0.ViewEncapsulation.None });
270
289
  }
271
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateTimePanel, decorators: [{
290
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateTimePanel, decorators: [{
272
291
  type: Component,
273
- args: [{ selector: 'wr-date-time-panel', encapsulation: ViewEncapsulation.None, host: { class: 'wr-date-time-panel' }, imports: [FormsModule, WrCalendar, WrTimePanel], template: "<wr-calendar\n [date]=\"calendarValue()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n (dateChange)=\"onCalendarSelect($event)\"\n/>\n\n<div class=\"wr-date-time-panel__time\">\n <wr-time-picker\n [ngModel]=\"timeValue()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onTimeChange($event)\"\n />\n</div>\n" }]
274
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
292
+ args: [{ selector: 'wr-date-time-panel', encapsulation: ViewEncapsulation.None, host: { class: 'wr-date-time-panel' }, imports: [WrCalendar, WrTimePanel], template: "<wr-calendar\n [date]=\"calendarValue()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n [autoFocus]=\"autoFocus()\"\n (dateChange)=\"onCalendarSelect($event)\"\n/>\n\n<div class=\"wr-date-time-panel__time\">\n <wr-time-picker\n [value]=\"timeValue()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onTimeChange($event)\"\n />\n</div>\n" }]
293
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
275
294
 
276
295
  /**
277
296
  * @license
@@ -279,6 +298,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
279
298
  * Use of this source code is governed by an MIT-style license that can be
280
299
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
281
300
  */
301
+ let panelUid = 0;
282
302
  /**
283
303
  * Unified date / time / date-time picker. Same `<input>` + popover skeleton
284
304
  * for every mode — the overlay content swaps based on `[mode]`:
@@ -372,6 +392,8 @@ class WrDatePicker {
372
392
  destroyRef = inject(DestroyRef);
373
393
  inputEl = viewChild.required('input', /* @ts-ignore */
374
394
  ...(ngDevMode ? [{ debugName: "inputEl" }] : /* istanbul ignore next */ []));
395
+ triggerEl = viewChild('trigger', /* @ts-ignore */
396
+ ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
375
397
  /** The picked Date. Bound by `[formField]`, or two-way via `[(value)]`. */
376
398
  value = model(null, /* @ts-ignore */
377
399
  ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
@@ -383,6 +405,14 @@ class WrDatePicker {
383
405
  /** Whether the popover is currently open. */
384
406
  overlayOpen = signal(false, /* @ts-ignore */
385
407
  ...(ngDevMode ? [{ debugName: "overlayOpen" }] : /* istanbul ignore next */ []));
408
+ /**
409
+ * Where focus came from, captured as an explicit argument at open time —
410
+ * never read off `document.activeElement`, which by then may already be the
411
+ * pane. Every close path that took focus INTO the panel hands it back here.
412
+ */
413
+ openedFrom = null;
414
+ /** Whether the panel this open cycle should take focus. */
415
+ autoFocusPanel = false;
386
416
  /** Resolved format — falls back to a mode-appropriate default. */
387
417
  resolvedFormat = computed(() => {
388
418
  const explicit = this.format();
@@ -408,6 +438,9 @@ class WrDatePicker {
408
438
  labelDate = readI18nText('datePicker.open', 'Open calendar');
409
439
  labelTime = readI18nText('datePicker.openTime', 'Open time picker');
410
440
  labelDateTime = readI18nText('datePicker.openDateTime', 'Open date and time picker');
441
+ panelLabelDate = readI18nText('datePicker.panel', 'Choose date');
442
+ panelLabelTime = readI18nText('datePicker.panelTime', 'Choose time');
443
+ panelLabelDateTime = readI18nText('datePicker.panelDateTime', 'Choose date and time');
411
444
  /**
412
445
  * Accessible name of the text field. Falls back to the placeholder, then to
413
446
  * the same catalog string the calendar button uses — the field is a
@@ -434,6 +467,28 @@ class WrDatePicker {
434
467
  return this.labelDate;
435
468
  }, /* @ts-ignore */
436
469
  ...(ngDevMode ? [{ debugName: "triggerLabel" }] : /* istanbul ignore next */ []));
470
+ /**
471
+ * Accessible name of the popup. The trigger advertises
472
+ * `aria-haspopup="dialog"`, so the panel is a `role="dialog"` — and an unnamed
473
+ * dialog announces as a bare "dialog". Defaults to the catalog's
474
+ * `datePicker.panel*` string for the current `mode`.
475
+ */
476
+ panelAriaLabel = input(null, /* @ts-ignore */
477
+ ...(ngDevMode ? [{ debugName: "panelAriaLabel" }] : /* istanbul ignore next */ []));
478
+ /** Popup id — what the trigger's `aria-controls` points at while open. */
479
+ panelId = `wr-date-picker-panel-${++panelUid}`;
480
+ resolvedPanelLabel = computed(() => {
481
+ const explicit = this.panelAriaLabel();
482
+ if (explicit)
483
+ return explicit;
484
+ const m = this.mode();
485
+ if (m === 'time')
486
+ return this.panelLabelTime;
487
+ if (m === 'datetime')
488
+ return this.panelLabelDateTime;
489
+ return this.panelLabelDate;
490
+ }, /* @ts-ignore */
491
+ ...(ngDevMode ? [{ debugName: "resolvedPanelLabel" }] : /* istanbul ignore next */ []));
437
492
  classes = computed(() => {
438
493
  const parts = ['wr-date-picker', `wr-date-picker--${this.mode()}`];
439
494
  if (this.disabled())
@@ -503,22 +558,69 @@ class WrDatePicker {
503
558
  openOnInput() {
504
559
  if (this.disabled() || this.overlayRef)
505
560
  return;
506
- this.openOverlay();
561
+ // Deliberately WITHOUT focus: this click placed a caret in the text field,
562
+ // and yanking focus into the grid would throw away what the user just did.
563
+ // `Alt+ArrowDown` / `ArrowDown` are the keyboard way in — see onFieldKey.
564
+ this.openOverlay(this.inputEl().nativeElement, false);
507
565
  }
508
566
  toggleOverlay() {
509
567
  if (this.disabled())
510
568
  return;
511
569
  if (this.overlayRef) {
570
+ // Focus is already on the trigger — nothing to restore.
512
571
  this.closeOverlay();
513
572
  }
514
573
  else {
515
- this.openOverlay();
574
+ this.openOverlay(this.triggerEl()?.nativeElement ?? null, true);
575
+ }
576
+ }
577
+ /**
578
+ * The keyboard route into the panel, per the APG date-picker pattern.
579
+ *
580
+ * `Alt+ArrowDown` opens and takes focus; a bare arrow moves focus in when the
581
+ * panel is ALREADY open, which is how someone who opened it by clicking the
582
+ * field gets to the grid. Every other key — characters, Backspace, the
583
+ * horizontal arrows, Home / End — is left to the field untouched, so typing a
584
+ * date keeps working exactly as before.
585
+ */
586
+ onFieldKey(event) {
587
+ if (this.disabled())
588
+ return;
589
+ const vertical = event.key === 'ArrowDown' || event.key === 'ArrowUp';
590
+ if (!vertical)
591
+ return;
592
+ if (event.altKey && event.key === 'ArrowDown' && !this.overlayRef) {
593
+ event.preventDefault();
594
+ this.openOverlay(this.inputEl().nativeElement, true);
595
+ return;
596
+ }
597
+ if (this.overlayRef) {
598
+ event.preventDefault();
599
+ this.focusPanel();
516
600
  }
517
601
  }
602
+ /**
603
+ * Move focus into an already-mounted panel. A plain query is right HERE and
604
+ * wrong at mount time: the panel has settled, so there is no deferral to get
605
+ * wrong — and it keeps `autoFocus` as the single piece of panel API.
606
+ */
607
+ focusPanel() {
608
+ const pane = this.overlayRef?.overlayElement;
609
+ const target = pane?.querySelector('.wr-calendar__day--focused:not([disabled])') ??
610
+ pane?.querySelector('.wr-time-picker__input');
611
+ target?.focus();
612
+ }
613
+ /** Hand focus back to whatever opened the panel, if it is still on the page. */
614
+ restoreFocus() {
615
+ const target = this.openedFrom?.isConnected ? this.openedFrom : this.inputEl().nativeElement;
616
+ target?.focus();
617
+ }
518
618
  // Overlay
519
- openOverlay() {
619
+ openOverlay(openedFrom = null, autoFocus = false) {
520
620
  if (this.overlayRef)
521
621
  return;
622
+ this.openedFrom = openedFrom;
623
+ this.autoFocusPanel = autoFocus;
522
624
  const positionStrategy = this.overlay
523
625
  .position()
524
626
  .flexibleConnectedTo(this.host)
@@ -534,6 +636,15 @@ class WrDatePicker {
534
636
  scrollStrategy: this.scrollStrategies.reposition(),
535
637
  panelClass: 'wr-date-picker-overlay',
536
638
  });
639
+ // The trigger promises `aria-haspopup="dialog"`; the pane is the element it
640
+ // points at, so the role, the name and the id all belong here. Non-modal on
641
+ // purpose — focus is not trapped, and the panel closes on outside click or
642
+ // Escape.
643
+ const pane = this.overlayRef.overlayElement;
644
+ pane.id = this.panelId;
645
+ pane.setAttribute('role', 'dialog');
646
+ pane.setAttribute('aria-modal', 'false');
647
+ pane.setAttribute('aria-label', this.resolvedPanelLabel());
537
648
  this.overlayOpen.set(true);
538
649
  // Dispatch by mode — pick the panel + wire its emissions.
539
650
  const m = this.mode();
@@ -571,6 +682,7 @@ class WrDatePicker {
571
682
  ref.setInput('min', this.min());
572
683
  ref.setInput('max', this.max());
573
684
  ref.setInput('dateFilter', this.dateFilter());
685
+ ref.setInput('autoFocus', this.autoFocusPanel);
574
686
  ref.instance.date.subscribe(next => {
575
687
  if (!next)
576
688
  return;
@@ -585,6 +697,7 @@ class WrDatePicker {
585
697
  ref.setInput('format', this.timeFormat());
586
698
  ref.setInput('showSeconds', this.showSeconds());
587
699
  ref.setInput('step', this.step());
700
+ ref.setInput('autoFocus', this.autoFocusPanel);
588
701
  ref.setInput('value', this.value() ?? this.adapter.today());
589
702
  ref.instance.value.subscribe((next) => {
590
703
  if (!next)
@@ -603,6 +716,7 @@ class WrDatePicker {
603
716
  ref.setInput('timeFormat', this.timeFormat());
604
717
  ref.setInput('showSeconds', this.showSeconds());
605
718
  ref.setInput('step', this.step());
719
+ ref.setInput('autoFocus', this.autoFocusPanel);
606
720
  ref.instance.changed.subscribe(next => {
607
721
  this.commit(next);
608
722
  ref.setInput('value', next);
@@ -618,8 +732,19 @@ class WrDatePicker {
618
732
  this.lastValue = next;
619
733
  this.value.set(next);
620
734
  }
735
+ /**
736
+ * Focus goes back to the opener only when it was still INSIDE the panel —
737
+ * dropped there, it would land on `<body>` and the next Tab would restart
738
+ * from the top of the page. When focus had already moved elsewhere (a click
739
+ * on another control, which is itself what closed us) it is left alone:
740
+ * stealing it back would fight the user for the caret.
741
+ */
621
742
  closeOverlay() {
743
+ const pane = this.overlayRef?.overlayElement;
744
+ const inside = !!pane && pane.contains(document.activeElement);
622
745
  this.dispose();
746
+ if (inside)
747
+ this.restoreFocus();
623
748
  }
624
749
  dispose() {
625
750
  if (this.overlayRef) {
@@ -628,6 +753,7 @@ class WrDatePicker {
628
753
  }
629
754
  this.dateRef.set(null);
630
755
  this.overlayOpen.set(false);
756
+ this.autoFocusPanel = false;
631
757
  }
632
758
  // Helpers
633
759
  isOutOfBounds(date) {
@@ -648,13 +774,13 @@ class WrDatePicker {
648
774
  return false;
649
775
  return a.getTime() === b.getTime();
650
776
  }
651
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDatePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
652
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrDatePicker, isStandalone: true, selector: "wr-date-picker", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0, template: "<wr-input-group>\n <!--\n A plain textbox, per the APG date-picker-dialog pattern: `aria-haspopup` and\n `aria-expanded` are not permitted on `textbox` and belong to the trigger\n button below, which is the thing that opens the dialog.\n -->\n <input\n #input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n @if (isTime()) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"7\" y1=\"7\" x2=\"7\" y2=\"3.75\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"7\" y1=\"7\" x2=\"9.5\" y2=\"7\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n </svg>\n } @else {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n }\n </button>\n</wr-input-group>\n", dependencies: [{ kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["wrSize", "rounded"] }, { kind: "component", type: WrInputGroup, selector: "wr-input-group", inputs: ["rounded"] }, { kind: "directive", type: WrInputSuffix, selector: "[wrInputSuffix]" }], encapsulation: i0.ViewEncapsulation.None });
777
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDatePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
778
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrDatePicker, isStandalone: true, selector: "wr-date-picker", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, panelAriaLabel: { classPropertyName: "panelAriaLabel", publicName: "panelAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }, { propertyName: "triggerEl", first: true, predicate: ["trigger"], descendants: true, isSignal: true }], ngImport: i0, template: "<wr-input-group>\n <!--\n A plain textbox, per the APG date-picker-dialog pattern: `aria-haspopup` and\n `aria-expanded` are not permitted on `textbox` and belong to the trigger\n button below, which is the thing that opens the dialog.\n -->\n <input\n #input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (keydown)=\"onFieldKey($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n #trigger\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [attr.aria-controls]=\"overlayOpen() ? panelId : null\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n @if (isTime()) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"7\" y1=\"7\" x2=\"7\" y2=\"3.75\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"7\" y1=\"7\" x2=\"9.5\" y2=\"7\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n </svg>\n } @else {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n }\n </button>\n</wr-input-group>\n", dependencies: [{ kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["wrSize", "rounded"] }, { kind: "component", type: WrInputGroup, selector: "wr-input-group", inputs: ["rounded"] }, { kind: "directive", type: WrInputSuffix, selector: "[wrInputSuffix]" }], encapsulation: i0.ViewEncapsulation.None });
653
779
  }
654
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDatePicker, decorators: [{
780
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDatePicker, decorators: [{
655
781
  type: Component,
656
- args: [{ selector: 'wr-date-picker', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrInput, WrInputGroup, WrInputSuffix], template: "<wr-input-group>\n <!--\n A plain textbox, per the APG date-picker-dialog pattern: `aria-haspopup` and\n `aria-expanded` are not permitted on `textbox` and belong to the trigger\n button below, which is the thing that opens the dialog.\n -->\n <input\n #input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n @if (isTime()) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"7\" y1=\"7\" x2=\"7\" y2=\"3.75\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"7\" y1=\"7\" x2=\"9.5\" y2=\"7\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n </svg>\n } @else {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n }\n </button>\n</wr-input-group>\n" }]
657
- }], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
782
+ args: [{ selector: 'wr-date-picker', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrInput, WrInputGroup, WrInputSuffix], template: "<wr-input-group>\n <!--\n A plain textbox, per the APG date-picker-dialog pattern: `aria-haspopup` and\n `aria-expanded` are not permitted on `textbox` and belong to the trigger\n button below, which is the thing that opens the dialog.\n -->\n <input\n #input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (keydown)=\"onFieldKey($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n #trigger\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [attr.aria-controls]=\"overlayOpen() ? panelId : null\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n @if (isTime()) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"7\" y1=\"7\" x2=\"7\" y2=\"3.75\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"7\" y1=\"7\" x2=\"9.5\" y2=\"7\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n </svg>\n } @else {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n }\n </button>\n</wr-input-group>\n" }]
783
+ }], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], triggerEl: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], panelAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelAriaLabel", required: false }] }] } });
658
784
 
659
785
  /**
660
786
  * @license
@@ -671,6 +797,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
671
797
  * preview); this panel only re-attaches the times so a datetime range keeps the
672
798
  * hours the user set while the dates move around.
673
799
  *
800
+ * The steppers bind `WrTimePanel`'s own `value` model, NOT `[ngModel]`. The
801
+ * classic-forms bridge defers its first write, and under zoneless change
802
+ * detection that write lost the race with the panel's own echo guard: a range
803
+ * bound to 16:00–17:00 opened showing 00:00 on both ends, and the first click
804
+ * on a stepper committed midnight-plus-one over the real value.
805
+ *
674
806
  * @internal
675
807
  */
676
808
  class WrDateRangePanel {
@@ -690,7 +822,24 @@ class WrDateRangePanel {
690
822
  ...(ngDevMode ? [{ debugName: "showSeconds" }] : /* istanbul ignore next */ []));
691
823
  step = input(1, /* @ts-ignore */
692
824
  ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
825
+ /**
826
+ * Forwarded to the calendar only: a range panel opened from the keyboard
827
+ * lands on the day grid, never on a time field. Dates come first here — the
828
+ * steppers are for the range you have already drawn.
829
+ */
830
+ autoFocus = input(false, /* @ts-ignore */
831
+ ...(ngDevMode ? [{ debugName: "autoFocus" }] : /* istanbul ignore next */ []));
832
+ /** A range change from the CALENDAR — the picker is free to sort it. */
693
833
  changed = output();
834
+ /**
835
+ * A range change from one of the TIME steppers, which must NOT be sorted while
836
+ * it is happening. The steppers are bound to positions, so sorting mid-edit
837
+ * moves the user's change to the other end: raising a same-day start past the
838
+ * end left the start stuck and pushed the END up instead, once per click, on
839
+ * the button the user was not pressing. Ordering is settled when the popup
840
+ * closes — the same rule the text inputs already follow for typing.
841
+ */
842
+ timeChanged = output();
694
843
  adapter = inject(WrDateAdapter);
695
844
  startTimeLabel = readI18nText('datePicker.startTime', 'Start time');
696
845
  endTimeLabel = readI18nText('datePicker.endTime', 'End time');
@@ -745,7 +894,7 @@ class WrDateRangePanel {
745
894
  this.pendingStartTime.set(time);
746
895
  return;
747
896
  }
748
- this.changed.emit([this.withTimeOf(start, time), end]);
897
+ this.timeChanged.emit([this.withTimeOf(start, time), end]);
749
898
  }
750
899
  onEndTimeChange(time) {
751
900
  if (!time)
@@ -755,7 +904,7 @@ class WrDateRangePanel {
755
904
  this.pendingEndTime.set(time);
756
905
  return;
757
906
  }
758
- this.changed.emit([start, this.withTimeOf(end, time)]);
907
+ this.timeChanged.emit([start, this.withTimeOf(end, time)]);
759
908
  }
760
909
  /** `date`'s calendar day carrying `time`'s clock. Null date stays null. */
761
910
  withTimeOf(date, time) {
@@ -765,13 +914,13 @@ class WrDateRangePanel {
765
914
  return date;
766
915
  return this.adapter.setTime(this.adapter.createDate(this.adapter.getYear(date), this.adapter.getMonth(date), this.adapter.getDate(date)), this.adapter.getHours(time), this.adapter.getMinutes(time), this.adapter.getSeconds(time));
767
916
  }
768
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateRangePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
769
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrDateRangePanel, isStandalone: true, selector: "wr-date-range-panel", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, withTime: { classPropertyName: "withTime", publicName: "withTime", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { classAttribute: "wr-date-range-panel" }, ngImport: i0, template: "<wr-calendar\n mode=\"range\"\n [range]=\"calendarRange()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n (rangeChange)=\"onRangeChange($event)\"\n/>\n\n@if (withTime()) {\n <div class=\"wr-date-range-panel__times\">\n <!-- A time picker is several inputs, not one control, so each end is a\n labelled group rather than a <label>. -->\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"startTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ startTimeLabel }}</span>\n <wr-time-picker\n [ngModel]=\"startTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onStartTimeChange($event)\"\n />\n </div>\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"endTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ endTimeLabel }}</span>\n <wr-time-picker\n [ngModel]=\"endTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onEndTimeChange($event)\"\n />\n </div>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: WrCalendar, selector: "wr-calendar", inputs: ["mode", "date", "range", "min", "max", "dateFilter", "disabled"], outputs: ["dateChange", "rangeChange"] }, { kind: "component", type: WrTimePanel, selector: "wr-time-picker", inputs: ["format", "showSeconds", "step", "disabled", "readonly", "value"], outputs: ["valueChange", "touch"] }], encapsulation: i0.ViewEncapsulation.None });
917
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateRangePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
918
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrDateRangePanel, isStandalone: true, selector: "wr-date-range-panel", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, withTime: { classPropertyName: "withTime", publicName: "withTime", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed", timeChanged: "timeChanged" }, host: { classAttribute: "wr-date-range-panel" }, ngImport: i0, template: "<wr-calendar\n mode=\"range\"\n [range]=\"calendarRange()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n [autoFocus]=\"autoFocus()\"\n (rangeChange)=\"onRangeChange($event)\"\n/>\n\n@if (withTime()) {\n <div class=\"wr-date-range-panel__times\">\n <!-- A time picker is several inputs, not one control, so each end is a\n labelled group rather than a <label>. -->\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"startTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ startTimeLabel }}</span>\n <wr-time-picker\n [value]=\"startTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onStartTimeChange($event)\"\n />\n </div>\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"endTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ endTimeLabel }}</span>\n <wr-time-picker\n [value]=\"endTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onEndTimeChange($event)\"\n />\n </div>\n </div>\n}\n", dependencies: [{ kind: "component", type: WrCalendar, selector: "wr-calendar", inputs: ["mode", "date", "range", "min", "max", "dateFilter", "autoFocus", "disabled"], outputs: ["dateChange", "rangeChange"] }, { kind: "component", type: WrTimePanel, selector: "wr-time-picker", inputs: ["format", "showSeconds", "step", "disabled", "readonly", "autoFocus", "value"], outputs: ["valueChange", "touch"] }], encapsulation: i0.ViewEncapsulation.None });
770
919
  }
771
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateRangePanel, decorators: [{
920
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateRangePanel, decorators: [{
772
921
  type: Component,
773
- args: [{ selector: 'wr-date-range-panel', encapsulation: ViewEncapsulation.None, host: { class: 'wr-date-range-panel' }, imports: [FormsModule, WrCalendar, WrTimePanel], template: "<wr-calendar\n mode=\"range\"\n [range]=\"calendarRange()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n (rangeChange)=\"onRangeChange($event)\"\n/>\n\n@if (withTime()) {\n <div class=\"wr-date-range-panel__times\">\n <!-- A time picker is several inputs, not one control, so each end is a\n labelled group rather than a <label>. -->\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"startTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ startTimeLabel }}</span>\n <wr-time-picker\n [ngModel]=\"startTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onStartTimeChange($event)\"\n />\n </div>\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"endTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ endTimeLabel }}</span>\n <wr-time-picker\n [ngModel]=\"endTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onEndTimeChange($event)\"\n />\n </div>\n </div>\n}\n" }]
774
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], withTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "withTime", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
922
+ args: [{ selector: 'wr-date-range-panel', encapsulation: ViewEncapsulation.None, host: { class: 'wr-date-range-panel' }, imports: [WrCalendar, WrTimePanel], template: "<wr-calendar\n mode=\"range\"\n [range]=\"calendarRange()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n [autoFocus]=\"autoFocus()\"\n (rangeChange)=\"onRangeChange($event)\"\n/>\n\n@if (withTime()) {\n <div class=\"wr-date-range-panel__times\">\n <!-- A time picker is several inputs, not one control, so each end is a\n labelled group rather than a <label>. -->\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"startTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ startTimeLabel }}</span>\n <wr-time-picker\n [value]=\"startTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onStartTimeChange($event)\"\n />\n </div>\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"endTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ endTimeLabel }}</span>\n <wr-time-picker\n [value]=\"endTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onEndTimeChange($event)\"\n />\n </div>\n </div>\n}\n" }]
923
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], withTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "withTime", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }], timeChanged: [{ type: i0.Output, args: ["timeChanged"] }] } });
775
924
 
776
925
  /**
777
926
  * @license
@@ -779,6 +928,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
779
928
  * Use of this source code is governed by an MIT-style license that can be
780
929
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
781
930
  */
931
+ /** Per-instance popup ids, so `aria-controls` can point at one panel. */
932
+ let rangePanelUid = 0;
782
933
  /**
783
934
  * Date-range picker — two text inputs sharing one range calendar.
784
935
  *
@@ -861,7 +1012,17 @@ class WrDateRangePicker {
861
1012
  * @default false
862
1013
  */
863
1014
  disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
864
- /** Read-only — inputs not typeable, but the trigger icon still opens the overlay. @default false */
1015
+ /**
1016
+ * Read-only — neither the inputs nor the calendar can change the value.
1017
+ *
1018
+ * Deliberately stricter than `wr-date-picker`, which still opens its popup
1019
+ * while read-only: with two fields feeding one calendar there is no reading
1020
+ * of "untypeable" that leaves the grid free to rewrite both ends. The doc
1021
+ * used to promise the trigger still opened; the code has always refused, and
1022
+ * refusing is the behaviour worth keeping.
1023
+ *
1024
+ * @default false
1025
+ */
865
1026
  readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
866
1027
  adapter = inject(WrDateAdapter);
867
1028
  overlay = inject(WR_OVERLAY);
@@ -871,6 +1032,10 @@ class WrDateRangePicker {
871
1032
  destroyRef = inject(DestroyRef);
872
1033
  startEl = viewChild.required('startInput', /* @ts-ignore */
873
1034
  ...(ngDevMode ? [{ debugName: "startEl" }] : /* istanbul ignore next */ []));
1035
+ endEl = viewChild.required('endInput', /* @ts-ignore */
1036
+ ...(ngDevMode ? [{ debugName: "endEl" }] : /* istanbul ignore next */ []));
1037
+ triggerEl = viewChild('trigger', /* @ts-ignore */
1038
+ ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
874
1039
  /** The picked range. Bound by `[formField]`, or two-way via `[(value)]`. */
875
1040
  value = model(null, /* @ts-ignore */
876
1041
  ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
@@ -884,6 +1049,16 @@ class WrDateRangePicker {
884
1049
  /** Whether the popover is currently open. */
885
1050
  overlayOpen = signal(false, /* @ts-ignore */
886
1051
  ...(ngDevMode ? [{ debugName: "overlayOpen" }] : /* istanbul ignore next */ []));
1052
+ /**
1053
+ * Which element opened the popup — captured as an argument, never read off
1054
+ * `document.activeElement`, which by then may already be the pane. With TWO
1055
+ * text inputs this is the whole point: "restore focus to the field" is
1056
+ * ambiguous here, and the old code resolved it by always picking the START
1057
+ * input, so closing from the end input threw the caret across the control.
1058
+ */
1059
+ openedFrom = null;
1060
+ /** Whether the panel this open cycle should take focus. */
1061
+ autoFocusPanel = false;
887
1062
  /** Resolved format — falls back to a mode-appropriate default. */
888
1063
  resolvedFormat = computed(() => this.format() ? String(this.format()) : this.mode() === 'datetime' ? 'shortDateTime' : 'shortDate', /* @ts-ignore */
889
1064
  ...(ngDevMode ? [{ debugName: "resolvedFormat" }] : /* istanbul ignore next */ []));
@@ -892,6 +1067,25 @@ class WrDateRangePicker {
892
1067
  triggerLabel = readI18nText('datePicker.openRange', 'Open range calendar');
893
1068
  startLabel = readI18nText('datePicker.rangeStart', 'Range start');
894
1069
  endLabel = readI18nText('datePicker.rangeEnd', 'Range end');
1070
+ panelLabelRange = readI18nText('datePicker.panelRange', 'Choose date range');
1071
+ panelLabelRangeDateTime = readI18nText('datePicker.panelRangeDateTime', 'Choose date and time range');
1072
+ /**
1073
+ * Accessible name of the popup. The trigger advertises
1074
+ * `aria-haspopup="dialog"`, so the pane is a `role="dialog"` — and an unnamed
1075
+ * dialog announces as a bare "dialog". Defaults to the catalog's
1076
+ * `datePicker.panelRange*` string for the current `mode`.
1077
+ */
1078
+ panelAriaLabel = input(null, /* @ts-ignore */
1079
+ ...(ngDevMode ? [{ debugName: "panelAriaLabel" }] : /* istanbul ignore next */ []));
1080
+ /** Popup id — what the trigger's `aria-controls` points at while open. */
1081
+ panelId = `wr-date-range-picker-panel-${++rangePanelUid}`;
1082
+ resolvedPanelLabel = computed(() => {
1083
+ const explicit = this.panelAriaLabel();
1084
+ if (explicit)
1085
+ return explicit;
1086
+ return this.isDateTime() ? this.panelLabelRangeDateTime : this.panelLabelRange;
1087
+ }, /* @ts-ignore */
1088
+ ...(ngDevMode ? [{ debugName: "resolvedPanelLabel" }] : /* istanbul ignore next */ []));
895
1089
  classes = computed(() => {
896
1090
  const parts = ['wr-date-range-picker', `wr-date-range-picker--${this.mode()}`];
897
1091
  if (this.disabled())
@@ -954,30 +1148,83 @@ class WrDateRangePicker {
954
1148
  // control as touched once focus actually leaves it, or tabbing from start to
955
1149
  // end would mark a bound field touched mid-entry.
956
1150
  const next = event.relatedTarget;
957
- if (!next || !this.host.nativeElement.contains(next))
1151
+ const leaving = !next || !this.host.nativeElement.contains(next);
1152
+ if (leaving)
958
1153
  this.touch.emit();
959
1154
  // Typing leaves the ends in whatever order they were entered; settle it
960
- // here, once the user has stopped.
961
- const [start, end] = this.commitRange(this.current(), { normalise: true });
1155
+ // here, once the user has stopped — and moving from one end to the other is
1156
+ // NOT stopping. Sorting on that hop took the start date the user had just
1157
+ // typed and moved it into the field they were tabbing into, leaving the old
1158
+ // end date under their cursor. Same rule the time steppers follow.
1159
+ const [start, end] = this.commitRange(this.current(), { normalise: leaving });
962
1160
  // Reformat to canonical on blur (cleans up `1/5/25` → `1/5/2025`).
963
1161
  this.startText.set(this.display(start));
964
1162
  this.endText.set(this.display(end));
965
1163
  }
966
1164
  /** Called by an input's click — opens the overlay if it isn't open already. */
967
- openOnInput() {
1165
+ openOnInput(end) {
968
1166
  if (this.disabled() || this.readonly() || this.overlayRef)
969
1167
  return;
970
- this.openOverlay();
1168
+ // Deliberately WITHOUT focus: this click placed a caret in one of the text
1169
+ // fields, and pulling focus into the grid would throw that away.
1170
+ // `Alt+ArrowDown` / `ArrowDown` are the keyboard way in — see onFieldKey.
1171
+ this.openOverlay(this.fieldEl(end), false);
971
1172
  }
972
1173
  toggleOverlay() {
973
1174
  // `readonly` blocks the calendar too — otherwise the inputs refuse typing
974
1175
  // while the popover happily edits the same value.
975
1176
  if (this.disabled() || this.readonly())
976
1177
  return;
977
- if (this.overlayRef)
1178
+ if (this.overlayRef) {
1179
+ // Focus is already on the trigger — nothing to restore.
978
1180
  this.closeOverlay();
979
- else
980
- this.openOverlay();
1181
+ }
1182
+ else {
1183
+ this.openOverlay(this.triggerEl()?.nativeElement ?? null, true);
1184
+ }
1185
+ }
1186
+ /**
1187
+ * The keyboard route into the popup, per the APG date-picker pattern, and the
1188
+ * only one either field has. `Alt+ArrowDown` opens and takes focus; a bare
1189
+ * vertical arrow walks focus in when the popup is ALREADY open, which is how
1190
+ * someone who opened it by clicking a field reaches the grid. Every other key
1191
+ * belongs to the field, so typing a date keeps working with the popup open.
1192
+ */
1193
+ onFieldKey(event, end) {
1194
+ if (this.disabled() || this.readonly())
1195
+ return;
1196
+ const vertical = event.key === 'ArrowDown' || event.key === 'ArrowUp';
1197
+ if (!vertical)
1198
+ return;
1199
+ if (event.altKey && event.key === 'ArrowDown' && !this.overlayRef) {
1200
+ event.preventDefault();
1201
+ this.openOverlay(this.fieldEl(end), true);
1202
+ return;
1203
+ }
1204
+ if (this.overlayRef) {
1205
+ event.preventDefault();
1206
+ this.focusPanel();
1207
+ }
1208
+ }
1209
+ /** The input element for an end — the two are otherwise addressed by index. */
1210
+ fieldEl(end) {
1211
+ return end === 0 ? this.startEl().nativeElement : this.endEl().nativeElement;
1212
+ }
1213
+ /**
1214
+ * Move focus into an already-mounted panel. A plain query is right HERE and
1215
+ * wrong at mount time: the panel has settled, so there is no deferral to get
1216
+ * wrong — and it keeps `autoFocus` as the single piece of panel API.
1217
+ */
1218
+ focusPanel() {
1219
+ const pane = this.overlayRef?.overlayElement;
1220
+ const target = pane?.querySelector('.wr-calendar__day--focused:not([disabled])') ??
1221
+ pane?.querySelector('.wr-time-picker__input');
1222
+ target?.focus();
1223
+ }
1224
+ /** Hand focus back to whatever opened the popup, if it is still on the page. */
1225
+ restoreFocus() {
1226
+ const target = this.openedFrom?.isConnected ? this.openedFrom : this.startEl().nativeElement;
1227
+ target.focus();
981
1228
  }
982
1229
  // Input parsing
983
1230
  onRangeInput(event, end) {
@@ -997,9 +1244,11 @@ class WrDateRangePicker {
997
1244
  this.commitRange(end === 0 ? [parsed, finish] : [start, parsed], { normalise: false });
998
1245
  }
999
1246
  // Overlay
1000
- openOverlay() {
1247
+ openOverlay(openedFrom = null, autoFocus = false) {
1001
1248
  if (this.overlayRef)
1002
1249
  return;
1250
+ this.openedFrom = openedFrom;
1251
+ this.autoFocusPanel = autoFocus;
1003
1252
  const positionStrategy = this.overlay
1004
1253
  .position()
1005
1254
  .flexibleConnectedTo(this.host)
@@ -1016,9 +1265,22 @@ class WrDateRangePicker {
1016
1265
  panelClass: 'wr-date-picker-overlay',
1017
1266
  });
1018
1267
  this.overlayOpen.set(true);
1268
+ // The trigger promises `aria-haspopup="dialog"`; the pane is the element it
1269
+ // points at, so the role, the name and the id all belong here. Non-modal on
1270
+ // purpose — the two text fields stay reachable while the calendar is up,
1271
+ // which is the whole interaction model.
1272
+ const pane = this.overlayRef.overlayElement;
1273
+ pane.id = this.panelId;
1274
+ pane.setAttribute('role', 'dialog');
1275
+ pane.setAttribute('aria-modal', 'false');
1276
+ pane.setAttribute('aria-label', this.resolvedPanelLabel());
1019
1277
  const ref = this.overlayRef.attach(new ComponentPortal(WrDateRangePanel));
1020
1278
  ref.setInput('value', this.value() ?? [null, null]);
1279
+ ref.setInput('autoFocus', this.autoFocusPanel);
1021
1280
  this.panelRef.set(ref);
1281
+ // A stepper edit belongs to the end it was made on. Sorting it here is what
1282
+ // made the start stepper stop responding once it passed the end.
1283
+ ref.instance.timeChanged.subscribe(next => this.commitRange(next, { normalise: false }));
1022
1284
  ref.instance.changed.subscribe(next => {
1023
1285
  const committed = this.commitRange(next, { normalise: true });
1024
1286
  // A complete date-only range is the end of the interaction; a datetime
@@ -1041,21 +1303,31 @@ class WrDateRangePicker {
1041
1303
  if (event.key === 'Escape') {
1042
1304
  event.preventDefault();
1043
1305
  this.closeOverlay();
1044
- this.startEl().nativeElement.focus();
1045
1306
  }
1046
1307
  });
1047
1308
  }
1048
1309
  /**
1049
- * Close the popover. `restoreFocus` returns focus to the start input — needed
1050
- * when the overlay is dismissed while focus lives inside it (picking the
1051
- * second date), because disposing then leaves focus on a removed element and
1052
- * the browser falls back to `<body>`.
1310
+ * Close the popover, handing focus back to whichever field or button opened
1311
+ * it — but ONLY when focus was still inside the pane. Dropped there it would
1312
+ * land on `<body>` and the next Tab would restart from the top of the page;
1313
+ * moved on by the user, it must be left where they put it.
1314
+ *
1315
+ * There is deliberately no "always restore" escape hatch. Escape reaches this
1316
+ * overlay from anywhere in the document (the CDK dispatches it to the topmost
1317
+ * one), so forcing a restore would drag the caret backwards out of the field
1318
+ * the user was actually typing in — into the one that happened to open the
1319
+ * popup, possibly several Tab stops away.
1053
1320
  */
1054
- closeOverlay(restoreFocus = false) {
1055
- const inside = this.overlayRef?.overlayElement.contains(this.host.nativeElement.ownerDocument.activeElement);
1321
+ closeOverlay() {
1322
+ const pane = this.overlayRef?.overlayElement;
1323
+ const inside = !!pane && pane.contains(this.host.nativeElement.ownerDocument.activeElement);
1056
1324
  this.dispose();
1057
- if (restoreFocus || inside)
1058
- this.startEl().nativeElement.focus();
1325
+ // The interaction is over, so settle the ordering an in-progress time edit
1326
+ // was allowed to leave inverted. Blur does the same for the text inputs;
1327
+ // without this, closing by clicking outside never passes through one.
1328
+ this.commitRange(this.current(), { normalise: true });
1329
+ if (inside)
1330
+ this.restoreFocus();
1059
1331
  }
1060
1332
  dispose() {
1061
1333
  if (this.overlayRef) {
@@ -1064,6 +1336,7 @@ class WrDateRangePicker {
1064
1336
  }
1065
1337
  this.panelRef.set(null);
1066
1338
  this.overlayOpen.set(false);
1339
+ this.autoFocusPanel = false;
1067
1340
  }
1068
1341
  // Commit
1069
1342
  /**
@@ -1150,20 +1423,29 @@ class WrDateRangePicker {
1150
1423
  return false;
1151
1424
  return a.getTime() === b.getTime();
1152
1425
  }
1426
+ /**
1427
+ * `null` and `[null, null]` are the same VALUE — an empty range — and treating
1428
+ * them as different is what let the FIRST blur on an untouched picker write
1429
+ * `[null, null]` over the `null` it was bound to. No date had moved, but
1430
+ * `model()` emitted: a bound `[formField]` went dirty from nothing but tabbing
1431
+ * through, and a consumer's `@if (period())` flipped from empty to truthy with
1432
+ * neither end picked. The write guard in `commitRange` is only as good as this
1433
+ * comparison.
1434
+ */
1153
1435
  sameRange(a, b) {
1154
1436
  if (a === b)
1155
1437
  return true;
1156
- if (!a || !b)
1157
- return false;
1158
- return this.sameDate(a[0], b[0]) && this.sameDate(a[1], b[1]);
1438
+ const [aStart, aEnd] = a ?? [null, null];
1439
+ const [bStart, bEnd] = b ?? [null, null];
1440
+ return this.sameDate(aStart, bStart) && this.sameDate(aEnd, bEnd);
1159
1441
  }
1160
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateRangePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
1161
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrDateRangePicker, isStandalone: true, selector: "wr-date-range-picker", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, startPlaceholder: { classPropertyName: "startPlaceholder", publicName: "startPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, endPlaceholder: { classPropertyName: "endPlaceholder", publicName: "endPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "startEl", first: true, predicate: ["startInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<wr-input-group>\n <input\n #startInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"startLabel\"\n [value]=\"startText()\"\n [placeholder]=\"startPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onStartInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <span class=\"wr-date-range-picker__separator\" aria-hidden=\"true\">{{ separator() }}</span>\n <input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"endLabel\"\n [value]=\"endText()\"\n [placeholder]=\"endPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onEndInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <button\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n </button>\n</wr-input-group>\n", dependencies: [{ kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["wrSize", "rounded"] }, { kind: "component", type: WrInputGroup, selector: "wr-input-group", inputs: ["rounded"] }, { kind: "directive", type: WrInputSuffix, selector: "[wrInputSuffix]" }], encapsulation: i0.ViewEncapsulation.None });
1442
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateRangePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
1443
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrDateRangePicker, isStandalone: true, selector: "wr-date-range-picker", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, startPlaceholder: { classPropertyName: "startPlaceholder", publicName: "startPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, endPlaceholder: { classPropertyName: "endPlaceholder", publicName: "endPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, panelAriaLabel: { classPropertyName: "panelAriaLabel", publicName: "panelAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "startEl", first: true, predicate: ["startInput"], descendants: true, isSignal: true }, { propertyName: "endEl", first: true, predicate: ["endInput"], descendants: true, isSignal: true }, { propertyName: "triggerEl", first: true, predicate: ["trigger"], descendants: true, isSignal: true }], ngImport: i0, template: "<wr-input-group>\n <input\n #startInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"startLabel\"\n [value]=\"startText()\"\n [placeholder]=\"startPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput(0)\"\n (keydown)=\"onFieldKey($event, 0)\"\n (input)=\"onStartInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <span class=\"wr-date-range-picker__separator\" aria-hidden=\"true\">{{ separator() }}</span>\n <input\n #endInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"endLabel\"\n [value]=\"endText()\"\n [placeholder]=\"endPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput(1)\"\n (keydown)=\"onFieldKey($event, 1)\"\n (input)=\"onEndInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <!--\n `readonly` refuses to open the popup, so the trigger is disabled with it \u2014\n otherwise it stays a focusable button advertising `aria-haspopup=\"dialog\"`\n for a dialog it will never show.\n -->\n <button\n #trigger\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [attr.aria-controls]=\"overlayOpen() ? panelId : null\"\n [disabled]=\"disabled() || readonly()\"\n (click)=\"toggleOverlay()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n </button>\n</wr-input-group>\n", dependencies: [{ kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["wrSize", "rounded"] }, { kind: "component", type: WrInputGroup, selector: "wr-input-group", inputs: ["rounded"] }, { kind: "directive", type: WrInputSuffix, selector: "[wrInputSuffix]" }], encapsulation: i0.ViewEncapsulation.None });
1162
1444
  }
1163
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateRangePicker, decorators: [{
1445
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateRangePicker, decorators: [{
1164
1446
  type: Component,
1165
- args: [{ selector: 'wr-date-range-picker', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrInput, WrInputGroup, WrInputSuffix], template: "<wr-input-group>\n <input\n #startInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"startLabel\"\n [value]=\"startText()\"\n [placeholder]=\"startPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onStartInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <span class=\"wr-date-range-picker__separator\" aria-hidden=\"true\">{{ separator() }}</span>\n <input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"endLabel\"\n [value]=\"endText()\"\n [placeholder]=\"endPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onEndInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <button\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n </button>\n</wr-input-group>\n" }]
1166
- }], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], startPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "startPlaceholder", required: false }] }], endPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "endPlaceholder", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], startEl: [{ type: i0.ViewChild, args: ['startInput', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
1447
+ args: [{ selector: 'wr-date-range-picker', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrInput, WrInputGroup, WrInputSuffix], template: "<wr-input-group>\n <input\n #startInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"startLabel\"\n [value]=\"startText()\"\n [placeholder]=\"startPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput(0)\"\n (keydown)=\"onFieldKey($event, 0)\"\n (input)=\"onStartInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <span class=\"wr-date-range-picker__separator\" aria-hidden=\"true\">{{ separator() }}</span>\n <input\n #endInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"endLabel\"\n [value]=\"endText()\"\n [placeholder]=\"endPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput(1)\"\n (keydown)=\"onFieldKey($event, 1)\"\n (input)=\"onEndInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <!--\n `readonly` refuses to open the popup, so the trigger is disabled with it \u2014\n otherwise it stays a focusable button advertising `aria-haspopup=\"dialog\"`\n for a dialog it will never show.\n -->\n <button\n #trigger\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [attr.aria-controls]=\"overlayOpen() ? panelId : null\"\n [disabled]=\"disabled() || readonly()\"\n (click)=\"toggleOverlay()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n </button>\n</wr-input-group>\n" }]
1448
+ }], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], startPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "startPlaceholder", required: false }] }], endPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "endPlaceholder", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], startEl: [{ type: i0.ViewChild, args: ['startInput', { isSignal: true }] }], endEl: [{ type: i0.ViewChild, args: ['endInput', { isSignal: true }] }], triggerEl: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }], panelAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelAriaLabel", required: false }] }] } });
1167
1449
 
1168
1450
  /**
1169
1451
  * Generated bundle index. Do not edit.