@wkly/datetime-picker 20.0.0 → 22.0.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.
@@ -1,1709 +1,2199 @@
1
- import * as i0 from '@angular/core';
2
- import { InjectionToken, input, booleanAttribute, output, Directive, EventEmitter, Output, Input, Component, signal, effect, untracked, LOCALE_ID, PLATFORM_ID, forwardRef, ViewChild, Inject, createComponent, Injectable, HostListener, NgModule } from '@angular/core';
3
- import * as i1 from '@angular/common';
4
- import { isPlatformBrowser, getLocaleFirstDayOfWeek, DOCUMENT, CommonModule } from '@angular/common';
5
- import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
6
- import { floorMod, integer, createWeekGenerator, absoluteWeekOf, firstEpochDayOf } from '@wkly/core';
7
- import { DEFAULT_OVERSCAN_WEEKS, WklyPickerInputsPropertyKeys, WklyPickerOutputsPropertyKeys, resolveWklyTranslation, validateDrafts, draftDayDifference, setDraftDayDifference, calendarMonthBounds, createWeekRows } from '@wkly/presentation';
8
- export * from '@wkly/presentation';
9
- import { normalizeDigits, WklyGregorianCalendarAdapter, resolveWeekOffset, error, validateSelection, decodeIso } from '@wkly/adapters';
10
-
1
+ import * as i0 from "@angular/core";
2
+ import { Component, Directive, EventEmitter, HostListener, Inject, Injectable, InjectionToken, Input, LOCALE_ID, NgModule, Output, PLATFORM_ID, ViewChild, booleanAttribute, createComponent, effect, forwardRef, input, output, signal, untracked } from "@angular/core";
3
+ import * as i1 from "@angular/common";
4
+ import { CommonModule, DOCUMENT, getLocaleFirstDayOfWeek, isPlatformBrowser } from "@angular/common";
5
+ import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from "@angular/forms";
6
+ import { absoluteWeekOf, createWeekGenerator, firstEpochDayOf, floorMod, integer } from "@wkly/core";
7
+ import { DEFAULT_OVERSCAN_WEEKS, WklyPickerInputsPropertyKeys, WklyPickerOutputsPropertyKeys, calendarMonthBounds, createWeekRows, draftDayDifference, resolveWklyTranslation, setDraftDayDifference, validateDrafts } from "@wkly/presentation";
8
+ import { WklyGregorianCalendarAdapter, decodeIso, error, normalizeDigits, resolveWeekOffset, validateSelection } from "@wkly/adapters";
9
+ export * from "@wkly/presentation";
11
10
  const WKLY_CLOCK = new InjectionToken("WKLY_CLOCK", {
12
- providedIn: "root",
13
- factory: () => ({ now: () => new Date() }),
11
+ providedIn: "root",
12
+ factory: () => ({ now: () => /* @__PURE__ */ new Date() })
13
+ });
14
+ const WKLY_CONFIG = new InjectionToken("WKLY_CONFIG", {
15
+ providedIn: "root",
16
+ factory: () => ({})
17
+ });
18
+ const WKLY_LOCALIZATION = new InjectionToken("WKLY_LOCALIZATION", {
19
+ providedIn: "root",
20
+ factory: () => ({})
21
+ });
22
+ const WKLY_TRANSLATIONS = new InjectionToken("WKLY_TRANSLATIONS", {
23
+ providedIn: "root",
24
+ factory: () => ({})
25
+ });
26
+ var WklyPickerInputs = class WklyPickerInputs {
27
+ modeInput = input("datetime", {
28
+ ...ngDevMode ? { debugName: "modeInput" } : /* istanbul ignore next */ {},
29
+ alias: "mode"
30
+ });
31
+ valueInput = input(null, {
32
+ ...ngDevMode ? { debugName: "valueInput" } : /* istanbul ignore next */ {},
33
+ alias: "value"
34
+ });
35
+ calendarAdapterInput = input(void 0, {
36
+ ...ngDevMode ? { debugName: "calendarAdapterInput" } : /* istanbul ignore next */ {},
37
+ alias: "calendarAdapter"
38
+ });
39
+ localeInput = input("", {
40
+ ...ngDevMode ? { debugName: "localeInput" } : /* istanbul ignore next */ {},
41
+ alias: "locale"
42
+ });
43
+ weekOffsetInput = input(null, {
44
+ ...ngDevMode ? { debugName: "weekOffsetInput" } : /* istanbul ignore next */ {},
45
+ alias: "weekOffset"
46
+ });
47
+ viewportPresetInput = input({ kind: "full-month" }, {
48
+ ...ngDevMode ? { debugName: "viewportPresetInput" } : /* istanbul ignore next */ {},
49
+ alias: "viewportPreset"
50
+ });
51
+ hourCycleInput = input("locale", {
52
+ ...ngDevMode ? { debugName: "hourCycleInput" } : /* istanbul ignore next */ {},
53
+ alias: "hourCycle"
54
+ });
55
+ showSecondsInput = input(false, {
56
+ ...ngDevMode ? { debugName: "showSecondsInput" } : /* istanbul ignore next */ {},
57
+ alias: "showSeconds",
58
+ transform: booleanAttribute
59
+ });
60
+ minuteStepInput = input(1, {
61
+ ...ngDevMode ? { debugName: "minuteStepInput" } : /* istanbul ignore next */ {},
62
+ alias: "minuteStep"
63
+ });
64
+ secondStepInput = input(1, {
65
+ ...ngDevMode ? { debugName: "secondStepInput" } : /* istanbul ignore next */ {},
66
+ alias: "secondStep"
67
+ });
68
+ minInput = input(null, {
69
+ ...ngDevMode ? { debugName: "minInput" } : /* istanbul ignore next */ {},
70
+ alias: "min"
71
+ });
72
+ maxInput = input(null, {
73
+ ...ngDevMode ? { debugName: "maxInput" } : /* istanbul ignore next */ {},
74
+ alias: "max"
75
+ });
76
+ isDateDisabledInput = input(null, {
77
+ ...ngDevMode ? { debugName: "isDateDisabledInput" } : /* istanbul ignore next */ {},
78
+ alias: "isDateDisabled"
79
+ });
80
+ isTimeDisabledInput = input(null, {
81
+ ...ngDevMode ? { debugName: "isTimeDisabledInput" } : /* istanbul ignore next */ {},
82
+ alias: "isTimeDisabled"
83
+ });
84
+ rangeValidatorInput = input(null, {
85
+ ...ngDevMode ? { debugName: "rangeValidatorInput" } : /* istanbul ignore next */ {},
86
+ alias: "rangeValidator"
87
+ });
88
+ allowRangeAcrossDisabledInput = input(false, {
89
+ ...ngDevMode ? { debugName: "allowRangeAcrossDisabledInput" } : /* istanbul ignore next */ {},
90
+ alias: "allowRangeAcrossDisabled",
91
+ transform: booleanAttribute
92
+ });
93
+ requiredInput = input(false, {
94
+ ...ngDevMode ? { debugName: "requiredInput" } : /* istanbul ignore next */ {},
95
+ alias: "required",
96
+ transform: booleanAttribute
97
+ });
98
+ disabledInput = input(false, {
99
+ ...ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {},
100
+ alias: "disabled",
101
+ transform: booleanAttribute
102
+ });
103
+ weekLabelModeInput = input("locale", {
104
+ ...ngDevMode ? { debugName: "weekLabelModeInput" } : /* istanbul ignore next */ {},
105
+ alias: "weekLabelMode"
106
+ });
107
+ weekLabelFormatterInput = input(null, {
108
+ ...ngDevMode ? { debugName: "weekLabelFormatterInput" } : /* istanbul ignore next */ {},
109
+ alias: "weekLabelFormatter"
110
+ });
111
+ weekCacheSizeInput = input(256, {
112
+ ...ngDevMode ? { debugName: "weekCacheSizeInput" } : /* istanbul ignore next */ {},
113
+ alias: "weekCacheSize"
114
+ });
115
+ overscanWeeksInput = input(DEFAULT_OVERSCAN_WEEKS, {
116
+ ...ngDevMode ? { debugName: "overscanWeeksInput" } : /* istanbul ignore next */ {},
117
+ alias: "overscanWeeks"
118
+ });
119
+ ariaLabelInput = input(null, {
120
+ ...ngDevMode ? { debugName: "ariaLabelInput" } : /* istanbul ignore next */ {},
121
+ alias: "ariaLabel"
122
+ });
123
+ ariaDescribedByInput = input(null, {
124
+ ...ngDevMode ? { debugName: "ariaDescribedByInput" } : /* istanbul ignore next */ {},
125
+ alias: "ariaDescribedBy"
126
+ });
127
+ initialEpochDayInput = input(null, {
128
+ ...ngDevMode ? { debugName: "initialEpochDayInput" } : /* istanbul ignore next */ {},
129
+ alias: "initialEpochDay"
130
+ });
131
+ closeOnBackdropInput = input(true, {
132
+ ...ngDevMode ? { debugName: "closeOnBackdropInput" } : /* istanbul ignore next */ {},
133
+ alias: "closeOnBackdrop",
134
+ transform: booleanAttribute
135
+ });
136
+ validatorsInput = input([], {
137
+ ...ngDevMode ? { debugName: "validatorsInput" } : /* istanbul ignore next */ {},
138
+ alias: "validators"
139
+ });
140
+ translationsInput = input(null, {
141
+ ...ngDevMode ? { debugName: "translationsInput" } : /* istanbul ignore next */ {},
142
+ alias: "translations"
143
+ });
144
+ [WklyPickerInputsPropertyKeys.Mode] = this.modeInput;
145
+ [WklyPickerInputsPropertyKeys.Value] = this.valueInput;
146
+ [WklyPickerInputsPropertyKeys.CalendarAdapter] = this.calendarAdapterInput;
147
+ [WklyPickerInputsPropertyKeys.Locale] = this.localeInput;
148
+ [WklyPickerInputsPropertyKeys.WeekOffset] = this.weekOffsetInput;
149
+ [WklyPickerInputsPropertyKeys.ViewportPreset] = this.viewportPresetInput;
150
+ [WklyPickerInputsPropertyKeys.HourCycle] = this.hourCycleInput;
151
+ [WklyPickerInputsPropertyKeys.ShowSeconds] = this.showSecondsInput;
152
+ [WklyPickerInputsPropertyKeys.MinuteStep] = this.minuteStepInput;
153
+ [WklyPickerInputsPropertyKeys.SecondStep] = this.secondStepInput;
154
+ [WklyPickerInputsPropertyKeys.Min] = this.minInput;
155
+ [WklyPickerInputsPropertyKeys.Max] = this.maxInput;
156
+ [WklyPickerInputsPropertyKeys.IsDateDisabled] = this.isDateDisabledInput;
157
+ [WklyPickerInputsPropertyKeys.IsTimeDisabled] = this.isTimeDisabledInput;
158
+ [WklyPickerInputsPropertyKeys.RangeValidator] = this.rangeValidatorInput;
159
+ [WklyPickerInputsPropertyKeys.AllowRangeAcrossDisabled] = this.allowRangeAcrossDisabledInput;
160
+ [WklyPickerInputsPropertyKeys.Required] = this.requiredInput;
161
+ [WklyPickerInputsPropertyKeys.Disabled] = this.disabledInput;
162
+ [WklyPickerInputsPropertyKeys.WeekLabelMode] = this.weekLabelModeInput;
163
+ [WklyPickerInputsPropertyKeys.WeekLabelFormatter] = this.weekLabelFormatterInput;
164
+ [WklyPickerInputsPropertyKeys.WeekCacheSize] = this.weekCacheSizeInput;
165
+ [WklyPickerInputsPropertyKeys.OverscanWeeks] = this.overscanWeeksInput;
166
+ [WklyPickerInputsPropertyKeys.AriaLabel] = this.ariaLabelInput;
167
+ [WklyPickerInputsPropertyKeys.AriaDescribedBy] = this.ariaDescribedByInput;
168
+ [WklyPickerInputsPropertyKeys.InitialEpochDay] = this.initialEpochDayInput;
169
+ [WklyPickerInputsPropertyKeys.CloseOnBackdrop] = this.closeOnBackdropInput;
170
+ [WklyPickerInputsPropertyKeys.Validators] = this.validatorsInput;
171
+ [WklyPickerInputsPropertyKeys.Translations] = this.translationsInput;
172
+ [WklyPickerOutputsPropertyKeys.ValueChange] = output();
173
+ [WklyPickerOutputsPropertyKeys.ValidationChange] = output();
174
+ [WklyPickerOutputsPropertyKeys.Opened] = output();
175
+ [WklyPickerOutputsPropertyKeys.Closed] = output();
176
+ [WklyPickerOutputsPropertyKeys.ViewportChange] = output();
177
+ [WklyPickerOutputsPropertyKeys.ViewModeChange] = output();
178
+ static ɵfac = i0.ɵɵngDeclareFactory({
179
+ minVersion: "12.0.0",
180
+ version: "22.2.1",
181
+ ngImport: i0,
182
+ type: WklyPickerInputs,
183
+ deps: [],
184
+ target: i0.ɵɵFactoryTarget.Directive
185
+ });
186
+ static ɵdir = i0.ɵɵngDeclareDirective({
187
+ minVersion: "17.1.0",
188
+ version: "22.2.1",
189
+ type: WklyPickerInputs,
190
+ isStandalone: true,
191
+ inputs: {
192
+ modeInput: {
193
+ classPropertyName: "modeInput",
194
+ publicName: "mode",
195
+ isSignal: true,
196
+ isRequired: false,
197
+ transformFunction: null
198
+ },
199
+ valueInput: {
200
+ classPropertyName: "valueInput",
201
+ publicName: "value",
202
+ isSignal: true,
203
+ isRequired: false,
204
+ transformFunction: null
205
+ },
206
+ calendarAdapterInput: {
207
+ classPropertyName: "calendarAdapterInput",
208
+ publicName: "calendarAdapter",
209
+ isSignal: true,
210
+ isRequired: false,
211
+ transformFunction: null
212
+ },
213
+ localeInput: {
214
+ classPropertyName: "localeInput",
215
+ publicName: "locale",
216
+ isSignal: true,
217
+ isRequired: false,
218
+ transformFunction: null
219
+ },
220
+ weekOffsetInput: {
221
+ classPropertyName: "weekOffsetInput",
222
+ publicName: "weekOffset",
223
+ isSignal: true,
224
+ isRequired: false,
225
+ transformFunction: null
226
+ },
227
+ viewportPresetInput: {
228
+ classPropertyName: "viewportPresetInput",
229
+ publicName: "viewportPreset",
230
+ isSignal: true,
231
+ isRequired: false,
232
+ transformFunction: null
233
+ },
234
+ hourCycleInput: {
235
+ classPropertyName: "hourCycleInput",
236
+ publicName: "hourCycle",
237
+ isSignal: true,
238
+ isRequired: false,
239
+ transformFunction: null
240
+ },
241
+ showSecondsInput: {
242
+ classPropertyName: "showSecondsInput",
243
+ publicName: "showSeconds",
244
+ isSignal: true,
245
+ isRequired: false,
246
+ transformFunction: null
247
+ },
248
+ minuteStepInput: {
249
+ classPropertyName: "minuteStepInput",
250
+ publicName: "minuteStep",
251
+ isSignal: true,
252
+ isRequired: false,
253
+ transformFunction: null
254
+ },
255
+ secondStepInput: {
256
+ classPropertyName: "secondStepInput",
257
+ publicName: "secondStep",
258
+ isSignal: true,
259
+ isRequired: false,
260
+ transformFunction: null
261
+ },
262
+ minInput: {
263
+ classPropertyName: "minInput",
264
+ publicName: "min",
265
+ isSignal: true,
266
+ isRequired: false,
267
+ transformFunction: null
268
+ },
269
+ maxInput: {
270
+ classPropertyName: "maxInput",
271
+ publicName: "max",
272
+ isSignal: true,
273
+ isRequired: false,
274
+ transformFunction: null
275
+ },
276
+ isDateDisabledInput: {
277
+ classPropertyName: "isDateDisabledInput",
278
+ publicName: "isDateDisabled",
279
+ isSignal: true,
280
+ isRequired: false,
281
+ transformFunction: null
282
+ },
283
+ isTimeDisabledInput: {
284
+ classPropertyName: "isTimeDisabledInput",
285
+ publicName: "isTimeDisabled",
286
+ isSignal: true,
287
+ isRequired: false,
288
+ transformFunction: null
289
+ },
290
+ rangeValidatorInput: {
291
+ classPropertyName: "rangeValidatorInput",
292
+ publicName: "rangeValidator",
293
+ isSignal: true,
294
+ isRequired: false,
295
+ transformFunction: null
296
+ },
297
+ allowRangeAcrossDisabledInput: {
298
+ classPropertyName: "allowRangeAcrossDisabledInput",
299
+ publicName: "allowRangeAcrossDisabled",
300
+ isSignal: true,
301
+ isRequired: false,
302
+ transformFunction: null
303
+ },
304
+ requiredInput: {
305
+ classPropertyName: "requiredInput",
306
+ publicName: "required",
307
+ isSignal: true,
308
+ isRequired: false,
309
+ transformFunction: null
310
+ },
311
+ disabledInput: {
312
+ classPropertyName: "disabledInput",
313
+ publicName: "disabled",
314
+ isSignal: true,
315
+ isRequired: false,
316
+ transformFunction: null
317
+ },
318
+ weekLabelModeInput: {
319
+ classPropertyName: "weekLabelModeInput",
320
+ publicName: "weekLabelMode",
321
+ isSignal: true,
322
+ isRequired: false,
323
+ transformFunction: null
324
+ },
325
+ weekLabelFormatterInput: {
326
+ classPropertyName: "weekLabelFormatterInput",
327
+ publicName: "weekLabelFormatter",
328
+ isSignal: true,
329
+ isRequired: false,
330
+ transformFunction: null
331
+ },
332
+ weekCacheSizeInput: {
333
+ classPropertyName: "weekCacheSizeInput",
334
+ publicName: "weekCacheSize",
335
+ isSignal: true,
336
+ isRequired: false,
337
+ transformFunction: null
338
+ },
339
+ overscanWeeksInput: {
340
+ classPropertyName: "overscanWeeksInput",
341
+ publicName: "overscanWeeks",
342
+ isSignal: true,
343
+ isRequired: false,
344
+ transformFunction: null
345
+ },
346
+ ariaLabelInput: {
347
+ classPropertyName: "ariaLabelInput",
348
+ publicName: "ariaLabel",
349
+ isSignal: true,
350
+ isRequired: false,
351
+ transformFunction: null
352
+ },
353
+ ariaDescribedByInput: {
354
+ classPropertyName: "ariaDescribedByInput",
355
+ publicName: "ariaDescribedBy",
356
+ isSignal: true,
357
+ isRequired: false,
358
+ transformFunction: null
359
+ },
360
+ initialEpochDayInput: {
361
+ classPropertyName: "initialEpochDayInput",
362
+ publicName: "initialEpochDay",
363
+ isSignal: true,
364
+ isRequired: false,
365
+ transformFunction: null
366
+ },
367
+ closeOnBackdropInput: {
368
+ classPropertyName: "closeOnBackdropInput",
369
+ publicName: "closeOnBackdrop",
370
+ isSignal: true,
371
+ isRequired: false,
372
+ transformFunction: null
373
+ },
374
+ validatorsInput: {
375
+ classPropertyName: "validatorsInput",
376
+ publicName: "validators",
377
+ isSignal: true,
378
+ isRequired: false,
379
+ transformFunction: null
380
+ },
381
+ translationsInput: {
382
+ classPropertyName: "translationsInput",
383
+ publicName: "translations",
384
+ isSignal: true,
385
+ isRequired: false,
386
+ transformFunction: null
387
+ }
388
+ },
389
+ outputs: {
390
+ valueChange: "valueChange",
391
+ validationChange: "validationChange",
392
+ opened: "opened",
393
+ closed: "closed",
394
+ viewportChange: "viewportChange",
395
+ viewModeChange: "viewModeChange"
396
+ },
397
+ ngImport: i0
398
+ });
399
+ };
400
+ i0.ɵɵngDeclareClassMetadata({
401
+ minVersion: "12.0.0",
402
+ version: "22.2.1",
403
+ ngImport: i0,
404
+ type: WklyPickerInputs,
405
+ decorators: [{
406
+ type: Directive,
407
+ args: [{ outputs: [
408
+ `${WklyPickerOutputsPropertyKeys.ValueChange}`,
409
+ `${WklyPickerOutputsPropertyKeys.ValidationChange}`,
410
+ `${WklyPickerOutputsPropertyKeys.Opened}`,
411
+ `${WklyPickerOutputsPropertyKeys.Closed}`,
412
+ `${WklyPickerOutputsPropertyKeys.ViewportChange}`,
413
+ `${WklyPickerOutputsPropertyKeys.ViewModeChange}`
414
+ ] }]
415
+ }],
416
+ propDecorators: {
417
+ modeInput: [{
418
+ type: i0.Input,
419
+ args: [{
420
+ isSignal: true,
421
+ alias: "mode",
422
+ required: false
423
+ }]
424
+ }],
425
+ valueInput: [{
426
+ type: i0.Input,
427
+ args: [{
428
+ isSignal: true,
429
+ alias: "value",
430
+ required: false
431
+ }]
432
+ }],
433
+ calendarAdapterInput: [{
434
+ type: i0.Input,
435
+ args: [{
436
+ isSignal: true,
437
+ alias: "calendarAdapter",
438
+ required: false
439
+ }]
440
+ }],
441
+ localeInput: [{
442
+ type: i0.Input,
443
+ args: [{
444
+ isSignal: true,
445
+ alias: "locale",
446
+ required: false
447
+ }]
448
+ }],
449
+ weekOffsetInput: [{
450
+ type: i0.Input,
451
+ args: [{
452
+ isSignal: true,
453
+ alias: "weekOffset",
454
+ required: false
455
+ }]
456
+ }],
457
+ viewportPresetInput: [{
458
+ type: i0.Input,
459
+ args: [{
460
+ isSignal: true,
461
+ alias: "viewportPreset",
462
+ required: false
463
+ }]
464
+ }],
465
+ hourCycleInput: [{
466
+ type: i0.Input,
467
+ args: [{
468
+ isSignal: true,
469
+ alias: "hourCycle",
470
+ required: false
471
+ }]
472
+ }],
473
+ showSecondsInput: [{
474
+ type: i0.Input,
475
+ args: [{
476
+ isSignal: true,
477
+ alias: "showSeconds",
478
+ required: false
479
+ }]
480
+ }],
481
+ minuteStepInput: [{
482
+ type: i0.Input,
483
+ args: [{
484
+ isSignal: true,
485
+ alias: "minuteStep",
486
+ required: false
487
+ }]
488
+ }],
489
+ secondStepInput: [{
490
+ type: i0.Input,
491
+ args: [{
492
+ isSignal: true,
493
+ alias: "secondStep",
494
+ required: false
495
+ }]
496
+ }],
497
+ minInput: [{
498
+ type: i0.Input,
499
+ args: [{
500
+ isSignal: true,
501
+ alias: "min",
502
+ required: false
503
+ }]
504
+ }],
505
+ maxInput: [{
506
+ type: i0.Input,
507
+ args: [{
508
+ isSignal: true,
509
+ alias: "max",
510
+ required: false
511
+ }]
512
+ }],
513
+ isDateDisabledInput: [{
514
+ type: i0.Input,
515
+ args: [{
516
+ isSignal: true,
517
+ alias: "isDateDisabled",
518
+ required: false
519
+ }]
520
+ }],
521
+ isTimeDisabledInput: [{
522
+ type: i0.Input,
523
+ args: [{
524
+ isSignal: true,
525
+ alias: "isTimeDisabled",
526
+ required: false
527
+ }]
528
+ }],
529
+ rangeValidatorInput: [{
530
+ type: i0.Input,
531
+ args: [{
532
+ isSignal: true,
533
+ alias: "rangeValidator",
534
+ required: false
535
+ }]
536
+ }],
537
+ allowRangeAcrossDisabledInput: [{
538
+ type: i0.Input,
539
+ args: [{
540
+ isSignal: true,
541
+ alias: "allowRangeAcrossDisabled",
542
+ required: false
543
+ }]
544
+ }],
545
+ requiredInput: [{
546
+ type: i0.Input,
547
+ args: [{
548
+ isSignal: true,
549
+ alias: "required",
550
+ required: false
551
+ }]
552
+ }],
553
+ disabledInput: [{
554
+ type: i0.Input,
555
+ args: [{
556
+ isSignal: true,
557
+ alias: "disabled",
558
+ required: false
559
+ }]
560
+ }],
561
+ weekLabelModeInput: [{
562
+ type: i0.Input,
563
+ args: [{
564
+ isSignal: true,
565
+ alias: "weekLabelMode",
566
+ required: false
567
+ }]
568
+ }],
569
+ weekLabelFormatterInput: [{
570
+ type: i0.Input,
571
+ args: [{
572
+ isSignal: true,
573
+ alias: "weekLabelFormatter",
574
+ required: false
575
+ }]
576
+ }],
577
+ weekCacheSizeInput: [{
578
+ type: i0.Input,
579
+ args: [{
580
+ isSignal: true,
581
+ alias: "weekCacheSize",
582
+ required: false
583
+ }]
584
+ }],
585
+ overscanWeeksInput: [{
586
+ type: i0.Input,
587
+ args: [{
588
+ isSignal: true,
589
+ alias: "overscanWeeks",
590
+ required: false
591
+ }]
592
+ }],
593
+ ariaLabelInput: [{
594
+ type: i0.Input,
595
+ args: [{
596
+ isSignal: true,
597
+ alias: "ariaLabel",
598
+ required: false
599
+ }]
600
+ }],
601
+ ariaDescribedByInput: [{
602
+ type: i0.Input,
603
+ args: [{
604
+ isSignal: true,
605
+ alias: "ariaDescribedBy",
606
+ required: false
607
+ }]
608
+ }],
609
+ initialEpochDayInput: [{
610
+ type: i0.Input,
611
+ args: [{
612
+ isSignal: true,
613
+ alias: "initialEpochDay",
614
+ required: false
615
+ }]
616
+ }],
617
+ closeOnBackdropInput: [{
618
+ type: i0.Input,
619
+ args: [{
620
+ isSignal: true,
621
+ alias: "closeOnBackdrop",
622
+ required: false
623
+ }]
624
+ }],
625
+ validatorsInput: [{
626
+ type: i0.Input,
627
+ args: [{
628
+ isSignal: true,
629
+ alias: "validators",
630
+ required: false
631
+ }]
632
+ }],
633
+ translationsInput: [{
634
+ type: i0.Input,
635
+ args: [{
636
+ isSignal: true,
637
+ alias: "translations",
638
+ required: false
639
+ }]
640
+ }]
641
+ }
14
642
  });
15
- const WKLY_CONFIG = new InjectionToken("WKLY_CONFIG", { providedIn: "root", factory: () => ({}) });
16
- const WKLY_LOCALIZATION = new InjectionToken("WKLY_LOCALIZATION", { providedIn: "root", factory: () => ({}) });
17
- const WKLY_TRANSLATIONS = new InjectionToken("WKLY_TRANSLATIONS", { providedIn: "root", factory: () => ({}) });
18
- class WklyPickerInputs {
19
- // Angular discovers signal inputs from identifier property declarations.
20
- modeInput = input("datetime", ...(ngDevMode ? [{ debugName: "modeInput", alias: "mode" }] : [{
21
- alias: "mode",
22
- }]));
23
- valueInput = input(null, ...(ngDevMode ? [{ debugName: "valueInput", alias: "value" }] : [{
24
- alias: "value",
25
- }]));
26
- calendarAdapterInput = input(undefined, ...(ngDevMode ? [{ debugName: "calendarAdapterInput", alias: "calendarAdapter" }] : [{ alias: "calendarAdapter" }]));
27
- localeInput = input("", ...(ngDevMode ? [{ debugName: "localeInput", alias: "locale" }] : [{ alias: "locale" }]));
28
- weekOffsetInput = input(null, ...(ngDevMode ? [{ debugName: "weekOffsetInput", alias: "weekOffset" }] : [{
29
- alias: "weekOffset",
30
- }]));
31
- viewportPresetInput = input({ kind: "full-month" }, ...(ngDevMode ? [{ debugName: "viewportPresetInput", alias: "viewportPreset" }] : [{ alias: "viewportPreset" }]));
32
- hourCycleInput = input("locale", ...(ngDevMode ? [{ debugName: "hourCycleInput", alias: "hourCycle" }] : [{
33
- alias: "hourCycle",
34
- }]));
35
- showSecondsInput = input(false, ...(ngDevMode ? [{ debugName: "showSecondsInput", alias: "showSeconds",
36
- transform: booleanAttribute }] : [{
37
- alias: "showSeconds",
38
- transform: booleanAttribute,
39
- }]));
40
- minuteStepInput = input(1, ...(ngDevMode ? [{ debugName: "minuteStepInput", alias: "minuteStep" }] : [{ alias: "minuteStep" }]));
41
- secondStepInput = input(1, ...(ngDevMode ? [{ debugName: "secondStepInput", alias: "secondStep" }] : [{ alias: "secondStep" }]));
42
- minInput = input(null, ...(ngDevMode ? [{ debugName: "minInput", alias: "min" }] : [{ alias: "min" }]));
43
- maxInput = input(null, ...(ngDevMode ? [{ debugName: "maxInput", alias: "max" }] : [{ alias: "max" }]));
44
- isDateDisabledInput = input(null, ...(ngDevMode ? [{ debugName: "isDateDisabledInput", alias: "isDateDisabled" }] : [{ alias: "isDateDisabled" }]));
45
- isTimeDisabledInput = input(null, ...(ngDevMode ? [{ debugName: "isTimeDisabledInput", alias: "isTimeDisabled" }] : [{ alias: "isTimeDisabled" }]));
46
- rangeValidatorInput = input(null, ...(ngDevMode ? [{ debugName: "rangeValidatorInput", alias: "rangeValidator" }] : [{ alias: "rangeValidator" }]));
47
- allowRangeAcrossDisabledInput = input(false, ...(ngDevMode ? [{ debugName: "allowRangeAcrossDisabledInput", alias: "allowRangeAcrossDisabled",
48
- transform: booleanAttribute }] : [{
49
- alias: "allowRangeAcrossDisabled",
50
- transform: booleanAttribute,
51
- }]));
52
- requiredInput = input(false, ...(ngDevMode ? [{ debugName: "requiredInput", alias: "required",
53
- transform: booleanAttribute }] : [{
54
- alias: "required",
55
- transform: booleanAttribute,
56
- }]));
57
- disabledInput = input(false, ...(ngDevMode ? [{ debugName: "disabledInput", alias: "disabled",
58
- transform: booleanAttribute }] : [{
59
- alias: "disabled",
60
- transform: booleanAttribute,
61
- }]));
62
- weekLabelModeInput = input("locale", ...(ngDevMode ? [{ debugName: "weekLabelModeInput", alias: "weekLabelMode" }] : [{
63
- alias: "weekLabelMode",
64
- }]));
65
- weekLabelFormatterInput = input(null, ...(ngDevMode ? [{ debugName: "weekLabelFormatterInput", alias: "weekLabelFormatter" }] : [{ alias: "weekLabelFormatter" }]));
66
- weekCacheSizeInput = input(256, ...(ngDevMode ? [{ debugName: "weekCacheSizeInput", alias: "weekCacheSize" }] : [{
67
- alias: "weekCacheSize",
68
- }]));
69
- overscanWeeksInput = input(DEFAULT_OVERSCAN_WEEKS, ...(ngDevMode ? [{ debugName: "overscanWeeksInput", alias: "overscanWeeks" }] : [{
70
- alias: "overscanWeeks",
71
- }]));
72
- ariaLabelInput = input(null, ...(ngDevMode ? [{ debugName: "ariaLabelInput", alias: "ariaLabel" }] : [{
73
- alias: "ariaLabel",
74
- }]));
75
- ariaDescribedByInput = input(null, ...(ngDevMode ? [{ debugName: "ariaDescribedByInput", alias: "ariaDescribedBy" }] : [{
76
- alias: "ariaDescribedBy",
77
- }]));
78
- initialEpochDayInput = input(null, ...(ngDevMode ? [{ debugName: "initialEpochDayInput", alias: "initialEpochDay" }] : [{
79
- alias: "initialEpochDay",
80
- }]));
81
- closeOnBackdropInput = input(true, ...(ngDevMode ? [{ debugName: "closeOnBackdropInput", alias: "closeOnBackdrop",
82
- transform: booleanAttribute }] : [{
83
- alias: "closeOnBackdrop",
84
- transform: booleanAttribute,
85
- }]));
86
- validatorsInput = input([], ...(ngDevMode ? [{ debugName: "validatorsInput", alias: "validators" }] : [{ alias: "validators" }]));
87
- translationsInput = input(null, ...(ngDevMode ? [{ debugName: "translationsInput", alias: "translations" }] : [{
88
- alias: "translations",
89
- }]));
90
- // Public members of the shared picker input contract.
91
- [WklyPickerInputsPropertyKeys.Mode] = this.modeInput;
92
- [WklyPickerInputsPropertyKeys.Value] = this.valueInput;
93
- [WklyPickerInputsPropertyKeys.CalendarAdapter] = this.calendarAdapterInput;
94
- [WklyPickerInputsPropertyKeys.Locale] = this.localeInput;
95
- [WklyPickerInputsPropertyKeys.WeekOffset] = this.weekOffsetInput;
96
- [WklyPickerInputsPropertyKeys.ViewportPreset] = this.viewportPresetInput;
97
- [WklyPickerInputsPropertyKeys.HourCycle] = this.hourCycleInput;
98
- [WklyPickerInputsPropertyKeys.ShowSeconds] = this.showSecondsInput;
99
- [WklyPickerInputsPropertyKeys.MinuteStep] = this.minuteStepInput;
100
- [WklyPickerInputsPropertyKeys.SecondStep] = this.secondStepInput;
101
- [WklyPickerInputsPropertyKeys.Min] = this.minInput;
102
- [WklyPickerInputsPropertyKeys.Max] = this.maxInput;
103
- [WklyPickerInputsPropertyKeys.IsDateDisabled] = this.isDateDisabledInput;
104
- [WklyPickerInputsPropertyKeys.IsTimeDisabled] = this.isTimeDisabledInput;
105
- [WklyPickerInputsPropertyKeys.RangeValidator] = this.rangeValidatorInput;
106
- [WklyPickerInputsPropertyKeys.AllowRangeAcrossDisabled] = this.allowRangeAcrossDisabledInput;
107
- [WklyPickerInputsPropertyKeys.Required] = this.requiredInput;
108
- [WklyPickerInputsPropertyKeys.Disabled] = this.disabledInput;
109
- [WklyPickerInputsPropertyKeys.WeekLabelMode] = this.weekLabelModeInput;
110
- [WklyPickerInputsPropertyKeys.WeekLabelFormatter] = this.weekLabelFormatterInput;
111
- [WklyPickerInputsPropertyKeys.WeekCacheSize] = this.weekCacheSizeInput;
112
- [WklyPickerInputsPropertyKeys.OverscanWeeks] = this.overscanWeeksInput;
113
- [WklyPickerInputsPropertyKeys.AriaLabel] = this.ariaLabelInput;
114
- [WklyPickerInputsPropertyKeys.AriaDescribedBy] = this.ariaDescribedByInput;
115
- [WklyPickerInputsPropertyKeys.InitialEpochDay] = this.initialEpochDayInput;
116
- [WklyPickerInputsPropertyKeys.CloseOnBackdrop] = this.closeOnBackdropInput;
117
- [WklyPickerInputsPropertyKeys.Validators] = this.validatorsInput;
118
- [WklyPickerInputsPropertyKeys.Translations] = this.translationsInput;
119
- [WklyPickerOutputsPropertyKeys.ValueChange] = output();
120
- [WklyPickerOutputsPropertyKeys.ValidationChange] = output();
121
- [WklyPickerOutputsPropertyKeys.Opened] = output();
122
- [WklyPickerOutputsPropertyKeys.Closed] = output();
123
- [WklyPickerOutputsPropertyKeys.ViewportChange] = output();
124
- [WklyPickerOutputsPropertyKeys.ViewModeChange] = output();
125
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyPickerInputs, deps: [], target: i0.ɵɵFactoryTarget.Directive });
126
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.33", type: WklyPickerInputs, isStandalone: true, inputs: { modeInput: { classPropertyName: "modeInput", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, calendarAdapterInput: { classPropertyName: "calendarAdapterInput", publicName: "calendarAdapter", isSignal: true, isRequired: false, transformFunction: null }, localeInput: { classPropertyName: "localeInput", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, weekOffsetInput: { classPropertyName: "weekOffsetInput", publicName: "weekOffset", isSignal: true, isRequired: false, transformFunction: null }, viewportPresetInput: { classPropertyName: "viewportPresetInput", publicName: "viewportPreset", isSignal: true, isRequired: false, transformFunction: null }, hourCycleInput: { classPropertyName: "hourCycleInput", publicName: "hourCycle", isSignal: true, isRequired: false, transformFunction: null }, showSecondsInput: { classPropertyName: "showSecondsInput", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, minuteStepInput: { classPropertyName: "minuteStepInput", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null }, secondStepInput: { classPropertyName: "secondStepInput", publicName: "secondStep", isSignal: true, isRequired: false, transformFunction: null }, minInput: { classPropertyName: "minInput", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, maxInput: { classPropertyName: "maxInput", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, isDateDisabledInput: { classPropertyName: "isDateDisabledInput", publicName: "isDateDisabled", isSignal: true, isRequired: false, transformFunction: null }, isTimeDisabledInput: { classPropertyName: "isTimeDisabledInput", publicName: "isTimeDisabled", isSignal: true, isRequired: false, transformFunction: null }, rangeValidatorInput: { classPropertyName: "rangeValidatorInput", publicName: "rangeValidator", isSignal: true, isRequired: false, transformFunction: null }, allowRangeAcrossDisabledInput: { classPropertyName: "allowRangeAcrossDisabledInput", publicName: "allowRangeAcrossDisabled", isSignal: true, isRequired: false, transformFunction: null }, requiredInput: { classPropertyName: "requiredInput", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, weekLabelModeInput: { classPropertyName: "weekLabelModeInput", publicName: "weekLabelMode", isSignal: true, isRequired: false, transformFunction: null }, weekLabelFormatterInput: { classPropertyName: "weekLabelFormatterInput", publicName: "weekLabelFormatter", isSignal: true, isRequired: false, transformFunction: null }, weekCacheSizeInput: { classPropertyName: "weekCacheSizeInput", publicName: "weekCacheSize", isSignal: true, isRequired: false, transformFunction: null }, overscanWeeksInput: { classPropertyName: "overscanWeeksInput", publicName: "overscanWeeks", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelInput: { classPropertyName: "ariaLabelInput", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedByInput: { classPropertyName: "ariaDescribedByInput", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, initialEpochDayInput: { classPropertyName: "initialEpochDayInput", publicName: "initialEpochDay", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdropInput: { classPropertyName: "closeOnBackdropInput", publicName: "closeOnBackdrop", isSignal: true, isRequired: false, transformFunction: null }, validatorsInput: { classPropertyName: "validatorsInput", publicName: "validators", isSignal: true, isRequired: false, transformFunction: null }, translationsInput: { classPropertyName: "translationsInput", publicName: "translations", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", validationChange: "validationChange", opened: "opened", closed: "closed", viewportChange: "viewportChange", viewModeChange: "viewModeChange" }, ngImport: i0 });
127
- }
128
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyPickerInputs, decorators: [{
129
- type: Directive,
130
- args: [{
131
- // Angular's metadata evaluator requires strings; template expressions
132
- // preserve the enum as their source.
133
- outputs: [
134
- `${WklyPickerOutputsPropertyKeys.ValueChange}`,
135
- `${WklyPickerOutputsPropertyKeys.ValidationChange}`,
136
- `${WklyPickerOutputsPropertyKeys.Opened}`,
137
- `${WklyPickerOutputsPropertyKeys.Closed}`,
138
- `${WklyPickerOutputsPropertyKeys.ViewportChange}`,
139
- `${WklyPickerOutputsPropertyKeys.ViewModeChange}`,
140
- ],
141
- }]
142
- }], propDecorators: { modeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], valueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], calendarAdapterInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "calendarAdapter", required: false }] }], localeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], weekOffsetInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekOffset", required: false }] }], viewportPresetInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewportPreset", required: false }] }], hourCycleInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "hourCycle", required: false }] }], showSecondsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], minuteStepInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], secondStepInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondStep", required: false }] }], minInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], maxInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], isDateDisabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDateDisabled", required: false }] }], isTimeDisabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "isTimeDisabled", required: false }] }], rangeValidatorInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeValidator", required: false }] }], allowRangeAcrossDisabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowRangeAcrossDisabled", required: false }] }], requiredInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], weekLabelModeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekLabelMode", required: false }] }], weekLabelFormatterInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekLabelFormatter", required: false }] }], weekCacheSizeInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekCacheSize", required: false }] }], overscanWeeksInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "overscanWeeks", required: false }] }], ariaLabelInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedByInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], initialEpochDayInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialEpochDay", required: false }] }], closeOnBackdropInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdrop", required: false }] }], validatorsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "validators", required: false }] }], translationsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "translations", required: false }] }] } });
143
643
  function unwrapWklyPickerSignalInputs(source) {
144
- const keys = Object.values(WklyPickerInputsPropertyKeys);
145
- return Object.fromEntries(keys.map((key) => [key, source[key]()]));
146
- }
147
-
148
- class WklyFieldComponent {
149
- value = 0;
150
- label = "";
151
- hideLabel = false;
152
- previousLabel = "";
153
- nextLabel = "";
154
- min = 0;
155
- max = 59;
156
- step = 1;
157
- locale = "en-US";
158
- disabled = false;
159
- invalid = false;
160
- labels = null;
161
- valueChange = new EventEmitter();
162
- complete = new EventEmitter();
163
- before = null;
164
- touchY = 0;
165
- touchSteps = 0;
166
- touchChanged = false;
167
- typed = null;
168
- inputTimer = null;
169
- wheelTimer = null;
170
- get display() {
171
- if (this.typed !== null)
172
- return this.typed;
173
- return this.value === null
174
- ? ""
175
- : this.labels
176
- ? this.labels[this.value - this.min] || String(this.value)
177
- : new Intl.NumberFormat(this.locale, {
178
- useGrouping: false,
179
- minimumIntegerDigits: this.max < 60 ? 2 : 1,
180
- }).format(this.value);
181
- }
182
- ngOnChanges(changes) {
183
- if (changes.value && this.min < 0 && this.typed !== null) {
184
- const typedValue = this.typed === "" || this.typed === "-" ? null : Number(this.typed);
185
- if (this.value !== typedValue) {
186
- // External date edits replace a pending relative-day preview.
187
- this.cancelInput();
188
- this.typed = null;
189
- }
190
- }
191
- }
192
- ngOnDestroy() {
193
- this.cancelInput();
194
- if (this.wheelTimer !== null)
195
- clearTimeout(this.wheelTimer);
196
- }
197
- next(delta) {
198
- const count = Math.floor((this.max - this.min) / this.step) + 1;
199
- return (this.min +
200
- floorMod(Math.floor(((this.value === null ? this.min : this.value) - this.min) /
201
- this.step) + delta, count) *
202
- this.step);
203
- }
204
- neighbor(delta) {
205
- const n = this.next(delta);
206
- return this.labels
207
- ? this.labels[n - this.min] || ""
208
- : new Intl.NumberFormat(this.locale, { useGrouping: false }).format(n);
209
- }
210
- stepBy(delta) {
211
- if (this.disabled)
212
- return;
213
- this.scrollBy(delta);
214
- this.complete.emit();
215
- }
216
- begin(event) {
217
- this.before = this.value;
218
- event.target.select();
219
- }
220
- type(event) {
221
- if (this.disabled)
222
- return;
223
- const input = event.target;
224
- const raw = input.value;
225
- const numeric = Array.from(raw).every((character) => normalizeDigits(character).length === 1);
226
- if (this.min < 0 && !this.labels) {
227
- // Preserve the sign while using the same locale digit normalization.
228
- const signed = raw
229
- .replace(/[\u200e\u200f\u061c]/g, "")
230
- .replace(/\u2212/g, "-");
231
- const digits = normalizeDigits(signed);
232
- this.typed = input.value = (signed.startsWith("-") ? "-" : "") + digits;
233
- this.value =
234
- digits === ""
235
- ? null
236
- : Math.max(this.min, Math.min(this.max, Number(this.typed)));
237
- if (this.value !== null && Number(this.typed) !== this.value)
238
- this.typed = input.value = String(this.value);
239
- }
240
- else if (numeric) {
241
- const normalized = normalizeDigits(raw);
242
- this.typed = input.value =
243
- this.min >= 0 && this.max < 100 ? normalized.slice(-2) : normalized;
244
- this.value = this.typed === "" ? null : Number(this.typed);
245
- }
246
- else if (this.labels) {
247
- const search = raw.trim().toLocaleLowerCase(this.locale);
248
- this.typed = raw;
249
- const matches = this.labels
250
- .map((label, index) => ({ label, index }))
251
- .filter((item) => item.label.toLocaleLowerCase(this.locale).includes(search));
252
- this.value = matches.length === 1 ? this.min + matches[0].index : null;
253
- }
254
- else {
255
- this.typed = input.value = normalizeDigits(raw);
256
- this.value = this.typed === "" ? null : Number(this.typed);
257
- }
258
- this.valueChange.emit(this.value);
259
- this.cancelInput();
260
- if (!numeric && this.labels && this.value !== null)
261
- this.complete.emit();
262
- this.inputTimer = setTimeout(() => {
263
- this.inputTimer = null;
264
- this.typed = null;
265
- if (!this.disabled)
266
- this.complete.emit();
267
- }, 1000);
268
- }
269
- key(event) {
270
- if (event.key === "Escape") {
271
- event.preventDefault();
272
- event.stopPropagation();
273
- this.cancelInput();
274
- this.typed = null;
275
- this.value = this.before;
276
- this.valueChange.emit(this.before);
277
- event.target.value = this.display;
278
- event.target.blur();
279
- }
280
- if (event.key === "Enter") {
281
- event.preventDefault();
282
- event.stopPropagation();
283
- this.finish();
284
- }
285
- const delta = event.key === "ArrowUp"
286
- ? -1
287
- : event.key === "ArrowDown"
288
- ? 1
289
- : event.key === "PageUp"
290
- ? -5
291
- : event.key === "PageDown"
292
- ? 5
293
- : 0;
294
- if (delta) {
295
- event.preventDefault();
296
- this.stepBy(delta);
297
- }
298
- }
299
- finish() {
300
- this.cancelInput();
301
- this.typed = null;
302
- this.complete.emit();
303
- }
304
- wheel(event) {
305
- if (this.disabled || Math.abs(event.deltaY) < 1)
306
- return;
307
- event.preventDefault();
308
- this.scrollBy(event.deltaY > 0 ? 1 : -1);
309
- if (this.wheelTimer !== null)
310
- clearTimeout(this.wheelTimer);
311
- this.wheelTimer = setTimeout(() => {
312
- this.wheelTimer = null;
313
- this.complete.emit();
314
- }, 140);
315
- }
316
- touchStart(event) {
317
- this.touchY = event.touches[0].clientY;
318
- this.touchSteps = 0;
319
- this.touchChanged = false;
320
- }
321
- touchMove(event) {
322
- this.applyTouchY(event.touches[0].clientY);
323
- }
324
- touchEnd(event) {
325
- this.applyTouchY(event.changedTouches[0].clientY);
326
- if (this.touchChanged)
327
- this.complete.emit();
328
- this.touchChanged = false;
329
- }
330
- cancelInput() {
331
- if (this.inputTimer !== null)
332
- clearTimeout(this.inputTimer);
333
- this.inputTimer = null;
334
- }
335
- scrollBy(delta) {
336
- if (this.disabled || !delta)
337
- return;
338
- this.cancelInput();
339
- this.typed = null;
340
- this.value = this.next(delta);
341
- this.valueChange.emit(this.value);
342
- }
343
- applyTouchY(y) {
344
- // Count total gesture steps so repeated move events do not duplicate changes.
345
- if (this.disabled)
346
- return;
347
- const delta = this.touchY - y;
348
- const steps = Math.abs(delta) > 16
349
- ? Math.sign(delta) * Math.max(1, Math.round(Math.abs(delta) / 40))
350
- : 0;
351
- const change = steps - this.touchSteps;
352
- if (!change)
353
- return;
354
- this.scrollBy(change);
355
- this.touchSteps = steps;
356
- this.touchChanged = true;
357
- }
358
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
359
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.33", type: WklyFieldComponent, isStandalone: false, selector: "wkly-field", inputs: { value: "value", label: "label", hideLabel: "hideLabel", previousLabel: "previousLabel", nextLabel: "nextLabel", min: "min", max: "max", step: "step", locale: "locale", disabled: "disabled", invalid: "invalid", labels: "labels" }, outputs: { valueChange: "valueChange", complete: "complete" }, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"field\"\n (wheel)=\"wheel($event)\"\n (touchstart)=\"touchStart($event)\"\n (touchmove)=\"touchMove($event)\"\n (touchend)=\"touchEnd($event)\"\n (touchcancel)=\"touchEnd($event)\"\n>\n <span *ngIf=\"!hideLabel\" class=\"label\">{{ label }}</span>\n <button\n type=\"button\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"previousLabel || label + ': previous'\"\n (click)=\"stepBy(-1)\"\n >\n {{ neighbor(-1) }}\n </button>\n <input\n [attr.aria-label]=\"label\"\n [attr.aria-invalid]=\"invalid\"\n [disabled]=\"disabled\"\n [value]=\"display\"\n [attr.inputmode]=\"labels ? 'text' : min < 0 ? 'text' : 'numeric'\"\n autocomplete=\"off\"\n (focus)=\"begin($event)\"\n (input)=\"type($event)\"\n (blur)=\"finish()\"\n (keydown)=\"key($event)\"\n />\n <button\n type=\"button\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"nextLabel || label + ': next'\"\n (click)=\"stepBy(1)\"\n >\n {{ neighbor(1) }}\n </button>\n</div>\n", styles: [".field{display:flex;flex-direction:column;align-items:stretch;min-width:0;text-align:center;touch-action:pan-x}.label{font-size:11px;color:var(--wkly-muted-color, #54616e);margin-bottom:4px}button,input{font:inherit;box-sizing:border-box;min-height:44px;width:100%;border:0;text-align:center;background:transparent;color:inherit;border-radius:7px}button{color:var(--wkly-muted-color, #54616e);cursor:pointer}input{font-size:18px;font-weight:650;background:var(--wkly-range-color, #e5f1ee);border-block:2px solid var(--wkly-accent-color, #176c55)}input[aria-invalid=true]{border-color:var(--wkly-error-color, #b42318)}:focus-visible{outline:2px solid var(--wkly-focus-color, #124ee0);outline-offset:1px}button:disabled,input:disabled{opacity:.45}button:hover:not(:disabled){background:var(--wkly-range-color, #e5f1ee)}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
360
- }
361
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyFieldComponent, decorators: [{
362
- type: Component,
363
- args: [{ standalone: false, selector: "wkly-field", template: "<div\n class=\"field\"\n (wheel)=\"wheel($event)\"\n (touchstart)=\"touchStart($event)\"\n (touchmove)=\"touchMove($event)\"\n (touchend)=\"touchEnd($event)\"\n (touchcancel)=\"touchEnd($event)\"\n>\n <span *ngIf=\"!hideLabel\" class=\"label\">{{ label }}</span>\n <button\n type=\"button\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"previousLabel || label + ': previous'\"\n (click)=\"stepBy(-1)\"\n >\n {{ neighbor(-1) }}\n </button>\n <input\n [attr.aria-label]=\"label\"\n [attr.aria-invalid]=\"invalid\"\n [disabled]=\"disabled\"\n [value]=\"display\"\n [attr.inputmode]=\"labels ? 'text' : min < 0 ? 'text' : 'numeric'\"\n autocomplete=\"off\"\n (focus)=\"begin($event)\"\n (input)=\"type($event)\"\n (blur)=\"finish()\"\n (keydown)=\"key($event)\"\n />\n <button\n type=\"button\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"nextLabel || label + ': next'\"\n (click)=\"stepBy(1)\"\n >\n {{ neighbor(1) }}\n </button>\n</div>\n", styles: [".field{display:flex;flex-direction:column;align-items:stretch;min-width:0;text-align:center;touch-action:pan-x}.label{font-size:11px;color:var(--wkly-muted-color, #54616e);margin-bottom:4px}button,input{font:inherit;box-sizing:border-box;min-height:44px;width:100%;border:0;text-align:center;background:transparent;color:inherit;border-radius:7px}button{color:var(--wkly-muted-color, #54616e);cursor:pointer}input{font-size:18px;font-weight:650;background:var(--wkly-range-color, #e5f1ee);border-block:2px solid var(--wkly-accent-color, #176c55)}input[aria-invalid=true]{border-color:var(--wkly-error-color, #b42318)}:focus-visible{outline:2px solid var(--wkly-focus-color, #124ee0);outline-offset:1px}button:disabled,input:disabled{opacity:.45}button:hover:not(:disabled){background:var(--wkly-range-color, #e5f1ee)}\n"] }]
364
- }], propDecorators: { value: [{
365
- type: Input
366
- }], label: [{
367
- type: Input
368
- }], hideLabel: [{
369
- type: Input
370
- }], previousLabel: [{
371
- type: Input
372
- }], nextLabel: [{
373
- type: Input
374
- }], min: [{
375
- type: Input
376
- }], max: [{
377
- type: Input
378
- }], step: [{
379
- type: Input
380
- }], locale: [{
381
- type: Input
382
- }], disabled: [{
383
- type: Input
384
- }], invalid: [{
385
- type: Input
386
- }], labels: [{
387
- type: Input
388
- }], valueChange: [{
389
- type: Output
390
- }], complete: [{
391
- type: Output
392
- }] } });
393
-
394
- class WklyDateTimePickerComponent extends WklyPickerInputs {
395
- defaultLocale;
396
- defaults;
397
- clock;
398
- strings;
399
- defaultTranslations;
400
- host;
401
- changeDetector;
402
- scroller;
403
- presentation = "inline";
404
- viewMode = "calendar";
405
- endView = "date";
406
- adapter;
407
- effectiveLocale = "en-US";
408
- effectiveOffset = 0;
409
- effectiveHourCycle = "h24";
410
- direction = "ltr";
411
- rows = [];
412
- weekdays = [];
413
- drafts = [];
414
- errors = [];
415
- today = 0;
416
- focused = 0;
417
- anchorWeek = 0;
418
- firstWeek = 0;
419
- visibleCount = 6;
420
- rowHeight = 76;
421
- scrollHeight = 152076;
422
- paddingTop = 0;
423
- initialized = false;
424
- compact = false;
425
- WklyPickerInputsPropertyKeys = WklyPickerInputsPropertyKeys;
426
- baseWeek = 0;
427
- firstSupportedDay = 0;
428
- lastSupportedDay = 0;
429
- firstSupportedWeek = 0;
430
- lastSupportedWeek = 0;
431
- generator;
432
- initialMonth = "";
433
- clipMonth = false;
434
- browser = false;
435
- observer;
436
- destroyed = false;
437
- scrollEndTimer;
438
- snapPending = false;
439
- onChange = () => { };
440
- onTouched = () => { };
441
- validatorChanged = () => { };
442
- configErrors = [];
443
- pendingValue = null;
444
- emittedValue = null;
445
- manualDateEndpoint = 0;
446
- formValue = signal(undefined, ...(ngDevMode ? [{ debugName: "formValue" }] : []));
447
- formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : []));
448
- previousInputs;
449
- currentValue() {
450
- return this.formValue() === undefined
451
- ? this[WklyPickerInputsPropertyKeys.Value]()
452
- : this.formValue();
453
- }
454
- isDisabled() {
455
- return this[WklyPickerInputsPropertyKeys.Disabled]() || this.formDisabled();
456
- }
457
- constructor(defaultLocale, defaults, clock, strings, defaultTranslations, platform, host, changeDetector) {
458
- super();
459
- this.defaultLocale = defaultLocale;
460
- this.defaults = defaults;
461
- this.clock = clock;
462
- this.strings = strings;
463
- this.defaultTranslations = defaultTranslations;
464
- this.host = host;
465
- this.changeDetector = changeDetector;
466
- this.browser = isPlatformBrowser(platform);
467
- effect(() => {
468
- const inputs = unwrapWklyPickerSignalInputs(this);
469
- const previous = this.previousInputs;
470
- this.previousInputs = inputs;
471
- if (!previous || !this.initialized)
472
- return;
473
- const changed = (key) => !Object.is(previous[key], inputs[key]);
474
- if (!Object.keys(inputs).some((key) => changed(key)))
475
- return;
476
- untracked(() => {
477
- if (changed(WklyPickerInputsPropertyKeys.Value))
478
- this.formValue.set(undefined);
479
- if (changed(WklyPickerInputsPropertyKeys.Value) &&
480
- this.emittedValue === JSON.stringify(this.currentValue()) &&
481
- Object.keys(inputs).every((key) => key === WklyPickerInputsPropertyKeys.Value ||
482
- !changed(key))) {
483
- this.emittedValue = null;
484
- return;
485
- }
486
- const focus = this.focused;
487
- this.configure();
488
- if (changed(WklyPickerInputsPropertyKeys.Value) ||
489
- changed(WklyPickerInputsPropertyKeys.Mode) ||
490
- changed(WklyPickerInputsPropertyKeys.CalendarAdapter)) {
491
- this.load(this.currentValue());
492
- this.position(this.focused, true);
493
- }
494
- else {
495
- this.check();
496
- if (changed(WklyPickerInputsPropertyKeys.ViewportPreset))
497
- this.position(focus, true);
498
- else
499
- this.scrollToEpochDay(focus);
500
- }
501
- });
502
- });
503
- }
504
- ngOnInit() {
505
- this.initialize();
506
- }
507
- initialize() {
508
- if (this.initialized)
509
- return;
510
- this.configure();
511
- const initialEpochDay = this[WklyPickerInputsPropertyKeys.InitialEpochDay]();
512
- this.today = this.browser
513
- ? Math.floor(this.clock.now().getTime() / 86400000)
514
- : initialEpochDay === null
515
- ? 0
516
- : initialEpochDay;
517
- this.focused =
518
- initialEpochDay === null
519
- ? this.defaults.initialEpochDay === undefined
520
- ? this.today
521
- : this.defaults.initialEpochDay
522
- : initialEpochDay;
523
- this.load(this.currentValue());
524
- this.initialized = true;
525
- this.position(this.focused, true);
526
- }
527
- configure() {
528
- this.configErrors = [];
529
- this.effectiveLocale =
530
- this[WklyPickerInputsPropertyKeys.Locale]() ||
531
- this.defaults.locale ||
532
- this.defaultLocale;
533
- this.direction = /^(ar|he|fa|ur)(-|$)/.test(this.effectiveLocale)
534
- ? "rtl"
535
- : "ltr";
536
- this.adapter =
537
- this[WklyPickerInputsPropertyKeys.CalendarAdapter]() ||
538
- new WklyGregorianCalendarAdapter(this.effectiveLocale);
539
- try {
540
- let firstDay;
541
- try {
542
- firstDay = getLocaleFirstDayOfWeek(this.effectiveLocale);
543
- }
544
- catch (_) { }
545
- this.effectiveOffset = resolveWeekOffset(this.effectiveLocale, this[WklyPickerInputsPropertyKeys.WeekOffset](), this.defaults.weekOffset, firstDay);
546
- integer(this[WklyPickerInputsPropertyKeys.WeekCacheSize]());
547
- integer(this[WklyPickerInputsPropertyKeys.OverscanWeeks]());
548
- if (this[WklyPickerInputsPropertyKeys.WeekCacheSize]() < 0 ||
549
- this[WklyPickerInputsPropertyKeys.OverscanWeeks]() < 0 ||
550
- this[WklyPickerInputsPropertyKeys.OverscanWeeks]() > 50)
551
- throw new RangeError();
552
- if (![
553
- "datetime",
554
- "date",
555
- "time",
556
- "datetime-range",
557
- "date-range",
558
- "time-range",
559
- ].includes(this[WklyPickerInputsPropertyKeys.Mode]()))
560
- throw new RangeError();
561
- const preset = this[WklyPickerInputsPropertyKeys.ViewportPreset]();
562
- if (preset.kind === "weeks") {
563
- integer(preset.visibleWeekCount);
564
- if (preset.visibleWeekCount < 1 || preset.visibleWeekCount > 52)
565
- throw new RangeError();
566
- }
567
- if (preset.kind === "full-month-and-around")
568
- for (const n of [
569
- preset.extraWeeksBefore || 0,
570
- preset.extraWeeksAfter || 0,
571
- ]) {
572
- integer(n);
573
- if (n < 0 || n > 52)
574
- throw new RangeError();
575
- }
576
- this.generator = createWeekGenerator({
577
- weekOffset: this.effectiveOffset,
578
- cacheSize: this[WklyPickerInputsPropertyKeys.WeekCacheSize](),
579
- });
580
- }
581
- catch (_) {
582
- this.configErrors.push(error("configuration-error", this[WklyPickerInputsPropertyKeys.WeekOffset]()));
583
- this.generator = createWeekGenerator();
584
- this.effectiveOffset = 0;
585
- }
586
- this.setSupportedScrollRange();
587
- this.effectiveHourCycle =
588
- this[WklyPickerInputsPropertyKeys.HourCycle]() === "h12"
589
- ? "h12"
590
- : this[WklyPickerInputsPropertyKeys.HourCycle]() === "locale"
591
- ? new Intl.DateTimeFormat(this.effectiveLocale, {
592
- hour: "numeric",
593
- timeZone: "UTC",
594
- }).resolvedOptions().hour12
595
- ? "h12"
596
- : "h24"
597
- : "h24";
598
- this.weekdays = Array.from({ length: 7 }, (_, i) => this.adapter.formatWeekday(this.effectiveOffset + i, "short"));
599
- }
600
- setSupportedScrollRange() {
601
- let [first, last] = this.adapter.supportedEpochDayRange;
602
- const [firstYear, lastYear] = this.adapter.supportedYearRange;
603
- const yearOf = (day) => this.adapter.epochDayToDate(day).year;
604
- if (yearOf(first) < firstYear) {
605
- let low = first, high = last;
606
- while (low < high) {
607
- const mid = Math.floor((low + high) / 2);
608
- if (yearOf(mid) < firstYear)
609
- low = mid + 1;
610
- else
611
- high = mid;
612
- }
613
- first = low;
614
- }
615
- if (yearOf(last) > lastYear) {
616
- let low = first, high = last;
617
- while (low < high) {
618
- const mid = Math.ceil((low + high) / 2);
619
- if (yearOf(mid) > lastYear)
620
- high = mid - 1;
621
- else
622
- low = mid;
623
- }
624
- last = low;
625
- }
626
- if (first > last ||
627
- yearOf(first) < firstYear ||
628
- yearOf(first) > lastYear ||
629
- yearOf(last) < firstYear ||
630
- yearOf(last) > lastYear)
631
- throw new RangeError("No supported days within the calendar year range");
632
- this.firstSupportedDay = first;
633
- this.lastSupportedDay = last;
634
- this.firstSupportedWeek = absoluteWeekOf(first, this.effectiveOffset);
635
- this.lastSupportedWeek = absoluteWeekOf(last, this.effectiveOffset);
636
- }
637
- clampFirstWeek(week) {
638
- // Keep supported weeks inside the viewport; renderRows adds the buffer rows.
639
- const last = Math.max(this.firstSupportedWeek, this.lastSupportedWeek - this.visibleCount + 1);
640
- return Math.max(this.firstSupportedWeek, Math.min(last, week));
641
- }
642
- ngAfterViewInit() {
643
- this.resetScroll();
644
- if (this.browser && typeof ResizeObserver !== "undefined") {
645
- this.observer = new ResizeObserver(() => {
646
- this.compact = this.host.nativeElement.clientWidth < 338;
647
- const row = this.host.nativeElement.querySelector(".week-row");
648
- // CSS heights and scrollTop use layout pixels; client rectangles include zoom.
649
- const height = row ? parseFloat(getComputedStyle(row).height) : 0;
650
- if (height && height !== this.rowHeight) {
651
- this.rowHeight = height;
652
- this.scrollHeight = this.rowHeight * 2001;
653
- this.renderRows();
654
- this.resetScroll();
655
- }
656
- });
657
- this.observer.observe(this.host.nativeElement);
658
- }
659
- }
660
- ngOnDestroy() {
661
- this.destroyed = true;
662
- if (this.observer)
663
- this.observer.disconnect();
664
- if (this.scrollEndTimer)
665
- clearTimeout(this.scrollEndTimer);
666
- if (this.generator)
667
- this.generator.clearCache();
668
- }
669
- t(key) {
670
- return resolveWklyTranslation(key, this.effectiveLocale, this[WklyPickerInputsPropertyKeys.Translations]() ||
671
- this.defaultTranslations, this.strings);
672
- }
673
- get isRange() {
674
- return this[WklyPickerInputsPropertyKeys.Mode]().endsWith("-range");
675
- }
676
- get hasDate() {
677
- return !this[WklyPickerInputsPropertyKeys.Mode]().startsWith("time");
678
- }
679
- get hasTime() {
680
- return (this[WklyPickerInputsPropertyKeys.Mode]() !== "date" &&
681
- this[WklyPickerInputsPropertyKeys.Mode]() !== "date-range");
682
- }
683
- get submitVisible() {
684
- return (this.presentation === "transient" &&
685
- (this[WklyPickerInputsPropertyKeys.Mode]() !== "date" ||
686
- this.viewMode === "manual"));
687
- }
688
- get title() {
689
- try {
690
- const d = this.adapter.epochDayToDate(Math.max(this.firstSupportedDay, Math.min(this.lastSupportedDay, firstEpochDayOf(this.anchorWeek, this.effectiveOffset))));
691
- return this.adapter.formatMonth(d) + " " + this.adapter.formatYear(d);
692
- }
693
- catch (_) {
694
- return "";
695
- }
696
- }
697
- get canSubmit() {
698
- return (!this.isDisabled() && !this.errors.length && this.pendingValue !== null);
699
- }
700
- blank(day) {
701
- const safe = Math.max(this.firstSupportedDay, Math.min(this.lastSupportedDay, day));
702
- return {
703
- date: this.adapter.epochDayToDate(safe),
704
- hour: 0,
705
- minute: 0,
706
- second: 0,
707
- present: false,
708
- };
709
- }
710
- load(value) {
711
- this.drafts = [this.blank(this.focused), this.blank(this.focused)];
712
- const validation = validateSelection(value, unwrapWklyPickerSignalInputs(this), this.adapter);
713
- if (value !== null && !validation.length) {
714
- const values = typeof value === "string" ? [value] : value;
715
- values.forEach((v, i) => {
716
- const d = decodeIso(v);
717
- this.drafts[i] = {
718
- date: this.hasDate
719
- ? this.adapter.epochDayToDate(d.epochDay)
720
- : this.blank(this.today).date,
721
- hour: d.hour,
722
- minute: d.minute,
723
- second: d.second,
724
- present: true,
725
- };
726
- if (i === 0 && this.hasDate)
727
- this.focused = d.epochDay;
728
- });
729
- }
730
- if (validation.length) {
731
- this.pendingValue = null;
732
- this.report(validation);
733
- }
734
- else
735
- this.check();
736
- }
737
- writeValue(value) {
738
- this.formValue.set(value);
739
- if (this.initialized) {
740
- this.load(value);
741
- this.position(this.focused, true);
742
- }
743
- }
744
- registerOnChange(fn) {
745
- this.onChange = fn;
746
- }
747
- registerOnTouched(fn) {
748
- this.onTouched = fn;
749
- }
750
- setDisabledState(disabled) {
751
- this.formDisabled.set(disabled);
752
- }
753
- validate(_control) {
754
- return this.errors.length ? { wkly: this.errors } : null;
755
- }
756
- registerOnValidatorChange(fn) {
757
- this.validatorChanged = fn;
758
- }
759
- touched() {
760
- Promise.resolve().then(() => this.onTouched());
761
- }
762
- report(errors) {
763
- const changed = JSON.stringify(this.errors) !== JSON.stringify(errors);
764
- this.errors = errors;
765
- if (changed) {
766
- this[WklyPickerOutputsPropertyKeys.ValidationChange].emit(errors);
767
- this.validatorChanged();
768
- }
769
- }
770
- check() {
771
- const result = validateDrafts({
772
- drafts: this.drafts,
773
- configErrors: this.configErrors,
774
- adapter: this.adapter,
775
- selection: unwrapWklyPickerSignalInputs(this),
776
- mode: this[WklyPickerInputsPropertyKeys.Mode](),
777
- isRange: this.isRange,
778
- hasDate: this.hasDate,
779
- hasTime: this.hasTime,
780
- showSeconds: this[WklyPickerInputsPropertyKeys.ShowSeconds](),
781
- required: this[WklyPickerInputsPropertyKeys.Required](),
782
- });
783
- this.pendingValue = result.pendingValue;
784
- this.report(result.errors);
785
- }
786
- trackDraft(index) {
787
- // Endpoint controls keep their identity and focus when draft objects swap.
788
- return index;
789
- }
790
- orderDrafts() {
791
- if (!this.isRange || !this.drafts.every((draft) => draft.present))
792
- return;
793
- if (this.drafts.some((draft) => draft.unsupportedEpochDay !== undefined))
794
- return;
795
- try {
796
- const a = this.drafts[0], b = this.drafts[1];
797
- const key = (d) => this.adapter.dateToEpochDay(d.date) * 86400 +
798
- (d.hour || 0) * 3600 +
799
- (d.minute || 0) * 60 +
800
- (d.second || 0);
801
- if (key(a) > key(b))
802
- this.drafts = [b, a];
803
- }
804
- catch (_) {
805
- // Impossible or incomplete dates remain editable until corrected.
806
- }
807
- }
808
- finish() {
809
- if (this.isDisabled())
810
- return;
811
- this.orderDrafts();
812
- if (this.viewMode === "manual" && this.hasDate)
813
- this.positionOnManualDate();
814
- this.check();
815
- if (this.presentation === "inline" && this.canSubmit)
816
- this.commit();
817
- }
818
- commit() {
819
- if (!this.canSubmit)
820
- return;
821
- const next = this.pendingValue;
822
- if (JSON.stringify(next) !== JSON.stringify(this.currentValue())) {
823
- this.formValue.set(next);
824
- this.emittedValue = JSON.stringify(next);
825
- this.onChange(next);
826
- this[WklyPickerOutputsPropertyKeys.ValueChange].emit(next);
827
- }
828
- this.onTouched();
829
- }
830
- submit(reason = "submit") {
831
- this.check();
832
- if (!this.canSubmit)
833
- return;
834
- this.commit();
835
- if (this.presentation === "transient")
836
- this[WklyPickerOutputsPropertyKeys.Closed].emit(reason);
837
- }
838
- cancel(reason = "close-button") {
839
- if (this.isDisabled())
840
- return;
841
- this.load(this.currentValue());
842
- this.onTouched();
843
- this[WklyPickerOutputsPropertyKeys.Closed].emit(reason);
844
- }
845
- now() {
846
- if (this.isDisabled())
847
- return;
848
- const n = this.clock.now();
849
- const day = Math.floor(n.getTime() / 86400000);
850
- this.drafts = [0, 1].map((index) => ({
851
- ...this.clockDraft(day, n),
852
- present: index === 0 || this.isRange,
853
- }));
854
- if (this.hasDate &&
855
- (day < this.firstSupportedDay || day > this.lastSupportedDay)) {
856
- this.report([error("unsupported-adapter-date", day)]);
857
- return;
858
- }
859
- this.focused = day;
860
- this.position(day, true);
861
- this.check();
862
- this.submit("now");
863
- }
864
- clockDraft(day, now) {
865
- return {
866
- ...this.blank(day),
867
- hour: now.getUTCHours(),
868
- minute: Math.floor(now.getUTCMinutes() / this[WklyPickerInputsPropertyKeys.MinuteStep]()) * this[WklyPickerInputsPropertyKeys.MinuteStep](),
869
- second: this[WklyPickerInputsPropertyKeys.ShowSeconds]()
870
- ? Math.floor(now.getUTCSeconds() /
871
- this[WklyPickerInputsPropertyKeys.SecondStep]()) * this[WklyPickerInputsPropertyKeys.SecondStep]()
872
- : 0,
873
- };
874
- }
875
- initializeManualRange() {
876
- if (!this.isRange ||
877
- !this.hasDate ||
878
- this.drafts.every((draft) => draft.present))
879
- return;
880
- let seed = this.drafts.find((draft) => draft.present);
881
- if (!seed) {
882
- if (this.currentValue() !== null)
883
- return;
884
- const now = this.clock.now();
885
- const initialEpochDay = this[WklyPickerInputsPropertyKeys.InitialEpochDay]();
886
- const day = initialEpochDay === null
887
- ? this.defaults.initialEpochDay === undefined
888
- ? Math.floor(now.getTime() / 86400000)
889
- : this.defaults.initialEpochDay
890
- : initialEpochDay;
891
- seed = { ...this.clockDraft(day, now), present: true };
892
- }
893
- // Complete missing endpoints without replacing selected or invalid drafts.
894
- const initial = seed;
895
- this.drafts = this.drafts.map((draft) => draft.present ? draft : { ...initial, date: { ...initial.date } });
896
- this.finish();
897
- // Positioning renders before validation; refresh completion controls afterward.
898
- this.changeDetector.markForCheck();
899
- }
900
- toggleView() {
901
- if (this.isDisabled() || !this.hasDate)
902
- return;
903
- this.viewMode = this.viewMode === "calendar" ? "manual" : "calendar";
904
- if (this.viewMode === "manual")
905
- this.initializeManualRange();
906
- if (this.viewMode === "calendar")
907
- this.positionOnManualDate();
908
- this[WklyPickerOutputsPropertyKeys.ViewModeChange].emit(this.viewMode);
909
- if (this.viewMode === "calendar")
910
- setTimeout(() => this.resetScroll());
911
- }
912
- positionOnManualDate() {
913
- const draft = this.drafts[this.manualDateEndpoint];
914
- if (!draft || !draft.present)
915
- return;
916
- try {
917
- // A valid day follows the selection. An impossible day keeps its draft
918
- // fields but still shows the chosen month in the calendar.
919
- const target = this.adapter.dateToEpochDay(draft.date);
920
- this.focused = target;
921
- this.position(target, true);
922
- }
923
- catch (_) {
924
- try {
925
- const first = this.adapter.dateToEpochDay({ ...draft.date, day: 1 });
926
- this.focused = first;
927
- this.position(first, true);
928
- }
929
- catch (_) { }
930
- }
931
- }
932
- months(draft) {
933
- try {
934
- return this.adapter.getMonths(draft.date.year).map((m) => m.label);
935
- }
936
- catch (_) {
937
- return [];
938
- }
939
- }
940
- monthCount(draft) {
941
- return this.months(draft).length || 12;
942
- }
943
- get inDays() {
944
- return draftDayDifference(this.drafts, this.adapter);
945
- }
946
- get inDaysLabel() {
947
- const days = this.inDays;
948
- return this.t("inDays").replace(/{{\s*days\s*}}/g, days === null
949
- ? this.t("daysUnavailable")
950
- : new Intl.NumberFormat(this.effectiveLocale, {
951
- useGrouping: false,
952
- }).format(days));
953
- }
954
- get resultingEndDate() {
955
- try {
956
- const draft = this.drafts[1];
957
- if (draft.unsupportedEpochDay !== undefined ||
958
- this.adapter.validateDate(draft.date).length)
959
- return "";
960
- return [
961
- this.adapter.formatDay(draft.date),
962
- this.adapter.formatMonth(draft.date),
963
- this.adapter.formatYear(draft.date),
964
- ].join(" ");
965
- }
966
- catch (_) {
967
- return "";
968
- }
969
- }
970
- toggleEndView(view) {
971
- if (this.isDisabled())
972
- return;
973
- this.endView = view;
974
- }
975
- days(value) {
976
- if (this.isDisabled())
977
- return;
978
- this.manualDateEndpoint = 1;
979
- setDraftDayDifference(this.drafts, this.adapter, value);
980
- this.check();
981
- }
982
- field(index, field, value) {
983
- if (this.isDisabled())
984
- return;
985
- const draft = this.drafts[index];
986
- draft.present = true;
987
- if (field === "day" || field === "year" || field === "month") {
988
- this.manualDateEndpoint = index;
989
- delete draft.unsupportedEpochDay;
990
- let date = { ...draft.date, [field]: value };
991
- if (field === "month") {
992
- let month;
993
- try {
994
- month = this.adapter
995
- .getMonths(date.year)
996
- .find((m) => m.month === value);
997
- }
998
- catch (_) { }
999
- date = { ...date, monthCode: month ? month.monthCode : "" };
1000
- }
1001
- if (field === "year" && value !== null) {
1002
- try {
1003
- const months = this.adapter.getMonths(value);
1004
- const month = months.find((m) => m.monthCode === date.monthCode);
1005
- if (month)
1006
- date = { ...date, month: month.month };
1007
- }
1008
- catch (_) { }
1009
- }
1010
- draft.date = date;
1011
- }
1012
- else if (field === "hour" && this.effectiveHourCycle === "h12")
1013
- draft.hour =
1014
- value === null
1015
- ? null
1016
- : value >= 1 && value <= 12
1017
- ? (value % 12) + ((draft.hour || 0) >= 12 ? 12 : 0)
1018
- : 24 + value;
1019
- else
1020
- draft[field] = value;
1021
- this.check();
1022
- }
1023
- displayHour(draft) {
1024
- return draft.hour === null
1025
- ? null
1026
- : this.effectiveHourCycle === "h12"
1027
- ? draft.hour % 12 || 12
1028
- : draft.hour;
1029
- }
1030
- period(index, period) {
1031
- if (this.isDisabled())
1032
- return;
1033
- if (period === "24")
1034
- this.effectiveHourCycle = "h24";
1035
- else {
1036
- this.effectiveHourCycle = "h12";
1037
- this.drafts[index].hour =
1038
- ((this.drafts[index].hour || 0) % 12) + (period === "pm" ? 12 : 0);
1039
- this.drafts[index].present = true;
1040
- this.finish();
1041
- }
1042
- }
1043
- selected(day) {
1044
- return this.drafts.some((d) => {
1045
- try {
1046
- return d.present && this.adapter.dateToEpochDay(d.date) === day;
1047
- }
1048
- catch (_) {
1049
- return false;
1050
- }
1051
- });
1052
- }
1053
- inRange(day) {
1054
- if (!this.isRange || !this.drafts.every((d) => d.present))
1055
- return false;
1056
- try {
1057
- const a = this.adapter.dateToEpochDay(this.drafts[0].date), b = this.adapter.dateToEpochDay(this.drafts[1].date);
1058
- return day > Math.min(a, b) && day < Math.max(a, b);
1059
- }
1060
- catch (_) {
1061
- return false;
1062
- }
1063
- }
1064
- dayDisabled(day) {
1065
- if (day < this.firstSupportedDay || day > this.lastSupportedDay)
1066
- return true;
1067
- try {
1068
- const date = this.adapter.epochDayToDate(day);
1069
- const isDateDisabled = this[WklyPickerInputsPropertyKeys.IsDateDisabled]();
1070
- if (isDateDisabled &&
1071
- isDateDisabled(day, {
1072
- mode: this[WklyPickerInputsPropertyKeys.Mode](),
1073
- endpoint: this.isRange
1074
- ? this.drafts[0]?.present && !this.drafts[1]?.present
1075
- ? "end"
1076
- : "start"
1077
- : "single",
1078
- calendarDate: date,
1079
- }))
1080
- return true;
1081
- const min = this[WklyPickerInputsPropertyKeys.Min](), max = this[WklyPickerInputsPropertyKeys.Max]();
1082
- if (min && day < decodeIso(min).epochDay)
1083
- return true;
1084
- if (max && day > decodeIso(max).epochDay)
1085
- return true;
1086
- return false;
1087
- }
1088
- catch (_) {
1089
- return true;
1090
- }
1091
- }
1092
- select(day) {
1093
- if (this.isDisabled() || this.dayDisabled(day))
1094
- return;
1095
- this.focused = day;
1096
- const index = this.isRange && this.drafts[0].present && !this.drafts[1].present ? 1 : 0;
1097
- if (this.isRange && index === 0)
1098
- this.drafts[1].present = false;
1099
- delete this.drafts[index].unsupportedEpochDay;
1100
- this.drafts[index].date = this.adapter.epochDayToDate(day);
1101
- this.drafts[index].present = true;
1102
- this.orderDrafts();
1103
- this.renderRows();
1104
- this.finish();
1105
- if (this.presentation === "transient" &&
1106
- this[WklyPickerInputsPropertyKeys.Mode]() === "date" &&
1107
- this.viewMode === "calendar")
1108
- this.submit("auto-submit");
1109
- }
1110
- key(event, day) {
1111
- let delta = 0;
1112
- if (event.key === "ArrowLeft")
1113
- delta = -1;
1114
- if (event.key === "ArrowRight")
1115
- delta = 1;
1116
- if (event.key === "ArrowUp")
1117
- delta = -7;
1118
- if (event.key === "ArrowDown")
1119
- delta = 7;
1120
- if (event.key === "PageUp")
1121
- delta = -7 * (event.shiftKey ? this.visibleCount : 1);
1122
- if (event.key === "PageDown")
1123
- delta = 7 * (event.shiftKey ? this.visibleCount : 1);
1124
- if (event.key === "Home") {
1125
- event.preventDefault();
1126
- this.scrollToEpochDay(this.today, { focus: true });
1127
- }
1128
- if (delta) {
1129
- event.preventDefault();
1130
- const target = day + delta;
1131
- if (target >= this.firstSupportedDay && target <= this.lastSupportedDay)
1132
- this.scrollToEpochDay(target, { focus: true });
1133
- }
1134
- }
1135
- position(day, preset = false, options = {}) {
1136
- day = Math.max(this.firstSupportedDay, Math.min(this.lastSupportedDay, day));
1137
- this.anchorWeek = absoluteWeekOf(day, this.effectiveOffset);
1138
- const viewportPreset = this[WklyPickerInputsPropertyKeys.ViewportPreset]();
1139
- this.clipMonth = preset && viewportPreset.kind === "full-month";
1140
- if (preset && viewportPreset.kind !== "weeks") {
1141
- const d = this.adapter.epochDayToDate(day);
1142
- this.initialMonth = d.year + "/" + d.monthCode;
1143
- const [start, end] = calendarMonthBounds(this.adapter, day);
1144
- this.firstWeek = absoluteWeekOf(start, this.effectiveOffset);
1145
- this.visibleCount =
1146
- absoluteWeekOf(end, this.effectiveOffset) - this.firstWeek + 1;
1147
- if (viewportPreset.kind === "full-month-and-around" &&
1148
- !this.configErrors.length) {
1149
- const before = viewportPreset.extraWeeksBefore || 0, after = viewportPreset.extraWeeksAfter || 0;
1150
- this.firstWeek -= before;
1151
- this.visibleCount += before + after;
1152
- }
1153
- }
1154
- else {
1155
- if (viewportPreset.kind === "weeks")
1156
- this.visibleCount = this.configErrors.length
1157
- ? 6
1158
- : viewportPreset.visibleWeekCount;
1159
- this.firstWeek =
1160
- this.anchorWeek -
1161
- (options.align === "start"
1162
- ? 0
1163
- : options.align === "end"
1164
- ? this.visibleCount - 1
1165
- : Math.floor(this.visibleCount / 2));
1166
- }
1167
- this.firstWeek = this.clampFirstWeek(this.firstWeek);
1168
- this.baseWeek = this.firstWeek - 1000;
1169
- this.renderRows();
1170
- // Apply the new runway before writing scrollTop or locating a focus target.
1171
- this.changeDetector.detectChanges();
1172
- this.resetScroll();
1173
- }
1174
- resetScroll() {
1175
- // Round week boundaries to avoid scrollTop truncation under CSS zoom.
1176
- if (this.scroller)
1177
- this.scroller.nativeElement.scrollTop = Math.round(1000 * this.rowHeight);
1178
- }
1179
- scroll(event) {
1180
- const element = event.target;
1181
- this.snapPending = true;
1182
- this.scheduleSnap();
1183
- // Quantize displacement around the reset point, equally in both directions.
1184
- const relativeRows = element.scrollTop / this.rowHeight - 1000;
1185
- const index = 1000 + Math.sign(relativeRows) * Math.round(Math.abs(relativeRows));
1186
- const requestedFirst = this.baseWeek + index;
1187
- const first = this.clampFirstWeek(requestedFirst);
1188
- if (requestedFirst !== first) {
1189
- element.scrollTop = Math.round((first - this.baseWeek) * this.rowHeight);
1190
- }
1191
- if (first === this.firstWeek)
1192
- return;
1193
- this.clipMonth = false;
1194
- this.firstWeek = first;
1195
- this.anchorWeek = first + Math.floor(this.visibleCount / 2);
1196
- if (index < 100 || index > 1900) {
1197
- // Preserve signed displacement from this week; modulo turns fractional
1198
- // rounding just below a boundary into almost a full row after rebasing.
1199
- const offset = element.scrollTop - (first - this.baseWeek) * this.rowHeight;
1200
- this.baseWeek = first - 1000;
1201
- element.scrollTop = Math.round(1000 * this.rowHeight + offset);
1202
- }
1203
- this.renderRows();
1204
- }
1205
- scheduleSnap() {
1206
- if (this.scrollEndTimer)
1207
- clearTimeout(this.scrollEndTimer);
1208
- this.scrollEndTimer = setTimeout(() => this.snapWeek(), 200);
1209
- }
1210
- snapWeek() {
1211
- if (this.scrollEndTimer)
1212
- clearTimeout(this.scrollEndTimer);
1213
- this.scrollEndTimer = undefined;
1214
- if (!this.snapPending || !this.scroller)
1215
- return;
1216
- this.snapPending = false;
1217
- // Align the current virtual week without rebuilding or rebasing its rows.
1218
- const element = this.scroller.nativeElement;
1219
- const target = Math.round((this.firstWeek - this.baseWeek) * this.rowHeight);
1220
- if (element.scrollTop !== target)
1221
- element.scrollTop = target;
1222
- }
1223
- showFirstWeek(week) {
1224
- const first = this.clampFirstWeek(week);
1225
- if (first === this.firstWeek)
1226
- return;
1227
- this.clipMonth = false;
1228
- this.firstWeek = first;
1229
- this.anchorWeek = first + Math.floor(this.visibleCount / 2);
1230
- this.baseWeek = first - 1000;
1231
- this.renderRows();
1232
- this.resetScroll();
1233
- }
1234
- canMoveWeek(delta) {
1235
- return this.clampFirstWeek(this.firstWeek + delta) !== this.firstWeek;
1236
- }
1237
- moveWeek(delta) {
1238
- if (!this.isDisabled())
1239
- this.showFirstWeek(this.firstWeek + delta);
1240
- }
1241
- renderRows() {
1242
- // Keep the virtual scroll offset here; row data is shared across Angular versions.
1243
- const overscan = Math.max(0, Math.min(50, this[WklyPickerInputsPropertyKeys.OverscanWeeks]() || 0));
1244
- const start = this.firstWeek - overscan;
1245
- this.paddingTop = (start - this.baseWeek) * this.rowHeight;
1246
- this.rows = createWeekRows({
1247
- generator: this.generator,
1248
- adapter: this.adapter,
1249
- startWeek: start,
1250
- count: this.visibleCount + 2 * overscan,
1251
- firstVisibleWeek: this.firstWeek,
1252
- firstSupportedDay: this.firstSupportedDay,
1253
- lastSupportedDay: this.lastSupportedDay,
1254
- clipMonth: this.clipMonth,
1255
- initialMonth: this.initialMonth,
1256
- weekLabelMode: this[WklyPickerInputsPropertyKeys.WeekLabelMode](),
1257
- weekLabelFormatter: this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]() || null,
1258
- isDayDisabled: (day) => this.dayDisabled(day),
1259
- });
1260
- this[WklyPickerOutputsPropertyKeys.ViewportChange].emit({
1261
- firstVisibleAbsoluteWeek: this.firstWeek,
1262
- lastVisibleAbsoluteWeek: this.firstWeek + this.visibleCount - 1,
1263
- anchorAbsoluteWeek: this.anchorWeek,
1264
- });
1265
- }
1266
- // Retain day DOM nodes and keyboard focus when row metadata is regenerated.
1267
- trackCell(_i, cell) {
1268
- return cell.epochDay;
1269
- }
1270
- trackRow(_i, row) {
1271
- return row.week.absoluteWeek;
1272
- }
1273
- scrollToEpochDay(day, options = {}) {
1274
- integer(day);
1275
- this.adapter.epochDayToDate(day);
1276
- day = Math.max(this.firstSupportedDay, Math.min(this.lastSupportedDay, day));
1277
- // position renders synchronously; publish the tab stop before that render.
1278
- if (options.focus)
1279
- this.focused = day;
1280
- this.position(day, false, options);
1281
- if (options.select)
1282
- this.select(day);
1283
- if (options.focus)
1284
- this.focusDay();
1285
- }
1286
- scrollToAbsoluteWeek(week, options = {}) {
1287
- // A boundary week can start before the adapter's first supported day.
1288
- const first = firstEpochDayOf(week, this.effectiveOffset);
1289
- this.scrollToEpochDay(week === this.firstSupportedWeek
1290
- ? Math.max(first, this.firstSupportedDay)
1291
- : first, options);
1292
- }
1293
- scrollToCalendarDate(date, options = {}) {
1294
- this.scrollToEpochDay(this.adapter.dateToEpochDay(date), options);
1295
- }
1296
- scrollToValue(value, options = {}) {
1297
- this.scrollToEpochDay(decodeIso(value).epochDay, options);
1298
- }
1299
- focusDay() {
1300
- if (!this.browser)
1301
- return;
1302
- setTimeout(() => {
1303
- if (this.destroyed)
1304
- return;
1305
- this.changeDetector.detectChanges();
1306
- const day = this.host.nativeElement.querySelector('[data-day="' + this.focused + '"]');
1307
- const fallback = this.host.nativeElement.querySelector("button:not(:disabled),input:not(:disabled)");
1308
- (day || fallback)?.focus({ preventScroll: true });
1309
- });
1310
- }
1311
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerComponent, deps: [{ token: LOCALE_ID }, { token: WKLY_CONFIG }, { token: WKLY_CLOCK }, { token: WKLY_LOCALIZATION }, { token: WKLY_TRANSLATIONS }, { token: PLATFORM_ID }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1312
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.33", type: WklyDateTimePickerComponent, isStandalone: false, selector: "wkly-datetime-picker", providers: [
1313
- {
1314
- provide: NG_VALUE_ACCESSOR,
1315
- useExisting: forwardRef(() => WklyDateTimePickerComponent),
1316
- multi: true,
1317
- },
1318
- {
1319
- provide: NG_VALIDATORS,
1320
- useExisting: forwardRef(() => WklyDateTimePickerComponent),
1321
- multi: true,
1322
- },
1323
- ], viewQueries: [{ propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<section\n class=\"wkly\"\n [attr.dir]=\"direction\"\n [attr.aria-label]=\"\n this[WklyPickerInputsPropertyKeys.AriaLabel]() || 'Date and time picker'\n \"\n [attr.aria-describedby]=\"this[WklyPickerInputsPropertyKeys.AriaDescribedBy]()\"\n (focusout)=\"touched()\"\n>\n <header class=\"toolbar\">\n @if (hasDate) {\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"t(viewMode === 'calendar' ? 'manual' : 'calendar')\"\n (click)=\"toggleView()\"\n >\n {{ viewMode === \"calendar\" ? \"\u2637\" : \"\u25A6\" }}\n </button>\n }\n @if (hasDate) {\n <span class=\"year-control\">{{ title }}</span>\n }\n <span class=\"spacer\"></span\n ><button\n type=\"button\"\n class=\"now\"\n [disabled]=\"isDisabled()\"\n (click)=\"now()\"\n >\n {{ t(\"now\") }}\n </button>\n @if (presentation === \"transient\") {\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"t('close')\"\n (click)=\"cancel()\"\n >\n \u00D7\n </button>\n }\n </header>\n <ng-container *ngIf=\"hasDate && viewMode === 'calendar'\">\n <div\n role=\"grid\"\n [attr.aria-label]=\"\n this[WklyPickerInputsPropertyKeys.AriaLabel]() || 'Calendar'\n \"\n [attr.aria-multiselectable]=\"isRange\"\n >\n <div\n role=\"row\"\n class=\"week-head\"\n [class.no-label]=\"\n compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() === 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n >\n <span\n *ngIf=\"\n !compact &&\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() !== 'hidden' ||\n this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n role=\"columnheader\"\n aria-label=\"Week\"\n ></span>\n @for (day of weekdays; track $index) {\n <span role=\"columnheader\">{{ day }}</span>\n }\n </div>\n <div\n #scroller\n class=\"week-scroll\"\n [style.height.px]=\"visibleCount * rowHeight\"\n (scroll)=\"scroll($event)\"\n (scrollend)=\"snapWeek()\"\n >\n <div [style.height.px]=\"scrollHeight\" class=\"scroll-space\">\n <div class=\"rows\" [style.top.px]=\"paddingTop\">\n <div\n *ngFor=\"let row of rows; trackBy: trackRow\"\n role=\"row\"\n class=\"week-row\"\n [class.no-label]=\"\n compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() ===\n 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n >\n <span\n *ngIf=\"\n !compact &&\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() !==\n 'hidden' ||\n this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n role=\"rowheader\"\n class=\"week-number\"\n >{{ row.label }}</span\n >\n <div\n *ngFor=\"\n let cell of row.cells;\n let dayIndex = index;\n trackBy: trackCell\n \"\n role=\"gridcell\"\n [attr.data-weekday-index]=\"dayIndex\"\n [attr.aria-colindex]=\"\n dayIndex +\n (compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() ===\n 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n ? 1\n : 2)\n \"\n [attr.aria-selected]=\"selected(cell.epochDay)\"\n [attr.aria-disabled]=\"cell.disabled || isDisabled()\"\n [class.range]=\"inRange(cell.epochDay)\"\n [class.hidden]=\"cell.hidden\"\n [class.odd-month]=\"cell.date && cell.date.month % 2 === 1\"\n >\n <span [class]=\"'annotation annotation--' + dayIndex\">{{\n cell.annotation\n }}</span>\n <button\n type=\"button\"\n class=\"day\"\n [attr.data-day]=\"cell.epochDay\"\n [attr.aria-label]=\"cell.accessible\"\n [attr.aria-current]=\"cell.epochDay === today ? 'date' : null\"\n [attr.aria-disabled]=\"cell.disabled || isDisabled()\"\n [attr.tabindex]=\"\n !cell.hidden && cell.epochDay === focused ? 0 : -1\n \"\n [class.selected]=\"selected(cell.epochDay)\"\n [class.today]=\"cell.epochDay === today\"\n (focus)=\"focused = cell.epochDay\"\n (click)=\"select(cell.epochDay)\"\n (keydown)=\"key($event, cell.epochDay)\"\n >\n {{ cell.label }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"week-navigation\">\n <button\n type=\"button\"\n [disabled]=\"isDisabled() || !canMoveWeek(-1)\"\n [attr.aria-label]=\"t('previous')\"\n (click)=\"moveWeek(-1)\"\n >\n \u2191</button\n ><span>{{ title }}</span\n ><button\n type=\"button\"\n [disabled]=\"isDisabled() || !canMoveWeek(1)\"\n [attr.aria-label]=\"t('next')\"\n (click)=\"moveWeek(1)\"\n >\n \u2193\n </button>\n </div>\n </ng-container>\n <ng-container\n *ngFor=\"let draft of drafts; let i = index; trackBy: trackDraft\"\n >\n <fieldset\n *ngIf=\"(i === 0 || isRange) && (hasTime || viewMode === 'manual')\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"isRange ? t(i === 0 ? 'start' : 'end') : null\"\n >\n <legend *ngIf=\"isRange\">\n <ng-container\n *ngIf=\"\n i === 1 && hasDate && viewMode === 'manual';\n else endpointLabel\n \"\n >\n <span class=\"end-view-toggle\">\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"endView === 'date'\"\n (click)=\"toggleEndView('date')\"\n >\n {{ t(\"end\") }}\n </button>\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"endView === 'days'\"\n (click)=\"toggleEndView('days')\"\n >\n {{ inDaysLabel }}\n </button>\n </span>\n </ng-container>\n <ng-template #endpointLabel>{{\n t(i === 0 ? \"start\" : \"end\")\n }}</ng-template>\n </legend>\n <div\n *ngIf=\"\n i === 1 && hasDate && viewMode === 'manual' && endView === 'days'\n \"\n class=\"date-fields in-days-fields\"\n >\n <span class=\"resulting-end-date\" [attr.aria-label]=\"t('endDate')\">{{\n resultingEndDate\n }}</span>\n <wkly-field\n [label]=\"t('days')\"\n [hideLabel]=\"true\"\n [previousLabel]=\"t('daysPrevious')\"\n [nextLabel]=\"t('daysNext')\"\n [locale]=\"effectiveLocale\"\n [value]=\"inDays\"\n [min]=\"-9999\"\n [max]=\"9999\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"days($event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n </div>\n <div\n *ngIf=\"\n hasDate && viewMode === 'manual' && (i === 0 || endView === 'date')\n \"\n class=\"date-fields\"\n >\n <wkly-field\n [label]=\"t('day')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.day\"\n [min]=\"1\"\n [max]=\"31\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'day', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('month')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.month\"\n [min]=\"1\"\n [max]=\"monthCount(draft)\"\n [labels]=\"months(draft)\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'month', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('year')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.year\"\n [min]=\"adapter.supportedYearRange[0]\"\n [max]=\"adapter.supportedYearRange[1]\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'year', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n </div>\n <div\n *ngIf=\"hasTime\"\n class=\"time-fields\"\n [class.seconds]=\"this[WklyPickerInputsPropertyKeys.ShowSeconds]()\"\n >\n <wkly-field\n [label]=\"t('hour')\"\n [locale]=\"effectiveLocale\"\n [value]=\"displayHour(draft)\"\n [min]=\"effectiveHourCycle === 'h12' ? 1 : 0\"\n [max]=\"effectiveHourCycle === 'h12' ? 12 : 23\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'hour', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('minute')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.minute\"\n [max]=\"59\"\n [step]=\"\n this[WklyPickerInputsPropertyKeys.MinuteStep]() > 0 &&\n 60 % this[WklyPickerInputsPropertyKeys.MinuteStep]() === 0\n ? this[WklyPickerInputsPropertyKeys.MinuteStep]()\n : 1\n \"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'minute', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n *ngIf=\"this[WklyPickerInputsPropertyKeys.ShowSeconds]()\"\n [label]=\"t('second')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.second\"\n [max]=\"59\"\n [step]=\"\n this[WklyPickerInputsPropertyKeys.SecondStep]() > 0 &&\n 60 % this[WklyPickerInputsPropertyKeys.SecondStep]() === 0\n ? this[WklyPickerInputsPropertyKeys.SecondStep]()\n : 1\n \"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'second', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <div class=\"period\">\n <button\n *ngIf=\"\n effectiveHourCycle === 'h12' ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() === 'switchable'\n \"\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"\n effectiveHourCycle === 'h12' && (draft.hour || 0) < 12\n \"\n (click)=\"period(i, 'am')\"\n >\n {{ t(\"am\") }}</button\n ><button\n type=\"button\"\n [disabled]=\"\n isDisabled() ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() !== 'switchable'\n \"\n [attr.aria-pressed]=\"effectiveHourCycle === 'h24'\"\n (click)=\"period(i, '24')\"\n >\n 24</button\n ><button\n *ngIf=\"\n effectiveHourCycle === 'h12' ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() === 'switchable'\n \"\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"\n effectiveHourCycle === 'h12' && (draft.hour || 0) >= 12\n \"\n (click)=\"period(i, 'pm')\"\n >\n {{ t(\"pm\") }}\n </button>\n </div>\n </div>\n </fieldset>\n </ng-container>\n <div class=\"validation\" role=\"status\" aria-live=\"polite\">\n <p *ngFor=\"let err of errors\">! {{ t(err.messageKey) }}</p>\n </div>\n <footer *ngIf=\"submitVisible\">\n <button\n type=\"button\"\n class=\"confirm\"\n [disabled]=\"!canSubmit\"\n (click)=\"submit()\"\n >\n {{ t(\"confirm\") }}\n </button>\n </footer>\n</section>\n", styles: [":host{display:block;width:100%;box-sizing:border-box;--wkly-background-color: #fff;--wkly-background-color-alternate: #fafafa;--wkly-text-color: #192c28;--wkly-muted-color: #52635e;--wkly-border-color: #dce5e1;--wkly-accent-color: #176c55;--wkly-accent-color-alternate: #6ea494;--wkly-accent-text-color: #fff;--wkly-range-color: #e5f1ee;--wkly-error-color: #b42318;--wkly-focus-color: #245bd6;--wkly-size-multiplier: 1;--wkly-size-unit: 3.5em;color:var(--wkly-text-color);font:14px/1.4 system-ui,sans-serif;container-type:inline-size}.wkly{background:var(--wkly-background-color);border:1px solid var(--wkly-border-color);border-radius:14px;overflow:hidden;min-width:0;font-size:calc(14px*clamp(1,var(--wkly-size-multiplier),1.5))}button{font:inherit;color:inherit;min-width:var(--wkly-size-unit);min-height:var(--wkly-size-unit);border:0;background:transparent;border-radius:8px;cursor:pointer}button:hover:not(:disabled):not([aria-disabled=true]){background:var(--wkly-accent-color-alternate)}button:disabled,button[aria-disabled=true]{opacity:.4;cursor:default}button:focus-visible{outline:2px solid var(--wkly-focus-color);outline-offset:-2px}.toolbar{display:flex;align-items:center;padding:8px;gap:3px;border-bottom:1px solid var(--wkly-border-color)}.spacer{flex:1}.year-control{padding:0 6px;font-weight:650;text-align:start;line-height:1.2}.now{color:var(--wkly-accent-color);font-weight:650}.week-head,.week-row{display:grid;grid-template-columns:28px repeat(7,minmax(0,1fr))}.week-head{font-size:.85em;color:var(--wkly-muted-color);height:34px;align-items:center;text-align:center}.week-row{height:calc(var(--wkly-size-unit) * clamp(1,var(--wkly-size-multiplier),1));align-items:end}.no-label{grid-template-columns:repeat(7,minmax(0,1fr))}.week-scroll{overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;overflow-anchor:none;scrollbar-width:thin;max-height:65vh;touch-action:pan-y}.scroll-space{position:relative}.rows{position:absolute;left:0;right:0}.week-number{font-size:.85em;text-align:center;align-self:end;line-height:var(--wkly-size-unit);color:var(--wkly-muted-color)}[role=gridcell]{position:relative;min-width:0;height:var(--wkly-size-unit);text-align:center}[role=gridcell].odd-month:not(.range):not(.today){background:var(--wkly-background-color-alternate)}.day{width:100%;min-width:0;height:var(--wkly-size-unit);padding:0;border-radius:8px}.annotation{position:absolute;bottom:.25em;white-space:nowrap;font-size:1.25em;font-weight:650;line-height:1;pointer-events:none;z-index:1;color:var(--wkly-muted-color);color:color-mix(in srgb,var(--wkly-muted-color) 50%,transparent);text-shadow:0 0 2px --wkly-background-color,0 0 4px --wkly-background-color}.odd-month .annotation{text-shadow:0 0 2px --wkly-background-color-alternate,0 0 4px --wkly-background-color-alternate}.annotation:empty{display:none}.annotation--0{inset-inline-start:10%;bottom:1.75em}.annotation--1{inset-inline-start:-5%}.annotation--2{inset-inline-start:-20%}.annotation--3{inset-inline-start:-50%;inset-inline-end:-50%}.annotation--4{inset-inline-end:-20%}.annotation--5{inset-inline-end:-5%}.annotation--6{inset-inline-end:10%}.range{background:var(--wkly-range-color)}.day.selected{background:var(--wkly-accent-color);color:var(--wkly-accent-text-color);font-weight:700}.today:after{content:\"\";display:block;width:5px;height:5px;background:currentColor;border-radius:50%;position:absolute;bottom:2px;left:calc(50% - 2px)}.today{font-weight:750;box-shadow:inset 0 0 0 1px var(--wkly-accent-color)}.hidden{visibility:hidden}.week-navigation{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--wkly-border-color);font-size:.85em;color:var(--wkly-muted-color)}fieldset{border:0;padding:0 12px;margin:0;min-width:0}legend{padding-top:.85em;font-weight:650;color:var(--wkly-accent-color)}.date-fields{display:grid;grid-template-columns:1fr 2fr 1.4fr;gap:7px;padding:12px 0}.end-view-toggle{display:inline-flex}.end-view-toggle button{min-height:0;min-width:0;padding:0 6px;border-radius:0;line-height:inherit}.end-view-toggle button:first-child{padding-inline-start:0}.end-view-toggle button+button{border-inline-start:1px solid var(--wkly-text-color)}.end-view-toggle button[aria-pressed=false]{color:var(--wkly-muted-color);font-weight:400}.in-days-fields{grid-template-columns:minmax(0,1fr);gap:0;text-align:center}.resulting-end-date{font-size:11px;color:var(--wkly-muted-color);height:1.4em;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.time-fields{display:grid;grid-template-columns:1fr 1fr 52px;gap:8px;padding:14px 0;border-top:1px solid var(--wkly-border-color)}.time-fields.seconds{grid-template-columns:1fr 1fr 1fr 48px}.period{display:flex;flex-direction:column;justify-content:center;gap:2px;padding-top:1.25em}.period button{font-size:.85em}.period [aria-pressed=true]{background:var(--wkly-range-color);box-shadow:inset 0 0 0 1px var(--wkly-accent-color);font-weight:700}.validation{color:var(--wkly-error-color);font-size:.85em}.validation p{margin:.5em .85em}footer{padding:12px;border-top:1px solid var(--wkly-border-color)}.confirm{background:var(--wkly-accent-color);color:var(--wkly-accent-text-color);width:100%;font-weight:650}.confirm:hover:not(:disabled){background:var(--wkly-accent-color-alternate)}@media(forced-colors:active){.day.selected{outline:2px solid Highlight}.range{border-bottom:2px solid Highlight}.today{outline:1px dashed CanvasText}}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;animation:none!important}}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: WklyFieldComponent, selector: "wkly-field", inputs: ["value", "label", "hideLabel", "previousLabel", "nextLabel", "min", "max", "step", "locale", "disabled", "invalid", "labels"], outputs: ["valueChange", "complete"] }] });
1324
- }
1325
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerComponent, decorators: [{
1326
- type: Component,
1327
- args: [{ selector: "wkly-datetime-picker", standalone: false, providers: [
1328
- {
1329
- provide: NG_VALUE_ACCESSOR,
1330
- useExisting: forwardRef(() => WklyDateTimePickerComponent),
1331
- multi: true,
1332
- },
1333
- {
1334
- provide: NG_VALIDATORS,
1335
- useExisting: forwardRef(() => WklyDateTimePickerComponent),
1336
- multi: true,
1337
- },
1338
- ], template: "<section\n class=\"wkly\"\n [attr.dir]=\"direction\"\n [attr.aria-label]=\"\n this[WklyPickerInputsPropertyKeys.AriaLabel]() || 'Date and time picker'\n \"\n [attr.aria-describedby]=\"this[WklyPickerInputsPropertyKeys.AriaDescribedBy]()\"\n (focusout)=\"touched()\"\n>\n <header class=\"toolbar\">\n @if (hasDate) {\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"t(viewMode === 'calendar' ? 'manual' : 'calendar')\"\n (click)=\"toggleView()\"\n >\n {{ viewMode === \"calendar\" ? \"\u2637\" : \"\u25A6\" }}\n </button>\n }\n @if (hasDate) {\n <span class=\"year-control\">{{ title }}</span>\n }\n <span class=\"spacer\"></span\n ><button\n type=\"button\"\n class=\"now\"\n [disabled]=\"isDisabled()\"\n (click)=\"now()\"\n >\n {{ t(\"now\") }}\n </button>\n @if (presentation === \"transient\") {\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"t('close')\"\n (click)=\"cancel()\"\n >\n \u00D7\n </button>\n }\n </header>\n <ng-container *ngIf=\"hasDate && viewMode === 'calendar'\">\n <div\n role=\"grid\"\n [attr.aria-label]=\"\n this[WklyPickerInputsPropertyKeys.AriaLabel]() || 'Calendar'\n \"\n [attr.aria-multiselectable]=\"isRange\"\n >\n <div\n role=\"row\"\n class=\"week-head\"\n [class.no-label]=\"\n compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() === 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n >\n <span\n *ngIf=\"\n !compact &&\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() !== 'hidden' ||\n this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n role=\"columnheader\"\n aria-label=\"Week\"\n ></span>\n @for (day of weekdays; track $index) {\n <span role=\"columnheader\">{{ day }}</span>\n }\n </div>\n <div\n #scroller\n class=\"week-scroll\"\n [style.height.px]=\"visibleCount * rowHeight\"\n (scroll)=\"scroll($event)\"\n (scrollend)=\"snapWeek()\"\n >\n <div [style.height.px]=\"scrollHeight\" class=\"scroll-space\">\n <div class=\"rows\" [style.top.px]=\"paddingTop\">\n <div\n *ngFor=\"let row of rows; trackBy: trackRow\"\n role=\"row\"\n class=\"week-row\"\n [class.no-label]=\"\n compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() ===\n 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n >\n <span\n *ngIf=\"\n !compact &&\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() !==\n 'hidden' ||\n this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n role=\"rowheader\"\n class=\"week-number\"\n >{{ row.label }}</span\n >\n <div\n *ngFor=\"\n let cell of row.cells;\n let dayIndex = index;\n trackBy: trackCell\n \"\n role=\"gridcell\"\n [attr.data-weekday-index]=\"dayIndex\"\n [attr.aria-colindex]=\"\n dayIndex +\n (compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() ===\n 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n ? 1\n : 2)\n \"\n [attr.aria-selected]=\"selected(cell.epochDay)\"\n [attr.aria-disabled]=\"cell.disabled || isDisabled()\"\n [class.range]=\"inRange(cell.epochDay)\"\n [class.hidden]=\"cell.hidden\"\n [class.odd-month]=\"cell.date && cell.date.month % 2 === 1\"\n >\n <span [class]=\"'annotation annotation--' + dayIndex\">{{\n cell.annotation\n }}</span>\n <button\n type=\"button\"\n class=\"day\"\n [attr.data-day]=\"cell.epochDay\"\n [attr.aria-label]=\"cell.accessible\"\n [attr.aria-current]=\"cell.epochDay === today ? 'date' : null\"\n [attr.aria-disabled]=\"cell.disabled || isDisabled()\"\n [attr.tabindex]=\"\n !cell.hidden && cell.epochDay === focused ? 0 : -1\n \"\n [class.selected]=\"selected(cell.epochDay)\"\n [class.today]=\"cell.epochDay === today\"\n (focus)=\"focused = cell.epochDay\"\n (click)=\"select(cell.epochDay)\"\n (keydown)=\"key($event, cell.epochDay)\"\n >\n {{ cell.label }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"week-navigation\">\n <button\n type=\"button\"\n [disabled]=\"isDisabled() || !canMoveWeek(-1)\"\n [attr.aria-label]=\"t('previous')\"\n (click)=\"moveWeek(-1)\"\n >\n \u2191</button\n ><span>{{ title }}</span\n ><button\n type=\"button\"\n [disabled]=\"isDisabled() || !canMoveWeek(1)\"\n [attr.aria-label]=\"t('next')\"\n (click)=\"moveWeek(1)\"\n >\n \u2193\n </button>\n </div>\n </ng-container>\n <ng-container\n *ngFor=\"let draft of drafts; let i = index; trackBy: trackDraft\"\n >\n <fieldset\n *ngIf=\"(i === 0 || isRange) && (hasTime || viewMode === 'manual')\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"isRange ? t(i === 0 ? 'start' : 'end') : null\"\n >\n <legend *ngIf=\"isRange\">\n <ng-container\n *ngIf=\"\n i === 1 && hasDate && viewMode === 'manual';\n else endpointLabel\n \"\n >\n <span class=\"end-view-toggle\">\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"endView === 'date'\"\n (click)=\"toggleEndView('date')\"\n >\n {{ t(\"end\") }}\n </button>\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"endView === 'days'\"\n (click)=\"toggleEndView('days')\"\n >\n {{ inDaysLabel }}\n </button>\n </span>\n </ng-container>\n <ng-template #endpointLabel>{{\n t(i === 0 ? \"start\" : \"end\")\n }}</ng-template>\n </legend>\n <div\n *ngIf=\"\n i === 1 && hasDate && viewMode === 'manual' && endView === 'days'\n \"\n class=\"date-fields in-days-fields\"\n >\n <span class=\"resulting-end-date\" [attr.aria-label]=\"t('endDate')\">{{\n resultingEndDate\n }}</span>\n <wkly-field\n [label]=\"t('days')\"\n [hideLabel]=\"true\"\n [previousLabel]=\"t('daysPrevious')\"\n [nextLabel]=\"t('daysNext')\"\n [locale]=\"effectiveLocale\"\n [value]=\"inDays\"\n [min]=\"-9999\"\n [max]=\"9999\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"days($event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n </div>\n <div\n *ngIf=\"\n hasDate && viewMode === 'manual' && (i === 0 || endView === 'date')\n \"\n class=\"date-fields\"\n >\n <wkly-field\n [label]=\"t('day')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.day\"\n [min]=\"1\"\n [max]=\"31\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'day', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('month')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.month\"\n [min]=\"1\"\n [max]=\"monthCount(draft)\"\n [labels]=\"months(draft)\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'month', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('year')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.year\"\n [min]=\"adapter.supportedYearRange[0]\"\n [max]=\"adapter.supportedYearRange[1]\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'year', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n </div>\n <div\n *ngIf=\"hasTime\"\n class=\"time-fields\"\n [class.seconds]=\"this[WklyPickerInputsPropertyKeys.ShowSeconds]()\"\n >\n <wkly-field\n [label]=\"t('hour')\"\n [locale]=\"effectiveLocale\"\n [value]=\"displayHour(draft)\"\n [min]=\"effectiveHourCycle === 'h12' ? 1 : 0\"\n [max]=\"effectiveHourCycle === 'h12' ? 12 : 23\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'hour', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('minute')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.minute\"\n [max]=\"59\"\n [step]=\"\n this[WklyPickerInputsPropertyKeys.MinuteStep]() > 0 &&\n 60 % this[WklyPickerInputsPropertyKeys.MinuteStep]() === 0\n ? this[WklyPickerInputsPropertyKeys.MinuteStep]()\n : 1\n \"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'minute', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n *ngIf=\"this[WklyPickerInputsPropertyKeys.ShowSeconds]()\"\n [label]=\"t('second')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.second\"\n [max]=\"59\"\n [step]=\"\n this[WklyPickerInputsPropertyKeys.SecondStep]() > 0 &&\n 60 % this[WklyPickerInputsPropertyKeys.SecondStep]() === 0\n ? this[WklyPickerInputsPropertyKeys.SecondStep]()\n : 1\n \"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'second', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <div class=\"period\">\n <button\n *ngIf=\"\n effectiveHourCycle === 'h12' ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() === 'switchable'\n \"\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"\n effectiveHourCycle === 'h12' && (draft.hour || 0) < 12\n \"\n (click)=\"period(i, 'am')\"\n >\n {{ t(\"am\") }}</button\n ><button\n type=\"button\"\n [disabled]=\"\n isDisabled() ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() !== 'switchable'\n \"\n [attr.aria-pressed]=\"effectiveHourCycle === 'h24'\"\n (click)=\"period(i, '24')\"\n >\n 24</button\n ><button\n *ngIf=\"\n effectiveHourCycle === 'h12' ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() === 'switchable'\n \"\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"\n effectiveHourCycle === 'h12' && (draft.hour || 0) >= 12\n \"\n (click)=\"period(i, 'pm')\"\n >\n {{ t(\"pm\") }}\n </button>\n </div>\n </div>\n </fieldset>\n </ng-container>\n <div class=\"validation\" role=\"status\" aria-live=\"polite\">\n <p *ngFor=\"let err of errors\">! {{ t(err.messageKey) }}</p>\n </div>\n <footer *ngIf=\"submitVisible\">\n <button\n type=\"button\"\n class=\"confirm\"\n [disabled]=\"!canSubmit\"\n (click)=\"submit()\"\n >\n {{ t(\"confirm\") }}\n </button>\n </footer>\n</section>\n", styles: [":host{display:block;width:100%;box-sizing:border-box;--wkly-background-color: #fff;--wkly-background-color-alternate: #fafafa;--wkly-text-color: #192c28;--wkly-muted-color: #52635e;--wkly-border-color: #dce5e1;--wkly-accent-color: #176c55;--wkly-accent-color-alternate: #6ea494;--wkly-accent-text-color: #fff;--wkly-range-color: #e5f1ee;--wkly-error-color: #b42318;--wkly-focus-color: #245bd6;--wkly-size-multiplier: 1;--wkly-size-unit: 3.5em;color:var(--wkly-text-color);font:14px/1.4 system-ui,sans-serif;container-type:inline-size}.wkly{background:var(--wkly-background-color);border:1px solid var(--wkly-border-color);border-radius:14px;overflow:hidden;min-width:0;font-size:calc(14px*clamp(1,var(--wkly-size-multiplier),1.5))}button{font:inherit;color:inherit;min-width:var(--wkly-size-unit);min-height:var(--wkly-size-unit);border:0;background:transparent;border-radius:8px;cursor:pointer}button:hover:not(:disabled):not([aria-disabled=true]){background:var(--wkly-accent-color-alternate)}button:disabled,button[aria-disabled=true]{opacity:.4;cursor:default}button:focus-visible{outline:2px solid var(--wkly-focus-color);outline-offset:-2px}.toolbar{display:flex;align-items:center;padding:8px;gap:3px;border-bottom:1px solid var(--wkly-border-color)}.spacer{flex:1}.year-control{padding:0 6px;font-weight:650;text-align:start;line-height:1.2}.now{color:var(--wkly-accent-color);font-weight:650}.week-head,.week-row{display:grid;grid-template-columns:28px repeat(7,minmax(0,1fr))}.week-head{font-size:.85em;color:var(--wkly-muted-color);height:34px;align-items:center;text-align:center}.week-row{height:calc(var(--wkly-size-unit) * clamp(1,var(--wkly-size-multiplier),1));align-items:end}.no-label{grid-template-columns:repeat(7,minmax(0,1fr))}.week-scroll{overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;overflow-anchor:none;scrollbar-width:thin;max-height:65vh;touch-action:pan-y}.scroll-space{position:relative}.rows{position:absolute;left:0;right:0}.week-number{font-size:.85em;text-align:center;align-self:end;line-height:var(--wkly-size-unit);color:var(--wkly-muted-color)}[role=gridcell]{position:relative;min-width:0;height:var(--wkly-size-unit);text-align:center}[role=gridcell].odd-month:not(.range):not(.today){background:var(--wkly-background-color-alternate)}.day{width:100%;min-width:0;height:var(--wkly-size-unit);padding:0;border-radius:8px}.annotation{position:absolute;bottom:.25em;white-space:nowrap;font-size:1.25em;font-weight:650;line-height:1;pointer-events:none;z-index:1;color:var(--wkly-muted-color);color:color-mix(in srgb,var(--wkly-muted-color) 50%,transparent);text-shadow:0 0 2px --wkly-background-color,0 0 4px --wkly-background-color}.odd-month .annotation{text-shadow:0 0 2px --wkly-background-color-alternate,0 0 4px --wkly-background-color-alternate}.annotation:empty{display:none}.annotation--0{inset-inline-start:10%;bottom:1.75em}.annotation--1{inset-inline-start:-5%}.annotation--2{inset-inline-start:-20%}.annotation--3{inset-inline-start:-50%;inset-inline-end:-50%}.annotation--4{inset-inline-end:-20%}.annotation--5{inset-inline-end:-5%}.annotation--6{inset-inline-end:10%}.range{background:var(--wkly-range-color)}.day.selected{background:var(--wkly-accent-color);color:var(--wkly-accent-text-color);font-weight:700}.today:after{content:\"\";display:block;width:5px;height:5px;background:currentColor;border-radius:50%;position:absolute;bottom:2px;left:calc(50% - 2px)}.today{font-weight:750;box-shadow:inset 0 0 0 1px var(--wkly-accent-color)}.hidden{visibility:hidden}.week-navigation{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--wkly-border-color);font-size:.85em;color:var(--wkly-muted-color)}fieldset{border:0;padding:0 12px;margin:0;min-width:0}legend{padding-top:.85em;font-weight:650;color:var(--wkly-accent-color)}.date-fields{display:grid;grid-template-columns:1fr 2fr 1.4fr;gap:7px;padding:12px 0}.end-view-toggle{display:inline-flex}.end-view-toggle button{min-height:0;min-width:0;padding:0 6px;border-radius:0;line-height:inherit}.end-view-toggle button:first-child{padding-inline-start:0}.end-view-toggle button+button{border-inline-start:1px solid var(--wkly-text-color)}.end-view-toggle button[aria-pressed=false]{color:var(--wkly-muted-color);font-weight:400}.in-days-fields{grid-template-columns:minmax(0,1fr);gap:0;text-align:center}.resulting-end-date{font-size:11px;color:var(--wkly-muted-color);height:1.4em;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.time-fields{display:grid;grid-template-columns:1fr 1fr 52px;gap:8px;padding:14px 0;border-top:1px solid var(--wkly-border-color)}.time-fields.seconds{grid-template-columns:1fr 1fr 1fr 48px}.period{display:flex;flex-direction:column;justify-content:center;gap:2px;padding-top:1.25em}.period button{font-size:.85em}.period [aria-pressed=true]{background:var(--wkly-range-color);box-shadow:inset 0 0 0 1px var(--wkly-accent-color);font-weight:700}.validation{color:var(--wkly-error-color);font-size:.85em}.validation p{margin:.5em .85em}footer{padding:12px;border-top:1px solid var(--wkly-border-color)}.confirm{background:var(--wkly-accent-color);color:var(--wkly-accent-text-color);width:100%;font-weight:650}.confirm:hover:not(:disabled){background:var(--wkly-accent-color-alternate)}@media(forced-colors:active){.day.selected{outline:2px solid Highlight}.range{border-bottom:2px solid Highlight}.today{outline:1px dashed CanvasText}}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;animation:none!important}}\n"] }]
1339
- }], ctorParameters: () => [{ type: undefined, decorators: [{
1340
- type: Inject,
1341
- args: [LOCALE_ID]
1342
- }] }, { type: undefined, decorators: [{
1343
- type: Inject,
1344
- args: [WKLY_CONFIG]
1345
- }] }, { type: undefined, decorators: [{
1346
- type: Inject,
1347
- args: [WKLY_CLOCK]
1348
- }] }, { type: undefined, decorators: [{
1349
- type: Inject,
1350
- args: [WKLY_LOCALIZATION]
1351
- }] }, { type: undefined, decorators: [{
1352
- type: Inject,
1353
- args: [WKLY_TRANSLATIONS]
1354
- }] }, { type: Object, decorators: [{
1355
- type: Inject,
1356
- args: [PLATFORM_ID]
1357
- }] }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { scroller: [{
1358
- type: ViewChild,
1359
- args: ["scroller"]
1360
- }] } });
1361
-
1362
- /** Native-dialog factory. Browser resources are allocated only by open(). */
1363
- class WklyDateTimePickerDialogService {
1364
- environmentInjector;
1365
- app;
1366
- document;
1367
- platform;
1368
- constructor(environmentInjector, app, document, platform) {
1369
- this.environmentInjector = environmentInjector;
1370
- this.app = app;
1371
- this.document = document;
1372
- this.platform = platform;
1373
- }
1374
- open(trigger, onCancel, backdrop = true, injector) {
1375
- if (!isPlatformBrowser(this.platform))
1376
- throw new Error("Picker presentations can only open in a browser");
1377
- const dialog = this.document.createElement("dialog");
1378
- dialog.setAttribute("aria-label", "Date and time picker");
1379
- Object.assign(dialog.style, {
1380
- padding: "0",
1381
- border: "0",
1382
- borderRadius: "14px",
1383
- width: "min(390px, 100vw)",
1384
- maxWidth: "100vw",
1385
- maxHeight: "94vh",
1386
- background: "transparent",
1387
- });
1388
- const component = createComponent(WklyDateTimePickerComponent, {
1389
- environmentInjector: this.environmentInjector,
1390
- elementInjector: injector,
1391
- });
1392
- component.instance.presentation = "transient";
1393
- dialog.appendChild(component.location.nativeElement);
1394
- this.document.body.appendChild(dialog);
1395
- this.app.attachView(component.hostView);
1396
- const cancel = (event) => {
1397
- event.preventDefault();
1398
- onCancel("escape");
1399
- };
1400
- const click = (event) => {
1401
- if (backdrop && event.target === dialog) {
1402
- const r = dialog.getBoundingClientRect();
1403
- if (event.clientX < r.left ||
1404
- event.clientX > r.right ||
1405
- event.clientY < r.top ||
1406
- event.clientY > r.bottom)
1407
- onCancel("backdrop");
1408
- }
1409
- };
1410
- const keydown = (event) => {
1411
- if (event.key !== "Tab")
1412
- return;
1413
- const controls = Array.from(dialog.querySelectorAll('button:not(:disabled),input:not(:disabled),[tabindex="0"]')).filter((el) => el.tabIndex >= 0 &&
1414
- el.getClientRects().length &&
1415
- getComputedStyle(el).visibility !== "hidden");
1416
- const first = controls[0], last = controls[controls.length - 1];
1417
- if (first &&
1418
- (event.shiftKey
1419
- ? this.document.activeElement === first
1420
- : this.document.activeElement === last)) {
1421
- event.preventDefault();
1422
- (event.shiftKey ? last : first).focus();
1423
- }
1424
- };
1425
- dialog.addEventListener("cancel", cancel);
1426
- dialog.addEventListener("click", click);
1427
- dialog.addEventListener("keydown", keydown);
1428
- dialog.showModal();
1429
- return {
1430
- component,
1431
- destroy: () => {
1432
- dialog.removeEventListener("cancel", cancel);
1433
- dialog.removeEventListener("click", click);
1434
- dialog.removeEventListener("keydown", keydown);
1435
- dialog.close();
1436
- this.app.detachView(component.hostView);
1437
- component.destroy();
1438
- dialog.remove();
1439
- trigger.focus();
1440
- },
1441
- };
1442
- }
1443
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerDialogService, deps: [{ token: i0.EnvironmentInjector }, { token: i0.ApplicationRef }, { token: DOCUMENT }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable });
1444
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerDialogService, providedIn: "root" });
1445
- }
1446
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerDialogService, decorators: [{
1447
- type: Injectable,
1448
- args: [{ providedIn: "root" }]
1449
- }], ctorParameters: () => [{ type: i0.EnvironmentInjector }, { type: i0.ApplicationRef }, { type: Document, decorators: [{
1450
- type: Inject,
1451
- args: [DOCUMENT]
1452
- }] }, { type: Object, decorators: [{
1453
- type: Inject,
1454
- args: [PLATFORM_ID]
1455
- }] }] });
1456
- /** Shared trigger lifecycle; optional presentation packages extend this class. */
1457
- class WklyTriggerBase extends WklyPickerInputs {
1458
- element;
1459
- ref = null;
1460
- subscriptions = [];
1461
- errors = [];
1462
- change = () => { };
1463
- touched = () => { };
1464
- validation = () => { };
1465
- formValue = signal(undefined, ...(ngDevMode ? [{ debugName: "formValue" }] : []));
1466
- formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "formDisabled" }] : []));
1467
- previousInputs;
1468
- currentValue() {
1469
- return this.formValue() === undefined
1470
- ? this[WklyPickerInputsPropertyKeys.Value]()
1471
- : this.formValue();
1472
- }
1473
- isDisabled() {
1474
- return this[WklyPickerInputsPropertyKeys.Disabled]() || this.formDisabled();
1475
- }
1476
- constructor(element) {
1477
- super();
1478
- this.element = element;
1479
- effect(() => {
1480
- const inputs = unwrapWklyPickerSignalInputs(this);
1481
- const previous = this.previousInputs;
1482
- this.previousInputs = inputs;
1483
- untracked(() => {
1484
- if (previous &&
1485
- !Object.is(previous[WklyPickerInputsPropertyKeys.Value], inputs[WklyPickerInputsPropertyKeys.Value]))
1486
- this.formValue.set(undefined);
1487
- if (!previous ||
1488
- Object.keys(inputs).some((key) => !Object.is(previous[key], inputs[key]))) {
1489
- this.checkValue();
1490
- this.display();
1491
- if (this.ref) {
1492
- this.copy();
1493
- this.ref.component.changeDetectorRef.detectChanges();
1494
- }
1495
- }
1496
- });
1497
- });
1498
- }
1499
- open() {
1500
- if (this.isDisabled() || this.ref)
1501
- return;
1502
- this.ref = this.create();
1503
- const picker = this.ref.component.instance;
1504
- this.copy();
1505
- this.subscriptions = [
1506
- picker[WklyPickerOutputsPropertyKeys.ValueChange].subscribe((value) => {
1507
- this.formValue.set(value);
1508
- this.change(value);
1509
- this[WklyPickerOutputsPropertyKeys.ValueChange].emit(value);
1510
- this.display();
1511
- }),
1512
- picker[WklyPickerOutputsPropertyKeys.ValidationChange].subscribe((errors) => {
1513
- this.errors = errors;
1514
- this[WklyPickerOutputsPropertyKeys.ValidationChange].emit(errors);
1515
- this.validation();
1516
- }),
1517
- picker[WklyPickerOutputsPropertyKeys.Closed].subscribe((reason) => this.close(reason)),
1518
- picker[WklyPickerOutputsPropertyKeys.ViewportChange].subscribe((value) => this[WklyPickerOutputsPropertyKeys.ViewportChange].emit(value)),
1519
- picker[WklyPickerOutputsPropertyKeys.ViewModeChange].subscribe((value) => this[WklyPickerOutputsPropertyKeys.ViewModeChange].emit(value)),
1520
- ];
1521
- this.ref.component.changeDetectorRef.detectChanges();
1522
- picker.focusDay();
1523
- this[WklyPickerOutputsPropertyKeys.Opened].emit();
1524
- }
1525
- key(event) {
1526
- if (event.key === "Enter" ||
1527
- event.key === " " ||
1528
- event.key === "ArrowDown") {
1529
- event.preventDefault();
1530
- this.open();
1531
- }
1532
- }
1533
- blur() {
1534
- this.touched();
1535
- }
1536
- close(reason = "programmatic") {
1537
- if (!this.ref)
1538
- return;
1539
- const ref = this.ref;
1540
- this.ref = null;
1541
- this.subscriptions.forEach((s) => s.unsubscribe());
1542
- this.subscriptions = [];
1543
- ref.destroy();
1544
- this.touched();
1545
- this[WklyPickerOutputsPropertyKeys.Closed].emit(reason);
1546
- }
1547
- ngOnDestroy() {
1548
- this.close();
1549
- }
1550
- copy() {
1551
- if (!this.ref)
1552
- return;
1553
- const inputs = unwrapWklyPickerSignalInputs(this);
1554
- for (const name of Object.values(WklyPickerInputsPropertyKeys))
1555
- this.ref.component.setInput(name, name === WklyPickerInputsPropertyKeys.Value
1556
- ? this.currentValue()
1557
- : name === WklyPickerInputsPropertyKeys.Disabled
1558
- ? this.isDisabled()
1559
- : inputs[name]);
1560
- }
1561
- display() {
1562
- const host = this.element.nativeElement;
1563
- if (host.tagName === "INPUT") {
1564
- host.readOnly = true;
1565
- const value = this.currentValue();
1566
- host.value =
1567
- value === null
1568
- ? ""
1569
- : typeof value === "string"
1570
- ? value
1571
- : value.join(" — ");
1572
- host.disabled = this.isDisabled();
1573
- host.setAttribute("aria-haspopup", "dialog");
1574
- }
1575
- }
1576
- checkValue() {
1577
- this.errors = validateSelection(this.currentValue(), unwrapWklyPickerSignalInputs(this), this[WklyPickerInputsPropertyKeys.CalendarAdapter]() ||
1578
- new WklyGregorianCalendarAdapter(this[WklyPickerInputsPropertyKeys.Locale]() || "en-US"));
1579
- this[WklyPickerOutputsPropertyKeys.ValidationChange].emit(this.errors);
1580
- this.validation();
1581
- }
1582
- writeValue(value) {
1583
- this.formValue.set(value);
1584
- this.checkValue();
1585
- this.display();
1586
- if (this.ref)
1587
- this.ref.component.instance.writeValue(value);
1588
- }
1589
- registerOnChange(fn) {
1590
- this.change = fn;
1591
- }
1592
- registerOnTouched(fn) {
1593
- this.touched = fn;
1594
- }
1595
- setDisabledState(value) {
1596
- this.formDisabled.set(value);
1597
- this.display();
1598
- if (this.ref)
1599
- this.ref.component.instance.setDisabledState(value);
1600
- }
1601
- validate() {
1602
- return this.errors.length ? { wkly: this.errors } : null;
1603
- }
1604
- registerOnValidatorChange(fn) {
1605
- this.validation = fn;
1606
- }
1607
- scrollToEpochDay(day, options) {
1608
- this.open();
1609
- this.ref?.component.instance.scrollToEpochDay(day, options);
1610
- }
1611
- scrollToAbsoluteWeek(week, options) {
1612
- this.open();
1613
- this.ref?.component.instance.scrollToAbsoluteWeek(week, options);
1614
- }
1615
- scrollToCalendarDate(date, options) {
1616
- this.open();
1617
- this.ref?.component.instance.scrollToCalendarDate(date, options);
1618
- }
1619
- scrollToValue(value, options) {
1620
- this.open();
1621
- this.ref?.component.instance.scrollToValue(value, options);
1622
- }
1623
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyTriggerBase, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
1624
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.33", type: WklyTriggerBase, isStandalone: true, host: { listeners: { "click": "open()", "keydown": "key($event)", "blur": "blur()" } }, usesInheritance: true, ngImport: i0 });
644
+ const keys = Object.values(WklyPickerInputsPropertyKeys);
645
+ return Object.fromEntries(keys.map((key) => [key, source[key]()]));
1625
646
  }
1626
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyTriggerBase, decorators: [{
1627
- type: Directive
1628
- }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { open: [{
1629
- type: HostListener,
1630
- args: ["click"]
1631
- }], key: [{
1632
- type: HostListener,
1633
- args: ["keydown", ["$event"]]
1634
- }], blur: [{
1635
- type: HostListener,
1636
- args: ["blur"]
1637
- }] } });
1638
- class WklyDateTimePickerDialogDirective extends WklyTriggerBase {
1639
- service;
1640
- triggerInjector;
1641
- constructor(element, service, triggerInjector) {
1642
- super(element);
1643
- this.service = service;
1644
- this.triggerInjector = triggerInjector;
1645
- }
1646
- create() {
1647
- return this.service.open(this.element.nativeElement, (reason) => this.close(reason), this[WklyPickerInputsPropertyKeys.CloseOnBackdrop](), this.triggerInjector);
1648
- }
1649
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerDialogDirective, deps: [{ token: i0.ElementRef }, { token: WklyDateTimePickerDialogService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Directive });
1650
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.33", type: WklyDateTimePickerDialogDirective, isStandalone: false, selector: "[wklyDateTimePickerDialog]", providers: [
1651
- {
1652
- provide: NG_VALUE_ACCESSOR,
1653
- useExisting: forwardRef(() => WklyDateTimePickerDialogDirective),
1654
- multi: true,
1655
- },
1656
- {
1657
- provide: NG_VALIDATORS,
1658
- useExisting: forwardRef(() => WklyDateTimePickerDialogDirective),
1659
- multi: true,
1660
- },
1661
- ], exportAs: ["wklyDialog"], usesInheritance: true, ngImport: i0 });
1662
- }
1663
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerDialogDirective, decorators: [{
1664
- type: Directive,
1665
- args: [{
1666
- selector: "[wklyDateTimePickerDialog]",
1667
- standalone: false,
1668
- exportAs: "wklyDialog",
1669
- providers: [
1670
- {
1671
- provide: NG_VALUE_ACCESSOR,
1672
- useExisting: forwardRef(() => WklyDateTimePickerDialogDirective),
1673
- multi: true,
1674
- },
1675
- {
1676
- provide: NG_VALIDATORS,
1677
- useExisting: forwardRef(() => WklyDateTimePickerDialogDirective),
1678
- multi: true,
1679
- },
1680
- ],
1681
- }]
1682
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: WklyDateTimePickerDialogService }, { type: i0.Injector }] });
1683
-
1684
- class WklyDateTimePickerModule {
1685
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1686
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerModule, declarations: [WklyDateTimePickerComponent,
1687
- WklyDateTimePickerDialogDirective,
1688
- WklyFieldComponent], imports: [CommonModule], exports: [WklyDateTimePickerComponent, WklyDateTimePickerDialogDirective] });
1689
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerModule, imports: [CommonModule] });
1690
- }
1691
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.33", ngImport: i0, type: WklyDateTimePickerModule, decorators: [{
1692
- type: NgModule,
1693
- args: [{
1694
- imports: [CommonModule],
1695
- declarations: [
1696
- WklyDateTimePickerComponent,
1697
- WklyDateTimePickerDialogDirective,
1698
- WklyFieldComponent,
1699
- ],
1700
- exports: [WklyDateTimePickerComponent, WklyDateTimePickerDialogDirective],
1701
- }]
1702
- }] });
1703
-
1704
- /**
1705
- * Generated bundle index. Do not edit.
1706
- */
1707
-
647
+ var WklyFieldComponent = class WklyFieldComponent {
648
+ value = 0;
649
+ label = "";
650
+ hideLabel = false;
651
+ previousLabel = "";
652
+ nextLabel = "";
653
+ min = 0;
654
+ max = 59;
655
+ step = 1;
656
+ locale = "en-US";
657
+ disabled = false;
658
+ invalid = false;
659
+ labels = null;
660
+ valueChange = new EventEmitter();
661
+ complete = new EventEmitter();
662
+ before = null;
663
+ touchY = 0;
664
+ touchSteps = 0;
665
+ touchChanged = false;
666
+ typed = null;
667
+ inputTimer = null;
668
+ wheelTimer = null;
669
+ get display() {
670
+ if (this.typed !== null) return this.typed;
671
+ return this.value === null ? "" : this.labels ? this.labels[this.value - this.min] || String(this.value) : new Intl.NumberFormat(this.locale, {
672
+ useGrouping: false,
673
+ minimumIntegerDigits: this.max < 60 ? 2 : 1
674
+ }).format(this.value);
675
+ }
676
+ ngOnChanges(changes) {
677
+ if (changes.value && this.min < 0 && this.typed !== null) {
678
+ const typedValue = this.typed === "" || this.typed === "-" ? null : Number(this.typed);
679
+ if (this.value !== typedValue) {
680
+ this.cancelInput();
681
+ this.typed = null;
682
+ }
683
+ }
684
+ }
685
+ ngOnDestroy() {
686
+ this.cancelInput();
687
+ if (this.wheelTimer !== null) clearTimeout(this.wheelTimer);
688
+ }
689
+ next(delta) {
690
+ const count = Math.floor((this.max - this.min) / this.step) + 1;
691
+ return this.min + floorMod(Math.floor(((this.value === null ? this.min : this.value) - this.min) / this.step) + delta, count) * this.step;
692
+ }
693
+ neighbor(delta) {
694
+ const n = this.next(delta);
695
+ return this.labels ? this.labels[n - this.min] || "" : new Intl.NumberFormat(this.locale, { useGrouping: false }).format(n);
696
+ }
697
+ stepBy(delta) {
698
+ if (this.disabled) return;
699
+ this.scrollBy(delta);
700
+ this.complete.emit();
701
+ }
702
+ begin(event) {
703
+ this.before = this.value;
704
+ event.target.select();
705
+ }
706
+ type(event) {
707
+ if (this.disabled) return;
708
+ const input = event.target;
709
+ const raw = input.value;
710
+ const numeric = Array.from(raw).every((character) => normalizeDigits(character).length === 1);
711
+ if (this.min < 0 && !this.labels) {
712
+ const signed = raw.replace(/[\u200e\u200f\u061c]/g, "").replace(/\u2212/g, "-");
713
+ const digits = normalizeDigits(signed);
714
+ this.typed = input.value = (signed.startsWith("-") ? "-" : "") + digits;
715
+ this.value = digits === "" ? null : Math.max(this.min, Math.min(this.max, Number(this.typed)));
716
+ if (this.value !== null && Number(this.typed) !== this.value) this.typed = input.value = String(this.value);
717
+ } else if (numeric) {
718
+ const normalized = normalizeDigits(raw);
719
+ this.typed = input.value = this.min >= 0 && this.max < 100 ? normalized.slice(-2) : normalized;
720
+ this.value = this.typed === "" ? null : Number(this.typed);
721
+ } else if (this.labels) {
722
+ const search = raw.trim().toLocaleLowerCase(this.locale);
723
+ this.typed = raw;
724
+ const matches = this.labels.map((label, index) => ({
725
+ label,
726
+ index
727
+ })).filter((item) => item.label.toLocaleLowerCase(this.locale).includes(search));
728
+ this.value = matches.length === 1 ? this.min + matches[0].index : null;
729
+ } else {
730
+ this.typed = input.value = normalizeDigits(raw);
731
+ this.value = this.typed === "" ? null : Number(this.typed);
732
+ }
733
+ this.valueChange.emit(this.value);
734
+ this.cancelInput();
735
+ if (!numeric && this.labels && this.value !== null) this.complete.emit();
736
+ this.inputTimer = setTimeout(() => {
737
+ this.inputTimer = null;
738
+ this.typed = null;
739
+ if (!this.disabled) this.complete.emit();
740
+ }, 1e3);
741
+ }
742
+ key(event) {
743
+ if (event.key === "Escape") {
744
+ event.preventDefault();
745
+ event.stopPropagation();
746
+ this.cancelInput();
747
+ this.typed = null;
748
+ this.value = this.before;
749
+ this.valueChange.emit(this.before);
750
+ event.target.value = this.display;
751
+ event.target.blur();
752
+ }
753
+ if (event.key === "Enter") {
754
+ event.preventDefault();
755
+ event.stopPropagation();
756
+ this.finish();
757
+ }
758
+ const delta = event.key === "ArrowUp" ? -1 : event.key === "ArrowDown" ? 1 : event.key === "PageUp" ? -5 : event.key === "PageDown" ? 5 : 0;
759
+ if (delta) {
760
+ event.preventDefault();
761
+ this.stepBy(delta);
762
+ }
763
+ }
764
+ finish() {
765
+ this.cancelInput();
766
+ this.typed = null;
767
+ this.complete.emit();
768
+ }
769
+ wheel(event) {
770
+ if (this.disabled || Math.abs(event.deltaY) < 1) return;
771
+ event.preventDefault();
772
+ this.scrollBy(event.deltaY > 0 ? 1 : -1);
773
+ if (this.wheelTimer !== null) clearTimeout(this.wheelTimer);
774
+ this.wheelTimer = setTimeout(() => {
775
+ this.wheelTimer = null;
776
+ this.complete.emit();
777
+ }, 140);
778
+ }
779
+ touchStart(event) {
780
+ this.touchY = event.touches[0].clientY;
781
+ this.touchSteps = 0;
782
+ this.touchChanged = false;
783
+ }
784
+ touchMove(event) {
785
+ this.applyTouchY(event.touches[0].clientY);
786
+ }
787
+ touchEnd(event) {
788
+ this.applyTouchY(event.changedTouches[0].clientY);
789
+ if (this.touchChanged) this.complete.emit();
790
+ this.touchChanged = false;
791
+ }
792
+ cancelInput() {
793
+ if (this.inputTimer !== null) clearTimeout(this.inputTimer);
794
+ this.inputTimer = null;
795
+ }
796
+ scrollBy(delta) {
797
+ if (this.disabled || !delta) return;
798
+ this.cancelInput();
799
+ this.typed = null;
800
+ this.value = this.next(delta);
801
+ this.valueChange.emit(this.value);
802
+ }
803
+ applyTouchY(y) {
804
+ if (this.disabled) return;
805
+ const delta = this.touchY - y;
806
+ const steps = Math.abs(delta) > 16 ? Math.sign(delta) * Math.max(1, Math.round(Math.abs(delta) / 40)) : 0;
807
+ const change = steps - this.touchSteps;
808
+ if (!change) return;
809
+ this.scrollBy(change);
810
+ this.touchSteps = steps;
811
+ this.touchChanged = true;
812
+ }
813
+ static ɵfac = i0.ɵɵngDeclareFactory({
814
+ minVersion: "12.0.0",
815
+ version: "22.2.1",
816
+ ngImport: i0,
817
+ type: WklyFieldComponent,
818
+ deps: [],
819
+ target: i0.ɵɵFactoryTarget.Component
820
+ });
821
+ static ɵcmp = i0.ɵɵngDeclareComponent({
822
+ minVersion: "14.0.0",
823
+ version: "22.2.1",
824
+ type: WklyFieldComponent,
825
+ isStandalone: false,
826
+ selector: "wkly-field",
827
+ inputs: {
828
+ value: "value",
829
+ label: "label",
830
+ hideLabel: "hideLabel",
831
+ previousLabel: "previousLabel",
832
+ nextLabel: "nextLabel",
833
+ min: "min",
834
+ max: "max",
835
+ step: "step",
836
+ locale: "locale",
837
+ disabled: "disabled",
838
+ invalid: "invalid",
839
+ labels: "labels"
840
+ },
841
+ outputs: {
842
+ valueChange: "valueChange",
843
+ complete: "complete"
844
+ },
845
+ usesOnChanges: true,
846
+ ngImport: i0,
847
+ template: "<div\n class=\"field\"\n (wheel)=\"wheel($event)\"\n (touchstart)=\"touchStart($event)\"\n (touchmove)=\"touchMove($event)\"\n (touchend)=\"touchEnd($event)\"\n (touchcancel)=\"touchEnd($event)\"\n>\n <span *ngIf=\"!hideLabel\" class=\"label\">{{ label }}</span>\n <button\n type=\"button\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"previousLabel || label + ': previous'\"\n (click)=\"stepBy(-1)\"\n >\n {{ neighbor(-1) }}\n </button>\n <input\n [attr.aria-label]=\"label\"\n [attr.aria-invalid]=\"invalid\"\n [disabled]=\"disabled\"\n [value]=\"display\"\n [attr.inputmode]=\"labels ? 'text' : min < 0 ? 'text' : 'numeric'\"\n autocomplete=\"off\"\n (focus)=\"begin($event)\"\n (input)=\"type($event)\"\n (blur)=\"finish()\"\n (keydown)=\"key($event)\"\n />\n <button\n type=\"button\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"nextLabel || label + ': next'\"\n (click)=\"stepBy(1)\"\n >\n {{ neighbor(1) }}\n </button>\n</div>\n",
848
+ styles: [".field{display:flex;flex-direction:column;align-items:stretch;min-width:0;text-align:center;touch-action:pan-x}.label{font-size:11px;color:var(--wkly-muted-color, #54616e);margin-bottom:4px}button,input{font:inherit;box-sizing:border-box;min-height:44px;width:100%;border:0;text-align:center;background:transparent;color:inherit;border-radius:7px}button{color:var(--wkly-muted-color, #54616e);cursor:pointer}input{font-size:18px;font-weight:650;background:var(--wkly-range-color, #e5f1ee);border-block:2px solid var(--wkly-accent-color, #176c55)}input[aria-invalid=true]{border-color:var(--wkly-error-color, #b42318)}:focus-visible{outline:2px solid var(--wkly-focus-color, #124ee0);outline-offset:1px}button:disabled,input:disabled{opacity:.45}button:hover:not(:disabled){background:var(--wkly-range-color, #e5f1ee)}\n"],
849
+ dependencies: [{
850
+ kind: "directive",
851
+ type: i1.NgIf,
852
+ selector: "[ngIf]",
853
+ inputs: [
854
+ "ngIf",
855
+ "ngIfThen",
856
+ "ngIfElse"
857
+ ]
858
+ }]
859
+ });
860
+ };
861
+ i0.ɵɵngDeclareClassMetadata({
862
+ minVersion: "12.0.0",
863
+ version: "22.2.1",
864
+ ngImport: i0,
865
+ type: WklyFieldComponent,
866
+ decorators: [{
867
+ type: Component,
868
+ args: [{
869
+ standalone: false,
870
+ selector: "wkly-field",
871
+ template: "<div\n class=\"field\"\n (wheel)=\"wheel($event)\"\n (touchstart)=\"touchStart($event)\"\n (touchmove)=\"touchMove($event)\"\n (touchend)=\"touchEnd($event)\"\n (touchcancel)=\"touchEnd($event)\"\n>\n <span *ngIf=\"!hideLabel\" class=\"label\">{{ label }}</span>\n <button\n type=\"button\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"previousLabel || label + ': previous'\"\n (click)=\"stepBy(-1)\"\n >\n {{ neighbor(-1) }}\n </button>\n <input\n [attr.aria-label]=\"label\"\n [attr.aria-invalid]=\"invalid\"\n [disabled]=\"disabled\"\n [value]=\"display\"\n [attr.inputmode]=\"labels ? 'text' : min < 0 ? 'text' : 'numeric'\"\n autocomplete=\"off\"\n (focus)=\"begin($event)\"\n (input)=\"type($event)\"\n (blur)=\"finish()\"\n (keydown)=\"key($event)\"\n />\n <button\n type=\"button\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"nextLabel || label + ': next'\"\n (click)=\"stepBy(1)\"\n >\n {{ neighbor(1) }}\n </button>\n</div>\n",
872
+ styles: [".field{display:flex;flex-direction:column;align-items:stretch;min-width:0;text-align:center;touch-action:pan-x}.label{font-size:11px;color:var(--wkly-muted-color, #54616e);margin-bottom:4px}button,input{font:inherit;box-sizing:border-box;min-height:44px;width:100%;border:0;text-align:center;background:transparent;color:inherit;border-radius:7px}button{color:var(--wkly-muted-color, #54616e);cursor:pointer}input{font-size:18px;font-weight:650;background:var(--wkly-range-color, #e5f1ee);border-block:2px solid var(--wkly-accent-color, #176c55)}input[aria-invalid=true]{border-color:var(--wkly-error-color, #b42318)}:focus-visible{outline:2px solid var(--wkly-focus-color, #124ee0);outline-offset:1px}button:disabled,input:disabled{opacity:.45}button:hover:not(:disabled){background:var(--wkly-range-color, #e5f1ee)}\n"]
873
+ }]
874
+ }],
875
+ propDecorators: {
876
+ value: [{ type: Input }],
877
+ label: [{ type: Input }],
878
+ hideLabel: [{ type: Input }],
879
+ previousLabel: [{ type: Input }],
880
+ nextLabel: [{ type: Input }],
881
+ min: [{ type: Input }],
882
+ max: [{ type: Input }],
883
+ step: [{ type: Input }],
884
+ locale: [{ type: Input }],
885
+ disabled: [{ type: Input }],
886
+ invalid: [{ type: Input }],
887
+ labels: [{ type: Input }],
888
+ valueChange: [{ type: Output }],
889
+ complete: [{ type: Output }]
890
+ }
891
+ });
892
+ var WklyDateTimePickerComponent = class WklyDateTimePickerComponent extends WklyPickerInputs {
893
+ defaultLocale;
894
+ defaults;
895
+ clock;
896
+ strings;
897
+ defaultTranslations;
898
+ host;
899
+ changeDetector;
900
+ scroller;
901
+ presentation = "inline";
902
+ viewMode = "calendar";
903
+ endView = "date";
904
+ adapter;
905
+ effectiveLocale = "en-US";
906
+ effectiveOffset = 0;
907
+ effectiveHourCycle = "h24";
908
+ direction = "ltr";
909
+ rows = [];
910
+ weekdays = [];
911
+ drafts = [];
912
+ errors = [];
913
+ today = 0;
914
+ focused = 0;
915
+ anchorWeek = 0;
916
+ firstWeek = 0;
917
+ visibleCount = 6;
918
+ rowHeight = 76;
919
+ scrollHeight = 152076;
920
+ paddingTop = 0;
921
+ initialized = false;
922
+ compact = false;
923
+ WklyPickerInputsPropertyKeys = WklyPickerInputsPropertyKeys;
924
+ baseWeek = 0;
925
+ firstSupportedDay = 0;
926
+ lastSupportedDay = 0;
927
+ firstSupportedWeek = 0;
928
+ lastSupportedWeek = 0;
929
+ generator;
930
+ initialMonth = "";
931
+ clipMonth = false;
932
+ browser = false;
933
+ observer;
934
+ destroyed = false;
935
+ scrollEndTimer;
936
+ snapPending = false;
937
+ onChange = () => {};
938
+ onTouched = () => {};
939
+ validatorChanged = () => {};
940
+ configErrors = [];
941
+ pendingValue = null;
942
+ emittedValue = null;
943
+ manualDateEndpoint = 0;
944
+ formValue = signal(void 0, ...ngDevMode ? [{ debugName: "formValue" }] : /* istanbul ignore next */ []);
945
+ formDisabled = signal(false, ...ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []);
946
+ previousInputs;
947
+ currentValue() {
948
+ return this.formValue() === void 0 ? this[WklyPickerInputsPropertyKeys.Value]() : this.formValue();
949
+ }
950
+ isDisabled() {
951
+ return this[WklyPickerInputsPropertyKeys.Disabled]() || this.formDisabled();
952
+ }
953
+ constructor(defaultLocale, defaults, clock, strings, defaultTranslations, platform, host, changeDetector) {
954
+ super();
955
+ this.defaultLocale = defaultLocale;
956
+ this.defaults = defaults;
957
+ this.clock = clock;
958
+ this.strings = strings;
959
+ this.defaultTranslations = defaultTranslations;
960
+ this.host = host;
961
+ this.changeDetector = changeDetector;
962
+ this.browser = isPlatformBrowser(platform);
963
+ effect(() => {
964
+ const inputs = unwrapWklyPickerSignalInputs(this);
965
+ const previous = this.previousInputs;
966
+ this.previousInputs = inputs;
967
+ if (!previous || !this.initialized) return;
968
+ const changed = (key) => !Object.is(previous[key], inputs[key]);
969
+ if (!Object.keys(inputs).some((key) => changed(key))) return;
970
+ untracked(() => {
971
+ if (changed(WklyPickerInputsPropertyKeys.Value)) this.formValue.set(void 0);
972
+ if (changed(WklyPickerInputsPropertyKeys.Value) && this.emittedValue === JSON.stringify(this.currentValue()) && Object.keys(inputs).every((key) => key === WklyPickerInputsPropertyKeys.Value || !changed(key))) {
973
+ this.emittedValue = null;
974
+ return;
975
+ }
976
+ const focus = this.focused;
977
+ this.configure();
978
+ if (changed(WklyPickerInputsPropertyKeys.Value) || changed(WklyPickerInputsPropertyKeys.Mode) || changed(WklyPickerInputsPropertyKeys.CalendarAdapter)) {
979
+ this.load(this.currentValue());
980
+ this.position(this.focused, true);
981
+ } else {
982
+ this.check();
983
+ if (changed(WklyPickerInputsPropertyKeys.ViewportPreset)) this.position(focus, true);
984
+ else this.scrollToEpochDay(focus);
985
+ }
986
+ });
987
+ });
988
+ }
989
+ ngOnInit() {
990
+ this.initialize();
991
+ }
992
+ initialize() {
993
+ if (this.initialized) return;
994
+ this.configure();
995
+ const initialEpochDay = this[WklyPickerInputsPropertyKeys.InitialEpochDay]();
996
+ this.today = this.browser ? Math.floor(this.clock.now().getTime() / 864e5) : initialEpochDay === null ? 0 : initialEpochDay;
997
+ this.focused = initialEpochDay === null ? this.defaults.initialEpochDay === void 0 ? this.today : this.defaults.initialEpochDay : initialEpochDay;
998
+ this.load(this.currentValue());
999
+ this.initialized = true;
1000
+ this.position(this.focused, true);
1001
+ }
1002
+ configure() {
1003
+ this.configErrors = [];
1004
+ this.effectiveLocale = this[WklyPickerInputsPropertyKeys.Locale]() || this.defaults.locale || this.defaultLocale;
1005
+ this.direction = /^(ar|he|fa|ur)(-|$)/.test(this.effectiveLocale) ? "rtl" : "ltr";
1006
+ this.adapter = this[WklyPickerInputsPropertyKeys.CalendarAdapter]() || new WklyGregorianCalendarAdapter(this.effectiveLocale);
1007
+ try {
1008
+ let firstDay;
1009
+ try {
1010
+ firstDay = getLocaleFirstDayOfWeek(this.effectiveLocale);
1011
+ } catch (_) {}
1012
+ this.effectiveOffset = resolveWeekOffset(this.effectiveLocale, this[WklyPickerInputsPropertyKeys.WeekOffset](), this.defaults.weekOffset, firstDay);
1013
+ integer(this[WklyPickerInputsPropertyKeys.WeekCacheSize]());
1014
+ integer(this[WklyPickerInputsPropertyKeys.OverscanWeeks]());
1015
+ if (this[WklyPickerInputsPropertyKeys.WeekCacheSize]() < 0 || this[WklyPickerInputsPropertyKeys.OverscanWeeks]() < 0 || this[WklyPickerInputsPropertyKeys.OverscanWeeks]() > 50) throw new RangeError();
1016
+ if (![
1017
+ "datetime",
1018
+ "date",
1019
+ "time",
1020
+ "datetime-range",
1021
+ "date-range",
1022
+ "time-range"
1023
+ ].includes(this[WklyPickerInputsPropertyKeys.Mode]())) throw new RangeError();
1024
+ const preset = this[WklyPickerInputsPropertyKeys.ViewportPreset]();
1025
+ if (preset.kind === "weeks") {
1026
+ integer(preset.visibleWeekCount);
1027
+ if (preset.visibleWeekCount < 1 || preset.visibleWeekCount > 52) throw new RangeError();
1028
+ }
1029
+ if (preset.kind === "full-month-and-around") for (const n of [preset.extraWeeksBefore || 0, preset.extraWeeksAfter || 0]) {
1030
+ integer(n);
1031
+ if (n < 0 || n > 52) throw new RangeError();
1032
+ }
1033
+ this.generator = createWeekGenerator({
1034
+ weekOffset: this.effectiveOffset,
1035
+ cacheSize: this[WklyPickerInputsPropertyKeys.WeekCacheSize]()
1036
+ });
1037
+ } catch (_) {
1038
+ this.configErrors.push(error("configuration-error", this[WklyPickerInputsPropertyKeys.WeekOffset]()));
1039
+ this.generator = createWeekGenerator();
1040
+ this.effectiveOffset = 0;
1041
+ }
1042
+ this.setSupportedScrollRange();
1043
+ this.effectiveHourCycle = this[WklyPickerInputsPropertyKeys.HourCycle]() === "h12" ? "h12" : this[WklyPickerInputsPropertyKeys.HourCycle]() === "locale" ? new Intl.DateTimeFormat(this.effectiveLocale, {
1044
+ hour: "numeric",
1045
+ timeZone: "UTC"
1046
+ }).resolvedOptions().hour12 ? "h12" : "h24" : "h24";
1047
+ this.weekdays = Array.from({ length: 7 }, (_, i) => this.adapter.formatWeekday(this.effectiveOffset + i, "short"));
1048
+ }
1049
+ setSupportedScrollRange() {
1050
+ let [first, last] = this.adapter.supportedEpochDayRange;
1051
+ const [firstYear, lastYear] = this.adapter.supportedYearRange;
1052
+ const yearOf = (day) => this.adapter.epochDayToDate(day).year;
1053
+ if (yearOf(first) < firstYear) {
1054
+ let low = first, high = last;
1055
+ while (low < high) {
1056
+ const mid = Math.floor((low + high) / 2);
1057
+ if (yearOf(mid) < firstYear) low = mid + 1;
1058
+ else high = mid;
1059
+ }
1060
+ first = low;
1061
+ }
1062
+ if (yearOf(last) > lastYear) {
1063
+ let low = first, high = last;
1064
+ while (low < high) {
1065
+ const mid = Math.ceil((low + high) / 2);
1066
+ if (yearOf(mid) > lastYear) high = mid - 1;
1067
+ else low = mid;
1068
+ }
1069
+ last = low;
1070
+ }
1071
+ if (first > last || yearOf(first) < firstYear || yearOf(first) > lastYear || yearOf(last) < firstYear || yearOf(last) > lastYear) throw new RangeError("No supported days within the calendar year range");
1072
+ this.firstSupportedDay = first;
1073
+ this.lastSupportedDay = last;
1074
+ this.firstSupportedWeek = absoluteWeekOf(first, this.effectiveOffset);
1075
+ this.lastSupportedWeek = absoluteWeekOf(last, this.effectiveOffset);
1076
+ }
1077
+ clampFirstWeek(week) {
1078
+ const last = Math.max(this.firstSupportedWeek, this.lastSupportedWeek - this.visibleCount + 1);
1079
+ return Math.max(this.firstSupportedWeek, Math.min(last, week));
1080
+ }
1081
+ ngAfterViewInit() {
1082
+ this.resetScroll();
1083
+ if (this.browser && typeof ResizeObserver !== "undefined") {
1084
+ this.observer = new ResizeObserver(() => {
1085
+ this.compact = this.host.nativeElement.clientWidth < 338;
1086
+ const row = this.host.nativeElement.querySelector(".week-row");
1087
+ const height = row ? parseFloat(getComputedStyle(row).height) : 0;
1088
+ if (height && height !== this.rowHeight) {
1089
+ this.rowHeight = height;
1090
+ this.scrollHeight = this.rowHeight * 2001;
1091
+ this.renderRows();
1092
+ this.resetScroll();
1093
+ }
1094
+ });
1095
+ this.observer.observe(this.host.nativeElement);
1096
+ }
1097
+ }
1098
+ ngOnDestroy() {
1099
+ this.destroyed = true;
1100
+ if (this.observer) this.observer.disconnect();
1101
+ if (this.scrollEndTimer) clearTimeout(this.scrollEndTimer);
1102
+ if (this.generator) this.generator.clearCache();
1103
+ }
1104
+ t(key) {
1105
+ return resolveWklyTranslation(key, this.effectiveLocale, this[WklyPickerInputsPropertyKeys.Translations]() || this.defaultTranslations, this.strings);
1106
+ }
1107
+ get isRange() {
1108
+ return this[WklyPickerInputsPropertyKeys.Mode]().endsWith("-range");
1109
+ }
1110
+ get hasDate() {
1111
+ return !this[WklyPickerInputsPropertyKeys.Mode]().startsWith("time");
1112
+ }
1113
+ get hasTime() {
1114
+ return this[WklyPickerInputsPropertyKeys.Mode]() !== "date" && this[WklyPickerInputsPropertyKeys.Mode]() !== "date-range";
1115
+ }
1116
+ get submitVisible() {
1117
+ return this.presentation === "transient" && (this[WklyPickerInputsPropertyKeys.Mode]() !== "date" || this.viewMode === "manual");
1118
+ }
1119
+ get title() {
1120
+ try {
1121
+ const d = this.adapter.epochDayToDate(Math.max(this.firstSupportedDay, Math.min(this.lastSupportedDay, firstEpochDayOf(this.anchorWeek, this.effectiveOffset))));
1122
+ return this.adapter.formatMonth(d) + " " + this.adapter.formatYear(d);
1123
+ } catch (_) {
1124
+ return "";
1125
+ }
1126
+ }
1127
+ get canSubmit() {
1128
+ return !this.isDisabled() && !this.errors.length && this.pendingValue !== null;
1129
+ }
1130
+ blank(day) {
1131
+ const safe = Math.max(this.firstSupportedDay, Math.min(this.lastSupportedDay, day));
1132
+ return {
1133
+ date: this.adapter.epochDayToDate(safe),
1134
+ hour: 0,
1135
+ minute: 0,
1136
+ second: 0,
1137
+ present: false
1138
+ };
1139
+ }
1140
+ load(value) {
1141
+ this.drafts = [this.blank(this.focused), this.blank(this.focused)];
1142
+ const validation = validateSelection(value, unwrapWklyPickerSignalInputs(this), this.adapter);
1143
+ if (value !== null && !validation.length) (typeof value === "string" ? [value] : value).forEach((v, i) => {
1144
+ const d = decodeIso(v);
1145
+ this.drafts[i] = {
1146
+ date: this.hasDate ? this.adapter.epochDayToDate(d.epochDay) : this.blank(this.today).date,
1147
+ hour: d.hour,
1148
+ minute: d.minute,
1149
+ second: d.second,
1150
+ present: true
1151
+ };
1152
+ if (i === 0 && this.hasDate) this.focused = d.epochDay;
1153
+ });
1154
+ if (validation.length) {
1155
+ this.pendingValue = null;
1156
+ this.report(validation);
1157
+ } else this.check();
1158
+ }
1159
+ writeValue(value) {
1160
+ this.formValue.set(value);
1161
+ if (this.initialized) {
1162
+ this.load(value);
1163
+ this.position(this.focused, true);
1164
+ this.changeDetector.markForCheck();
1165
+ }
1166
+ }
1167
+ registerOnChange(fn) {
1168
+ this.onChange = fn;
1169
+ }
1170
+ registerOnTouched(fn) {
1171
+ this.onTouched = fn;
1172
+ }
1173
+ setDisabledState(disabled) {
1174
+ this.formDisabled.set(disabled);
1175
+ }
1176
+ validate(_control) {
1177
+ return this.errors.length ? { wkly: this.errors } : null;
1178
+ }
1179
+ registerOnValidatorChange(fn) {
1180
+ this.validatorChanged = fn;
1181
+ }
1182
+ touched() {
1183
+ Promise.resolve().then(() => this.onTouched());
1184
+ }
1185
+ report(errors) {
1186
+ const changed = JSON.stringify(this.errors) !== JSON.stringify(errors);
1187
+ this.errors = errors;
1188
+ if (changed) {
1189
+ this[WklyPickerOutputsPropertyKeys.ValidationChange].emit(errors);
1190
+ this.validatorChanged();
1191
+ }
1192
+ }
1193
+ check() {
1194
+ const result = validateDrafts({
1195
+ drafts: this.drafts,
1196
+ configErrors: this.configErrors,
1197
+ adapter: this.adapter,
1198
+ selection: unwrapWklyPickerSignalInputs(this),
1199
+ mode: this[WklyPickerInputsPropertyKeys.Mode](),
1200
+ isRange: this.isRange,
1201
+ hasDate: this.hasDate,
1202
+ hasTime: this.hasTime,
1203
+ showSeconds: this[WklyPickerInputsPropertyKeys.ShowSeconds](),
1204
+ required: this[WklyPickerInputsPropertyKeys.Required]()
1205
+ });
1206
+ this.pendingValue = result.pendingValue;
1207
+ this.report(result.errors);
1208
+ }
1209
+ trackDraft(index) {
1210
+ return index;
1211
+ }
1212
+ orderDrafts() {
1213
+ if (!this.isRange || !this.drafts.every((draft) => draft.present)) return;
1214
+ if (this.drafts.some((draft) => draft.unsupportedEpochDay !== void 0)) return;
1215
+ try {
1216
+ const a = this.drafts[0], b = this.drafts[1];
1217
+ const key = (d) => this.adapter.dateToEpochDay(d.date) * 86400 + (d.hour || 0) * 3600 + (d.minute || 0) * 60 + (d.second || 0);
1218
+ if (key(a) > key(b)) this.drafts = [b, a];
1219
+ } catch (_) {}
1220
+ }
1221
+ finish() {
1222
+ if (this.isDisabled()) return;
1223
+ this.orderDrafts();
1224
+ if (this.viewMode === "manual" && this.hasDate) this.positionOnManualDate();
1225
+ this.check();
1226
+ if (this.presentation === "inline" && this.canSubmit) this.commit();
1227
+ }
1228
+ commit() {
1229
+ if (!this.canSubmit) return;
1230
+ const next = this.pendingValue;
1231
+ if (JSON.stringify(next) !== JSON.stringify(this.currentValue())) {
1232
+ this.formValue.set(next);
1233
+ this.emittedValue = JSON.stringify(next);
1234
+ this.onChange(next);
1235
+ this[WklyPickerOutputsPropertyKeys.ValueChange].emit(next);
1236
+ }
1237
+ this.onTouched();
1238
+ }
1239
+ submit(reason = "submit") {
1240
+ this.check();
1241
+ if (!this.canSubmit) return;
1242
+ this.commit();
1243
+ if (this.presentation === "transient") this[WklyPickerOutputsPropertyKeys.Closed].emit(reason);
1244
+ }
1245
+ cancel(reason = "close-button") {
1246
+ if (this.isDisabled()) return;
1247
+ this.load(this.currentValue());
1248
+ this.onTouched();
1249
+ this[WklyPickerOutputsPropertyKeys.Closed].emit(reason);
1250
+ }
1251
+ now() {
1252
+ if (this.isDisabled()) return;
1253
+ const n = this.clock.now();
1254
+ const day = Math.floor(n.getTime() / 864e5);
1255
+ this.drafts = [0, 1].map((index) => ({
1256
+ ...this.clockDraft(day, n),
1257
+ present: index === 0 || this.isRange
1258
+ }));
1259
+ if (this.hasDate && (day < this.firstSupportedDay || day > this.lastSupportedDay)) {
1260
+ this.report([error("unsupported-adapter-date", day)]);
1261
+ return;
1262
+ }
1263
+ this.focused = day;
1264
+ this.position(day, true);
1265
+ this.check();
1266
+ this.submit("now");
1267
+ }
1268
+ clockDraft(day, now) {
1269
+ return {
1270
+ ...this.blank(day),
1271
+ hour: now.getUTCHours(),
1272
+ minute: Math.floor(now.getUTCMinutes() / this[WklyPickerInputsPropertyKeys.MinuteStep]()) * this[WklyPickerInputsPropertyKeys.MinuteStep](),
1273
+ second: this[WklyPickerInputsPropertyKeys.ShowSeconds]() ? Math.floor(now.getUTCSeconds() / this[WklyPickerInputsPropertyKeys.SecondStep]()) * this[WklyPickerInputsPropertyKeys.SecondStep]() : 0
1274
+ };
1275
+ }
1276
+ initializeManualRange() {
1277
+ if (!this.isRange || !this.hasDate || this.drafts.every((draft) => draft.present)) return;
1278
+ let seed = this.drafts.find((draft) => draft.present);
1279
+ if (!seed) {
1280
+ if (this.currentValue() !== null) return;
1281
+ const now = this.clock.now();
1282
+ const initialEpochDay = this[WklyPickerInputsPropertyKeys.InitialEpochDay]();
1283
+ const day = initialEpochDay === null ? this.defaults.initialEpochDay === void 0 ? Math.floor(now.getTime() / 864e5) : this.defaults.initialEpochDay : initialEpochDay;
1284
+ seed = {
1285
+ ...this.clockDraft(day, now),
1286
+ present: true
1287
+ };
1288
+ }
1289
+ const initial = seed;
1290
+ this.drafts = this.drafts.map((draft) => draft.present ? draft : {
1291
+ ...initial,
1292
+ date: { ...initial.date }
1293
+ });
1294
+ this.finish();
1295
+ this.changeDetector.markForCheck();
1296
+ }
1297
+ toggleView() {
1298
+ if (this.isDisabled() || !this.hasDate) return;
1299
+ this.viewMode = this.viewMode === "calendar" ? "manual" : "calendar";
1300
+ if (this.viewMode === "manual") this.initializeManualRange();
1301
+ if (this.viewMode === "calendar") this.positionOnManualDate();
1302
+ this[WklyPickerOutputsPropertyKeys.ViewModeChange].emit(this.viewMode);
1303
+ if (this.viewMode === "calendar") setTimeout(() => this.resetScroll());
1304
+ }
1305
+ positionOnManualDate() {
1306
+ const draft = this.drafts[this.manualDateEndpoint];
1307
+ if (!draft || !draft.present) return;
1308
+ try {
1309
+ const target = this.adapter.dateToEpochDay(draft.date);
1310
+ this.focused = target;
1311
+ this.position(target, true);
1312
+ } catch (_) {
1313
+ try {
1314
+ const first = this.adapter.dateToEpochDay({
1315
+ ...draft.date,
1316
+ day: 1
1317
+ });
1318
+ this.focused = first;
1319
+ this.position(first, true);
1320
+ } catch (_) {}
1321
+ }
1322
+ }
1323
+ months(draft) {
1324
+ try {
1325
+ return this.adapter.getMonths(draft.date.year).map((m) => m.label);
1326
+ } catch (_) {
1327
+ return [];
1328
+ }
1329
+ }
1330
+ monthCount(draft) {
1331
+ return this.months(draft).length || 12;
1332
+ }
1333
+ get inDays() {
1334
+ return draftDayDifference(this.drafts, this.adapter);
1335
+ }
1336
+ get inDaysLabel() {
1337
+ const days = this.inDays;
1338
+ return this.t("inDays").replace(/{{\s*days\s*}}/g, days === null ? this.t("daysUnavailable") : new Intl.NumberFormat(this.effectiveLocale, { useGrouping: false }).format(days));
1339
+ }
1340
+ get resultingEndDate() {
1341
+ try {
1342
+ const draft = this.drafts[1];
1343
+ if (draft.unsupportedEpochDay !== void 0 || this.adapter.validateDate(draft.date).length) return "";
1344
+ return [
1345
+ this.adapter.formatDay(draft.date),
1346
+ this.adapter.formatMonth(draft.date),
1347
+ this.adapter.formatYear(draft.date)
1348
+ ].join(" ");
1349
+ } catch (_) {
1350
+ return "";
1351
+ }
1352
+ }
1353
+ toggleEndView(view) {
1354
+ if (this.isDisabled()) return;
1355
+ this.endView = view;
1356
+ }
1357
+ days(value) {
1358
+ if (this.isDisabled()) return;
1359
+ this.manualDateEndpoint = 1;
1360
+ setDraftDayDifference(this.drafts, this.adapter, value);
1361
+ this.check();
1362
+ }
1363
+ field(index, field, value) {
1364
+ if (this.isDisabled()) return;
1365
+ const draft = this.drafts[index];
1366
+ draft.present = true;
1367
+ if (field === "day" || field === "year" || field === "month") {
1368
+ this.manualDateEndpoint = index;
1369
+ delete draft.unsupportedEpochDay;
1370
+ let date = {
1371
+ ...draft.date,
1372
+ [field]: value
1373
+ };
1374
+ if (field === "month") {
1375
+ let month;
1376
+ try {
1377
+ month = this.adapter.getMonths(date.year).find((m) => m.month === value);
1378
+ } catch (_) {}
1379
+ date = {
1380
+ ...date,
1381
+ monthCode: month ? month.monthCode : ""
1382
+ };
1383
+ }
1384
+ if (field === "year" && value !== null) try {
1385
+ const month = this.adapter.getMonths(value).find((m) => m.monthCode === date.monthCode);
1386
+ if (month) date = {
1387
+ ...date,
1388
+ month: month.month
1389
+ };
1390
+ } catch (_) {}
1391
+ draft.date = date;
1392
+ } else if (field === "hour" && this.effectiveHourCycle === "h12") draft.hour = value === null ? null : value >= 1 && value <= 12 ? value % 12 + ((draft.hour || 0) >= 12 ? 12 : 0) : 24 + value;
1393
+ else draft[field] = value;
1394
+ this.check();
1395
+ }
1396
+ displayHour(draft) {
1397
+ return draft.hour === null ? null : this.effectiveHourCycle === "h12" ? draft.hour % 12 || 12 : draft.hour;
1398
+ }
1399
+ period(index, period) {
1400
+ if (this.isDisabled()) return;
1401
+ if (period === "24") this.effectiveHourCycle = "h24";
1402
+ else {
1403
+ this.effectiveHourCycle = "h12";
1404
+ this.drafts[index].hour = (this.drafts[index].hour || 0) % 12 + (period === "pm" ? 12 : 0);
1405
+ this.drafts[index].present = true;
1406
+ this.finish();
1407
+ }
1408
+ }
1409
+ selected(day) {
1410
+ return this.drafts.some((d) => {
1411
+ try {
1412
+ return d.present && this.adapter.dateToEpochDay(d.date) === day;
1413
+ } catch (_) {
1414
+ return false;
1415
+ }
1416
+ });
1417
+ }
1418
+ inRange(day) {
1419
+ if (!this.isRange || !this.drafts.every((d) => d.present)) return false;
1420
+ try {
1421
+ const a = this.adapter.dateToEpochDay(this.drafts[0].date), b = this.adapter.dateToEpochDay(this.drafts[1].date);
1422
+ return day > Math.min(a, b) && day < Math.max(a, b);
1423
+ } catch (_) {
1424
+ return false;
1425
+ }
1426
+ }
1427
+ dayDisabled(day) {
1428
+ if (day < this.firstSupportedDay || day > this.lastSupportedDay) return true;
1429
+ try {
1430
+ const date = this.adapter.epochDayToDate(day);
1431
+ const isDateDisabled = this[WklyPickerInputsPropertyKeys.IsDateDisabled]();
1432
+ if (isDateDisabled && isDateDisabled(day, {
1433
+ mode: this[WklyPickerInputsPropertyKeys.Mode](),
1434
+ endpoint: this.isRange ? this.drafts[0]?.present && !this.drafts[1]?.present ? "end" : "start" : "single",
1435
+ calendarDate: date
1436
+ })) return true;
1437
+ const min = this[WklyPickerInputsPropertyKeys.Min](), max = this[WklyPickerInputsPropertyKeys.Max]();
1438
+ if (min && day < decodeIso(min).epochDay) return true;
1439
+ if (max && day > decodeIso(max).epochDay) return true;
1440
+ return false;
1441
+ } catch (_) {
1442
+ return true;
1443
+ }
1444
+ }
1445
+ select(day) {
1446
+ if (this.isDisabled() || this.dayDisabled(day)) return;
1447
+ this.focused = day;
1448
+ const index = this.isRange && this.drafts[0].present && !this.drafts[1].present ? 1 : 0;
1449
+ if (this.isRange && index === 0) this.drafts[1].present = false;
1450
+ delete this.drafts[index].unsupportedEpochDay;
1451
+ this.drafts[index].date = this.adapter.epochDayToDate(day);
1452
+ this.drafts[index].present = true;
1453
+ this.orderDrafts();
1454
+ this.renderRows();
1455
+ this.finish();
1456
+ if (this.presentation === "transient" && this[WklyPickerInputsPropertyKeys.Mode]() === "date" && this.viewMode === "calendar") this.submit("auto-submit");
1457
+ }
1458
+ key(event, day) {
1459
+ let delta = 0;
1460
+ if (event.key === "ArrowLeft") delta = -1;
1461
+ if (event.key === "ArrowRight") delta = 1;
1462
+ if (event.key === "ArrowUp") delta = -7;
1463
+ if (event.key === "ArrowDown") delta = 7;
1464
+ if (event.key === "PageUp") delta = -7 * (event.shiftKey ? this.visibleCount : 1);
1465
+ if (event.key === "PageDown") delta = 7 * (event.shiftKey ? this.visibleCount : 1);
1466
+ if (event.key === "Home") {
1467
+ event.preventDefault();
1468
+ this.scrollToEpochDay(this.today, { focus: true });
1469
+ }
1470
+ if (delta) {
1471
+ event.preventDefault();
1472
+ const target = day + delta;
1473
+ if (target >= this.firstSupportedDay && target <= this.lastSupportedDay) this.scrollToEpochDay(target, { focus: true });
1474
+ }
1475
+ }
1476
+ position(day, preset = false, options = {}) {
1477
+ day = Math.max(this.firstSupportedDay, Math.min(this.lastSupportedDay, day));
1478
+ this.anchorWeek = absoluteWeekOf(day, this.effectiveOffset);
1479
+ const viewportPreset = this[WklyPickerInputsPropertyKeys.ViewportPreset]();
1480
+ this.clipMonth = preset && viewportPreset.kind === "full-month";
1481
+ if (preset && viewportPreset.kind !== "weeks") {
1482
+ const d = this.adapter.epochDayToDate(day);
1483
+ this.initialMonth = d.year + "/" + d.monthCode;
1484
+ const [start, end] = calendarMonthBounds(this.adapter, day);
1485
+ this.firstWeek = absoluteWeekOf(start, this.effectiveOffset);
1486
+ this.visibleCount = absoluteWeekOf(end, this.effectiveOffset) - this.firstWeek + 1;
1487
+ if (viewportPreset.kind === "full-month-and-around" && !this.configErrors.length) {
1488
+ const before = viewportPreset.extraWeeksBefore || 0, after = viewportPreset.extraWeeksAfter || 0;
1489
+ this.firstWeek -= before;
1490
+ this.visibleCount += before + after;
1491
+ }
1492
+ } else {
1493
+ if (viewportPreset.kind === "weeks") this.visibleCount = this.configErrors.length ? 6 : viewportPreset.visibleWeekCount;
1494
+ this.firstWeek = this.anchorWeek - (options.align === "start" ? 0 : options.align === "end" ? this.visibleCount - 1 : Math.floor(this.visibleCount / 2));
1495
+ }
1496
+ this.firstWeek = this.clampFirstWeek(this.firstWeek);
1497
+ this.baseWeek = this.firstWeek - 1e3;
1498
+ this.renderRows();
1499
+ this.changeDetector.detectChanges();
1500
+ this.resetScroll();
1501
+ }
1502
+ resetScroll() {
1503
+ if (this.scroller) this.scroller.nativeElement.scrollTop = Math.round(1e3 * this.rowHeight);
1504
+ }
1505
+ scroll(event) {
1506
+ const element = event.target;
1507
+ this.snapPending = true;
1508
+ this.scheduleSnap();
1509
+ const relativeRows = element.scrollTop / this.rowHeight - 1e3;
1510
+ const index = 1e3 + Math.sign(relativeRows) * Math.round(Math.abs(relativeRows));
1511
+ const requestedFirst = this.baseWeek + index;
1512
+ const first = this.clampFirstWeek(requestedFirst);
1513
+ if (requestedFirst !== first) element.scrollTop = Math.round((first - this.baseWeek) * this.rowHeight);
1514
+ if (first === this.firstWeek) return;
1515
+ this.clipMonth = false;
1516
+ this.firstWeek = first;
1517
+ this.anchorWeek = first + Math.floor(this.visibleCount / 2);
1518
+ if (index < 100 || index > 1900) {
1519
+ const offset = element.scrollTop - (first - this.baseWeek) * this.rowHeight;
1520
+ this.baseWeek = first - 1e3;
1521
+ element.scrollTop = Math.round(1e3 * this.rowHeight + offset);
1522
+ }
1523
+ this.renderRows();
1524
+ }
1525
+ scheduleSnap() {
1526
+ if (this.scrollEndTimer) clearTimeout(this.scrollEndTimer);
1527
+ this.scrollEndTimer = setTimeout(() => this.snapWeek(), 200);
1528
+ }
1529
+ snapWeek() {
1530
+ if (this.scrollEndTimer) clearTimeout(this.scrollEndTimer);
1531
+ this.scrollEndTimer = void 0;
1532
+ if (!this.snapPending || !this.scroller) return;
1533
+ this.snapPending = false;
1534
+ const element = this.scroller.nativeElement;
1535
+ const target = Math.round((this.firstWeek - this.baseWeek) * this.rowHeight);
1536
+ if (element.scrollTop !== target) element.scrollTop = target;
1537
+ }
1538
+ showFirstWeek(week) {
1539
+ const first = this.clampFirstWeek(week);
1540
+ if (first === this.firstWeek) return;
1541
+ this.clipMonth = false;
1542
+ this.firstWeek = first;
1543
+ this.anchorWeek = first + Math.floor(this.visibleCount / 2);
1544
+ this.baseWeek = first - 1e3;
1545
+ this.renderRows();
1546
+ this.resetScroll();
1547
+ }
1548
+ canMoveWeek(delta) {
1549
+ return this.clampFirstWeek(this.firstWeek + delta) !== this.firstWeek;
1550
+ }
1551
+ moveWeek(delta) {
1552
+ if (!this.isDisabled()) this.showFirstWeek(this.firstWeek + delta);
1553
+ }
1554
+ renderRows() {
1555
+ const overscan = Math.max(0, Math.min(50, this[WklyPickerInputsPropertyKeys.OverscanWeeks]() || 0));
1556
+ const start = this.firstWeek - overscan;
1557
+ this.paddingTop = (start - this.baseWeek) * this.rowHeight;
1558
+ this.rows = createWeekRows({
1559
+ generator: this.generator,
1560
+ adapter: this.adapter,
1561
+ startWeek: start,
1562
+ count: this.visibleCount + 2 * overscan,
1563
+ firstVisibleWeek: this.firstWeek,
1564
+ firstSupportedDay: this.firstSupportedDay,
1565
+ lastSupportedDay: this.lastSupportedDay,
1566
+ clipMonth: this.clipMonth,
1567
+ initialMonth: this.initialMonth,
1568
+ weekLabelMode: this[WklyPickerInputsPropertyKeys.WeekLabelMode](),
1569
+ weekLabelFormatter: this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]() || null,
1570
+ isDayDisabled: (day) => this.dayDisabled(day)
1571
+ });
1572
+ this[WklyPickerOutputsPropertyKeys.ViewportChange].emit({
1573
+ firstVisibleAbsoluteWeek: this.firstWeek,
1574
+ lastVisibleAbsoluteWeek: this.firstWeek + this.visibleCount - 1,
1575
+ anchorAbsoluteWeek: this.anchorWeek
1576
+ });
1577
+ }
1578
+ trackCell(_i, cell) {
1579
+ return cell.epochDay;
1580
+ }
1581
+ trackRow(_i, row) {
1582
+ return row.week.absoluteWeek;
1583
+ }
1584
+ scrollToEpochDay(day, options = {}) {
1585
+ integer(day);
1586
+ this.adapter.epochDayToDate(day);
1587
+ day = Math.max(this.firstSupportedDay, Math.min(this.lastSupportedDay, day));
1588
+ if (options.focus) this.focused = day;
1589
+ this.position(day, false, options);
1590
+ if (options.select) this.select(day);
1591
+ if (options.focus) this.focusDay();
1592
+ }
1593
+ scrollToAbsoluteWeek(week, options = {}) {
1594
+ const first = firstEpochDayOf(week, this.effectiveOffset);
1595
+ this.scrollToEpochDay(week === this.firstSupportedWeek ? Math.max(first, this.firstSupportedDay) : first, options);
1596
+ }
1597
+ scrollToCalendarDate(date, options = {}) {
1598
+ this.scrollToEpochDay(this.adapter.dateToEpochDay(date), options);
1599
+ }
1600
+ scrollToValue(value, options = {}) {
1601
+ this.scrollToEpochDay(decodeIso(value).epochDay, options);
1602
+ }
1603
+ focusDay() {
1604
+ if (!this.browser) return;
1605
+ setTimeout(() => {
1606
+ if (this.destroyed) return;
1607
+ this.changeDetector.detectChanges();
1608
+ const day = this.host.nativeElement.querySelector("[data-day=\"" + this.focused + "\"]");
1609
+ const fallback = this.host.nativeElement.querySelector("button:not(:disabled),input:not(:disabled)");
1610
+ (day || fallback)?.focus({ preventScroll: true });
1611
+ });
1612
+ }
1613
+ static ɵfac = i0.ɵɵngDeclareFactory({
1614
+ minVersion: "12.0.0",
1615
+ version: "22.2.1",
1616
+ ngImport: i0,
1617
+ type: WklyDateTimePickerComponent,
1618
+ deps: [
1619
+ { token: LOCALE_ID },
1620
+ { token: WKLY_CONFIG },
1621
+ { token: WKLY_CLOCK },
1622
+ { token: WKLY_LOCALIZATION },
1623
+ { token: WKLY_TRANSLATIONS },
1624
+ { token: PLATFORM_ID },
1625
+ { token: i0.ElementRef },
1626
+ { token: i0.ChangeDetectorRef }
1627
+ ],
1628
+ target: i0.ɵɵFactoryTarget.Component
1629
+ });
1630
+ static ɵcmp = i0.ɵɵngDeclareComponent({
1631
+ minVersion: "17.0.0",
1632
+ version: "22.2.1",
1633
+ type: WklyDateTimePickerComponent,
1634
+ isStandalone: false,
1635
+ selector: "wkly-datetime-picker",
1636
+ providers: [{
1637
+ provide: NG_VALUE_ACCESSOR,
1638
+ useExisting: forwardRef(() => WklyDateTimePickerComponent),
1639
+ multi: true
1640
+ }, {
1641
+ provide: NG_VALIDATORS,
1642
+ useExisting: forwardRef(() => WklyDateTimePickerComponent),
1643
+ multi: true
1644
+ }],
1645
+ viewQueries: [{
1646
+ propertyName: "scroller",
1647
+ first: true,
1648
+ predicate: ["scroller"],
1649
+ descendants: true
1650
+ }],
1651
+ usesInheritance: true,
1652
+ ngImport: i0,
1653
+ template: "<section\n class=\"wkly\"\n [attr.dir]=\"direction\"\n [attr.aria-label]=\"\n this[WklyPickerInputsPropertyKeys.AriaLabel]() || 'Date and time picker'\n \"\n [attr.aria-describedby]=\"this[WklyPickerInputsPropertyKeys.AriaDescribedBy]()\"\n (focusout)=\"touched()\"\n>\n <header class=\"toolbar\">\n @if (hasDate) {\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"t(viewMode === 'calendar' ? 'manual' : 'calendar')\"\n (click)=\"toggleView()\"\n >\n {{ viewMode === \"calendar\" ? \"☷\" : \"▦\" }}\n </button>\n }\n @if (hasDate) {\n <span class=\"year-control\">{{ title }}</span>\n }\n <span class=\"spacer\"></span\n ><button\n type=\"button\"\n class=\"now\"\n [disabled]=\"isDisabled()\"\n (click)=\"now()\"\n >\n {{ t(\"now\") }}\n </button>\n @if (presentation === \"transient\") {\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"t('close')\"\n (click)=\"cancel()\"\n >\n ×\n </button>\n }\n </header>\n <ng-container *ngIf=\"hasDate && viewMode === 'calendar'\">\n <div\n role=\"grid\"\n [attr.aria-label]=\"\n this[WklyPickerInputsPropertyKeys.AriaLabel]() || 'Calendar'\n \"\n [attr.aria-multiselectable]=\"isRange\"\n >\n <div\n role=\"row\"\n class=\"week-head\"\n [class.no-label]=\"\n compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() === 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n >\n <span\n *ngIf=\"\n !compact &&\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() !== 'hidden' ||\n this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n role=\"columnheader\"\n aria-label=\"Week\"\n ></span>\n @for (day of weekdays; track $index) {\n <span role=\"columnheader\">{{ day }}</span>\n }\n </div>\n <div\n #scroller\n class=\"week-scroll\"\n [style.height.px]=\"visibleCount * rowHeight\"\n (scroll)=\"scroll($event)\"\n (scrollend)=\"snapWeek()\"\n >\n <div [style.height.px]=\"scrollHeight\" class=\"scroll-space\">\n <div class=\"rows\" [style.top.px]=\"paddingTop\">\n <div\n *ngFor=\"let row of rows; trackBy: trackRow\"\n role=\"row\"\n class=\"week-row\"\n [class.no-label]=\"\n compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() ===\n 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n >\n <span\n *ngIf=\"\n !compact &&\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() !==\n 'hidden' ||\n this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n role=\"rowheader\"\n class=\"week-number\"\n >{{ row.label }}</span\n >\n <div\n *ngFor=\"\n let cell of row.cells;\n let dayIndex = index;\n trackBy: trackCell\n \"\n role=\"gridcell\"\n [attr.data-weekday-index]=\"dayIndex\"\n [attr.aria-colindex]=\"\n dayIndex +\n (compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() ===\n 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n ? 1\n : 2)\n \"\n [attr.aria-selected]=\"selected(cell.epochDay)\"\n [attr.aria-disabled]=\"cell.disabled || isDisabled()\"\n [class.range]=\"inRange(cell.epochDay)\"\n [class.hidden]=\"cell.hidden\"\n [class.odd-month]=\"cell.date && cell.date.month % 2 === 1\"\n >\n <span [class]=\"'annotation annotation--' + dayIndex\">{{\n cell.annotation\n }}</span>\n <button\n type=\"button\"\n class=\"day\"\n [attr.data-day]=\"cell.epochDay\"\n [attr.aria-label]=\"cell.accessible\"\n [attr.aria-current]=\"cell.epochDay === today ? 'date' : null\"\n [attr.aria-disabled]=\"cell.disabled || isDisabled()\"\n [attr.tabindex]=\"\n !cell.hidden && cell.epochDay === focused ? 0 : -1\n \"\n [class.selected]=\"selected(cell.epochDay)\"\n [class.today]=\"cell.epochDay === today\"\n (focus)=\"focused = cell.epochDay\"\n (click)=\"select(cell.epochDay)\"\n (keydown)=\"key($event, cell.epochDay)\"\n >\n {{ cell.label }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"week-navigation\">\n <button\n type=\"button\"\n [disabled]=\"isDisabled() || !canMoveWeek(-1)\"\n [attr.aria-label]=\"t('previous')\"\n (click)=\"moveWeek(-1)\"\n >\n ↑</button\n ><span>{{ title }}</span\n ><button\n type=\"button\"\n [disabled]=\"isDisabled() || !canMoveWeek(1)\"\n [attr.aria-label]=\"t('next')\"\n (click)=\"moveWeek(1)\"\n >\n ↓\n </button>\n </div>\n </ng-container>\n <ng-container\n *ngFor=\"let draft of drafts; let i = index; trackBy: trackDraft\"\n >\n <fieldset\n *ngIf=\"(i === 0 || isRange) && (hasTime || viewMode === 'manual')\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"isRange ? t(i === 0 ? 'start' : 'end') : null\"\n >\n <legend *ngIf=\"isRange\">\n <ng-container\n *ngIf=\"\n i === 1 && hasDate && viewMode === 'manual';\n else endpointLabel\n \"\n >\n <span class=\"end-view-toggle\">\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"endView === 'date'\"\n (click)=\"toggleEndView('date')\"\n >\n {{ t(\"end\") }}\n </button>\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"endView === 'days'\"\n (click)=\"toggleEndView('days')\"\n >\n {{ inDaysLabel }}\n </button>\n </span>\n </ng-container>\n <ng-template #endpointLabel>{{\n t(i === 0 ? \"start\" : \"end\")\n }}</ng-template>\n </legend>\n <div\n *ngIf=\"\n i === 1 && hasDate && viewMode === 'manual' && endView === 'days'\n \"\n class=\"date-fields in-days-fields\"\n >\n <span class=\"resulting-end-date\" [attr.aria-label]=\"t('endDate')\">{{\n resultingEndDate\n }}</span>\n <wkly-field\n [label]=\"t('days')\"\n [hideLabel]=\"true\"\n [previousLabel]=\"t('daysPrevious')\"\n [nextLabel]=\"t('daysNext')\"\n [locale]=\"effectiveLocale\"\n [value]=\"inDays\"\n [min]=\"-9999\"\n [max]=\"9999\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"days($event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n </div>\n <div\n *ngIf=\"\n hasDate && viewMode === 'manual' && (i === 0 || endView === 'date')\n \"\n class=\"date-fields\"\n >\n <wkly-field\n [label]=\"t('day')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.day\"\n [min]=\"1\"\n [max]=\"31\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'day', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('month')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.month\"\n [min]=\"1\"\n [max]=\"monthCount(draft)\"\n [labels]=\"months(draft)\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'month', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('year')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.year\"\n [min]=\"adapter.supportedYearRange[0]\"\n [max]=\"adapter.supportedYearRange[1]\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'year', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n </div>\n <div\n *ngIf=\"hasTime\"\n class=\"time-fields\"\n [class.seconds]=\"this[WklyPickerInputsPropertyKeys.ShowSeconds]()\"\n >\n <wkly-field\n [label]=\"t('hour')\"\n [locale]=\"effectiveLocale\"\n [value]=\"displayHour(draft)\"\n [min]=\"effectiveHourCycle === 'h12' ? 1 : 0\"\n [max]=\"effectiveHourCycle === 'h12' ? 12 : 23\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'hour', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('minute')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.minute\"\n [max]=\"59\"\n [step]=\"\n this[WklyPickerInputsPropertyKeys.MinuteStep]() > 0 &&\n 60 % this[WklyPickerInputsPropertyKeys.MinuteStep]() === 0\n ? this[WklyPickerInputsPropertyKeys.MinuteStep]()\n : 1\n \"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'minute', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n *ngIf=\"this[WklyPickerInputsPropertyKeys.ShowSeconds]()\"\n [label]=\"t('second')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.second\"\n [max]=\"59\"\n [step]=\"\n this[WklyPickerInputsPropertyKeys.SecondStep]() > 0 &&\n 60 % this[WklyPickerInputsPropertyKeys.SecondStep]() === 0\n ? this[WklyPickerInputsPropertyKeys.SecondStep]()\n : 1\n \"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'second', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <div class=\"period\">\n <button\n *ngIf=\"\n effectiveHourCycle === 'h12' ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() === 'switchable'\n \"\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"\n effectiveHourCycle === 'h12' && (draft.hour || 0) < 12\n \"\n (click)=\"period(i, 'am')\"\n >\n {{ t(\"am\") }}</button\n ><button\n type=\"button\"\n [disabled]=\"\n isDisabled() ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() !== 'switchable'\n \"\n [attr.aria-pressed]=\"effectiveHourCycle === 'h24'\"\n (click)=\"period(i, '24')\"\n >\n 24</button\n ><button\n *ngIf=\"\n effectiveHourCycle === 'h12' ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() === 'switchable'\n \"\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"\n effectiveHourCycle === 'h12' && (draft.hour || 0) >= 12\n \"\n (click)=\"period(i, 'pm')\"\n >\n {{ t(\"pm\") }}\n </button>\n </div>\n </div>\n </fieldset>\n </ng-container>\n <div class=\"validation\" role=\"status\" aria-live=\"polite\">\n <p *ngFor=\"let err of errors\">! {{ t(err.messageKey) }}</p>\n </div>\n <footer *ngIf=\"submitVisible\">\n <button\n type=\"button\"\n class=\"confirm\"\n [disabled]=\"!canSubmit\"\n (click)=\"submit()\"\n >\n {{ t(\"confirm\") }}\n </button>\n </footer>\n</section>\n",
1654
+ styles: [":host{display:block;width:100%;box-sizing:border-box;--wkly-background-color: #fff;--wkly-background-color-alternate: #fafafa;--wkly-text-color: #192c28;--wkly-muted-color: #52635e;--wkly-border-color: #dce5e1;--wkly-accent-color: #176c55;--wkly-accent-color-alternate: #6ea494;--wkly-accent-text-color: #fff;--wkly-range-color: #e5f1ee;--wkly-error-color: #b42318;--wkly-focus-color: #245bd6;--wkly-size-multiplier: 1;--wkly-size-unit: 3.5em;color:var(--wkly-text-color);font:14px/1.4 system-ui,sans-serif;container-type:inline-size}.wkly{background:var(--wkly-background-color);border:1px solid var(--wkly-border-color);border-radius:14px;overflow:hidden;min-width:0;font-size:calc(14px*clamp(1,var(--wkly-size-multiplier),1.5))}button{font:inherit;color:inherit;min-width:var(--wkly-size-unit);min-height:var(--wkly-size-unit);border:0;background:transparent;border-radius:8px;cursor:pointer}button:hover:not(:disabled):not([aria-disabled=true]){background:var(--wkly-accent-color-alternate)}button:disabled,button[aria-disabled=true]{opacity:.4;cursor:default}button:focus-visible{outline:2px solid var(--wkly-focus-color);outline-offset:-2px}.toolbar{display:flex;align-items:center;padding:8px;gap:3px;border-bottom:1px solid var(--wkly-border-color)}.spacer{flex:1}.year-control{padding:0 6px;font-weight:650;text-align:start;line-height:1.2}.now{color:var(--wkly-accent-color);font-weight:650}.week-head,.week-row{display:grid;grid-template-columns:28px repeat(7,minmax(0,1fr))}.week-head{font-size:.85em;color:var(--wkly-muted-color);height:34px;align-items:center;text-align:center}.week-row{height:calc(var(--wkly-size-unit) * clamp(1,var(--wkly-size-multiplier),1));align-items:end}.no-label{grid-template-columns:repeat(7,minmax(0,1fr))}.week-scroll{overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;overflow-anchor:none;scrollbar-width:thin;max-height:65vh;touch-action:pan-y}.scroll-space{position:relative}.rows{position:absolute;left:0;right:0}.week-number{font-size:.85em;text-align:center;align-self:end;line-height:var(--wkly-size-unit);color:var(--wkly-muted-color)}[role=gridcell]{position:relative;min-width:0;height:var(--wkly-size-unit);text-align:center}[role=gridcell].odd-month:not(.range):not(.today){background:var(--wkly-background-color-alternate)}.day{width:100%;min-width:0;height:var(--wkly-size-unit);padding:0;border-radius:8px}.annotation{position:absolute;bottom:.25em;white-space:nowrap;font-size:1.25em;font-weight:650;line-height:1;pointer-events:none;z-index:1;color:var(--wkly-muted-color);color:color-mix(in srgb,var(--wkly-muted-color) 50%,transparent);text-shadow:0 0 2px --wkly-background-color,0 0 4px --wkly-background-color}.odd-month .annotation{text-shadow:0 0 2px --wkly-background-color-alternate,0 0 4px --wkly-background-color-alternate}.annotation:empty{display:none}.annotation--0{inset-inline-start:10%;bottom:1.75em}.annotation--1{inset-inline-start:-5%}.annotation--2{inset-inline-start:-20%}.annotation--3{inset-inline-start:-50%;inset-inline-end:-50%}.annotation--4{inset-inline-end:-20%}.annotation--5{inset-inline-end:-5%}.annotation--6{inset-inline-end:10%}.range{background:var(--wkly-range-color)}.day.selected{background:var(--wkly-accent-color);color:var(--wkly-accent-text-color);font-weight:700}.today:after{content:\"\";display:block;width:5px;height:5px;background:currentColor;border-radius:50%;position:absolute;bottom:2px;left:calc(50% - 2px)}.today{font-weight:750;box-shadow:inset 0 0 0 1px var(--wkly-accent-color)}.hidden{visibility:hidden}.week-navigation{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--wkly-border-color);font-size:.85em;color:var(--wkly-muted-color)}fieldset{border:0;padding:0 12px;margin:0;min-width:0}legend{padding-top:.85em;font-weight:650;color:var(--wkly-accent-color)}.date-fields{display:grid;grid-template-columns:1fr 2fr 1.4fr;gap:7px;padding:12px 0}.end-view-toggle{display:inline-flex}.end-view-toggle button{min-height:0;min-width:0;padding:0 6px;border-radius:0;line-height:inherit}.end-view-toggle button:first-child{padding-inline-start:0}.end-view-toggle button+button{border-inline-start:1px solid var(--wkly-text-color)}.end-view-toggle button[aria-pressed=false]{color:var(--wkly-muted-color);font-weight:400}.in-days-fields{grid-template-columns:minmax(0,1fr);gap:0;text-align:center}.resulting-end-date{font-size:11px;color:var(--wkly-muted-color);height:1.4em;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.time-fields{display:grid;grid-template-columns:1fr 1fr 52px;gap:8px;padding:14px 0;border-top:1px solid var(--wkly-border-color)}.time-fields.seconds{grid-template-columns:1fr 1fr 1fr 48px}.period{display:flex;flex-direction:column;justify-content:center;gap:2px;padding-top:1.25em}.period button{font-size:.85em}.period [aria-pressed=true]{background:var(--wkly-range-color);box-shadow:inset 0 0 0 1px var(--wkly-accent-color);font-weight:700}.validation{color:var(--wkly-error-color);font-size:.85em}.validation p{margin:.5em .85em}footer{padding:12px;border-top:1px solid var(--wkly-border-color)}.confirm{background:var(--wkly-accent-color);color:var(--wkly-accent-text-color);width:100%;font-weight:650}.confirm:hover:not(:disabled){background:var(--wkly-accent-color-alternate)}@media(forced-colors:active){.day.selected{outline:2px solid Highlight}.range{border-bottom:2px solid Highlight}.today{outline:1px dashed CanvasText}}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;animation:none!important}}\n"],
1655
+ dependencies: [
1656
+ {
1657
+ kind: "directive",
1658
+ type: i1.NgForOf,
1659
+ selector: "[ngFor][ngForOf]",
1660
+ inputs: [
1661
+ "ngForOf",
1662
+ "ngForTrackBy",
1663
+ "ngForTemplate"
1664
+ ]
1665
+ },
1666
+ {
1667
+ kind: "directive",
1668
+ type: i1.NgIf,
1669
+ selector: "[ngIf]",
1670
+ inputs: [
1671
+ "ngIf",
1672
+ "ngIfThen",
1673
+ "ngIfElse"
1674
+ ]
1675
+ },
1676
+ {
1677
+ kind: "component",
1678
+ type: WklyFieldComponent,
1679
+ selector: "wkly-field",
1680
+ inputs: [
1681
+ "value",
1682
+ "label",
1683
+ "hideLabel",
1684
+ "previousLabel",
1685
+ "nextLabel",
1686
+ "min",
1687
+ "max",
1688
+ "step",
1689
+ "locale",
1690
+ "disabled",
1691
+ "invalid",
1692
+ "labels"
1693
+ ],
1694
+ outputs: ["valueChange", "complete"]
1695
+ }
1696
+ ]
1697
+ });
1698
+ };
1699
+ i0.ɵɵngDeclareClassMetadata({
1700
+ minVersion: "12.0.0",
1701
+ version: "22.2.1",
1702
+ ngImport: i0,
1703
+ type: WklyDateTimePickerComponent,
1704
+ decorators: [{
1705
+ type: Component,
1706
+ args: [{
1707
+ selector: "wkly-datetime-picker",
1708
+ standalone: false,
1709
+ providers: [{
1710
+ provide: NG_VALUE_ACCESSOR,
1711
+ useExisting: forwardRef(() => WklyDateTimePickerComponent),
1712
+ multi: true
1713
+ }, {
1714
+ provide: NG_VALIDATORS,
1715
+ useExisting: forwardRef(() => WklyDateTimePickerComponent),
1716
+ multi: true
1717
+ }],
1718
+ template: "<section\n class=\"wkly\"\n [attr.dir]=\"direction\"\n [attr.aria-label]=\"\n this[WklyPickerInputsPropertyKeys.AriaLabel]() || 'Date and time picker'\n \"\n [attr.aria-describedby]=\"this[WklyPickerInputsPropertyKeys.AriaDescribedBy]()\"\n (focusout)=\"touched()\"\n>\n <header class=\"toolbar\">\n @if (hasDate) {\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"t(viewMode === 'calendar' ? 'manual' : 'calendar')\"\n (click)=\"toggleView()\"\n >\n {{ viewMode === \"calendar\" ? \"☷\" : \"▦\" }}\n </button>\n }\n @if (hasDate) {\n <span class=\"year-control\">{{ title }}</span>\n }\n <span class=\"spacer\"></span\n ><button\n type=\"button\"\n class=\"now\"\n [disabled]=\"isDisabled()\"\n (click)=\"now()\"\n >\n {{ t(\"now\") }}\n </button>\n @if (presentation === \"transient\") {\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"t('close')\"\n (click)=\"cancel()\"\n >\n ×\n </button>\n }\n </header>\n <ng-container *ngIf=\"hasDate && viewMode === 'calendar'\">\n <div\n role=\"grid\"\n [attr.aria-label]=\"\n this[WklyPickerInputsPropertyKeys.AriaLabel]() || 'Calendar'\n \"\n [attr.aria-multiselectable]=\"isRange\"\n >\n <div\n role=\"row\"\n class=\"week-head\"\n [class.no-label]=\"\n compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() === 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n >\n <span\n *ngIf=\"\n !compact &&\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() !== 'hidden' ||\n this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n role=\"columnheader\"\n aria-label=\"Week\"\n ></span>\n @for (day of weekdays; track $index) {\n <span role=\"columnheader\">{{ day }}</span>\n }\n </div>\n <div\n #scroller\n class=\"week-scroll\"\n [style.height.px]=\"visibleCount * rowHeight\"\n (scroll)=\"scroll($event)\"\n (scrollend)=\"snapWeek()\"\n >\n <div [style.height.px]=\"scrollHeight\" class=\"scroll-space\">\n <div class=\"rows\" [style.top.px]=\"paddingTop\">\n <div\n *ngFor=\"let row of rows; trackBy: trackRow\"\n role=\"row\"\n class=\"week-row\"\n [class.no-label]=\"\n compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() ===\n 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n >\n <span\n *ngIf=\"\n !compact &&\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() !==\n 'hidden' ||\n this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n \"\n role=\"rowheader\"\n class=\"week-number\"\n >{{ row.label }}</span\n >\n <div\n *ngFor=\"\n let cell of row.cells;\n let dayIndex = index;\n trackBy: trackCell\n \"\n role=\"gridcell\"\n [attr.data-weekday-index]=\"dayIndex\"\n [attr.aria-colindex]=\"\n dayIndex +\n (compact ||\n (this[WklyPickerInputsPropertyKeys.WeekLabelMode]() ===\n 'hidden' &&\n !this[WklyPickerInputsPropertyKeys.WeekLabelFormatter]())\n ? 1\n : 2)\n \"\n [attr.aria-selected]=\"selected(cell.epochDay)\"\n [attr.aria-disabled]=\"cell.disabled || isDisabled()\"\n [class.range]=\"inRange(cell.epochDay)\"\n [class.hidden]=\"cell.hidden\"\n [class.odd-month]=\"cell.date && cell.date.month % 2 === 1\"\n >\n <span [class]=\"'annotation annotation--' + dayIndex\">{{\n cell.annotation\n }}</span>\n <button\n type=\"button\"\n class=\"day\"\n [attr.data-day]=\"cell.epochDay\"\n [attr.aria-label]=\"cell.accessible\"\n [attr.aria-current]=\"cell.epochDay === today ? 'date' : null\"\n [attr.aria-disabled]=\"cell.disabled || isDisabled()\"\n [attr.tabindex]=\"\n !cell.hidden && cell.epochDay === focused ? 0 : -1\n \"\n [class.selected]=\"selected(cell.epochDay)\"\n [class.today]=\"cell.epochDay === today\"\n (focus)=\"focused = cell.epochDay\"\n (click)=\"select(cell.epochDay)\"\n (keydown)=\"key($event, cell.epochDay)\"\n >\n {{ cell.label }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"week-navigation\">\n <button\n type=\"button\"\n [disabled]=\"isDisabled() || !canMoveWeek(-1)\"\n [attr.aria-label]=\"t('previous')\"\n (click)=\"moveWeek(-1)\"\n >\n ↑</button\n ><span>{{ title }}</span\n ><button\n type=\"button\"\n [disabled]=\"isDisabled() || !canMoveWeek(1)\"\n [attr.aria-label]=\"t('next')\"\n (click)=\"moveWeek(1)\"\n >\n ↓\n </button>\n </div>\n </ng-container>\n <ng-container\n *ngFor=\"let draft of drafts; let i = index; trackBy: trackDraft\"\n >\n <fieldset\n *ngIf=\"(i === 0 || isRange) && (hasTime || viewMode === 'manual')\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"isRange ? t(i === 0 ? 'start' : 'end') : null\"\n >\n <legend *ngIf=\"isRange\">\n <ng-container\n *ngIf=\"\n i === 1 && hasDate && viewMode === 'manual';\n else endpointLabel\n \"\n >\n <span class=\"end-view-toggle\">\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"endView === 'date'\"\n (click)=\"toggleEndView('date')\"\n >\n {{ t(\"end\") }}\n </button>\n <button\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"endView === 'days'\"\n (click)=\"toggleEndView('days')\"\n >\n {{ inDaysLabel }}\n </button>\n </span>\n </ng-container>\n <ng-template #endpointLabel>{{\n t(i === 0 ? \"start\" : \"end\")\n }}</ng-template>\n </legend>\n <div\n *ngIf=\"\n i === 1 && hasDate && viewMode === 'manual' && endView === 'days'\n \"\n class=\"date-fields in-days-fields\"\n >\n <span class=\"resulting-end-date\" [attr.aria-label]=\"t('endDate')\">{{\n resultingEndDate\n }}</span>\n <wkly-field\n [label]=\"t('days')\"\n [hideLabel]=\"true\"\n [previousLabel]=\"t('daysPrevious')\"\n [nextLabel]=\"t('daysNext')\"\n [locale]=\"effectiveLocale\"\n [value]=\"inDays\"\n [min]=\"-9999\"\n [max]=\"9999\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"days($event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n </div>\n <div\n *ngIf=\"\n hasDate && viewMode === 'manual' && (i === 0 || endView === 'date')\n \"\n class=\"date-fields\"\n >\n <wkly-field\n [label]=\"t('day')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.day\"\n [min]=\"1\"\n [max]=\"31\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'day', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('month')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.month\"\n [min]=\"1\"\n [max]=\"monthCount(draft)\"\n [labels]=\"months(draft)\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'month', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('year')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.date.year\"\n [min]=\"adapter.supportedYearRange[0]\"\n [max]=\"adapter.supportedYearRange[1]\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'year', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n </div>\n <div\n *ngIf=\"hasTime\"\n class=\"time-fields\"\n [class.seconds]=\"this[WklyPickerInputsPropertyKeys.ShowSeconds]()\"\n >\n <wkly-field\n [label]=\"t('hour')\"\n [locale]=\"effectiveLocale\"\n [value]=\"displayHour(draft)\"\n [min]=\"effectiveHourCycle === 'h12' ? 1 : 0\"\n [max]=\"effectiveHourCycle === 'h12' ? 12 : 23\"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'hour', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n [label]=\"t('minute')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.minute\"\n [max]=\"59\"\n [step]=\"\n this[WklyPickerInputsPropertyKeys.MinuteStep]() > 0 &&\n 60 % this[WklyPickerInputsPropertyKeys.MinuteStep]() === 0\n ? this[WklyPickerInputsPropertyKeys.MinuteStep]()\n : 1\n \"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'minute', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <wkly-field\n *ngIf=\"this[WklyPickerInputsPropertyKeys.ShowSeconds]()\"\n [label]=\"t('second')\"\n [locale]=\"effectiveLocale\"\n [value]=\"draft.second\"\n [max]=\"59\"\n [step]=\"\n this[WklyPickerInputsPropertyKeys.SecondStep]() > 0 &&\n 60 % this[WklyPickerInputsPropertyKeys.SecondStep]() === 0\n ? this[WklyPickerInputsPropertyKeys.SecondStep]()\n : 1\n \"\n [disabled]=\"isDisabled()\"\n [invalid]=\"!!errors.length\"\n (valueChange)=\"field(i, 'second', $event)\"\n (complete)=\"finish()\"\n ></wkly-field>\n <div class=\"period\">\n <button\n *ngIf=\"\n effectiveHourCycle === 'h12' ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() === 'switchable'\n \"\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"\n effectiveHourCycle === 'h12' && (draft.hour || 0) < 12\n \"\n (click)=\"period(i, 'am')\"\n >\n {{ t(\"am\") }}</button\n ><button\n type=\"button\"\n [disabled]=\"\n isDisabled() ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() !== 'switchable'\n \"\n [attr.aria-pressed]=\"effectiveHourCycle === 'h24'\"\n (click)=\"period(i, '24')\"\n >\n 24</button\n ><button\n *ngIf=\"\n effectiveHourCycle === 'h12' ||\n this[WklyPickerInputsPropertyKeys.HourCycle]() === 'switchable'\n \"\n type=\"button\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"\n effectiveHourCycle === 'h12' && (draft.hour || 0) >= 12\n \"\n (click)=\"period(i, 'pm')\"\n >\n {{ t(\"pm\") }}\n </button>\n </div>\n </div>\n </fieldset>\n </ng-container>\n <div class=\"validation\" role=\"status\" aria-live=\"polite\">\n <p *ngFor=\"let err of errors\">! {{ t(err.messageKey) }}</p>\n </div>\n <footer *ngIf=\"submitVisible\">\n <button\n type=\"button\"\n class=\"confirm\"\n [disabled]=\"!canSubmit\"\n (click)=\"submit()\"\n >\n {{ t(\"confirm\") }}\n </button>\n </footer>\n</section>\n",
1719
+ styles: [":host{display:block;width:100%;box-sizing:border-box;--wkly-background-color: #fff;--wkly-background-color-alternate: #fafafa;--wkly-text-color: #192c28;--wkly-muted-color: #52635e;--wkly-border-color: #dce5e1;--wkly-accent-color: #176c55;--wkly-accent-color-alternate: #6ea494;--wkly-accent-text-color: #fff;--wkly-range-color: #e5f1ee;--wkly-error-color: #b42318;--wkly-focus-color: #245bd6;--wkly-size-multiplier: 1;--wkly-size-unit: 3.5em;color:var(--wkly-text-color);font:14px/1.4 system-ui,sans-serif;container-type:inline-size}.wkly{background:var(--wkly-background-color);border:1px solid var(--wkly-border-color);border-radius:14px;overflow:hidden;min-width:0;font-size:calc(14px*clamp(1,var(--wkly-size-multiplier),1.5))}button{font:inherit;color:inherit;min-width:var(--wkly-size-unit);min-height:var(--wkly-size-unit);border:0;background:transparent;border-radius:8px;cursor:pointer}button:hover:not(:disabled):not([aria-disabled=true]){background:var(--wkly-accent-color-alternate)}button:disabled,button[aria-disabled=true]{opacity:.4;cursor:default}button:focus-visible{outline:2px solid var(--wkly-focus-color);outline-offset:-2px}.toolbar{display:flex;align-items:center;padding:8px;gap:3px;border-bottom:1px solid var(--wkly-border-color)}.spacer{flex:1}.year-control{padding:0 6px;font-weight:650;text-align:start;line-height:1.2}.now{color:var(--wkly-accent-color);font-weight:650}.week-head,.week-row{display:grid;grid-template-columns:28px repeat(7,minmax(0,1fr))}.week-head{font-size:.85em;color:var(--wkly-muted-color);height:34px;align-items:center;text-align:center}.week-row{height:calc(var(--wkly-size-unit) * clamp(1,var(--wkly-size-multiplier),1));align-items:end}.no-label{grid-template-columns:repeat(7,minmax(0,1fr))}.week-scroll{overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;overflow-anchor:none;scrollbar-width:thin;max-height:65vh;touch-action:pan-y}.scroll-space{position:relative}.rows{position:absolute;left:0;right:0}.week-number{font-size:.85em;text-align:center;align-self:end;line-height:var(--wkly-size-unit);color:var(--wkly-muted-color)}[role=gridcell]{position:relative;min-width:0;height:var(--wkly-size-unit);text-align:center}[role=gridcell].odd-month:not(.range):not(.today){background:var(--wkly-background-color-alternate)}.day{width:100%;min-width:0;height:var(--wkly-size-unit);padding:0;border-radius:8px}.annotation{position:absolute;bottom:.25em;white-space:nowrap;font-size:1.25em;font-weight:650;line-height:1;pointer-events:none;z-index:1;color:var(--wkly-muted-color);color:color-mix(in srgb,var(--wkly-muted-color) 50%,transparent);text-shadow:0 0 2px --wkly-background-color,0 0 4px --wkly-background-color}.odd-month .annotation{text-shadow:0 0 2px --wkly-background-color-alternate,0 0 4px --wkly-background-color-alternate}.annotation:empty{display:none}.annotation--0{inset-inline-start:10%;bottom:1.75em}.annotation--1{inset-inline-start:-5%}.annotation--2{inset-inline-start:-20%}.annotation--3{inset-inline-start:-50%;inset-inline-end:-50%}.annotation--4{inset-inline-end:-20%}.annotation--5{inset-inline-end:-5%}.annotation--6{inset-inline-end:10%}.range{background:var(--wkly-range-color)}.day.selected{background:var(--wkly-accent-color);color:var(--wkly-accent-text-color);font-weight:700}.today:after{content:\"\";display:block;width:5px;height:5px;background:currentColor;border-radius:50%;position:absolute;bottom:2px;left:calc(50% - 2px)}.today{font-weight:750;box-shadow:inset 0 0 0 1px var(--wkly-accent-color)}.hidden{visibility:hidden}.week-navigation{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--wkly-border-color);font-size:.85em;color:var(--wkly-muted-color)}fieldset{border:0;padding:0 12px;margin:0;min-width:0}legend{padding-top:.85em;font-weight:650;color:var(--wkly-accent-color)}.date-fields{display:grid;grid-template-columns:1fr 2fr 1.4fr;gap:7px;padding:12px 0}.end-view-toggle{display:inline-flex}.end-view-toggle button{min-height:0;min-width:0;padding:0 6px;border-radius:0;line-height:inherit}.end-view-toggle button:first-child{padding-inline-start:0}.end-view-toggle button+button{border-inline-start:1px solid var(--wkly-text-color)}.end-view-toggle button[aria-pressed=false]{color:var(--wkly-muted-color);font-weight:400}.in-days-fields{grid-template-columns:minmax(0,1fr);gap:0;text-align:center}.resulting-end-date{font-size:11px;color:var(--wkly-muted-color);height:1.4em;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.time-fields{display:grid;grid-template-columns:1fr 1fr 52px;gap:8px;padding:14px 0;border-top:1px solid var(--wkly-border-color)}.time-fields.seconds{grid-template-columns:1fr 1fr 1fr 48px}.period{display:flex;flex-direction:column;justify-content:center;gap:2px;padding-top:1.25em}.period button{font-size:.85em}.period [aria-pressed=true]{background:var(--wkly-range-color);box-shadow:inset 0 0 0 1px var(--wkly-accent-color);font-weight:700}.validation{color:var(--wkly-error-color);font-size:.85em}.validation p{margin:.5em .85em}footer{padding:12px;border-top:1px solid var(--wkly-border-color)}.confirm{background:var(--wkly-accent-color);color:var(--wkly-accent-text-color);width:100%;font-weight:650}.confirm:hover:not(:disabled){background:var(--wkly-accent-color-alternate)}@media(forced-colors:active){.day.selected{outline:2px solid Highlight}.range{border-bottom:2px solid Highlight}.today{outline:1px dashed CanvasText}}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;animation:none!important}}\n"]
1720
+ }]
1721
+ }],
1722
+ ctorParameters: () => [
1723
+ {
1724
+ type: void 0,
1725
+ decorators: [{
1726
+ type: Inject,
1727
+ args: [LOCALE_ID]
1728
+ }]
1729
+ },
1730
+ {
1731
+ type: void 0,
1732
+ decorators: [{
1733
+ type: Inject,
1734
+ args: [WKLY_CONFIG]
1735
+ }]
1736
+ },
1737
+ {
1738
+ type: void 0,
1739
+ decorators: [{
1740
+ type: Inject,
1741
+ args: [WKLY_CLOCK]
1742
+ }]
1743
+ },
1744
+ {
1745
+ type: void 0,
1746
+ decorators: [{
1747
+ type: Inject,
1748
+ args: [WKLY_LOCALIZATION]
1749
+ }]
1750
+ },
1751
+ {
1752
+ type: void 0,
1753
+ decorators: [{
1754
+ type: Inject,
1755
+ args: [WKLY_TRANSLATIONS]
1756
+ }]
1757
+ },
1758
+ {
1759
+ type: Object,
1760
+ decorators: [{
1761
+ type: Inject,
1762
+ args: [PLATFORM_ID]
1763
+ }]
1764
+ },
1765
+ { type: i0.ElementRef },
1766
+ { type: i0.ChangeDetectorRef }
1767
+ ],
1768
+ propDecorators: { scroller: [{
1769
+ type: ViewChild,
1770
+ args: ["scroller"]
1771
+ }] }
1772
+ });
1773
+ var WklyDateTimePickerDialogService = class WklyDateTimePickerDialogService {
1774
+ environmentInjector;
1775
+ app;
1776
+ document;
1777
+ platform;
1778
+ constructor(environmentInjector, app, document, platform) {
1779
+ this.environmentInjector = environmentInjector;
1780
+ this.app = app;
1781
+ this.document = document;
1782
+ this.platform = platform;
1783
+ }
1784
+ open(trigger, onCancel, backdrop = true, injector) {
1785
+ if (!isPlatformBrowser(this.platform)) throw new Error("Picker presentations can only open in a browser");
1786
+ const dialog = this.document.createElement("dialog");
1787
+ dialog.setAttribute("aria-label", "Date and time picker");
1788
+ Object.assign(dialog.style, {
1789
+ padding: "0",
1790
+ border: "0",
1791
+ borderRadius: "14px",
1792
+ width: "min(390px, 100vw)",
1793
+ maxWidth: "100vw",
1794
+ maxHeight: "94vh",
1795
+ background: "transparent"
1796
+ });
1797
+ const component = createComponent(WklyDateTimePickerComponent, {
1798
+ environmentInjector: this.environmentInjector,
1799
+ elementInjector: injector
1800
+ });
1801
+ component.instance.presentation = "transient";
1802
+ dialog.appendChild(component.location.nativeElement);
1803
+ this.document.body.appendChild(dialog);
1804
+ this.app.attachView(component.hostView);
1805
+ const cancel = (event) => {
1806
+ event.preventDefault();
1807
+ onCancel("escape");
1808
+ };
1809
+ const click = (event) => {
1810
+ if (backdrop && event.target === dialog) {
1811
+ const r = dialog.getBoundingClientRect();
1812
+ if (event.clientX < r.left || event.clientX > r.right || event.clientY < r.top || event.clientY > r.bottom) onCancel("backdrop");
1813
+ }
1814
+ };
1815
+ const keydown = (event) => {
1816
+ if (event.key !== "Tab") return;
1817
+ const controls = Array.from(dialog.querySelectorAll("button:not(:disabled),input:not(:disabled),[tabindex=\"0\"]")).filter((el) => el.tabIndex >= 0 && el.getClientRects().length && getComputedStyle(el).visibility !== "hidden");
1818
+ const first = controls[0], last = controls[controls.length - 1];
1819
+ if (first && (event.shiftKey ? this.document.activeElement === first : this.document.activeElement === last)) {
1820
+ event.preventDefault();
1821
+ (event.shiftKey ? last : first).focus();
1822
+ }
1823
+ };
1824
+ dialog.addEventListener("cancel", cancel);
1825
+ dialog.addEventListener("click", click);
1826
+ dialog.addEventListener("keydown", keydown);
1827
+ dialog.showModal();
1828
+ return {
1829
+ component,
1830
+ destroy: () => {
1831
+ dialog.removeEventListener("cancel", cancel);
1832
+ dialog.removeEventListener("click", click);
1833
+ dialog.removeEventListener("keydown", keydown);
1834
+ dialog.close();
1835
+ this.app.detachView(component.hostView);
1836
+ component.destroy();
1837
+ dialog.remove();
1838
+ trigger.focus();
1839
+ }
1840
+ };
1841
+ }
1842
+ static ɵfac = i0.ɵɵngDeclareFactory({
1843
+ minVersion: "12.0.0",
1844
+ version: "22.2.1",
1845
+ ngImport: i0,
1846
+ type: WklyDateTimePickerDialogService,
1847
+ deps: [
1848
+ { token: i0.EnvironmentInjector },
1849
+ { token: i0.ApplicationRef },
1850
+ { token: DOCUMENT },
1851
+ { token: PLATFORM_ID }
1852
+ ],
1853
+ target: i0.ɵɵFactoryTarget.Injectable
1854
+ });
1855
+ static ɵprov = i0.ɵɵngDeclareInjectable({
1856
+ minVersion: "12.0.0",
1857
+ version: "22.2.1",
1858
+ ngImport: i0,
1859
+ type: WklyDateTimePickerDialogService,
1860
+ providedIn: "root"
1861
+ });
1862
+ };
1863
+ i0.ɵɵngDeclareClassMetadata({
1864
+ minVersion: "12.0.0",
1865
+ version: "22.2.1",
1866
+ ngImport: i0,
1867
+ type: WklyDateTimePickerDialogService,
1868
+ decorators: [{
1869
+ type: Injectable,
1870
+ args: [{ providedIn: "root" }]
1871
+ }],
1872
+ ctorParameters: () => [
1873
+ { type: i0.EnvironmentInjector },
1874
+ { type: i0.ApplicationRef },
1875
+ {
1876
+ type: Document,
1877
+ decorators: [{
1878
+ type: Inject,
1879
+ args: [DOCUMENT]
1880
+ }]
1881
+ },
1882
+ {
1883
+ type: Object,
1884
+ decorators: [{
1885
+ type: Inject,
1886
+ args: [PLATFORM_ID]
1887
+ }]
1888
+ }
1889
+ ]
1890
+ });
1891
+ var WklyTriggerBase = class WklyTriggerBase extends WklyPickerInputs {
1892
+ element;
1893
+ ref = null;
1894
+ subscriptions = [];
1895
+ errors = [];
1896
+ change = () => {};
1897
+ touched = () => {};
1898
+ validation = () => {};
1899
+ formValue = signal(void 0, ...ngDevMode ? [{ debugName: "formValue" }] : /* istanbul ignore next */ []);
1900
+ formDisabled = signal(false, ...ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []);
1901
+ previousInputs;
1902
+ currentValue() {
1903
+ return this.formValue() === void 0 ? this[WklyPickerInputsPropertyKeys.Value]() : this.formValue();
1904
+ }
1905
+ isDisabled() {
1906
+ return this[WklyPickerInputsPropertyKeys.Disabled]() || this.formDisabled();
1907
+ }
1908
+ constructor(element) {
1909
+ super();
1910
+ this.element = element;
1911
+ effect(() => {
1912
+ const inputs = unwrapWklyPickerSignalInputs(this);
1913
+ const previous = this.previousInputs;
1914
+ this.previousInputs = inputs;
1915
+ untracked(() => {
1916
+ if (previous && !Object.is(previous[WklyPickerInputsPropertyKeys.Value], inputs[WklyPickerInputsPropertyKeys.Value])) this.formValue.set(void 0);
1917
+ if (!previous || Object.keys(inputs).some((key) => !Object.is(previous[key], inputs[key]))) {
1918
+ this.checkValue();
1919
+ this.display();
1920
+ if (this.ref) {
1921
+ this.copy();
1922
+ this.ref.component.changeDetectorRef.detectChanges();
1923
+ }
1924
+ }
1925
+ });
1926
+ });
1927
+ }
1928
+ open() {
1929
+ if (this.isDisabled() || this.ref) return;
1930
+ this.ref = this.create();
1931
+ const picker = this.ref.component.instance;
1932
+ this.copy();
1933
+ this.subscriptions = [
1934
+ picker[WklyPickerOutputsPropertyKeys.ValueChange].subscribe((value) => {
1935
+ this.formValue.set(value);
1936
+ this.change(value);
1937
+ this[WklyPickerOutputsPropertyKeys.ValueChange].emit(value);
1938
+ this.display();
1939
+ }),
1940
+ picker[WklyPickerOutputsPropertyKeys.ValidationChange].subscribe((errors) => {
1941
+ this.errors = errors;
1942
+ this[WklyPickerOutputsPropertyKeys.ValidationChange].emit(errors);
1943
+ this.validation();
1944
+ }),
1945
+ picker[WklyPickerOutputsPropertyKeys.Closed].subscribe((reason) => this.close(reason)),
1946
+ picker[WklyPickerOutputsPropertyKeys.ViewportChange].subscribe((value) => this[WklyPickerOutputsPropertyKeys.ViewportChange].emit(value)),
1947
+ picker[WklyPickerOutputsPropertyKeys.ViewModeChange].subscribe((value) => this[WklyPickerOutputsPropertyKeys.ViewModeChange].emit(value))
1948
+ ];
1949
+ this.ref.component.changeDetectorRef.detectChanges();
1950
+ picker.focusDay();
1951
+ this[WklyPickerOutputsPropertyKeys.Opened].emit();
1952
+ }
1953
+ key(event) {
1954
+ if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown") {
1955
+ event.preventDefault();
1956
+ this.open();
1957
+ }
1958
+ }
1959
+ blur() {
1960
+ this.touched();
1961
+ }
1962
+ close(reason = "programmatic") {
1963
+ if (!this.ref) return;
1964
+ const ref = this.ref;
1965
+ this.ref = null;
1966
+ this.subscriptions.forEach((s) => s.unsubscribe());
1967
+ this.subscriptions = [];
1968
+ ref.destroy();
1969
+ this.touched();
1970
+ this[WklyPickerOutputsPropertyKeys.Closed].emit(reason);
1971
+ }
1972
+ ngOnDestroy() {
1973
+ this.close();
1974
+ }
1975
+ copy() {
1976
+ if (!this.ref) return;
1977
+ const inputs = unwrapWklyPickerSignalInputs(this);
1978
+ for (const name of Object.values(WklyPickerInputsPropertyKeys)) this.ref.component.setInput(name, name === WklyPickerInputsPropertyKeys.Value ? this.currentValue() : name === WklyPickerInputsPropertyKeys.Disabled ? this.isDisabled() : inputs[name]);
1979
+ }
1980
+ display() {
1981
+ const host = this.element.nativeElement;
1982
+ if (host.tagName === "INPUT") {
1983
+ host.readOnly = true;
1984
+ const value = this.currentValue();
1985
+ host.value = value === null ? "" : typeof value === "string" ? value : value.join(" — ");
1986
+ host.disabled = this.isDisabled();
1987
+ host.setAttribute("aria-haspopup", "dialog");
1988
+ }
1989
+ }
1990
+ checkValue() {
1991
+ this.errors = validateSelection(this.currentValue(), unwrapWklyPickerSignalInputs(this), this[WklyPickerInputsPropertyKeys.CalendarAdapter]() || new WklyGregorianCalendarAdapter(this[WklyPickerInputsPropertyKeys.Locale]() || "en-US"));
1992
+ this[WklyPickerOutputsPropertyKeys.ValidationChange].emit(this.errors);
1993
+ this.validation();
1994
+ }
1995
+ writeValue(value) {
1996
+ this.formValue.set(value);
1997
+ this.checkValue();
1998
+ this.display();
1999
+ if (this.ref) this.ref.component.instance.writeValue(value);
2000
+ }
2001
+ registerOnChange(fn) {
2002
+ this.change = fn;
2003
+ }
2004
+ registerOnTouched(fn) {
2005
+ this.touched = fn;
2006
+ }
2007
+ setDisabledState(value) {
2008
+ this.formDisabled.set(value);
2009
+ this.display();
2010
+ if (this.ref) this.ref.component.instance.setDisabledState(value);
2011
+ }
2012
+ validate() {
2013
+ return this.errors.length ? { wkly: this.errors } : null;
2014
+ }
2015
+ registerOnValidatorChange(fn) {
2016
+ this.validation = fn;
2017
+ }
2018
+ scrollToEpochDay(day, options) {
2019
+ this.open();
2020
+ this.ref?.component.instance.scrollToEpochDay(day, options);
2021
+ }
2022
+ scrollToAbsoluteWeek(week, options) {
2023
+ this.open();
2024
+ this.ref?.component.instance.scrollToAbsoluteWeek(week, options);
2025
+ }
2026
+ scrollToCalendarDate(date, options) {
2027
+ this.open();
2028
+ this.ref?.component.instance.scrollToCalendarDate(date, options);
2029
+ }
2030
+ scrollToValue(value, options) {
2031
+ this.open();
2032
+ this.ref?.component.instance.scrollToValue(value, options);
2033
+ }
2034
+ static ɵfac = i0.ɵɵngDeclareFactory({
2035
+ minVersion: "12.0.0",
2036
+ version: "22.2.1",
2037
+ ngImport: i0,
2038
+ type: WklyTriggerBase,
2039
+ deps: [{ token: i0.ElementRef }],
2040
+ target: i0.ɵɵFactoryTarget.Directive
2041
+ });
2042
+ static ɵdir = i0.ɵɵngDeclareDirective({
2043
+ minVersion: "14.0.0",
2044
+ version: "22.2.1",
2045
+ type: WklyTriggerBase,
2046
+ isStandalone: true,
2047
+ host: { listeners: {
2048
+ "click": "open()",
2049
+ "keydown": "key($event)",
2050
+ "blur": "blur()"
2051
+ } },
2052
+ usesInheritance: true,
2053
+ ngImport: i0
2054
+ });
2055
+ };
2056
+ i0.ɵɵngDeclareClassMetadata({
2057
+ minVersion: "12.0.0",
2058
+ version: "22.2.1",
2059
+ ngImport: i0,
2060
+ type: WklyTriggerBase,
2061
+ decorators: [{ type: Directive }],
2062
+ ctorParameters: () => [{ type: i0.ElementRef }],
2063
+ propDecorators: {
2064
+ open: [{
2065
+ type: HostListener,
2066
+ args: ["click"]
2067
+ }],
2068
+ key: [{
2069
+ type: HostListener,
2070
+ args: ["keydown", ["$event"]]
2071
+ }],
2072
+ blur: [{
2073
+ type: HostListener,
2074
+ args: ["blur"]
2075
+ }]
2076
+ }
2077
+ });
2078
+ var WklyDateTimePickerDialogDirective = class WklyDateTimePickerDialogDirective extends WklyTriggerBase {
2079
+ service;
2080
+ triggerInjector;
2081
+ constructor(element, service, triggerInjector) {
2082
+ super(element);
2083
+ this.service = service;
2084
+ this.triggerInjector = triggerInjector;
2085
+ }
2086
+ create() {
2087
+ return this.service.open(this.element.nativeElement, (reason) => this.close(reason), this[WklyPickerInputsPropertyKeys.CloseOnBackdrop](), this.triggerInjector);
2088
+ }
2089
+ static ɵfac = i0.ɵɵngDeclareFactory({
2090
+ minVersion: "12.0.0",
2091
+ version: "22.2.1",
2092
+ ngImport: i0,
2093
+ type: WklyDateTimePickerDialogDirective,
2094
+ deps: [
2095
+ { token: i0.ElementRef },
2096
+ { token: WklyDateTimePickerDialogService },
2097
+ { token: i0.Injector }
2098
+ ],
2099
+ target: i0.ɵɵFactoryTarget.Directive
2100
+ });
2101
+ static ɵdir = i0.ɵɵngDeclareDirective({
2102
+ minVersion: "14.0.0",
2103
+ version: "22.2.1",
2104
+ type: WklyDateTimePickerDialogDirective,
2105
+ isStandalone: false,
2106
+ selector: "[wklyDateTimePickerDialog]",
2107
+ providers: [{
2108
+ provide: NG_VALUE_ACCESSOR,
2109
+ useExisting: forwardRef(() => WklyDateTimePickerDialogDirective),
2110
+ multi: true
2111
+ }, {
2112
+ provide: NG_VALIDATORS,
2113
+ useExisting: forwardRef(() => WklyDateTimePickerDialogDirective),
2114
+ multi: true
2115
+ }],
2116
+ exportAs: ["wklyDialog"],
2117
+ usesInheritance: true,
2118
+ ngImport: i0
2119
+ });
2120
+ };
2121
+ i0.ɵɵngDeclareClassMetadata({
2122
+ minVersion: "12.0.0",
2123
+ version: "22.2.1",
2124
+ ngImport: i0,
2125
+ type: WklyDateTimePickerDialogDirective,
2126
+ decorators: [{
2127
+ type: Directive,
2128
+ args: [{
2129
+ selector: "[wklyDateTimePickerDialog]",
2130
+ standalone: false,
2131
+ exportAs: "wklyDialog",
2132
+ providers: [{
2133
+ provide: NG_VALUE_ACCESSOR,
2134
+ useExisting: forwardRef(() => WklyDateTimePickerDialogDirective),
2135
+ multi: true
2136
+ }, {
2137
+ provide: NG_VALIDATORS,
2138
+ useExisting: forwardRef(() => WklyDateTimePickerDialogDirective),
2139
+ multi: true
2140
+ }]
2141
+ }]
2142
+ }],
2143
+ ctorParameters: () => [
2144
+ { type: i0.ElementRef },
2145
+ { type: WklyDateTimePickerDialogService },
2146
+ { type: i0.Injector }
2147
+ ]
2148
+ });
2149
+ var WklyDateTimePickerModule = class WklyDateTimePickerModule {
2150
+ static ɵfac = i0.ɵɵngDeclareFactory({
2151
+ minVersion: "12.0.0",
2152
+ version: "22.2.1",
2153
+ ngImport: i0,
2154
+ type: WklyDateTimePickerModule,
2155
+ deps: [],
2156
+ target: i0.ɵɵFactoryTarget.NgModule
2157
+ });
2158
+ static ɵmod = i0.ɵɵngDeclareNgModule({
2159
+ minVersion: "14.0.0",
2160
+ version: "22.2.1",
2161
+ ngImport: i0,
2162
+ type: WklyDateTimePickerModule,
2163
+ declarations: [
2164
+ WklyDateTimePickerComponent,
2165
+ WklyDateTimePickerDialogDirective,
2166
+ WklyFieldComponent
2167
+ ],
2168
+ imports: [CommonModule],
2169
+ exports: [WklyDateTimePickerComponent, WklyDateTimePickerDialogDirective]
2170
+ });
2171
+ static ɵinj = i0.ɵɵngDeclareInjector({
2172
+ minVersion: "12.0.0",
2173
+ version: "22.2.1",
2174
+ ngImport: i0,
2175
+ type: WklyDateTimePickerModule,
2176
+ imports: [CommonModule]
2177
+ });
2178
+ };
2179
+ i0.ɵɵngDeclareClassMetadata({
2180
+ minVersion: "12.0.0",
2181
+ version: "22.2.1",
2182
+ ngImport: i0,
2183
+ type: WklyDateTimePickerModule,
2184
+ decorators: [{
2185
+ type: NgModule,
2186
+ args: [{
2187
+ imports: [CommonModule],
2188
+ declarations: [
2189
+ WklyDateTimePickerComponent,
2190
+ WklyDateTimePickerDialogDirective,
2191
+ WklyFieldComponent
2192
+ ],
2193
+ exports: [WklyDateTimePickerComponent, WklyDateTimePickerDialogDirective]
2194
+ }]
2195
+ }]
2196
+ });
1708
2197
  export { WKLY_CLOCK, WKLY_CONFIG, WKLY_LOCALIZATION, WKLY_TRANSLATIONS, WklyDateTimePickerComponent, WklyDateTimePickerDialogDirective, WklyDateTimePickerDialogService, WklyDateTimePickerModule, WklyFieldComponent, WklyPickerInputs, WklyTriggerBase, unwrapWklyPickerSignalInputs };
1709
- //# sourceMappingURL=wkly-datetime-picker.mjs.map
2198
+
2199
+ //# sourceMappingURL=wkly-datetime-picker.mjs.map