@angular/material 21.0.0-next.9 → 21.0.0-rc.0

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 (202) hide show
  1. package/core/tokens/_classes.scss +1 -1
  2. package/core/tokens/m2/_md-sys-color.scss +17 -17
  3. package/fesm2022/_animation-chunk.mjs +10 -16
  4. package/fesm2022/_animation-chunk.mjs.map +1 -1
  5. package/fesm2022/_date-formats-chunk.mjs +68 -164
  6. package/fesm2022/_date-formats-chunk.mjs.map +1 -1
  7. package/fesm2022/_date-range-input-harness-chunk.mjs +284 -463
  8. package/fesm2022/_date-range-input-harness-chunk.mjs.map +1 -1
  9. package/fesm2022/_error-options-chunk.mjs +56 -19
  10. package/fesm2022/_error-options-chunk.mjs.map +1 -1
  11. package/fesm2022/_error-state-chunk.mjs +24 -31
  12. package/fesm2022/_error-state-chunk.mjs.map +1 -1
  13. package/fesm2022/_form-field-chunk.mjs +1224 -1017
  14. package/fesm2022/_form-field-chunk.mjs.map +1 -1
  15. package/fesm2022/_icon-button-chunk.mjs +243 -187
  16. package/fesm2022/_icon-button-chunk.mjs.map +1 -1
  17. package/fesm2022/_icon-registry-chunk.mjs +350 -575
  18. package/fesm2022/_icon-registry-chunk.mjs.map +1 -1
  19. package/fesm2022/_input-harness-chunk.mjs +56 -107
  20. package/fesm2022/_input-harness-chunk.mjs.map +1 -1
  21. package/fesm2022/_input-value-accessor-chunk.mjs +0 -6
  22. package/fesm2022/_input-value-accessor-chunk.mjs.map +1 -1
  23. package/fesm2022/_internal-form-field-chunk.mjs +59 -19
  24. package/fesm2022/_internal-form-field-chunk.mjs.map +1 -1
  25. package/fesm2022/_line-chunk.mjs +83 -43
  26. package/fesm2022/_line-chunk.mjs.map +1 -1
  27. package/fesm2022/_option-chunk.mjs +348 -311
  28. package/fesm2022/_option-chunk.mjs.map +1 -1
  29. package/fesm2022/_option-harness-chunk.mjs +23 -39
  30. package/fesm2022/_option-harness-chunk.mjs.map +1 -1
  31. package/fesm2022/_option-module-chunk.mjs +36 -10
  32. package/fesm2022/_option-module-chunk.mjs.map +1 -1
  33. package/fesm2022/_pseudo-checkbox-chunk.mjs +79 -44
  34. package/fesm2022/_pseudo-checkbox-chunk.mjs.map +1 -1
  35. package/fesm2022/_pseudo-checkbox-module-chunk.mjs +36 -10
  36. package/fesm2022/_pseudo-checkbox-module-chunk.mjs.map +1 -1
  37. package/fesm2022/_public-api-chunk.mjs +71 -134
  38. package/fesm2022/_public-api-chunk.mjs.map +1 -1
  39. package/fesm2022/_ripple-chunk.mjs +504 -600
  40. package/fesm2022/_ripple-chunk.mjs.map +1 -1
  41. package/fesm2022/_ripple-loader-chunk.mjs +120 -138
  42. package/fesm2022/_ripple-loader-chunk.mjs.map +1 -1
  43. package/fesm2022/_ripple-module-chunk.mjs +36 -10
  44. package/fesm2022/_ripple-module-chunk.mjs.map +1 -1
  45. package/fesm2022/_structural-styles-chunk.mjs +37 -10
  46. package/fesm2022/_structural-styles-chunk.mjs.map +1 -1
  47. package/fesm2022/_tooltip-chunk.mjs +810 -888
  48. package/fesm2022/_tooltip-chunk.mjs.map +1 -1
  49. package/fesm2022/autocomplete-testing.mjs +62 -86
  50. package/fesm2022/autocomplete-testing.mjs.map +1 -1
  51. package/fesm2022/autocomplete.mjs +965 -1126
  52. package/fesm2022/autocomplete.mjs.map +1 -1
  53. package/fesm2022/badge-testing.mjs +38 -54
  54. package/fesm2022/badge-testing.mjs.map +1 -1
  55. package/fesm2022/badge.mjs +321 -272
  56. package/fesm2022/badge.mjs.map +1 -1
  57. package/fesm2022/bottom-sheet-testing.mjs +10 -24
  58. package/fesm2022/bottom-sheet-testing.mjs.map +1 -1
  59. package/fesm2022/bottom-sheet.mjs +349 -344
  60. package/fesm2022/bottom-sheet.mjs.map +1 -1
  61. package/fesm2022/button-testing.mjs +60 -94
  62. package/fesm2022/button-testing.mjs.map +1 -1
  63. package/fesm2022/button-toggle-testing.mjs +76 -125
  64. package/fesm2022/button-toggle-testing.mjs.map +1 -1
  65. package/fesm2022/button-toggle.mjs +752 -662
  66. package/fesm2022/button-toggle.mjs.map +1 -1
  67. package/fesm2022/button.mjs +263 -158
  68. package/fesm2022/button.mjs.map +1 -1
  69. package/fesm2022/card-testing.mjs +19 -33
  70. package/fesm2022/card-testing.mjs.map +1 -1
  71. package/fesm2022/card.mjs +576 -272
  72. package/fesm2022/card.mjs.map +1 -1
  73. package/fesm2022/checkbox-testing.mjs +71 -123
  74. package/fesm2022/checkbox-testing.mjs.map +1 -1
  75. package/fesm2022/checkbox.mjs +515 -477
  76. package/fesm2022/checkbox.mjs.map +1 -1
  77. package/fesm2022/chips-testing.mjs +201 -344
  78. package/fesm2022/chips-testing.mjs.map +1 -1
  79. package/fesm2022/chips.mjs +2552 -2289
  80. package/fesm2022/chips.mjs.map +1 -1
  81. package/fesm2022/core-testing.mjs +14 -28
  82. package/fesm2022/core-testing.mjs.map +1 -1
  83. package/fesm2022/core.mjs +357 -328
  84. package/fesm2022/core.mjs.map +1 -1
  85. package/fesm2022/datepicker-testing.mjs +15 -25
  86. package/fesm2022/datepicker-testing.mjs.map +1 -1
  87. package/fesm2022/datepicker.mjs +4826 -4563
  88. package/fesm2022/datepicker.mjs.map +1 -1
  89. package/fesm2022/dialog-testing.mjs +93 -129
  90. package/fesm2022/dialog-testing.mjs.map +1 -1
  91. package/fesm2022/dialog.mjs +810 -829
  92. package/fesm2022/dialog.mjs.map +1 -1
  93. package/fesm2022/divider-testing.mjs +10 -11
  94. package/fesm2022/divider-testing.mjs.map +1 -1
  95. package/fesm2022/divider.mjs +119 -43
  96. package/fesm2022/divider.mjs.map +1 -1
  97. package/fesm2022/expansion-testing.mjs +74 -130
  98. package/fesm2022/expansion-testing.mjs.map +1 -1
  99. package/fesm2022/expansion.mjs +703 -515
  100. package/fesm2022/expansion.mjs.map +1 -1
  101. package/fesm2022/form-field-testing-control.mjs +16 -33
  102. package/fesm2022/form-field-testing-control.mjs.map +1 -1
  103. package/fesm2022/form-field-testing.mjs +118 -179
  104. package/fesm2022/form-field-testing.mjs.map +1 -1
  105. package/fesm2022/form-field.mjs +36 -10
  106. package/fesm2022/form-field.mjs.map +1 -1
  107. package/fesm2022/grid-list-testing.mjs +65 -113
  108. package/fesm2022/grid-list-testing.mjs.map +1 -1
  109. package/fesm2022/grid-list.mjs +559 -494
  110. package/fesm2022/grid-list.mjs.map +1 -1
  111. package/fesm2022/icon-testing.mjs +148 -127
  112. package/fesm2022/icon-testing.mjs.map +1 -1
  113. package/fesm2022/icon.mjs +325 -351
  114. package/fesm2022/icon.mjs.map +1 -1
  115. package/fesm2022/input-testing.mjs +59 -99
  116. package/fesm2022/input-testing.mjs.map +1 -1
  117. package/fesm2022/input.mjs +457 -520
  118. package/fesm2022/input.mjs.map +1 -1
  119. package/fesm2022/list-testing.mjs +251 -434
  120. package/fesm2022/list-testing.mjs.map +1 -1
  121. package/fesm2022/list.mjs +1522 -1204
  122. package/fesm2022/list.mjs.map +1 -1
  123. package/fesm2022/material.mjs +0 -5
  124. package/fesm2022/material.mjs.map +1 -1
  125. package/fesm2022/menu-testing.mjs +159 -228
  126. package/fesm2022/menu-testing.mjs.map +1 -1
  127. package/fesm2022/menu.mjs +1338 -1343
  128. package/fesm2022/menu.mjs.map +1 -1
  129. package/fesm2022/paginator-testing.mjs +55 -79
  130. package/fesm2022/paginator-testing.mjs.map +1 -1
  131. package/fesm2022/paginator.mjs +381 -309
  132. package/fesm2022/paginator.mjs.map +1 -1
  133. package/fesm2022/progress-bar-testing.mjs +12 -21
  134. package/fesm2022/progress-bar-testing.mjs.map +1 -1
  135. package/fesm2022/progress-bar.mjs +224 -169
  136. package/fesm2022/progress-bar.mjs.map +1 -1
  137. package/fesm2022/progress-spinner-testing.mjs +13 -23
  138. package/fesm2022/progress-spinner-testing.mjs.map +1 -1
  139. package/fesm2022/progress-spinner.mjs +235 -160
  140. package/fesm2022/progress-spinner.mjs.map +1 -1
  141. package/fesm2022/radio-testing.mjs +133 -208
  142. package/fesm2022/radio-testing.mjs.map +1 -1
  143. package/fesm2022/radio.mjs +712 -679
  144. package/fesm2022/radio.mjs.map +1 -1
  145. package/fesm2022/select-testing.mjs +83 -117
  146. package/fesm2022/select-testing.mjs.map +1 -1
  147. package/fesm2022/select.mjs +1116 -1246
  148. package/fesm2022/select.mjs.map +1 -1
  149. package/fesm2022/sidenav-testing.mjs +54 -120
  150. package/fesm2022/sidenav-testing.mjs.map +1 -1
  151. package/fesm2022/sidenav.mjs +1078 -995
  152. package/fesm2022/sidenav.mjs.map +1 -1
  153. package/fesm2022/slide-toggle-testing.mjs +57 -92
  154. package/fesm2022/slide-toggle-testing.mjs.map +1 -1
  155. package/fesm2022/slide-toggle.mjs +369 -279
  156. package/fesm2022/slide-toggle.mjs.map +1 -1
  157. package/fesm2022/slider-testing.mjs +90 -138
  158. package/fesm2022/slider-testing.mjs.map +1 -1
  159. package/fesm2022/slider.mjs +1651 -1716
  160. package/fesm2022/slider.mjs.map +1 -1
  161. package/fesm2022/snack-bar-testing.mjs +40 -87
  162. package/fesm2022/snack-bar-testing.mjs.map +1 -1
  163. package/fesm2022/snack-bar.mjs +763 -714
  164. package/fesm2022/snack-bar.mjs.map +1 -1
  165. package/fesm2022/sort-testing.mjs +45 -66
  166. package/fesm2022/sort-testing.mjs.map +1 -1
  167. package/fesm2022/sort.mjs +419 -344
  168. package/fesm2022/sort.mjs.map +1 -1
  169. package/fesm2022/stepper-testing.mjs +78 -154
  170. package/fesm2022/stepper-testing.mjs.map +1 -1
  171. package/fesm2022/stepper.mjs +790 -498
  172. package/fesm2022/stepper.mjs.map +1 -1
  173. package/fesm2022/table-testing.mjs +120 -213
  174. package/fesm2022/table-testing.mjs.map +1 -1
  175. package/fesm2022/table.mjs +1026 -684
  176. package/fesm2022/table.mjs.map +1 -1
  177. package/fesm2022/tabs-testing.mjs +125 -197
  178. package/fesm2022/tabs-testing.mjs.map +1 -1
  179. package/fesm2022/tabs.mjs +2351 -2028
  180. package/fesm2022/tabs.mjs.map +1 -1
  181. package/fesm2022/timepicker-testing.mjs +113 -172
  182. package/fesm2022/timepicker-testing.mjs.map +1 -1
  183. package/fesm2022/timepicker.mjs +1019 -826
  184. package/fesm2022/timepicker.mjs.map +1 -1
  185. package/fesm2022/toolbar-testing.mjs +16 -27
  186. package/fesm2022/toolbar-testing.mjs.map +1 -1
  187. package/fesm2022/toolbar.mjs +163 -78
  188. package/fesm2022/toolbar.mjs.map +1 -1
  189. package/fesm2022/tooltip-testing.mjs +41 -52
  190. package/fesm2022/tooltip-testing.mjs.map +1 -1
  191. package/fesm2022/tooltip.mjs +36 -10
  192. package/fesm2022/tooltip.mjs.map +1 -1
  193. package/fesm2022/tree-testing.mjs +86 -162
  194. package/fesm2022/tree-testing.mjs.map +1 -1
  195. package/fesm2022/tree.mjs +638 -466
  196. package/fesm2022/tree.mjs.map +1 -1
  197. package/package.json +2 -2
  198. package/schematics/ng-add/index.js +1 -1
  199. package/types/expansion.d.ts +4 -2
  200. package/types/menu-testing.d.ts +2 -0
  201. package/types/select.d.ts +1 -1
  202. package/types/timepicker.d.ts +1 -0
@@ -26,887 +26,1080 @@ import 'rxjs/operators';
26
26
  import '@angular/cdk/observers/private';
27
27
  import './_ripple-loader-chunk.mjs';
28
28
 
29
- /** Pattern that interval strings have to match. */
30
29
  const INTERVAL_PATTERN = /^(\d*\.?\d+)\s*(h|hour|hours|m|min|minute|minutes|s|second|seconds)?$/i;
31
- /**
32
- * Injection token that can be used to configure the default options for the timepicker component.
33
- */
34
30
  const MAT_TIMEPICKER_CONFIG = new InjectionToken('MAT_TIMEPICKER_CONFIG');
35
- /** Parses an interval value into seconds. */
36
31
  function parseInterval(value) {
37
- let result;
38
- if (value === null) {
39
- return null;
32
+ let result;
33
+ if (value === null) {
34
+ return null;
35
+ } else if (typeof value === 'number') {
36
+ result = value;
37
+ } else {
38
+ if (value.trim().length === 0) {
39
+ return null;
40
40
  }
41
- else if (typeof value === 'number') {
42
- result = value;
41
+ const parsed = value.match(INTERVAL_PATTERN);
42
+ const amount = parsed ? parseFloat(parsed[1]) : null;
43
+ const unit = parsed?.[2]?.toLowerCase() || null;
44
+ if (!parsed || amount === null || isNaN(amount)) {
45
+ return null;
43
46
  }
44
- else {
45
- if (value.trim().length === 0) {
46
- return null;
47
- }
48
- const parsed = value.match(INTERVAL_PATTERN);
49
- const amount = parsed ? parseFloat(parsed[1]) : null;
50
- const unit = parsed?.[2]?.toLowerCase() || null;
51
- if (!parsed || amount === null || isNaN(amount)) {
52
- return null;
53
- }
54
- if (unit === 'h' || unit === 'hour' || unit === 'hours') {
55
- result = amount * 3600;
56
- }
57
- else if (unit === 'm' || unit === 'min' || unit === 'minute' || unit === 'minutes') {
58
- result = amount * 60;
59
- }
60
- else {
61
- result = amount;
62
- }
47
+ if (unit === 'h' || unit === 'hour' || unit === 'hours') {
48
+ result = amount * 3600;
49
+ } else if (unit === 'm' || unit === 'min' || unit === 'minute' || unit === 'minutes') {
50
+ result = amount * 60;
51
+ } else {
52
+ result = amount;
63
53
  }
64
- return result;
54
+ }
55
+ return result;
65
56
  }
66
- /**
67
- * Generates the options to show in a timepicker.
68
- * @param adapter Date adapter to be used to generate the options.
69
- * @param formats Formatting config to use when displaying the options.
70
- * @param min Time from which to start generating the options.
71
- * @param max Time at which to stop generating the options.
72
- * @param interval Amount of seconds between each option.
73
- */
74
57
  function generateOptions(adapter, formats, min, max, interval) {
75
- const options = [];
76
- let current = adapter.compareTime(min, max) < 1 ? min : max;
77
- while (adapter.sameDate(current, min) &&
78
- adapter.compareTime(current, max) < 1 &&
79
- adapter.isValid(current)) {
80
- options.push({ value: current, label: adapter.format(current, formats.display.timeOptionLabel) });
81
- current = adapter.addSeconds(current, interval);
82
- }
83
- return options;
58
+ const options = [];
59
+ let current = adapter.compareTime(min, max) < 1 ? min : max;
60
+ while (adapter.sameDate(current, min) && adapter.compareTime(current, max) < 1 && adapter.isValid(current)) {
61
+ options.push({
62
+ value: current,
63
+ label: adapter.format(current, formats.display.timeOptionLabel)
64
+ });
65
+ current = adapter.addSeconds(current, interval);
66
+ }
67
+ return options;
84
68
  }
85
- /** Checks whether a date adapter is set up correctly for use with the timepicker. */
86
69
  function validateAdapter(adapter, formats) {
87
- function missingAdapterError(provider) {
88
- return Error(`MatTimepicker: No provider found for ${provider}. You must add one of the following ` +
89
- `to your app config: provideNativeDateAdapter, provideDateFnsAdapter, ` +
90
- `provideLuxonDateAdapter, provideMomentDateAdapter, or provide a custom implementation.`);
91
- }
92
- if (!adapter) {
93
- throw missingAdapterError('DateAdapter');
94
- }
95
- if (!formats) {
96
- throw missingAdapterError('MAT_DATE_FORMATS');
97
- }
98
- if (formats.display.timeInput === undefined ||
99
- formats.display.timeOptionLabel === undefined ||
100
- formats.parse.timeInput === undefined) {
101
- throw new Error('MatTimepicker: Incomplete `MAT_DATE_FORMATS` has been provided. ' +
102
- '`MAT_DATE_FORMATS` must provide `display.timeInput`, `display.timeOptionLabel` ' +
103
- 'and `parse.timeInput` formats in order to be compatible with MatTimepicker.');
104
- }
70
+ function missingAdapterError(provider) {
71
+ return Error(`MatTimepicker: No provider found for ${provider}. You must add one of the following ` + `to your app config: provideNativeDateAdapter, provideDateFnsAdapter, ` + `provideLuxonDateAdapter, provideMomentDateAdapter, or provide a custom implementation.`);
72
+ }
73
+ if (!adapter) {
74
+ throw missingAdapterError('DateAdapter');
75
+ }
76
+ if (!formats) {
77
+ throw missingAdapterError('MAT_DATE_FORMATS');
78
+ }
79
+ if (formats.display.timeInput === undefined || formats.display.timeOptionLabel === undefined || formats.parse.timeInput === undefined) {
80
+ throw new Error('MatTimepicker: Incomplete `MAT_DATE_FORMATS` has been provided. ' + '`MAT_DATE_FORMATS` must provide `display.timeInput`, `display.timeOptionLabel` ' + 'and `parse.timeInput` formats in order to be compatible with MatTimepicker.');
81
+ }
105
82
  }
106
83
 
107
- /** Injection token used to configure the behavior of the timepicker dropdown while scrolling. */
108
84
  const MAT_TIMEPICKER_SCROLL_STRATEGY = new InjectionToken('MAT_TIMEPICKER_SCROLL_STRATEGY', {
109
- providedIn: 'root',
110
- factory: () => {
111
- const injector = inject(Injector);
112
- return () => createRepositionScrollStrategy(injector);
113
- },
85
+ providedIn: 'root',
86
+ factory: () => {
87
+ const injector = inject(Injector);
88
+ return () => createRepositionScrollStrategy(injector);
89
+ }
114
90
  });
115
- /**
116
- * Renders out a listbox that can be used to select a time of day.
117
- * Intended to be used together with `MatTimepickerInput`.
118
- */
119
91
  class MatTimepicker {
120
- _dir = inject(Directionality, { optional: true });
121
- _viewContainerRef = inject(ViewContainerRef);
122
- _injector = inject(Injector);
123
- _defaultConfig = inject(MAT_TIMEPICKER_CONFIG, { optional: true });
124
- _dateAdapter = inject(DateAdapter, { optional: true });
125
- _dateFormats = inject(MAT_DATE_FORMATS, { optional: true });
126
- _scrollStrategyFactory = inject(MAT_TIMEPICKER_SCROLL_STRATEGY);
127
- _animationsDisabled = _animationsDisabled();
128
- _isOpen = signal(false, ...(ngDevMode ? [{ debugName: "_isOpen" }] : []));
129
- _activeDescendant = signal(null, ...(ngDevMode ? [{ debugName: "_activeDescendant" }] : []));
130
- _input = signal(null, ...(ngDevMode ? [{ debugName: "_input" }] : []));
131
- _overlayRef = null;
132
- _portal = null;
133
- _optionsCacheKey = null;
134
- _localeChanges;
135
- _onOpenRender = null;
136
- _panelTemplate = viewChild.required('panelTemplate');
137
- _timeOptions = [];
138
- _options = viewChildren(MatOption, ...(ngDevMode ? [{ debugName: "_options" }] : []));
139
- _keyManager = new ActiveDescendantKeyManager(this._options, this._injector)
140
- .withHomeAndEnd(true)
141
- .withPageUpDown(true)
142
- .withVerticalOrientation(true);
143
- /**
144
- * Interval between each option in the timepicker. The value can either be an amount of
145
- * seconds (e.g. 90) or a number with a unit (e.g. 45m). Supported units are `s` for seconds,
146
- * `m` for minutes or `h` for hours.
147
- */
148
- interval = input(parseInterval(this._defaultConfig?.interval || null), ...(ngDevMode ? [{ debugName: "interval", transform: parseInterval }] : [{ transform: parseInterval }]));
149
- /**
150
- * Array of pre-defined options that the user can select from, as an alternative to using the
151
- * `interval` input. An error will be thrown if both `options` and `interval` are specified.
152
- */
153
- options = input(null, ...(ngDevMode ? [{ debugName: "options" }] : []));
154
- /** Whether the timepicker is open. */
155
- isOpen = this._isOpen.asReadonly();
156
- /** Emits when the user selects a time. */
157
- selected = output();
158
- /** Emits when the timepicker is opened. */
159
- opened = output();
160
- /** Emits when the timepicker is closed. */
161
- closed = output();
162
- /** ID of the active descendant option. */
163
- activeDescendant = this._activeDescendant.asReadonly();
164
- /** Unique ID of the timepicker's panel */
165
- panelId = inject(_IdGenerator).getId('mat-timepicker-panel-');
166
- /** Whether ripples within the timepicker should be disabled. */
167
- disableRipple = input(this._defaultConfig?.disableRipple ?? false, ...(ngDevMode ? [{ debugName: "disableRipple", transform: booleanAttribute }] : [{
168
- transform: booleanAttribute,
169
- }]));
170
- /** ARIA label for the timepicker panel. */
171
- ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel", alias: 'aria-label' }] : [{
172
- alias: 'aria-label',
173
- }]));
174
- /** ID of the label element for the timepicker panel. */
175
- ariaLabelledby = input(null, ...(ngDevMode ? [{ debugName: "ariaLabelledby", alias: 'aria-labelledby' }] : [{
176
- alias: 'aria-labelledby',
177
- }]));
178
- /** Whether the timepicker is currently disabled. */
179
- disabled = computed(() => !!this._input()?.disabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
180
- constructor() {
181
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
182
- validateAdapter(this._dateAdapter, this._dateFormats);
183
- effect(() => {
184
- const options = this.options();
185
- const interval = this.interval();
186
- if (options !== null && interval !== null) {
187
- throw new Error('Cannot specify both the `options` and `interval` inputs at the same time');
188
- }
189
- else if (options?.length === 0) {
190
- throw new Error('Value of `options` input cannot be an empty array');
191
- }
192
- });
193
- }
194
- // Since the panel ID is static, we can set it once without having to maintain a host binding.
195
- const element = inject(ElementRef);
196
- element.nativeElement.setAttribute('mat-timepicker-panel-id', this.panelId);
197
- this._handleLocaleChanges();
198
- this._handleInputStateChanges();
199
- this._keyManager.change.subscribe(() => this._activeDescendant.set(this._keyManager.activeItem?.id || null));
200
- }
201
- /** Opens the timepicker. */
202
- open() {
203
- const input = this._input();
204
- if (!input) {
205
- return;
206
- }
207
- // Focus should already be on the input, but this call is in case the timepicker is opened
208
- // programmatically. We need to call this even if the timepicker is already open, because
209
- // the user might be clicking the toggle.
210
- input.focus();
211
- if (this._isOpen()) {
212
- return;
213
- }
214
- this._isOpen.set(true);
215
- this._generateOptions();
216
- const overlayRef = this._getOverlayRef();
217
- overlayRef.updateSize({ width: input.getOverlayOrigin().nativeElement.offsetWidth });
218
- this._portal ??= new TemplatePortal(this._panelTemplate(), this._viewContainerRef);
219
- // We need to check this in case `isOpen` was flipped, but change detection hasn't
220
- // had a chance to run yet. See https://github.com/angular/components/issues/30637
221
- if (!overlayRef.hasAttached()) {
222
- overlayRef.attach(this._portal);
92
+ _dir = inject(Directionality, {
93
+ optional: true
94
+ });
95
+ _viewContainerRef = inject(ViewContainerRef);
96
+ _injector = inject(Injector);
97
+ _defaultConfig = inject(MAT_TIMEPICKER_CONFIG, {
98
+ optional: true
99
+ });
100
+ _dateAdapter = inject(DateAdapter, {
101
+ optional: true
102
+ });
103
+ _dateFormats = inject(MAT_DATE_FORMATS, {
104
+ optional: true
105
+ });
106
+ _scrollStrategyFactory = inject(MAT_TIMEPICKER_SCROLL_STRATEGY);
107
+ _animationsDisabled = _animationsDisabled();
108
+ _isOpen = signal(false, ...(ngDevMode ? [{
109
+ debugName: "_isOpen"
110
+ }] : []));
111
+ _activeDescendant = signal(null, ...(ngDevMode ? [{
112
+ debugName: "_activeDescendant"
113
+ }] : []));
114
+ _input = signal(null, ...(ngDevMode ? [{
115
+ debugName: "_input"
116
+ }] : []));
117
+ _overlayRef = null;
118
+ _portal = null;
119
+ _optionsCacheKey = null;
120
+ _localeChanges;
121
+ _onOpenRender = null;
122
+ _panelTemplate = viewChild.required('panelTemplate');
123
+ _timeOptions = [];
124
+ _options = viewChildren(MatOption, ...(ngDevMode ? [{
125
+ debugName: "_options"
126
+ }] : []));
127
+ _keyManager = new ActiveDescendantKeyManager(this._options, this._injector).withHomeAndEnd(true).withPageUpDown(true).withVerticalOrientation(true);
128
+ interval = input(parseInterval(this._defaultConfig?.interval || null), ...(ngDevMode ? [{
129
+ debugName: "interval",
130
+ transform: parseInterval
131
+ }] : [{
132
+ transform: parseInterval
133
+ }]));
134
+ options = input(null, ...(ngDevMode ? [{
135
+ debugName: "options"
136
+ }] : []));
137
+ isOpen = this._isOpen.asReadonly();
138
+ selected = output();
139
+ opened = output();
140
+ closed = output();
141
+ activeDescendant = this._activeDescendant.asReadonly();
142
+ panelId = inject(_IdGenerator).getId('mat-timepicker-panel-');
143
+ disableRipple = input(this._defaultConfig?.disableRipple ?? false, ...(ngDevMode ? [{
144
+ debugName: "disableRipple",
145
+ transform: booleanAttribute
146
+ }] : [{
147
+ transform: booleanAttribute
148
+ }]));
149
+ ariaLabel = input(null, ...(ngDevMode ? [{
150
+ debugName: "ariaLabel",
151
+ alias: 'aria-label'
152
+ }] : [{
153
+ alias: 'aria-label'
154
+ }]));
155
+ ariaLabelledby = input(null, ...(ngDevMode ? [{
156
+ debugName: "ariaLabelledby",
157
+ alias: 'aria-labelledby'
158
+ }] : [{
159
+ alias: 'aria-labelledby'
160
+ }]));
161
+ disabled = computed(() => !!this._input()?.disabled(), ...(ngDevMode ? [{
162
+ debugName: "disabled"
163
+ }] : []));
164
+ constructor() {
165
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
166
+ validateAdapter(this._dateAdapter, this._dateFormats);
167
+ effect(() => {
168
+ const options = this.options();
169
+ const interval = this.interval();
170
+ if (options !== null && interval !== null) {
171
+ throw new Error('Cannot specify both the `options` and `interval` inputs at the same time');
172
+ } else if (options?.length === 0) {
173
+ throw new Error('Value of `options` input cannot be an empty array');
223
174
  }
224
- this._onOpenRender?.destroy();
225
- this._onOpenRender = afterNextRender(() => {
226
- const options = this._options();
227
- this._syncSelectedState(input.value(), options, options[0]);
228
- this._onOpenRender = null;
229
- }, { injector: this._injector });
230
- this.opened.emit();
175
+ });
231
176
  }
232
- /** Closes the timepicker. */
233
- close() {
234
- if (this._isOpen()) {
235
- this._isOpen.set(false);
236
- this.closed.emit();
237
- if (this._animationsDisabled) {
238
- this._overlayRef?.detach();
239
- }
240
- }
177
+ const element = inject(ElementRef);
178
+ element.nativeElement.setAttribute('mat-timepicker-panel-id', this.panelId);
179
+ this._handleLocaleChanges();
180
+ this._handleInputStateChanges();
181
+ this._keyManager.change.subscribe(() => this._activeDescendant.set(this._keyManager.activeItem?.id || null));
182
+ }
183
+ open() {
184
+ const input = this._input();
185
+ if (!input) {
186
+ return;
241
187
  }
242
- /** Registers an input with the timepicker. */
243
- registerInput(input) {
244
- const currentInput = this._input();
245
- if (currentInput && input !== currentInput && (typeof ngDevMode === 'undefined' || ngDevMode)) {
246
- throw new Error('MatTimepicker can only be registered with one input at a time');
247
- }
248
- this._input.set(input);
188
+ input.focus();
189
+ if (this._isOpen()) {
190
+ return;
249
191
  }
250
- ngOnDestroy() {
251
- this._keyManager.destroy();
252
- this._localeChanges.unsubscribe();
253
- this._onOpenRender?.destroy();
254
- this._overlayRef?.dispose();
192
+ this._isOpen.set(true);
193
+ this._generateOptions();
194
+ const overlayRef = this._getOverlayRef();
195
+ overlayRef.updateSize({
196
+ width: input.getOverlayOrigin().nativeElement.offsetWidth
197
+ });
198
+ this._portal ??= new TemplatePortal(this._panelTemplate(), this._viewContainerRef);
199
+ if (!overlayRef.hasAttached()) {
200
+ overlayRef.attach(this._portal);
255
201
  }
256
- /** Selects a specific time value. */
257
- _selectValue(option) {
258
- this.close();
259
- this._keyManager.setActiveItem(option);
260
- this._options().forEach(current => {
261
- // This is primarily here so we don't show two selected options while animating away.
262
- if (current !== option) {
263
- current.deselect(false);
264
- }
265
- });
266
- // Notify the input first so it can sync up the form control before emitting to `selected`.
267
- this._input()?.timepickerValueAssigned(option.value);
268
- this.selected.emit({ value: option.value, source: this });
269
- this._input()?.focus();
202
+ this._onOpenRender?.destroy();
203
+ this._onOpenRender = afterNextRender(() => {
204
+ const options = this._options();
205
+ this._syncSelectedState(input.value(), options, options[0]);
206
+ this._onOpenRender = null;
207
+ }, {
208
+ injector: this._injector
209
+ });
210
+ this.opened.emit();
211
+ }
212
+ close() {
213
+ if (this._isOpen()) {
214
+ this._isOpen.set(false);
215
+ this.closed.emit();
216
+ if (this._animationsDisabled) {
217
+ this._overlayRef?.detach();
218
+ }
270
219
  }
271
- /** Gets the value of the `aria-labelledby` attribute. */
272
- _getAriaLabelledby() {
273
- if (this.ariaLabel()) {
274
- return null;
275
- }
276
- return this.ariaLabelledby() || this._input()?.getLabelId() || null;
220
+ }
221
+ registerInput(input) {
222
+ const currentInput = this._input();
223
+ if (currentInput && input !== currentInput && (typeof ngDevMode === 'undefined' || ngDevMode)) {
224
+ throw new Error('MatTimepicker can only be registered with one input at a time');
277
225
  }
278
- /** Handles animation events coming from the panel. */
279
- _handleAnimationEnd(event) {
280
- if (event.animationName === '_mat-timepicker-exit') {
281
- this._overlayRef?.detach();
282
- }
226
+ this._input.set(input);
227
+ }
228
+ ngOnDestroy() {
229
+ this._keyManager.destroy();
230
+ this._localeChanges.unsubscribe();
231
+ this._onOpenRender?.destroy();
232
+ this._overlayRef?.dispose();
233
+ }
234
+ _getOverlayHost() {
235
+ return this._overlayRef?.hostElement;
236
+ }
237
+ _selectValue(option) {
238
+ this.close();
239
+ this._keyManager.setActiveItem(option);
240
+ this._options().forEach(current => {
241
+ if (current !== option) {
242
+ current.deselect(false);
243
+ }
244
+ });
245
+ this._input()?.timepickerValueAssigned(option.value);
246
+ this.selected.emit({
247
+ value: option.value,
248
+ source: this
249
+ });
250
+ this._input()?.focus();
251
+ }
252
+ _getAriaLabelledby() {
253
+ if (this.ariaLabel()) {
254
+ return null;
283
255
  }
284
- /** Creates an overlay reference for the timepicker panel. */
285
- _getOverlayRef() {
286
- if (this._overlayRef) {
287
- return this._overlayRef;
288
- }
289
- const positionStrategy = createFlexibleConnectedPositionStrategy(this._injector, this._input().getOverlayOrigin())
290
- .withFlexibleDimensions(false)
291
- .withPush(false)
292
- .withTransformOriginOn('.mat-timepicker-panel')
293
- .withPositions([
294
- {
295
- originX: 'start',
296
- originY: 'bottom',
297
- overlayX: 'start',
298
- overlayY: 'top',
299
- },
300
- {
301
- originX: 'start',
302
- originY: 'top',
303
- overlayX: 'start',
304
- overlayY: 'bottom',
305
- panelClass: 'mat-timepicker-above',
306
- },
307
- ]);
308
- this._overlayRef = createOverlayRef(this._injector, {
309
- positionStrategy,
310
- scrollStrategy: this._scrollStrategyFactory(),
311
- direction: this._dir || 'ltr',
312
- hasBackdrop: false,
313
- disableAnimations: this._animationsDisabled,
314
- });
315
- this._overlayRef.detachments().subscribe(() => this.close());
316
- this._overlayRef.keydownEvents().subscribe(event => this._handleKeydown(event));
317
- this._overlayRef.outsidePointerEvents().subscribe(event => {
318
- const target = _getEventTarget(event);
319
- const origin = this._input()?.getOverlayOrigin().nativeElement;
320
- if (target && origin && target !== origin && !origin.contains(target)) {
321
- this.close();
322
- }
323
- });
324
- return this._overlayRef;
256
+ return this.ariaLabelledby() || this._input()?.getLabelId() || null;
257
+ }
258
+ _handleAnimationEnd(event) {
259
+ if (event.animationName === '_mat-timepicker-exit') {
260
+ this._overlayRef?.detach();
325
261
  }
326
- /** Generates the list of options from which the user can select.. */
327
- _generateOptions() {
328
- // Default the interval to 30 minutes.
329
- const interval = this.interval() ?? 30 * 60;
330
- const options = this.options();
331
- if (options !== null) {
332
- this._timeOptions = options;
333
- }
334
- else {
335
- const input = this._input();
336
- const adapter = this._dateAdapter;
337
- const timeFormat = this._dateFormats.display.timeInput;
338
- const min = input?.min() || adapter.setTime(adapter.today(), 0, 0, 0);
339
- const max = input?.max() || adapter.setTime(adapter.today(), 23, 59, 0);
340
- const cacheKey = interval + '/' + adapter.format(min, timeFormat) + '/' + adapter.format(max, timeFormat);
341
- // Don't re-generate the options if the inputs haven't changed.
342
- if (cacheKey !== this._optionsCacheKey) {
343
- this._optionsCacheKey = cacheKey;
344
- this._timeOptions = generateOptions(adapter, this._dateFormats, min, max, interval);
345
- }
346
- }
262
+ }
263
+ _getOverlayRef() {
264
+ if (this._overlayRef) {
265
+ return this._overlayRef;
347
266
  }
348
- /**
349
- * Synchronizes the internal state of the component based on a specific selected date.
350
- * @param value Currently selected date.
351
- * @param options Options rendered out in the timepicker.
352
- * @param fallback Option to set as active if no option is selected.
353
- */
354
- _syncSelectedState(value, options, fallback) {
355
- let hasSelected = false;
356
- for (const option of options) {
357
- if (value && this._dateAdapter.sameTime(option.value, value)) {
358
- option.select(false);
359
- scrollOptionIntoView(option, 'center');
360
- untracked(() => this._keyManager.setActiveItem(option));
361
- hasSelected = true;
362
- }
363
- else {
364
- option.deselect(false);
365
- }
366
- }
367
- // If no option was selected, we need to reset the key manager since
368
- // it might be holding onto an option that no longer exists.
369
- if (!hasSelected) {
370
- if (fallback) {
371
- untracked(() => this._keyManager.setActiveItem(fallback));
372
- scrollOptionIntoView(fallback, 'center');
373
- }
374
- else {
375
- untracked(() => this._keyManager.setActiveItem(-1));
376
- }
377
- }
267
+ const positionStrategy = createFlexibleConnectedPositionStrategy(this._injector, this._input().getOverlayOrigin()).withFlexibleDimensions(false).withPush(false).withTransformOriginOn('.mat-timepicker-panel').withPositions([{
268
+ originX: 'start',
269
+ originY: 'bottom',
270
+ overlayX: 'start',
271
+ overlayY: 'top'
272
+ }, {
273
+ originX: 'start',
274
+ originY: 'top',
275
+ overlayX: 'start',
276
+ overlayY: 'bottom',
277
+ panelClass: 'mat-timepicker-above'
278
+ }]);
279
+ this._overlayRef = createOverlayRef(this._injector, {
280
+ positionStrategy,
281
+ scrollStrategy: this._scrollStrategyFactory(),
282
+ direction: this._dir || 'ltr',
283
+ hasBackdrop: false,
284
+ disableAnimations: this._animationsDisabled
285
+ });
286
+ this._overlayRef.detachments().subscribe(() => this.close());
287
+ this._overlayRef.keydownEvents().subscribe(event => this._handleKeydown(event));
288
+ this._overlayRef.outsidePointerEvents().subscribe(event => {
289
+ const target = _getEventTarget(event);
290
+ const origin = this._input()?.getOverlayOrigin().nativeElement;
291
+ if (target && origin && target !== origin && !origin.contains(target)) {
292
+ this.close();
293
+ }
294
+ });
295
+ return this._overlayRef;
296
+ }
297
+ _generateOptions() {
298
+ const interval = this.interval() ?? 30 * 60;
299
+ const options = this.options();
300
+ if (options !== null) {
301
+ this._timeOptions = options;
302
+ } else {
303
+ const input = this._input();
304
+ const adapter = this._dateAdapter;
305
+ const timeFormat = this._dateFormats.display.timeInput;
306
+ const min = input?.min() || adapter.setTime(adapter.today(), 0, 0, 0);
307
+ const max = input?.max() || adapter.setTime(adapter.today(), 23, 59, 0);
308
+ const cacheKey = interval + '/' + adapter.format(min, timeFormat) + '/' + adapter.format(max, timeFormat);
309
+ if (cacheKey !== this._optionsCacheKey) {
310
+ this._optionsCacheKey = cacheKey;
311
+ this._timeOptions = generateOptions(adapter, this._dateFormats, min, max, interval);
312
+ }
378
313
  }
379
- /** Handles keyboard events while the overlay is open. */
380
- _handleKeydown(event) {
381
- const keyCode = event.keyCode;
382
- if (keyCode === TAB) {
383
- this.close();
384
- }
385
- else if (keyCode === ESCAPE && !hasModifierKey(event)) {
386
- event.preventDefault();
387
- this.close();
388
- }
389
- else if (keyCode === ENTER) {
390
- event.preventDefault();
391
- if (this._keyManager.activeItem) {
392
- this._selectValue(this._keyManager.activeItem);
393
- }
394
- else {
395
- this.close();
396
- }
397
- }
398
- else {
399
- const previousActive = this._keyManager.activeItem;
400
- this._keyManager.onKeydown(event);
401
- const currentActive = this._keyManager.activeItem;
402
- if (currentActive && currentActive !== previousActive) {
403
- scrollOptionIntoView(currentActive, 'nearest');
404
- }
405
- }
314
+ }
315
+ _syncSelectedState(value, options, fallback) {
316
+ let hasSelected = false;
317
+ for (const option of options) {
318
+ if (value && this._dateAdapter.sameTime(option.value, value)) {
319
+ option.select(false);
320
+ scrollOptionIntoView(option, 'center');
321
+ untracked(() => this._keyManager.setActiveItem(option));
322
+ hasSelected = true;
323
+ } else {
324
+ option.deselect(false);
325
+ }
406
326
  }
407
- /** Sets up the logic that updates the timepicker when the locale changes. */
408
- _handleLocaleChanges() {
409
- // Re-generate the options list if the locale changes.
410
- this._localeChanges = this._dateAdapter.localeChanges.subscribe(() => {
411
- this._optionsCacheKey = null;
412
- if (this.isOpen()) {
413
- this._generateOptions();
414
- }
415
- });
327
+ if (!hasSelected) {
328
+ if (fallback) {
329
+ untracked(() => this._keyManager.setActiveItem(fallback));
330
+ scrollOptionIntoView(fallback, 'center');
331
+ } else {
332
+ untracked(() => this._keyManager.setActiveItem(-1));
333
+ }
416
334
  }
417
- /**
418
- * Sets up the logic that updates the timepicker when the state of the connected input changes.
419
- */
420
- _handleInputStateChanges() {
421
- effect(() => {
422
- const input = this._input();
423
- const options = this._options();
424
- if (this._isOpen() && input) {
425
- this._syncSelectedState(input.value(), options, null);
426
- }
427
- });
335
+ }
336
+ _handleKeydown(event) {
337
+ const keyCode = event.keyCode;
338
+ if (keyCode === TAB) {
339
+ this.close();
340
+ } else if (keyCode === ESCAPE && !hasModifierKey(event)) {
341
+ event.preventDefault();
342
+ this.close();
343
+ } else if (keyCode === ENTER) {
344
+ event.preventDefault();
345
+ if (this._keyManager.activeItem) {
346
+ this._selectValue(this._keyManager.activeItem);
347
+ } else {
348
+ this.close();
349
+ }
350
+ } else {
351
+ const previousActive = this._keyManager.activeItem;
352
+ this._keyManager.onKeydown(event);
353
+ const currentActive = this._keyManager.activeItem;
354
+ if (currentActive && currentActive !== previousActive) {
355
+ scrollOptionIntoView(currentActive, 'nearest');
356
+ }
428
357
  }
429
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatTimepicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
430
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.2.0-next.2", type: MatTimepicker, isStandalone: true, selector: "mat-timepicker", inputs: { interval: { classPropertyName: "interval", publicName: "interval", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, disableRipple: { classPropertyName: "disableRipple", publicName: "disableRipple", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected", opened: "opened", closed: "closed" }, providers: [
431
- {
432
- provide: MAT_OPTION_PARENT_COMPONENT,
433
- useExisting: MatTimepicker,
434
- },
435
- ], viewQueries: [{ propertyName: "_panelTemplate", first: true, predicate: ["panelTemplate"], descendants: true, isSignal: true }, { propertyName: "_options", predicate: MatOption, descendants: true, isSignal: true }], exportAs: ["matTimepicker"], ngImport: i0, template: "<ng-template #panelTemplate>\n <div\n role=\"listbox\"\n class=\"mat-timepicker-panel\"\n [class.mat-timepicker-panel-animations-enabled]=\"!_animationsDisabled\"\n [class.mat-timepicker-panel-exit]=\"!isOpen()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"_getAriaLabelledby()\"\n [id]=\"panelId\"\n (animationend)=\"_handleAnimationEnd($event)\">\n @for (option of _timeOptions; track option.value) {\n <mat-option\n [value]=\"option.value\"\n (onSelectionChange)=\"_selectValue($event.source)\">{{option.label}}</mat-option>\n }\n </div>\n</ng-template>\n", styles: ["@keyframes _mat-timepicker-enter{from{opacity:0;transform:scaleY(0.8)}to{opacity:1;transform:none}}@keyframes _mat-timepicker-exit{from{opacity:1}to{opacity:0}}mat-timepicker{display:none}.mat-timepicker-panel{width:100%;max-height:256px;transform-origin:center top;overflow:auto;padding:8px 0;box-sizing:border-box;position:relative;border-bottom-left-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));border-bottom-right-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));box-shadow:var(--mat-timepicker-container-elevation-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));background-color:var(--mat-timepicker-container-background-color, var(--mat-sys-surface-container))}@media(forced-colors: active){.mat-timepicker-panel{outline:solid 1px}}.mat-timepicker-above .mat-timepicker-panel{border-bottom-left-radius:0;border-bottom-right-radius:0;border-top-left-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));border-top-right-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small))}.mat-timepicker-panel-animations-enabled{animation:_mat-timepicker-enter 120ms cubic-bezier(0, 0, 0.2, 1)}.mat-timepicker-panel-animations-enabled.mat-timepicker-panel-exit{animation:_mat-timepicker-exit 100ms linear}.mat-timepicker-input[readonly]{cursor:pointer}@media(forced-colors: active){.mat-timepicker-toggle-default-icon{color:CanvasText}}\n"], dependencies: [{ kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
358
+ }
359
+ _handleLocaleChanges() {
360
+ this._localeChanges = this._dateAdapter.localeChanges.subscribe(() => {
361
+ this._optionsCacheKey = null;
362
+ if (this.isOpen()) {
363
+ this._generateOptions();
364
+ }
365
+ });
366
+ }
367
+ _handleInputStateChanges() {
368
+ effect(() => {
369
+ const input = this._input();
370
+ const options = this._options();
371
+ if (this._isOpen() && input) {
372
+ this._syncSelectedState(input.value(), options, null);
373
+ }
374
+ });
375
+ }
376
+ static ɵfac = i0.ɵɵngDeclareFactory({
377
+ minVersion: "12.0.0",
378
+ version: "20.2.0-next.2",
379
+ ngImport: i0,
380
+ type: MatTimepicker,
381
+ deps: [],
382
+ target: i0.ɵɵFactoryTarget.Component
383
+ });
384
+ static ɵcmp = i0.ɵɵngDeclareComponent({
385
+ minVersion: "17.0.0",
386
+ version: "20.2.0-next.2",
387
+ type: MatTimepicker,
388
+ isStandalone: true,
389
+ selector: "mat-timepicker",
390
+ inputs: {
391
+ interval: {
392
+ classPropertyName: "interval",
393
+ publicName: "interval",
394
+ isSignal: true,
395
+ isRequired: false,
396
+ transformFunction: null
397
+ },
398
+ options: {
399
+ classPropertyName: "options",
400
+ publicName: "options",
401
+ isSignal: true,
402
+ isRequired: false,
403
+ transformFunction: null
404
+ },
405
+ disableRipple: {
406
+ classPropertyName: "disableRipple",
407
+ publicName: "disableRipple",
408
+ isSignal: true,
409
+ isRequired: false,
410
+ transformFunction: null
411
+ },
412
+ ariaLabel: {
413
+ classPropertyName: "ariaLabel",
414
+ publicName: "aria-label",
415
+ isSignal: true,
416
+ isRequired: false,
417
+ transformFunction: null
418
+ },
419
+ ariaLabelledby: {
420
+ classPropertyName: "ariaLabelledby",
421
+ publicName: "aria-labelledby",
422
+ isSignal: true,
423
+ isRequired: false,
424
+ transformFunction: null
425
+ }
426
+ },
427
+ outputs: {
428
+ selected: "selected",
429
+ opened: "opened",
430
+ closed: "closed"
431
+ },
432
+ providers: [{
433
+ provide: MAT_OPTION_PARENT_COMPONENT,
434
+ useExisting: MatTimepicker
435
+ }],
436
+ viewQueries: [{
437
+ propertyName: "_panelTemplate",
438
+ first: true,
439
+ predicate: ["panelTemplate"],
440
+ descendants: true,
441
+ isSignal: true
442
+ }, {
443
+ propertyName: "_options",
444
+ predicate: MatOption,
445
+ descendants: true,
446
+ isSignal: true
447
+ }],
448
+ exportAs: ["matTimepicker"],
449
+ ngImport: i0,
450
+ template: "<ng-template #panelTemplate>\n <div\n role=\"listbox\"\n class=\"mat-timepicker-panel\"\n [class.mat-timepicker-panel-animations-enabled]=\"!_animationsDisabled\"\n [class.mat-timepicker-panel-exit]=\"!isOpen()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"_getAriaLabelledby()\"\n [id]=\"panelId\"\n (animationend)=\"_handleAnimationEnd($event)\">\n @for (option of _timeOptions; track option.value) {\n <mat-option\n [value]=\"option.value\"\n (onSelectionChange)=\"_selectValue($event.source)\">{{option.label}}</mat-option>\n }\n </div>\n</ng-template>\n",
451
+ styles: ["@keyframes _mat-timepicker-enter{from{opacity:0;transform:scaleY(0.8)}to{opacity:1;transform:none}}@keyframes _mat-timepicker-exit{from{opacity:1}to{opacity:0}}mat-timepicker{display:none}.mat-timepicker-panel{width:100%;max-height:256px;transform-origin:center top;overflow:auto;padding:8px 0;box-sizing:border-box;position:relative;border-bottom-left-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));border-bottom-right-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));box-shadow:var(--mat-timepicker-container-elevation-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));background-color:var(--mat-timepicker-container-background-color, var(--mat-sys-surface-container))}@media(forced-colors: active){.mat-timepicker-panel{outline:solid 1px}}.mat-timepicker-above .mat-timepicker-panel{border-bottom-left-radius:0;border-bottom-right-radius:0;border-top-left-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));border-top-right-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small))}.mat-timepicker-panel-animations-enabled{animation:_mat-timepicker-enter 120ms cubic-bezier(0, 0, 0.2, 1)}.mat-timepicker-panel-animations-enabled.mat-timepicker-panel-exit{animation:_mat-timepicker-exit 100ms linear}.mat-timepicker-input[readonly]{cursor:pointer}@media(forced-colors: active){.mat-timepicker-toggle-default-icon{color:CanvasText}}\n"],
452
+ dependencies: [{
453
+ kind: "component",
454
+ type: MatOption,
455
+ selector: "mat-option",
456
+ inputs: ["value", "id", "disabled"],
457
+ outputs: ["onSelectionChange"],
458
+ exportAs: ["matOption"]
459
+ }],
460
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
461
+ encapsulation: i0.ViewEncapsulation.None
462
+ });
436
463
  }
437
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatTimepicker, decorators: [{
438
- type: Component,
439
- args: [{ selector: 'mat-timepicker', exportAs: 'matTimepicker', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [MatOption], providers: [
440
- {
441
- provide: MAT_OPTION_PARENT_COMPONENT,
442
- useExisting: MatTimepicker,
443
- },
444
- ], template: "<ng-template #panelTemplate>\n <div\n role=\"listbox\"\n class=\"mat-timepicker-panel\"\n [class.mat-timepicker-panel-animations-enabled]=\"!_animationsDisabled\"\n [class.mat-timepicker-panel-exit]=\"!isOpen()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"_getAriaLabelledby()\"\n [id]=\"panelId\"\n (animationend)=\"_handleAnimationEnd($event)\">\n @for (option of _timeOptions; track option.value) {\n <mat-option\n [value]=\"option.value\"\n (onSelectionChange)=\"_selectValue($event.source)\">{{option.label}}</mat-option>\n }\n </div>\n</ng-template>\n", styles: ["@keyframes _mat-timepicker-enter{from{opacity:0;transform:scaleY(0.8)}to{opacity:1;transform:none}}@keyframes _mat-timepicker-exit{from{opacity:1}to{opacity:0}}mat-timepicker{display:none}.mat-timepicker-panel{width:100%;max-height:256px;transform-origin:center top;overflow:auto;padding:8px 0;box-sizing:border-box;position:relative;border-bottom-left-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));border-bottom-right-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));box-shadow:var(--mat-timepicker-container-elevation-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));background-color:var(--mat-timepicker-container-background-color, var(--mat-sys-surface-container))}@media(forced-colors: active){.mat-timepicker-panel{outline:solid 1px}}.mat-timepicker-above .mat-timepicker-panel{border-bottom-left-radius:0;border-bottom-right-radius:0;border-top-left-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));border-top-right-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small))}.mat-timepicker-panel-animations-enabled{animation:_mat-timepicker-enter 120ms cubic-bezier(0, 0, 0.2, 1)}.mat-timepicker-panel-animations-enabled.mat-timepicker-panel-exit{animation:_mat-timepicker-exit 100ms linear}.mat-timepicker-input[readonly]{cursor:pointer}@media(forced-colors: active){.mat-timepicker-toggle-default-icon{color:CanvasText}}\n"] }]
445
- }], ctorParameters: () => [] });
446
- /**
447
- * Scrolls an option into view.
448
- * @param option Option to be scrolled into view.
449
- * @param position Position to which to align the option relative to the scrollable container.
450
- */
464
+ i0.ɵɵngDeclareClassMetadata({
465
+ minVersion: "12.0.0",
466
+ version: "20.2.0-next.2",
467
+ ngImport: i0,
468
+ type: MatTimepicker,
469
+ decorators: [{
470
+ type: Component,
471
+ args: [{
472
+ selector: 'mat-timepicker',
473
+ exportAs: 'matTimepicker',
474
+ changeDetection: ChangeDetectionStrategy.OnPush,
475
+ encapsulation: ViewEncapsulation.None,
476
+ imports: [MatOption],
477
+ providers: [{
478
+ provide: MAT_OPTION_PARENT_COMPONENT,
479
+ useExisting: MatTimepicker
480
+ }],
481
+ template: "<ng-template #panelTemplate>\n <div\n role=\"listbox\"\n class=\"mat-timepicker-panel\"\n [class.mat-timepicker-panel-animations-enabled]=\"!_animationsDisabled\"\n [class.mat-timepicker-panel-exit]=\"!isOpen()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-labelledby]=\"_getAriaLabelledby()\"\n [id]=\"panelId\"\n (animationend)=\"_handleAnimationEnd($event)\">\n @for (option of _timeOptions; track option.value) {\n <mat-option\n [value]=\"option.value\"\n (onSelectionChange)=\"_selectValue($event.source)\">{{option.label}}</mat-option>\n }\n </div>\n</ng-template>\n",
482
+ styles: ["@keyframes _mat-timepicker-enter{from{opacity:0;transform:scaleY(0.8)}to{opacity:1;transform:none}}@keyframes _mat-timepicker-exit{from{opacity:1}to{opacity:0}}mat-timepicker{display:none}.mat-timepicker-panel{width:100%;max-height:256px;transform-origin:center top;overflow:auto;padding:8px 0;box-sizing:border-box;position:relative;border-bottom-left-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));border-bottom-right-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));box-shadow:var(--mat-timepicker-container-elevation-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));background-color:var(--mat-timepicker-container-background-color, var(--mat-sys-surface-container))}@media(forced-colors: active){.mat-timepicker-panel{outline:solid 1px}}.mat-timepicker-above .mat-timepicker-panel{border-bottom-left-radius:0;border-bottom-right-radius:0;border-top-left-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small));border-top-right-radius:var(--mat-timepicker-container-shape, var(--mat-sys-corner-extra-small))}.mat-timepicker-panel-animations-enabled{animation:_mat-timepicker-enter 120ms cubic-bezier(0, 0, 0.2, 1)}.mat-timepicker-panel-animations-enabled.mat-timepicker-panel-exit{animation:_mat-timepicker-exit 100ms linear}.mat-timepicker-input[readonly]{cursor:pointer}@media(forced-colors: active){.mat-timepicker-toggle-default-icon{color:CanvasText}}\n"]
483
+ }]
484
+ }],
485
+ ctorParameters: () => []
486
+ });
451
487
  function scrollOptionIntoView(option, position) {
452
- option._getHostElement().scrollIntoView({ block: position, inline: position });
488
+ option._getHostElement().scrollIntoView({
489
+ block: position,
490
+ inline: position
491
+ });
453
492
  }
454
493
 
455
- /**
456
- * Input that can be used to enter time and connect to a `mat-timepicker`.
457
- */
458
494
  class MatTimepickerInput {
459
- _elementRef = inject(ElementRef);
460
- _dateAdapter = inject(DateAdapter, { optional: true });
461
- _dateFormats = inject(MAT_DATE_FORMATS, { optional: true });
462
- _formField = inject(MAT_FORM_FIELD, { optional: true });
463
- _onChange;
464
- _onTouched;
465
- _validatorOnChange;
466
- _cleanupClick;
467
- _accessorDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_accessorDisabled" }] : []));
468
- _localeSubscription;
469
- _timepickerSubscription;
470
- _validator;
471
- _lastValueValid = true;
472
- _lastValidDate = null;
473
- /** Value of the `aria-activedescendant` attribute. */
474
- _ariaActiveDescendant = computed(() => {
475
- const timepicker = this.timepicker();
476
- const isOpen = timepicker.isOpen();
477
- const activeDescendant = timepicker.activeDescendant();
478
- return isOpen && activeDescendant ? activeDescendant : null;
479
- }, ...(ngDevMode ? [{ debugName: "_ariaActiveDescendant" }] : []));
480
- /** Value of the `aria-expanded` attribute. */
481
- _ariaExpanded = computed(() => this.timepicker().isOpen() + '', ...(ngDevMode ? [{ debugName: "_ariaExpanded" }] : []));
482
- /** Value of the `aria-controls` attribute. */
483
- _ariaControls = computed(() => {
484
- const timepicker = this.timepicker();
485
- return timepicker.isOpen() ? timepicker.panelId : null;
486
- }, ...(ngDevMode ? [{ debugName: "_ariaControls" }] : []));
487
- /** Current value of the input. */
488
- value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
489
- /** Timepicker that the input is associated with. */
490
- timepicker = input.required(...(ngDevMode ? [{ debugName: "timepicker", alias: 'matTimepicker' }] : [{
491
- alias: 'matTimepicker',
492
- }]));
493
- /**
494
- * Minimum time that can be selected or typed in. Can be either
495
- * a date object (only time will be used) or a valid time string.
496
- */
497
- min = input(null, ...(ngDevMode ? [{ debugName: "min", alias: 'matTimepickerMin',
498
- transform: (value) => this._transformDateInput(value) }] : [{
499
- alias: 'matTimepickerMin',
500
- transform: (value) => this._transformDateInput(value),
501
- }]));
502
- /**
503
- * Maximum time that can be selected or typed in. Can be either
504
- * a date object (only time will be used) or a valid time string.
505
- */
506
- max = input(null, ...(ngDevMode ? [{ debugName: "max", alias: 'matTimepickerMax',
507
- transform: (value) => this._transformDateInput(value) }] : [{
508
- alias: 'matTimepickerMax',
509
- transform: (value) => this._transformDateInput(value),
510
- }]));
511
- /**
512
- * Whether to open the timepicker overlay when clicking on the input. Enabled by default.
513
- * Note that when disabling this option, you'll have to provide your own logic for opening
514
- * the overlay.
515
- */
516
- openOnClick = input(true, ...(ngDevMode ? [{ debugName: "openOnClick", alias: 'matTimepickerOpenOnClick',
517
- transform: booleanAttribute }] : [{
518
- alias: 'matTimepickerOpenOnClick',
519
- transform: booleanAttribute,
520
- }]));
521
- /** Whether the input is disabled. */
522
- disabled = computed(() => this.disabledInput() || this._accessorDisabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
523
- /**
524
- * Whether the input should be disabled through the template.
525
- * @docs-private
526
- */
527
- disabledInput = input(false, ...(ngDevMode ? [{ debugName: "disabledInput", transform: booleanAttribute,
528
- alias: 'disabled' }] : [{
529
- transform: booleanAttribute,
530
- alias: 'disabled',
531
- }]));
532
- constructor() {
533
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
534
- validateAdapter(this._dateAdapter, this._dateFormats);
535
- }
536
- const renderer = inject(Renderer2);
537
- this._validator = this._getValidator();
538
- this._respondToValueChanges();
539
- this._respondToMinMaxChanges();
540
- this._registerTimepicker();
541
- this._localeSubscription = this._dateAdapter.localeChanges.subscribe(() => {
542
- if (!this._hasFocus()) {
543
- this._formatValue(this.value());
544
- }
545
- });
546
- // Bind the click listener manually to the overlay origin, because we want the entire
547
- // form field to be clickable, if the timepicker is used in `mat-form-field`.
548
- this._cleanupClick = renderer.listen(this.getOverlayOrigin().nativeElement, 'click', this._handleClick);
549
- }
550
- /**
551
- * Implemented as a part of `ControlValueAccessor`.
552
- * @docs-private
553
- */
554
- writeValue(value) {
555
- // Note that we need to deserialize here, rather than depend on the value change effect,
556
- // because `getValidDateOrNull` will clobber the value if it's parseable, but not created by
557
- // the current adapter (see #30140).
558
- const deserialized = this._dateAdapter.deserialize(value);
559
- this.value.set(this._dateAdapter.getValidDateOrNull(deserialized));
560
- }
561
- /**
562
- * Implemented as a part of `ControlValueAccessor`.
563
- * @docs-private
564
- */
565
- registerOnChange(fn) {
566
- this._onChange = fn;
567
- }
568
- /**
569
- * Implemented as a part of `ControlValueAccessor`.
570
- * @docs-private
571
- */
572
- registerOnTouched(fn) {
573
- this._onTouched = fn;
574
- }
575
- /**
576
- * Implemented as a part of `ControlValueAccessor`.
577
- * @docs-private
578
- */
579
- setDisabledState(isDisabled) {
580
- this._accessorDisabled.set(isDisabled);
581
- }
582
- /**
583
- * Implemented as a part of `Validator`.
584
- * @docs-private
585
- */
586
- validate(control) {
587
- return this._validator(control);
588
- }
589
- /**
590
- * Implemented as a part of `Validator`.
591
- * @docs-private
592
- */
593
- registerOnValidatorChange(fn) {
594
- this._validatorOnChange = fn;
495
+ _elementRef = inject(ElementRef);
496
+ _dateAdapter = inject(DateAdapter, {
497
+ optional: true
498
+ });
499
+ _dateFormats = inject(MAT_DATE_FORMATS, {
500
+ optional: true
501
+ });
502
+ _formField = inject(MAT_FORM_FIELD, {
503
+ optional: true
504
+ });
505
+ _onChange;
506
+ _onTouched;
507
+ _validatorOnChange;
508
+ _cleanupClick;
509
+ _accessorDisabled = signal(false, ...(ngDevMode ? [{
510
+ debugName: "_accessorDisabled"
511
+ }] : []));
512
+ _localeSubscription;
513
+ _timepickerSubscription;
514
+ _validator;
515
+ _lastValueValid = true;
516
+ _lastValidDate = null;
517
+ _ariaActiveDescendant = computed(() => {
518
+ const timepicker = this.timepicker();
519
+ const isOpen = timepicker.isOpen();
520
+ const activeDescendant = timepicker.activeDescendant();
521
+ return isOpen && activeDescendant ? activeDescendant : null;
522
+ }, ...(ngDevMode ? [{
523
+ debugName: "_ariaActiveDescendant"
524
+ }] : []));
525
+ _ariaExpanded = computed(() => this.timepicker().isOpen() + '', ...(ngDevMode ? [{
526
+ debugName: "_ariaExpanded"
527
+ }] : []));
528
+ _ariaControls = computed(() => {
529
+ const timepicker = this.timepicker();
530
+ return timepicker.isOpen() ? timepicker.panelId : null;
531
+ }, ...(ngDevMode ? [{
532
+ debugName: "_ariaControls"
533
+ }] : []));
534
+ value = model(null, ...(ngDevMode ? [{
535
+ debugName: "value"
536
+ }] : []));
537
+ timepicker = input.required(...(ngDevMode ? [{
538
+ debugName: "timepicker",
539
+ alias: 'matTimepicker'
540
+ }] : [{
541
+ alias: 'matTimepicker'
542
+ }]));
543
+ min = input(null, ...(ngDevMode ? [{
544
+ debugName: "min",
545
+ alias: 'matTimepickerMin',
546
+ transform: value => this._transformDateInput(value)
547
+ }] : [{
548
+ alias: 'matTimepickerMin',
549
+ transform: value => this._transformDateInput(value)
550
+ }]));
551
+ max = input(null, ...(ngDevMode ? [{
552
+ debugName: "max",
553
+ alias: 'matTimepickerMax',
554
+ transform: value => this._transformDateInput(value)
555
+ }] : [{
556
+ alias: 'matTimepickerMax',
557
+ transform: value => this._transformDateInput(value)
558
+ }]));
559
+ openOnClick = input(true, ...(ngDevMode ? [{
560
+ debugName: "openOnClick",
561
+ alias: 'matTimepickerOpenOnClick',
562
+ transform: booleanAttribute
563
+ }] : [{
564
+ alias: 'matTimepickerOpenOnClick',
565
+ transform: booleanAttribute
566
+ }]));
567
+ disabled = computed(() => this.disabledInput() || this._accessorDisabled(), ...(ngDevMode ? [{
568
+ debugName: "disabled"
569
+ }] : []));
570
+ disabledInput = input(false, ...(ngDevMode ? [{
571
+ debugName: "disabledInput",
572
+ transform: booleanAttribute,
573
+ alias: 'disabled'
574
+ }] : [{
575
+ transform: booleanAttribute,
576
+ alias: 'disabled'
577
+ }]));
578
+ constructor() {
579
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
580
+ validateAdapter(this._dateAdapter, this._dateFormats);
595
581
  }
596
- /** Gets the element to which the timepicker popup should be attached. */
597
- getOverlayOrigin() {
598
- return this._formField?.getConnectedOverlayOrigin() || this._elementRef;
582
+ const renderer = inject(Renderer2);
583
+ this._validator = this._getValidator();
584
+ this._respondToValueChanges();
585
+ this._respondToMinMaxChanges();
586
+ this._registerTimepicker();
587
+ this._localeSubscription = this._dateAdapter.localeChanges.subscribe(() => {
588
+ if (!this._hasFocus()) {
589
+ this._formatValue(this.value());
590
+ }
591
+ });
592
+ this._cleanupClick = renderer.listen(this.getOverlayOrigin().nativeElement, 'click', this._handleClick);
593
+ }
594
+ writeValue(value) {
595
+ const deserialized = this._dateAdapter.deserialize(value);
596
+ this.value.set(this._dateAdapter.getValidDateOrNull(deserialized));
597
+ }
598
+ registerOnChange(fn) {
599
+ this._onChange = fn;
600
+ }
601
+ registerOnTouched(fn) {
602
+ this._onTouched = fn;
603
+ }
604
+ setDisabledState(isDisabled) {
605
+ this._accessorDisabled.set(isDisabled);
606
+ }
607
+ validate(control) {
608
+ return this._validator(control);
609
+ }
610
+ registerOnValidatorChange(fn) {
611
+ this._validatorOnChange = fn;
612
+ }
613
+ getOverlayOrigin() {
614
+ return this._formField?.getConnectedOverlayOrigin() || this._elementRef;
615
+ }
616
+ focus() {
617
+ this._elementRef.nativeElement.focus();
618
+ }
619
+ ngOnDestroy() {
620
+ this._cleanupClick();
621
+ this._timepickerSubscription?.unsubscribe();
622
+ this._localeSubscription.unsubscribe();
623
+ }
624
+ getLabelId() {
625
+ return this._formField?.getLabelId() || null;
626
+ }
627
+ _handleClick = event => {
628
+ if (this.disabled() || !this.openOnClick()) {
629
+ return;
599
630
  }
600
- /** Focuses the input. */
601
- focus() {
602
- this._elementRef.nativeElement.focus();
631
+ const target = _getEventTarget(event);
632
+ const overlayHost = this.timepicker()._getOverlayHost();
633
+ if (!target || !overlayHost || !overlayHost.contains(target)) {
634
+ this.timepicker().open();
603
635
  }
604
- ngOnDestroy() {
605
- this._cleanupClick();
606
- this._timepickerSubscription?.unsubscribe();
607
- this._localeSubscription.unsubscribe();
636
+ };
637
+ _handleInput(event) {
638
+ const value = event.target.value;
639
+ const currentValue = this.value();
640
+ const date = this._dateAdapter.parseTime(value, this._dateFormats.parse.timeInput);
641
+ const hasChanged = !this._dateAdapter.sameTime(date, currentValue);
642
+ if (!date || hasChanged || !!(value && !currentValue)) {
643
+ this._assignUserSelection(date, true);
644
+ } else {
645
+ this._validatorOnChange?.();
608
646
  }
609
- /** Gets the ID of the input's label. */
610
- getLabelId() {
611
- return this._formField?.getLabelId() || null;
647
+ }
648
+ _handleBlur() {
649
+ const value = this.value();
650
+ if (value && this._isValid(value)) {
651
+ this._formatValue(value);
612
652
  }
613
- /** Handles clicks on the input or the containing form field. */
614
- _handleClick = () => {
615
- if (!this.disabled() && this.openOnClick()) {
616
- this.timepicker().open();
617
- }
618
- };
619
- /** Handles the `input` event. */
620
- _handleInput(event) {
621
- const value = event.target.value;
622
- const currentValue = this.value();
623
- const date = this._dateAdapter.parseTime(value, this._dateFormats.parse.timeInput);
624
- const hasChanged = !this._dateAdapter.sameTime(date, currentValue);
625
- if (!date || hasChanged || !!(value && !currentValue)) {
626
- // We need to fire the CVA change event for all nulls, otherwise the validators won't run.
627
- this._assignUserSelection(date, true);
628
- }
629
- else {
630
- // Call the validator even if the value hasn't changed since
631
- // some fields change depending on what the user has entered.
632
- this._validatorOnChange?.();
633
- }
653
+ if (!this.timepicker().isOpen()) {
654
+ this._onTouched?.();
634
655
  }
635
- /** Handles the `blur` event. */
636
- _handleBlur() {
637
- const value = this.value();
638
- // Only reformat on blur so the value doesn't change while the user is interacting.
639
- if (value && this._isValid(value)) {
640
- this._formatValue(value);
641
- }
642
- if (!this.timepicker().isOpen()) {
643
- this._onTouched?.();
644
- }
645
- }
646
- /** Handles the `keydown` event. */
647
- _handleKeydown(event) {
648
- // All keyboard events while open are handled through the timepicker.
649
- if (this.timepicker().isOpen() || this.disabled()) {
650
- return;
651
- }
652
- if (event.keyCode === ESCAPE && !hasModifierKey(event) && this.value() !== null) {
653
- event.preventDefault();
654
- this.value.set(null);
655
- this._formatValue(null);
656
- }
657
- else if (event.keyCode === DOWN_ARROW || event.keyCode === UP_ARROW) {
658
- event.preventDefault();
659
- this.timepicker().open();
660
- }
656
+ }
657
+ _handleKeydown(event) {
658
+ if (this.timepicker().isOpen() || this.disabled()) {
659
+ return;
661
660
  }
662
- /** Called by the timepicker to sync up the user-selected value. */
663
- timepickerValueAssigned(value) {
664
- if (!this._dateAdapter.sameTime(value, this.value())) {
665
- this._assignUserSelection(value, true);
666
- this._formatValue(value);
667
- }
661
+ if (event.keyCode === ESCAPE && !hasModifierKey(event) && this.value() !== null) {
662
+ event.preventDefault();
663
+ this.value.set(null);
664
+ this._formatValue(null);
665
+ } else if (event.keyCode === DOWN_ARROW || event.keyCode === UP_ARROW) {
666
+ event.preventDefault();
667
+ this.timepicker().open();
668
668
  }
669
- /** Sets up the code that watches for changes in the value and adjusts the input. */
670
- _respondToValueChanges() {
671
- effect(() => {
672
- const value = this._dateAdapter.deserialize(this.value());
673
- const wasValid = this._lastValueValid;
674
- this._lastValueValid = this._isValid(value);
675
- // Reformat the value if it changes while the user isn't interacting.
676
- if (!this._hasFocus()) {
677
- this._formatValue(value);
678
- }
679
- if (value && this._lastValueValid) {
680
- this._lastValidDate = value;
681
- }
682
- // Trigger the validator if the state changed.
683
- if (wasValid !== this._lastValueValid) {
684
- this._validatorOnChange?.();
685
- }
686
- });
669
+ }
670
+ timepickerValueAssigned(value) {
671
+ if (!this._dateAdapter.sameTime(value, this.value())) {
672
+ this._assignUserSelection(value, true);
673
+ this._formatValue(value);
687
674
  }
688
- /** Sets up the logic that registers the input with the timepicker. */
689
- _registerTimepicker() {
690
- effect(() => {
691
- const timepicker = this.timepicker();
692
- timepicker.registerInput(this);
693
- timepicker.closed.subscribe(() => this._onTouched?.());
694
- });
675
+ }
676
+ _respondToValueChanges() {
677
+ effect(() => {
678
+ const value = this._dateAdapter.deserialize(this.value());
679
+ const wasValid = this._lastValueValid;
680
+ this._lastValueValid = this._isValid(value);
681
+ if (!this._hasFocus()) {
682
+ this._formatValue(value);
683
+ }
684
+ if (value && this._lastValueValid) {
685
+ this._lastValidDate = value;
686
+ }
687
+ if (wasValid !== this._lastValueValid) {
688
+ this._validatorOnChange?.();
689
+ }
690
+ });
691
+ }
692
+ _registerTimepicker() {
693
+ effect(() => {
694
+ const timepicker = this.timepicker();
695
+ timepicker.registerInput(this);
696
+ timepicker.closed.subscribe(() => this._onTouched?.());
697
+ });
698
+ }
699
+ _respondToMinMaxChanges() {
700
+ effect(() => {
701
+ this.min();
702
+ this.max();
703
+ this._validatorOnChange?.();
704
+ });
705
+ }
706
+ _assignUserSelection(selection, propagateToAccessor) {
707
+ let toAssign;
708
+ if (selection == null || !this._isValid(selection)) {
709
+ toAssign = selection;
710
+ } else {
711
+ const adapter = this._dateAdapter;
712
+ const target = adapter.getValidDateOrNull(this._lastValidDate || this.value());
713
+ const hours = adapter.getHours(selection);
714
+ const minutes = adapter.getMinutes(selection);
715
+ const seconds = adapter.getSeconds(selection);
716
+ toAssign = target ? adapter.setTime(target, hours, minutes, seconds) : selection;
695
717
  }
696
- /** Sets up the logic that adjusts the input if the min/max changes. */
697
- _respondToMinMaxChanges() {
698
- effect(() => {
699
- // Read the min/max so the effect knows when to fire.
700
- this.min();
701
- this.max();
702
- this._validatorOnChange?.();
703
- });
718
+ if (propagateToAccessor) {
719
+ this._onChange?.(toAssign);
704
720
  }
705
- /**
706
- * Assigns a value set by the user to the input's model.
707
- * @param selection Time selected by the user that should be assigned.
708
- * @param propagateToAccessor Whether the value should be propagated to the ControlValueAccessor.
709
- */
710
- _assignUserSelection(selection, propagateToAccessor) {
711
- let toAssign;
712
- if (selection == null || !this._isValid(selection)) {
713
- toAssign = selection;
714
- }
715
- else {
716
- // If a datepicker and timepicker are writing to the same object and the user enters an
717
- // invalid time into the timepicker, we may end up clearing their selection from the
718
- // datepicker. If the user enters a valid time afterwards, the datepicker's selection will
719
- // have been lost. This logic restores the previously-valid date and sets its time to
720
- // the newly-selected time.
721
- const adapter = this._dateAdapter;
722
- const target = adapter.getValidDateOrNull(this._lastValidDate || this.value());
723
- const hours = adapter.getHours(selection);
724
- const minutes = adapter.getMinutes(selection);
725
- const seconds = adapter.getSeconds(selection);
726
- toAssign = target ? adapter.setTime(target, hours, minutes, seconds) : selection;
721
+ this.value.set(toAssign);
722
+ }
723
+ _formatValue(value) {
724
+ value = this._dateAdapter.getValidDateOrNull(value);
725
+ this._elementRef.nativeElement.value = value == null ? '' : this._dateAdapter.format(value, this._dateFormats.display.timeInput);
726
+ }
727
+ _isValid(value) {
728
+ return !value || this._dateAdapter.isValid(value);
729
+ }
730
+ _transformDateInput(value) {
731
+ const date = typeof value === 'string' ? this._dateAdapter.parseTime(value, this._dateFormats.parse.timeInput) : this._dateAdapter.deserialize(value);
732
+ return date && this._dateAdapter.isValid(date) ? date : null;
733
+ }
734
+ _hasFocus() {
735
+ return _getFocusedElementPierceShadowDom() === this._elementRef.nativeElement;
736
+ }
737
+ _getValidator() {
738
+ return Validators.compose([() => this._lastValueValid ? null : {
739
+ 'matTimepickerParse': {
740
+ 'text': this._elementRef.nativeElement.value
741
+ }
742
+ }, control => {
743
+ const controlValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
744
+ const min = this.min();
745
+ return !min || !controlValue || this._dateAdapter.compareTime(min, controlValue) <= 0 ? null : {
746
+ 'matTimepickerMin': {
747
+ 'min': min,
748
+ 'actual': controlValue
727
749
  }
728
- // Propagate to the form control before emitting to `valueChange`.
729
- if (propagateToAccessor) {
730
- this._onChange?.(toAssign);
750
+ };
751
+ }, control => {
752
+ const controlValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
753
+ const max = this.max();
754
+ return !max || !controlValue || this._dateAdapter.compareTime(max, controlValue) >= 0 ? null : {
755
+ 'matTimepickerMax': {
756
+ 'max': max,
757
+ 'actual': controlValue
731
758
  }
732
- this.value.set(toAssign);
733
- }
734
- /** Formats the current value and assigns it to the input. */
735
- _formatValue(value) {
736
- value = this._dateAdapter.getValidDateOrNull(value);
737
- this._elementRef.nativeElement.value =
738
- value == null ? '' : this._dateAdapter.format(value, this._dateFormats.display.timeInput);
739
- }
740
- /** Checks whether a value is valid. */
741
- _isValid(value) {
742
- return !value || this._dateAdapter.isValid(value);
743
- }
744
- /** Transforms an arbitrary value into a value that can be assigned to a date-based input. */
745
- _transformDateInput(value) {
746
- const date = typeof value === 'string'
747
- ? this._dateAdapter.parseTime(value, this._dateFormats.parse.timeInput)
748
- : this._dateAdapter.deserialize(value);
749
- return date && this._dateAdapter.isValid(date) ? date : null;
750
- }
751
- /** Whether the input is currently focused. */
752
- _hasFocus() {
753
- return _getFocusedElementPierceShadowDom() === this._elementRef.nativeElement;
754
- }
755
- /** Gets a function that can be used to validate the input. */
756
- _getValidator() {
757
- return Validators.compose([
758
- () => this._lastValueValid
759
- ? null
760
- : { 'matTimepickerParse': { 'text': this._elementRef.nativeElement.value } },
761
- control => {
762
- const controlValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
763
- const min = this.min();
764
- return !min || !controlValue || this._dateAdapter.compareTime(min, controlValue) <= 0
765
- ? null
766
- : { 'matTimepickerMin': { 'min': min, 'actual': controlValue } };
767
- },
768
- control => {
769
- const controlValue = this._dateAdapter.getValidDateOrNull(this._dateAdapter.deserialize(control.value));
770
- const max = this.max();
771
- return !max || !controlValue || this._dateAdapter.compareTime(max, controlValue) >= 0
772
- ? null
773
- : { 'matTimepickerMax': { 'max': max, 'actual': controlValue } };
774
- },
775
- ]);
776
- }
777
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatTimepickerInput, deps: [], target: i0.ɵɵFactoryTarget.Directive });
778
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0-next.2", type: MatTimepickerInput, isStandalone: true, selector: "input[matTimepicker]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, timepicker: { classPropertyName: "timepicker", publicName: "matTimepicker", isSignal: true, isRequired: true, transformFunction: null }, min: { classPropertyName: "min", publicName: "matTimepickerMin", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "matTimepickerMax", isSignal: true, isRequired: false, transformFunction: null }, openOnClick: { classPropertyName: "openOnClick", publicName: "matTimepickerOpenOnClick", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "role": "combobox", "type": "text", "aria-haspopup": "listbox" }, listeners: { "blur": "_handleBlur()", "input": "_handleInput($event)", "keydown": "_handleKeydown($event)" }, properties: { "attr.aria-activedescendant": "_ariaActiveDescendant()", "attr.aria-expanded": "_ariaExpanded()", "attr.aria-controls": "_ariaControls()", "attr.mat-timepicker-id": "timepicker()?.panelId", "disabled": "disabled()" }, classAttribute: "mat-timepicker-input" }, providers: [
779
- {
780
- provide: NG_VALUE_ACCESSOR,
781
- useExisting: MatTimepickerInput,
782
- multi: true,
783
- },
784
- {
785
- provide: NG_VALIDATORS,
786
- useExisting: MatTimepickerInput,
787
- multi: true,
788
- },
789
- {
790
- provide: MAT_INPUT_VALUE_ACCESSOR,
791
- useExisting: MatTimepickerInput,
792
- },
793
- ], exportAs: ["matTimepickerInput"], ngImport: i0 });
759
+ };
760
+ }]);
761
+ }
762
+ static ɵfac = i0.ɵɵngDeclareFactory({
763
+ minVersion: "12.0.0",
764
+ version: "20.2.0-next.2",
765
+ ngImport: i0,
766
+ type: MatTimepickerInput,
767
+ deps: [],
768
+ target: i0.ɵɵFactoryTarget.Directive
769
+ });
770
+ static ɵdir = i0.ɵɵngDeclareDirective({
771
+ minVersion: "17.1.0",
772
+ version: "20.2.0-next.2",
773
+ type: MatTimepickerInput,
774
+ isStandalone: true,
775
+ selector: "input[matTimepicker]",
776
+ inputs: {
777
+ value: {
778
+ classPropertyName: "value",
779
+ publicName: "value",
780
+ isSignal: true,
781
+ isRequired: false,
782
+ transformFunction: null
783
+ },
784
+ timepicker: {
785
+ classPropertyName: "timepicker",
786
+ publicName: "matTimepicker",
787
+ isSignal: true,
788
+ isRequired: true,
789
+ transformFunction: null
790
+ },
791
+ min: {
792
+ classPropertyName: "min",
793
+ publicName: "matTimepickerMin",
794
+ isSignal: true,
795
+ isRequired: false,
796
+ transformFunction: null
797
+ },
798
+ max: {
799
+ classPropertyName: "max",
800
+ publicName: "matTimepickerMax",
801
+ isSignal: true,
802
+ isRequired: false,
803
+ transformFunction: null
804
+ },
805
+ openOnClick: {
806
+ classPropertyName: "openOnClick",
807
+ publicName: "matTimepickerOpenOnClick",
808
+ isSignal: true,
809
+ isRequired: false,
810
+ transformFunction: null
811
+ },
812
+ disabledInput: {
813
+ classPropertyName: "disabledInput",
814
+ publicName: "disabled",
815
+ isSignal: true,
816
+ isRequired: false,
817
+ transformFunction: null
818
+ }
819
+ },
820
+ outputs: {
821
+ value: "valueChange"
822
+ },
823
+ host: {
824
+ attributes: {
825
+ "role": "combobox",
826
+ "type": "text",
827
+ "aria-haspopup": "listbox"
828
+ },
829
+ listeners: {
830
+ "blur": "_handleBlur()",
831
+ "input": "_handleInput($event)",
832
+ "keydown": "_handleKeydown($event)"
833
+ },
834
+ properties: {
835
+ "attr.aria-activedescendant": "_ariaActiveDescendant()",
836
+ "attr.aria-expanded": "_ariaExpanded()",
837
+ "attr.aria-controls": "_ariaControls()",
838
+ "attr.mat-timepicker-id": "timepicker()?.panelId",
839
+ "disabled": "disabled()"
840
+ },
841
+ classAttribute: "mat-timepicker-input"
842
+ },
843
+ providers: [{
844
+ provide: NG_VALUE_ACCESSOR,
845
+ useExisting: MatTimepickerInput,
846
+ multi: true
847
+ }, {
848
+ provide: NG_VALIDATORS,
849
+ useExisting: MatTimepickerInput,
850
+ multi: true
851
+ }, {
852
+ provide: MAT_INPUT_VALUE_ACCESSOR,
853
+ useExisting: MatTimepickerInput
854
+ }],
855
+ exportAs: ["matTimepickerInput"],
856
+ ngImport: i0
857
+ });
794
858
  }
795
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatTimepickerInput, decorators: [{
796
- type: Directive,
797
- args: [{
798
- selector: 'input[matTimepicker]',
799
- exportAs: 'matTimepickerInput',
800
- host: {
801
- 'class': 'mat-timepicker-input',
802
- 'role': 'combobox',
803
- 'type': 'text',
804
- 'aria-haspopup': 'listbox',
805
- '[attr.aria-activedescendant]': '_ariaActiveDescendant()',
806
- '[attr.aria-expanded]': '_ariaExpanded()',
807
- '[attr.aria-controls]': '_ariaControls()',
808
- '[attr.mat-timepicker-id]': 'timepicker()?.panelId',
809
- '[disabled]': 'disabled()',
810
- '(blur)': '_handleBlur()',
811
- '(input)': '_handleInput($event)',
812
- '(keydown)': '_handleKeydown($event)',
813
- },
814
- providers: [
815
- {
816
- provide: NG_VALUE_ACCESSOR,
817
- useExisting: MatTimepickerInput,
818
- multi: true,
819
- },
820
- {
821
- provide: NG_VALIDATORS,
822
- useExisting: MatTimepickerInput,
823
- multi: true,
824
- },
825
- {
826
- provide: MAT_INPUT_VALUE_ACCESSOR,
827
- useExisting: MatTimepickerInput,
828
- },
829
- ],
830
- }]
831
- }], ctorParameters: () => [] });
859
+ i0.ɵɵngDeclareClassMetadata({
860
+ minVersion: "12.0.0",
861
+ version: "20.2.0-next.2",
862
+ ngImport: i0,
863
+ type: MatTimepickerInput,
864
+ decorators: [{
865
+ type: Directive,
866
+ args: [{
867
+ selector: 'input[matTimepicker]',
868
+ exportAs: 'matTimepickerInput',
869
+ host: {
870
+ 'class': 'mat-timepicker-input',
871
+ 'role': 'combobox',
872
+ 'type': 'text',
873
+ 'aria-haspopup': 'listbox',
874
+ '[attr.aria-activedescendant]': '_ariaActiveDescendant()',
875
+ '[attr.aria-expanded]': '_ariaExpanded()',
876
+ '[attr.aria-controls]': '_ariaControls()',
877
+ '[attr.mat-timepicker-id]': 'timepicker()?.panelId',
878
+ '[disabled]': 'disabled()',
879
+ '(blur)': '_handleBlur()',
880
+ '(input)': '_handleInput($event)',
881
+ '(keydown)': '_handleKeydown($event)'
882
+ },
883
+ providers: [{
884
+ provide: NG_VALUE_ACCESSOR,
885
+ useExisting: MatTimepickerInput,
886
+ multi: true
887
+ }, {
888
+ provide: NG_VALIDATORS,
889
+ useExisting: MatTimepickerInput,
890
+ multi: true
891
+ }, {
892
+ provide: MAT_INPUT_VALUE_ACCESSOR,
893
+ useExisting: MatTimepickerInput
894
+ }]
895
+ }]
896
+ }],
897
+ ctorParameters: () => []
898
+ });
832
899
 
833
- /** Button that can be used to open a `mat-timepicker`. */
834
900
  class MatTimepickerToggle {
835
- _defaultConfig = inject(MAT_TIMEPICKER_CONFIG, { optional: true });
836
- _defaultTabIndex = (() => {
837
- const value = inject(new HostAttributeToken('tabindex'), { optional: true });
838
- const parsed = Number(value);
839
- return isNaN(parsed) ? null : parsed;
840
- })();
841
- _isDisabled = computed(() => {
842
- const timepicker = this.timepicker();
843
- return this.disabled() || timepicker.disabled();
844
- }, ...(ngDevMode ? [{ debugName: "_isDisabled" }] : []));
845
- /** Timepicker instance that the button will toggle. */
846
- timepicker = input.required(...(ngDevMode ? [{ debugName: "timepicker", alias: 'for' }] : [{
847
- alias: 'for',
848
- }]));
849
- /** Screen-reader label for the button. */
850
- ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel", alias: 'aria-label' }] : [{
851
- alias: 'aria-label',
852
- }]));
853
- /** Screen-reader labelled by id for the button. */
854
- ariaLabelledby = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabelledby", alias: 'aria-labelledby' }] : [{
855
- alias: 'aria-labelledby',
856
- }]));
857
- /** Default aria-label for the toggle if none is provided. */
858
- _defaultAriaLabel = 'Open timepicker options';
859
- /** Whether the toggle button is disabled. */
860
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", transform: booleanAttribute,
861
- alias: 'disabled' }] : [{
862
- transform: booleanAttribute,
863
- alias: 'disabled',
864
- }]));
865
- /** Tabindex for the toggle. */
866
- tabIndex = input(this._defaultTabIndex, ...(ngDevMode ? [{ debugName: "tabIndex" }] : []));
867
- /** Whether ripples on the toggle should be disabled. */
868
- disableRipple = input(this._defaultConfig?.disableRipple ?? false, ...(ngDevMode ? [{ debugName: "disableRipple", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
869
- /** Opens the connected timepicker. */
870
- _open(event) {
871
- if (this.timepicker() && !this._isDisabled()) {
872
- this.timepicker().open();
873
- event.stopPropagation();
874
- }
875
- }
876
- /**
877
- * Checks for ariaLabelledby and if empty uses custom
878
- * aria-label or defaultAriaLabel if neither is provided.
879
- */
880
- getAriaLabel() {
881
- return this.ariaLabelledby() ? null : this.ariaLabel() || this._defaultAriaLabel;
901
+ _defaultConfig = inject(MAT_TIMEPICKER_CONFIG, {
902
+ optional: true
903
+ });
904
+ _defaultTabIndex = (() => {
905
+ const value = inject(new HostAttributeToken('tabindex'), {
906
+ optional: true
907
+ });
908
+ const parsed = Number(value);
909
+ return isNaN(parsed) ? null : parsed;
910
+ })();
911
+ _isDisabled = computed(() => {
912
+ const timepicker = this.timepicker();
913
+ return this.disabled() || timepicker.disabled();
914
+ }, ...(ngDevMode ? [{
915
+ debugName: "_isDisabled"
916
+ }] : []));
917
+ timepicker = input.required(...(ngDevMode ? [{
918
+ debugName: "timepicker",
919
+ alias: 'for'
920
+ }] : [{
921
+ alias: 'for'
922
+ }]));
923
+ ariaLabel = input(undefined, ...(ngDevMode ? [{
924
+ debugName: "ariaLabel",
925
+ alias: 'aria-label'
926
+ }] : [{
927
+ alias: 'aria-label'
928
+ }]));
929
+ ariaLabelledby = input(undefined, ...(ngDevMode ? [{
930
+ debugName: "ariaLabelledby",
931
+ alias: 'aria-labelledby'
932
+ }] : [{
933
+ alias: 'aria-labelledby'
934
+ }]));
935
+ _defaultAriaLabel = 'Open timepicker options';
936
+ disabled = input(false, ...(ngDevMode ? [{
937
+ debugName: "disabled",
938
+ transform: booleanAttribute,
939
+ alias: 'disabled'
940
+ }] : [{
941
+ transform: booleanAttribute,
942
+ alias: 'disabled'
943
+ }]));
944
+ tabIndex = input(this._defaultTabIndex, ...(ngDevMode ? [{
945
+ debugName: "tabIndex"
946
+ }] : []));
947
+ disableRipple = input(this._defaultConfig?.disableRipple ?? false, ...(ngDevMode ? [{
948
+ debugName: "disableRipple",
949
+ transform: booleanAttribute
950
+ }] : [{
951
+ transform: booleanAttribute
952
+ }]));
953
+ _open(event) {
954
+ if (this.timepicker() && !this._isDisabled()) {
955
+ this.timepicker().open();
956
+ event.stopPropagation();
882
957
  }
883
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatTimepickerToggle, deps: [], target: i0.ɵɵFactoryTarget.Component });
884
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.2.0-next.2", type: MatTimepickerToggle, isStandalone: true, selector: "mat-timepicker-toggle", inputs: { timepicker: { classPropertyName: "timepicker", publicName: "for", isSignal: true, isRequired: true, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, disableRipple: { classPropertyName: "disableRipple", publicName: "disableRipple", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "_open($event)" }, properties: { "attr.tabindex": "null" }, classAttribute: "mat-timepicker-toggle" }, exportAs: ["matTimepickerToggle"], ngImport: i0, template: "<button\n matIconButton\n type=\"button\"\n aria-haspopup=\"listbox\"\n [attr.aria-label]=\"getAriaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n [attr.aria-expanded]=\"timepicker().isOpen()\"\n [tabIndex]=\"_isDisabled() ? -1 : tabIndex()\"\n [disabled]=\"_isDisabled()\"\n [disableRipple]=\"disableRipple()\">\n\n <ng-content select=\"[matTimepickerToggleIcon]\">\n <svg\n class=\"mat-timepicker-toggle-default-icon\"\n height=\"24px\"\n width=\"24px\"\n viewBox=\"0 -960 960 960\"\n fill=\"currentColor\"\n focusable=\"false\"\n aria-hidden=\"true\">\n <path d=\"m612-292 56-56-148-148v-184h-80v216l172 172ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q133 0 226.5-93.5T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160Z\"/>\n </svg>\n </ng-content>\n</button>\n", dependencies: [{ kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
958
+ }
959
+ getAriaLabel() {
960
+ return this.ariaLabelledby() ? null : this.ariaLabel() || this._defaultAriaLabel;
961
+ }
962
+ static ɵfac = i0.ɵɵngDeclareFactory({
963
+ minVersion: "12.0.0",
964
+ version: "20.2.0-next.2",
965
+ ngImport: i0,
966
+ type: MatTimepickerToggle,
967
+ deps: [],
968
+ target: i0.ɵɵFactoryTarget.Component
969
+ });
970
+ static ɵcmp = i0.ɵɵngDeclareComponent({
971
+ minVersion: "17.1.0",
972
+ version: "20.2.0-next.2",
973
+ type: MatTimepickerToggle,
974
+ isStandalone: true,
975
+ selector: "mat-timepicker-toggle",
976
+ inputs: {
977
+ timepicker: {
978
+ classPropertyName: "timepicker",
979
+ publicName: "for",
980
+ isSignal: true,
981
+ isRequired: true,
982
+ transformFunction: null
983
+ },
984
+ ariaLabel: {
985
+ classPropertyName: "ariaLabel",
986
+ publicName: "aria-label",
987
+ isSignal: true,
988
+ isRequired: false,
989
+ transformFunction: null
990
+ },
991
+ ariaLabelledby: {
992
+ classPropertyName: "ariaLabelledby",
993
+ publicName: "aria-labelledby",
994
+ isSignal: true,
995
+ isRequired: false,
996
+ transformFunction: null
997
+ },
998
+ disabled: {
999
+ classPropertyName: "disabled",
1000
+ publicName: "disabled",
1001
+ isSignal: true,
1002
+ isRequired: false,
1003
+ transformFunction: null
1004
+ },
1005
+ tabIndex: {
1006
+ classPropertyName: "tabIndex",
1007
+ publicName: "tabIndex",
1008
+ isSignal: true,
1009
+ isRequired: false,
1010
+ transformFunction: null
1011
+ },
1012
+ disableRipple: {
1013
+ classPropertyName: "disableRipple",
1014
+ publicName: "disableRipple",
1015
+ isSignal: true,
1016
+ isRequired: false,
1017
+ transformFunction: null
1018
+ }
1019
+ },
1020
+ host: {
1021
+ listeners: {
1022
+ "click": "_open($event)"
1023
+ },
1024
+ properties: {
1025
+ "attr.tabindex": "null"
1026
+ },
1027
+ classAttribute: "mat-timepicker-toggle"
1028
+ },
1029
+ exportAs: ["matTimepickerToggle"],
1030
+ ngImport: i0,
1031
+ template: "<button\n matIconButton\n type=\"button\"\n aria-haspopup=\"listbox\"\n [attr.aria-label]=\"getAriaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n [attr.aria-expanded]=\"timepicker().isOpen()\"\n [tabIndex]=\"_isDisabled() ? -1 : tabIndex()\"\n [disabled]=\"_isDisabled()\"\n [disableRipple]=\"disableRipple()\">\n\n <ng-content select=\"[matTimepickerToggleIcon]\">\n <svg\n class=\"mat-timepicker-toggle-default-icon\"\n height=\"24px\"\n width=\"24px\"\n viewBox=\"0 -960 960 960\"\n fill=\"currentColor\"\n focusable=\"false\"\n aria-hidden=\"true\">\n <path d=\"m612-292 56-56-148-148v-184h-80v216l172 172ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q133 0 226.5-93.5T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160Z\"/>\n </svg>\n </ng-content>\n</button>\n",
1032
+ dependencies: [{
1033
+ kind: "component",
1034
+ type: MatIconButton,
1035
+ selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]",
1036
+ exportAs: ["matButton", "matAnchor"]
1037
+ }],
1038
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
1039
+ encapsulation: i0.ViewEncapsulation.None
1040
+ });
885
1041
  }
886
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatTimepickerToggle, decorators: [{
887
- type: Component,
888
- args: [{ selector: 'mat-timepicker-toggle', host: {
889
- 'class': 'mat-timepicker-toggle',
890
- '[attr.tabindex]': 'null',
891
- // Bind the `click` on the host, rather than the inner `button`, so that we can call
892
- // `stopPropagation` on it without affecting the user's `click` handlers. We need to stop
893
- // it so that the input doesn't get focused automatically by the form field (See #21836).
894
- '(click)': '_open($event)',
895
- }, exportAs: 'matTimepickerToggle', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatIconButton], template: "<button\n matIconButton\n type=\"button\"\n aria-haspopup=\"listbox\"\n [attr.aria-label]=\"getAriaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n [attr.aria-expanded]=\"timepicker().isOpen()\"\n [tabIndex]=\"_isDisabled() ? -1 : tabIndex()\"\n [disabled]=\"_isDisabled()\"\n [disableRipple]=\"disableRipple()\">\n\n <ng-content select=\"[matTimepickerToggleIcon]\">\n <svg\n class=\"mat-timepicker-toggle-default-icon\"\n height=\"24px\"\n width=\"24px\"\n viewBox=\"0 -960 960 960\"\n fill=\"currentColor\"\n focusable=\"false\"\n aria-hidden=\"true\">\n <path d=\"m612-292 56-56-148-148v-184h-80v216l172 172ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q133 0 226.5-93.5T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160Z\"/>\n </svg>\n </ng-content>\n</button>\n" }]
896
- }] });
1042
+ i0.ɵɵngDeclareClassMetadata({
1043
+ minVersion: "12.0.0",
1044
+ version: "20.2.0-next.2",
1045
+ ngImport: i0,
1046
+ type: MatTimepickerToggle,
1047
+ decorators: [{
1048
+ type: Component,
1049
+ args: [{
1050
+ selector: 'mat-timepicker-toggle',
1051
+ host: {
1052
+ 'class': 'mat-timepicker-toggle',
1053
+ '[attr.tabindex]': 'null',
1054
+ '(click)': '_open($event)'
1055
+ },
1056
+ exportAs: 'matTimepickerToggle',
1057
+ encapsulation: ViewEncapsulation.None,
1058
+ changeDetection: ChangeDetectionStrategy.OnPush,
1059
+ imports: [MatIconButton],
1060
+ template: "<button\n matIconButton\n type=\"button\"\n aria-haspopup=\"listbox\"\n [attr.aria-label]=\"getAriaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n [attr.aria-expanded]=\"timepicker().isOpen()\"\n [tabIndex]=\"_isDisabled() ? -1 : tabIndex()\"\n [disabled]=\"_isDisabled()\"\n [disableRipple]=\"disableRipple()\">\n\n <ng-content select=\"[matTimepickerToggleIcon]\">\n <svg\n class=\"mat-timepicker-toggle-default-icon\"\n height=\"24px\"\n width=\"24px\"\n viewBox=\"0 -960 960 960\"\n fill=\"currentColor\"\n focusable=\"false\"\n aria-hidden=\"true\">\n <path d=\"m612-292 56-56-148-148v-184h-80v216l172 172ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q133 0 226.5-93.5T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160Z\"/>\n </svg>\n </ng-content>\n</button>\n"
1061
+ }]
1062
+ }]
1063
+ });
897
1064
 
898
1065
  class MatTimepickerModule {
899
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatTimepickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
900
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatTimepickerModule, imports: [MatTimepicker, MatTimepickerInput, MatTimepickerToggle], exports: [CdkScrollableModule, MatTimepicker, MatTimepickerInput, MatTimepickerToggle] });
901
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatTimepickerModule, imports: [MatTimepicker, MatTimepickerToggle, CdkScrollableModule] });
1066
+ static ɵfac = i0.ɵɵngDeclareFactory({
1067
+ minVersion: "12.0.0",
1068
+ version: "20.2.0-next.2",
1069
+ ngImport: i0,
1070
+ type: MatTimepickerModule,
1071
+ deps: [],
1072
+ target: i0.ɵɵFactoryTarget.NgModule
1073
+ });
1074
+ static ɵmod = i0.ɵɵngDeclareNgModule({
1075
+ minVersion: "14.0.0",
1076
+ version: "20.2.0-next.2",
1077
+ ngImport: i0,
1078
+ type: MatTimepickerModule,
1079
+ imports: [MatTimepicker, MatTimepickerInput, MatTimepickerToggle],
1080
+ exports: [CdkScrollableModule, MatTimepicker, MatTimepickerInput, MatTimepickerToggle]
1081
+ });
1082
+ static ɵinj = i0.ɵɵngDeclareInjector({
1083
+ minVersion: "12.0.0",
1084
+ version: "20.2.0-next.2",
1085
+ ngImport: i0,
1086
+ type: MatTimepickerModule,
1087
+ imports: [MatTimepicker, MatTimepickerToggle, CdkScrollableModule]
1088
+ });
902
1089
  }
903
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: MatTimepickerModule, decorators: [{
904
- type: NgModule,
905
- args: [{
906
- imports: [MatTimepicker, MatTimepickerInput, MatTimepickerToggle],
907
- exports: [CdkScrollableModule, MatTimepicker, MatTimepickerInput, MatTimepickerToggle],
908
- }]
909
- }] });
1090
+ i0.ɵɵngDeclareClassMetadata({
1091
+ minVersion: "12.0.0",
1092
+ version: "20.2.0-next.2",
1093
+ ngImport: i0,
1094
+ type: MatTimepickerModule,
1095
+ decorators: [{
1096
+ type: NgModule,
1097
+ args: [{
1098
+ imports: [MatTimepicker, MatTimepickerInput, MatTimepickerToggle],
1099
+ exports: [CdkScrollableModule, MatTimepicker, MatTimepickerInput, MatTimepickerToggle]
1100
+ }]
1101
+ }]
1102
+ });
910
1103
 
911
1104
  export { MAT_TIMEPICKER_CONFIG, MAT_TIMEPICKER_SCROLL_STRATEGY, MatTimepicker, MatTimepickerInput, MatTimepickerModule, MatTimepickerToggle };
912
1105
  //# sourceMappingURL=timepicker.mjs.map