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