@wkly/datetime-picker 21.0.0 → 22.0.0

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