ngx-com 0.0.21 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -33
- package/fesm2022/ngx-com-components-alert.mjs +21 -11
- package/fesm2022/ngx-com-components-alert.mjs.map +1 -1
- package/fesm2022/ngx-com-components-avatar.mjs +9 -7
- package/fesm2022/ngx-com-components-avatar.mjs.map +1 -1
- package/fesm2022/ngx-com-components-button.mjs +1 -1
- package/fesm2022/ngx-com-components-button.mjs.map +1 -1
- package/fesm2022/ngx-com-components-calendar.mjs +27 -3112
- package/fesm2022/ngx-com-components-calendar.mjs.map +1 -1
- package/fesm2022/ngx-com-components-card.mjs +8 -8
- package/fesm2022/ngx-com-components-card.mjs.map +1 -1
- package/fesm2022/ngx-com-components-carousel.mjs +16 -4
- package/fesm2022/ngx-com-components-carousel.mjs.map +1 -1
- package/fesm2022/ngx-com-components-checkbox.mjs +1 -1
- package/fesm2022/ngx-com-components-checkbox.mjs.map +1 -1
- package/fesm2022/ngx-com-components-code-block.mjs +9 -9
- package/fesm2022/ngx-com-components-code-block.mjs.map +1 -1
- package/fesm2022/ngx-com-components-collapsible.mjs +15 -13
- package/fesm2022/ngx-com-components-collapsible.mjs.map +1 -1
- package/fesm2022/ngx-com-components-confirm.mjs +4 -4
- package/fesm2022/ngx-com-components-confirm.mjs.map +1 -1
- package/fesm2022/ngx-com-components-datepicker.mjs +2334 -0
- package/fesm2022/ngx-com-components-datepicker.mjs.map +1 -0
- package/fesm2022/ngx-com-components-dialog.mjs +47 -45
- package/fesm2022/ngx-com-components-dialog.mjs.map +1 -1
- package/fesm2022/ngx-com-components-dropdown.mjs +446 -340
- package/fesm2022/ngx-com-components-dropdown.mjs.map +1 -1
- package/fesm2022/ngx-com-components-empty-state.mjs +5 -3
- package/fesm2022/ngx-com-components-empty-state.mjs.map +1 -1
- package/fesm2022/ngx-com-components-form-field.mjs +11 -6
- package/fesm2022/ngx-com-components-form-field.mjs.map +1 -1
- package/fesm2022/ngx-com-components-icon-lucide.mjs +41 -0
- package/fesm2022/ngx-com-components-icon-lucide.mjs.map +1 -0
- package/fesm2022/ngx-com-components-icon.mjs +89 -61
- package/fesm2022/ngx-com-components-icon.mjs.map +1 -1
- package/fesm2022/ngx-com-components-item.mjs +14 -4
- package/fesm2022/ngx-com-components-item.mjs.map +1 -1
- package/fesm2022/ngx-com-components-menu.mjs +61 -69
- package/fesm2022/ngx-com-components-menu.mjs.map +1 -1
- package/fesm2022/ngx-com-components-native-control.mjs +170 -0
- package/fesm2022/ngx-com-components-native-control.mjs.map +1 -0
- package/fesm2022/ngx-com-components-paginator.mjs +11 -3
- package/fesm2022/ngx-com-components-paginator.mjs.map +1 -1
- package/fesm2022/ngx-com-components-popover.mjs +58 -33
- package/fesm2022/ngx-com-components-popover.mjs.map +1 -1
- package/fesm2022/ngx-com-components-radio.mjs +4 -4
- package/fesm2022/ngx-com-components-radio.mjs.map +1 -1
- package/fesm2022/ngx-com-components-segmented-control.mjs +6 -4
- package/fesm2022/ngx-com-components-segmented-control.mjs.map +1 -1
- package/fesm2022/ngx-com-components-sort.mjs +63 -57
- package/fesm2022/ngx-com-components-sort.mjs.map +1 -1
- package/fesm2022/ngx-com-components-spinner.mjs +6 -6
- package/fesm2022/ngx-com-components-spinner.mjs.map +1 -1
- package/fesm2022/ngx-com-components-switch.mjs +18 -9
- package/fesm2022/ngx-com-components-switch.mjs.map +1 -1
- package/fesm2022/ngx-com-components-table.mjs +23 -9
- package/fesm2022/ngx-com-components-table.mjs.map +1 -1
- package/fesm2022/ngx-com-components-tabs.mjs +81 -58
- package/fesm2022/ngx-com-components-tabs.mjs.map +1 -1
- package/fesm2022/ngx-com-components-timepicker.mjs +1048 -0
- package/fesm2022/ngx-com-components-timepicker.mjs.map +1 -0
- package/fesm2022/ngx-com-components-toast.mjs +18 -14
- package/fesm2022/ngx-com-components-toast.mjs.map +1 -1
- package/fesm2022/ngx-com-components-tooltip.mjs +5 -5
- package/fesm2022/ngx-com-components-tooltip.mjs.map +1 -1
- package/fesm2022/ngx-com-components.mjs +0 -13
- package/fesm2022/ngx-com-components.mjs.map +1 -1
- package/fesm2022/ngx-com-tokens.mjs +0 -8
- package/fesm2022/ngx-com-tokens.mjs.map +1 -1
- package/fesm2022/ngx-com-utils.mjs +13 -1
- package/fesm2022/ngx-com-utils.mjs.map +1 -1
- package/fesm2022/ngx-com.mjs +1 -1
- package/fesm2022/ngx-com.mjs.map +1 -1
- package/package.json +51 -8
- package/styles/animations.css +38 -0
- package/styles/candy.css +121 -0
- package/styles/dark.css +159 -0
- package/styles/forest.css +117 -0
- package/styles/ocean.css +117 -0
- package/styles/themes.css +7 -0
- package/styles/tokens.css +277 -0
- package/styles/utilities.css +16 -0
- package/types/ngx-com-components-alert.d.ts +14 -4
- package/types/ngx-com-components-avatar.d.ts +2 -0
- package/types/ngx-com-components-calendar.d.ts +3 -747
- package/types/ngx-com-components-card.d.ts +2 -2
- package/types/ngx-com-components-carousel.d.ts +11 -1
- package/types/ngx-com-components-code-block.d.ts +4 -4
- package/types/ngx-com-components-collapsible.d.ts +10 -2
- package/types/ngx-com-components-confirm.d.ts +2 -2
- package/types/ngx-com-components-datepicker.d.ts +623 -0
- package/types/ngx-com-components-dialog.d.ts +5 -2
- package/types/ngx-com-components-dropdown.d.ts +22 -4
- package/types/ngx-com-components-empty-state.d.ts +2 -0
- package/types/ngx-com-components-form-field.d.ts +4 -1
- package/types/ngx-com-components-icon-lucide.d.ts +32 -0
- package/types/ngx-com-components-icon.d.ts +49 -35
- package/types/ngx-com-components-item.d.ts +12 -2
- package/types/ngx-com-components-menu.d.ts +38 -38
- package/types/ngx-com-components-native-control.d.ts +99 -0
- package/types/ngx-com-components-paginator.d.ts +2 -0
- package/types/ngx-com-components-popover.d.ts +19 -12
- package/types/ngx-com-components-segmented-control.d.ts +3 -1
- package/types/ngx-com-components-sort.d.ts +13 -10
- package/types/ngx-com-components-switch.d.ts +7 -2
- package/types/ngx-com-components-table.d.ts +16 -2
- package/types/ngx-com-components-tabs.d.ts +46 -34
- package/types/ngx-com-components-timepicker.d.ts +273 -0
- package/types/ngx-com-components-toast.d.ts +4 -2
- package/types/ngx-com-components-tooltip.d.ts +1 -1
- package/types/ngx-com-components.d.ts +6 -7
- package/types/ngx-com-tokens.d.ts +5 -3
- package/types/ngx-com-utils.d.ts +11 -1
- package/types/ngx-com.d.ts +1 -1
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, LOCALE_ID, Injectable, viewChild, input, output, computed, ChangeDetectionStrategy, Component, signal, afterEveryRender, Directive, viewChildren, linkedSignal
|
|
2
|
+
import { InjectionToken, inject, LOCALE_ID, Injectable, viewChild, input, output, computed, ChangeDetectionStrategy, Component, signal, afterEveryRender, Directive, viewChildren, linkedSignal } from '@angular/core';
|
|
3
3
|
import { cva } from 'class-variance-authority';
|
|
4
4
|
import { NgTemplateOutlet } from '@angular/common';
|
|
5
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
|
-
import { NgControl } from '@angular/forms';
|
|
7
|
-
import { Overlay, OverlayModule } from '@angular/cdk/overlay';
|
|
8
|
-
import { TemplatePortal } from '@angular/cdk/portal';
|
|
9
|
-
import * as i1 from '@angular/cdk/a11y';
|
|
10
|
-
import { A11yModule } from '@angular/cdk/a11y';
|
|
11
|
-
import { ComIcon } from 'ngx-com/components/icon';
|
|
12
5
|
|
|
13
6
|
/**
|
|
14
7
|
* Calendar shared types and interfaces
|
|
@@ -339,14 +332,14 @@ const calendarCellVariants = cva(
|
|
|
339
332
|
'cursor-pointer',
|
|
340
333
|
'select-none',
|
|
341
334
|
'transition-colors',
|
|
342
|
-
'duration-
|
|
335
|
+
'duration-normal',
|
|
343
336
|
'focus-visible:outline-[1px]',
|
|
344
337
|
'focus-visible:outline-offset-2',
|
|
345
338
|
'focus-visible:outline-ring',
|
|
346
339
|
], {
|
|
347
340
|
variants: {
|
|
348
341
|
view: {
|
|
349
|
-
month: ['h-9', 'w-9', 'text-sm', 'rounded-
|
|
342
|
+
month: ['h-9', 'w-9', 'text-sm', 'rounded-pill'],
|
|
350
343
|
year: ['h-10', 'w-16', 'text-sm', 'rounded-calendar-cell'],
|
|
351
344
|
'multi-year': ['h-10', 'w-14', 'text-sm', 'rounded-calendar-cell'],
|
|
352
345
|
},
|
|
@@ -369,7 +362,7 @@ const calendarCellVariants = cva(
|
|
|
369
362
|
'bg-primary',
|
|
370
363
|
'text-primary-foreground',
|
|
371
364
|
'font-semibold',
|
|
372
|
-
'rounded-l-
|
|
365
|
+
'rounded-l-pill',
|
|
373
366
|
'rounded-r-none',
|
|
374
367
|
'hover:bg-primary-hover',
|
|
375
368
|
],
|
|
@@ -383,14 +376,17 @@ const calendarCellVariants = cva(
|
|
|
383
376
|
'bg-primary',
|
|
384
377
|
'text-primary-foreground',
|
|
385
378
|
'font-semibold',
|
|
386
|
-
'rounded-r-
|
|
379
|
+
'rounded-r-pill',
|
|
387
380
|
'rounded-l-none',
|
|
388
381
|
'hover:bg-primary-hover',
|
|
389
382
|
],
|
|
383
|
+
// Preview states use opacity-70 intentionally: the reduced opacity distinguishes
|
|
384
|
+
// the hover preview range from the committed selection, providing clear UX feedback.
|
|
385
|
+
// No semantic token exists for this transient visual state.
|
|
390
386
|
'preview-start': [
|
|
391
387
|
'bg-primary-subtle',
|
|
392
388
|
'text-primary-subtle-foreground',
|
|
393
|
-
'rounded-l-
|
|
389
|
+
'rounded-l-pill',
|
|
394
390
|
'rounded-r-none',
|
|
395
391
|
'ring-1',
|
|
396
392
|
'ring-ring',
|
|
@@ -405,7 +401,7 @@ const calendarCellVariants = cva(
|
|
|
405
401
|
'preview-end': [
|
|
406
402
|
'bg-primary-subtle',
|
|
407
403
|
'text-primary-subtle-foreground',
|
|
408
|
-
'rounded-r-
|
|
404
|
+
'rounded-r-pill',
|
|
409
405
|
'rounded-l-none',
|
|
410
406
|
'ring-1',
|
|
411
407
|
'ring-ring',
|
|
@@ -444,9 +440,9 @@ const calendarCellWrapperVariants = cva(['relative', 'flex', 'items-center', 'ju
|
|
|
444
440
|
variants: {
|
|
445
441
|
range: {
|
|
446
442
|
none: [],
|
|
447
|
-
start: ['bg-primary-subtle', 'rounded-l-
|
|
443
|
+
start: ['bg-primary-subtle', 'rounded-l-pill'],
|
|
448
444
|
middle: ['bg-primary-subtle'],
|
|
449
|
-
end: ['bg-primary-subtle', 'rounded-r-
|
|
445
|
+
end: ['bg-primary-subtle', 'rounded-r-pill'],
|
|
450
446
|
single: [],
|
|
451
447
|
},
|
|
452
448
|
},
|
|
@@ -481,7 +477,7 @@ const calendarHeaderButtonVariants = cva([
|
|
|
481
477
|
'justify-center',
|
|
482
478
|
'select-none',
|
|
483
479
|
'transition-colors',
|
|
484
|
-
'duration-
|
|
480
|
+
'duration-normal',
|
|
485
481
|
'text-foreground',
|
|
486
482
|
'focus-visible:outline-[1px]',
|
|
487
483
|
'focus-visible:outline-offset-2',
|
|
@@ -494,7 +490,7 @@ const calendarHeaderButtonVariants = cva([
|
|
|
494
490
|
navigation: [
|
|
495
491
|
'h-9',
|
|
496
492
|
'w-9',
|
|
497
|
-
'rounded-
|
|
493
|
+
'rounded-pill',
|
|
498
494
|
'hover:bg-muted',
|
|
499
495
|
],
|
|
500
496
|
period: [
|
|
@@ -696,17 +692,6 @@ function isYearDisabled(year, minDate, maxDate, adapter) {
|
|
|
696
692
|
function getMultiYearStartingYear(activeYear, yearsPerPage = 24) {
|
|
697
693
|
return Math.floor(activeYear / yearsPerPage) * yearsPerPage;
|
|
698
694
|
}
|
|
699
|
-
/**
|
|
700
|
-
* Joins CSS class strings, filtering out null/undefined values.
|
|
701
|
-
* Unlike `mergeClasses` from utils, this does NOT resolve Tailwind conflicts -
|
|
702
|
-
* it simply concatenates class strings. Use when classes are guaranteed not to conflict.
|
|
703
|
-
*
|
|
704
|
-
* @param classes - Class strings (may include null/undefined)
|
|
705
|
-
* @returns Space-separated class string
|
|
706
|
-
*/
|
|
707
|
-
function joinClasses(...classes) {
|
|
708
|
-
return classes.filter(Boolean).join(' ');
|
|
709
|
-
}
|
|
710
695
|
|
|
711
696
|
/**
|
|
712
697
|
* A single cell in the calendar grid.
|
|
@@ -1292,7 +1277,7 @@ const TOTAL_CELLS = DAYS_PER_WEEK * WEEKS_PER_MONTH;
|
|
|
1292
1277
|
class ComCalendarMonthView extends CalendarViewBase {
|
|
1293
1278
|
view = 'month';
|
|
1294
1279
|
/** Cell components for focus management */
|
|
1295
|
-
cellComponents = viewChildren(
|
|
1280
|
+
cellComponents = viewChildren(ComCalendarCell, ...(ngDevMode ? [{ debugName: "cellComponents" }] : []));
|
|
1296
1281
|
/** Override first day of week (0=Sun, 1=Mon, ..., 6=Sat) */
|
|
1297
1282
|
firstDayOfWeek = input(0, ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : []));
|
|
1298
1283
|
/** Grid index for dual-month display (0=left, 1=right) */
|
|
@@ -1312,8 +1297,8 @@ class ComCalendarMonthView extends CalendarViewBase {
|
|
|
1312
1297
|
/** Grid of day cells (7 columns x 6 rows = 42 cells) */
|
|
1313
1298
|
cells = computed(() => {
|
|
1314
1299
|
const activeDate = this.activeDate();
|
|
1315
|
-
const
|
|
1316
|
-
const
|
|
1300
|
+
const _year = this.dateAdapter.getYear(activeDate);
|
|
1301
|
+
const _month = this.dateAdapter.getMonth(activeDate);
|
|
1317
1302
|
const firstOfMonth = this.dateAdapter.getFirstDayOfMonth(activeDate);
|
|
1318
1303
|
const firstDayOfWeek = this.firstDayOfWeek();
|
|
1319
1304
|
// Calculate the offset to start the grid
|
|
@@ -1441,7 +1426,7 @@ class ComCalendarMonthView extends CalendarViewBase {
|
|
|
1441
1426
|
}
|
|
1442
1427
|
}
|
|
1443
1428
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComCalendarMonthView, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
1444
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComCalendarMonthView, isStandalone: true, selector: "com-calendar-month-view", inputs: { firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, gridIndex: { classPropertyName: "gridIndex", publicName: "gridIndex", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "com-calendar-month-view-host" }, viewQueries: [{ propertyName: "cellComponents", predicate:
|
|
1429
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComCalendarMonthView, isStandalone: true, selector: "com-calendar-month-view", inputs: { firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, gridIndex: { classPropertyName: "gridIndex", publicName: "gridIndex", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "com-calendar-month-view-host" }, viewQueries: [{ propertyName: "cellComponents", predicate: ComCalendarCell, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
1445
1430
|
<div
|
|
1446
1431
|
role="grid"
|
|
1447
1432
|
class="com-calendar-month-view"
|
|
@@ -1554,7 +1539,7 @@ const MONTHS_PER_YEAR = 12;
|
|
|
1554
1539
|
class ComCalendarYearView extends CalendarViewBase {
|
|
1555
1540
|
view = 'year';
|
|
1556
1541
|
/** Cell components for focus management */
|
|
1557
|
-
cellComponents = viewChildren(
|
|
1542
|
+
cellComponents = viewChildren(ComCalendarCell, ...(ngDevMode ? [{ debugName: "cellComponents" }] : []));
|
|
1558
1543
|
/** The year being displayed */
|
|
1559
1544
|
displayYear = computed(() => {
|
|
1560
1545
|
return this.dateAdapter.getYear(this.activeDate());
|
|
@@ -1566,7 +1551,7 @@ class ComCalendarYearView extends CalendarViewBase {
|
|
|
1566
1551
|
const today = this.today();
|
|
1567
1552
|
const todayYear = this.dateAdapter.getYear(today);
|
|
1568
1553
|
const todayMonth = this.dateAdapter.getMonth(today);
|
|
1569
|
-
const
|
|
1554
|
+
const _activeMonth = this.dateAdapter.getMonth(this.activeDate());
|
|
1570
1555
|
const minDate = this.minDate();
|
|
1571
1556
|
const maxDate = this.maxDate();
|
|
1572
1557
|
const dateClass = this.dateClass();
|
|
@@ -1730,7 +1715,7 @@ class ComCalendarYearView extends CalendarViewBase {
|
|
|
1730
1715
|
this.dateAdapter.compareDate(monthDate, endMonth) < 0);
|
|
1731
1716
|
}
|
|
1732
1717
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComCalendarYearView, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
1733
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComCalendarYearView, isStandalone: true, selector: "com-calendar-year-view", host: { classAttribute: "com-calendar-year-view-host" }, viewQueries: [{ propertyName: "cellComponents", predicate:
|
|
1718
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComCalendarYearView, isStandalone: true, selector: "com-calendar-year-view", host: { classAttribute: "com-calendar-year-view-host" }, viewQueries: [{ propertyName: "cellComponents", predicate: ComCalendarCell, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
1734
1719
|
<div
|
|
1735
1720
|
role="grid"
|
|
1736
1721
|
class="com-calendar-year-view"
|
|
@@ -1812,7 +1797,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1812
1797
|
class ComCalendarMultiYearView extends CalendarViewBase {
|
|
1813
1798
|
view = 'multi-year';
|
|
1814
1799
|
/** Cell components for focus management */
|
|
1815
|
-
cellComponents = viewChildren(
|
|
1800
|
+
cellComponents = viewChildren(ComCalendarCell, ...(ngDevMode ? [{ debugName: "cellComponents" }] : []));
|
|
1816
1801
|
/** The first year in the displayed range */
|
|
1817
1802
|
startYear = computed(() => {
|
|
1818
1803
|
const activeYear = this.dateAdapter.getYear(this.activeDate());
|
|
@@ -1827,7 +1812,7 @@ class ComCalendarMultiYearView extends CalendarViewBase {
|
|
|
1827
1812
|
const start = this.startYear();
|
|
1828
1813
|
const today = this.today();
|
|
1829
1814
|
const todayYear = this.dateAdapter.getYear(today);
|
|
1830
|
-
const
|
|
1815
|
+
const _activeYear = this.dateAdapter.getYear(this.activeDate());
|
|
1831
1816
|
const minDate = this.minDate();
|
|
1832
1817
|
const maxDate = this.maxDate();
|
|
1833
1818
|
const dateClass = this.dateClass();
|
|
@@ -1984,7 +1969,7 @@ class ComCalendarMultiYearView extends CalendarViewBase {
|
|
|
1984
1969
|
return year > startYear && year < endYear;
|
|
1985
1970
|
}
|
|
1986
1971
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComCalendarMultiYearView, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
1987
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComCalendarMultiYearView, isStandalone: true, selector: "com-calendar-multi-year-view", host: { classAttribute: "com-calendar-multi-year-view-host" }, viewQueries: [{ propertyName: "cellComponents", predicate:
|
|
1972
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComCalendarMultiYearView, isStandalone: true, selector: "com-calendar-multi-year-view", host: { classAttribute: "com-calendar-multi-year-view-host" }, viewQueries: [{ propertyName: "cellComponents", predicate: ComCalendarCell, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
1988
1973
|
<div
|
|
1989
1974
|
role="grid"
|
|
1990
1975
|
class="com-calendar-multi-year-view"
|
|
@@ -2409,7 +2394,7 @@ class ComCalendar {
|
|
|
2409
2394
|
optional: true,
|
|
2410
2395
|
});
|
|
2411
2396
|
/** Query for month views for cross-grid focus management */
|
|
2412
|
-
monthViews = viewChildren(
|
|
2397
|
+
monthViews = viewChildren(ComCalendarMonthView, ...(ngDevMode ? [{ debugName: "monthViews" }] : []));
|
|
2413
2398
|
/** The date to display and navigate from */
|
|
2414
2399
|
activeDate = input(...(ngDevMode ? [undefined, { debugName: "activeDate" }] : []));
|
|
2415
2400
|
/** The currently selected date or date range */
|
|
@@ -2777,7 +2762,7 @@ class ComCalendar {
|
|
|
2777
2762
|
this.liveAnnouncement.set(`Navigated to ${direction} ${this.periodLabel()}`);
|
|
2778
2763
|
}
|
|
2779
2764
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComCalendar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2780
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComCalendar, isStandalone: true, selector: "com-calendar", inputs: { activeDate: { classPropertyName: "activeDate", publicName: "activeDate", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, dateClass: { classPropertyName: "dateClass", publicName: "dateClass", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, startView: { classPropertyName: "startView", publicName: "startView", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, monthColumns: { classPropertyName: "monthColumns", publicName: "monthColumns", isSignal: true, isRequired: false, transformFunction: null }, cellTemplate: { classPropertyName: "cellTemplate", publicName: "cellTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedChange: "selectedChange", viewChanged: "viewChanged", activeDateChange: "activeDateChange" }, host: { classAttribute: "com-calendar-host block" }, viewQueries: [{ propertyName: "monthViews", predicate:
|
|
2765
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComCalendar, isStandalone: true, selector: "com-calendar", inputs: { activeDate: { classPropertyName: "activeDate", publicName: "activeDate", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, dateClass: { classPropertyName: "dateClass", publicName: "dateClass", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, startView: { classPropertyName: "startView", publicName: "startView", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, monthColumns: { classPropertyName: "monthColumns", publicName: "monthColumns", isSignal: true, isRequired: false, transformFunction: null }, cellTemplate: { classPropertyName: "cellTemplate", publicName: "cellTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedChange: "selectedChange", viewChanged: "viewChanged", activeDateChange: "activeDateChange" }, host: { classAttribute: "com-calendar-host block" }, viewQueries: [{ propertyName: "monthViews", predicate: ComCalendarMonthView, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
2781
2766
|
<div
|
|
2782
2767
|
[class]="calendarClasses()"
|
|
2783
2768
|
role="application"
|
|
@@ -3085,3076 +3070,6 @@ function provideWeekSelectionStrategy() {
|
|
|
3085
3070
|
return { provide: CALENDAR_SELECTION_STRATEGY, useClass: WeekSelectionStrategy };
|
|
3086
3071
|
}
|
|
3087
3072
|
|
|
3088
|
-
/**
|
|
3089
|
-
* Types and interfaces for DatePicker and DateRangePicker components.
|
|
3090
|
-
*/
|
|
3091
|
-
/** Creates a DateRangeValue */
|
|
3092
|
-
function createDateRangeValue(start = null, end = null) {
|
|
3093
|
-
return { start, end };
|
|
3094
|
-
}
|
|
3095
|
-
/** Generates a unique ID for datepicker instances */
|
|
3096
|
-
let datepickerIdCounter = 0;
|
|
3097
|
-
function generateDatepickerId() {
|
|
3098
|
-
return `com-datepicker-${datepickerIdCounter++}`;
|
|
3099
|
-
}
|
|
3100
|
-
|
|
3101
|
-
/**
|
|
3102
|
-
* CVA variants for the datepicker trigger input.
|
|
3103
|
-
* Uses semantic theme tokens for consistent cross-theme styling.
|
|
3104
|
-
*
|
|
3105
|
-
* @tokens `--color-input-background`, `--color-input-foreground`, `--color-input-border`,
|
|
3106
|
-
* `--color-input-placeholder`, `--color-ring`, `--color-muted`, `--color-muted-hover`,
|
|
3107
|
-
* `--color-warn`, `--color-success`, `--color-primary`, `--color-border`,
|
|
3108
|
-
* `--color-disabled`, `--color-disabled-foreground`, `--radius-input`
|
|
3109
|
-
*/
|
|
3110
|
-
const datepickerTriggerVariants = cva([
|
|
3111
|
-
'inline-flex',
|
|
3112
|
-
'items-center',
|
|
3113
|
-
'justify-between',
|
|
3114
|
-
'w-full',
|
|
3115
|
-
'rounded-input',
|
|
3116
|
-
'border',
|
|
3117
|
-
'bg-input-background',
|
|
3118
|
-
'text-input-foreground',
|
|
3119
|
-
'transition-colors',
|
|
3120
|
-
'duration-150',
|
|
3121
|
-
'placeholder:text-input-placeholder',
|
|
3122
|
-
'focus-within:outline-[1px]',
|
|
3123
|
-
'focus-within:outline-offset-2',
|
|
3124
|
-
'focus-within:outline-ring',
|
|
3125
|
-
'cursor-pointer',
|
|
3126
|
-
], {
|
|
3127
|
-
variants: {
|
|
3128
|
-
variant: {
|
|
3129
|
-
default: [
|
|
3130
|
-
'border-input-border',
|
|
3131
|
-
'hover:border-border',
|
|
3132
|
-
],
|
|
3133
|
-
outline: [
|
|
3134
|
-
'border-2',
|
|
3135
|
-
'border-input-border',
|
|
3136
|
-
'hover:border-foreground',
|
|
3137
|
-
],
|
|
3138
|
-
ghost: [
|
|
3139
|
-
'border-transparent',
|
|
3140
|
-
'bg-transparent',
|
|
3141
|
-
'hover:bg-muted',
|
|
3142
|
-
],
|
|
3143
|
-
filled: [
|
|
3144
|
-
'border-transparent',
|
|
3145
|
-
'bg-muted',
|
|
3146
|
-
'hover:bg-muted-hover',
|
|
3147
|
-
],
|
|
3148
|
-
},
|
|
3149
|
-
size: {
|
|
3150
|
-
sm: ['h-8', 'px-2', 'text-xs', 'gap-1'],
|
|
3151
|
-
default: ['h-10', 'px-3', 'text-sm', 'gap-2'],
|
|
3152
|
-
lg: ['h-12', 'px-4', 'text-base', 'gap-3'],
|
|
3153
|
-
},
|
|
3154
|
-
state: {
|
|
3155
|
-
default: [],
|
|
3156
|
-
error: [
|
|
3157
|
-
'border-warn',
|
|
3158
|
-
'focus-within:outline-warn',
|
|
3159
|
-
],
|
|
3160
|
-
success: [
|
|
3161
|
-
'border-success',
|
|
3162
|
-
'focus-within:outline-success',
|
|
3163
|
-
],
|
|
3164
|
-
},
|
|
3165
|
-
open: {
|
|
3166
|
-
true: ['outline-[1px]', 'outline-ring', 'border-primary'],
|
|
3167
|
-
false: [],
|
|
3168
|
-
},
|
|
3169
|
-
},
|
|
3170
|
-
compoundVariants: [
|
|
3171
|
-
{
|
|
3172
|
-
open: true,
|
|
3173
|
-
variant: 'default',
|
|
3174
|
-
class: ['border-primary'],
|
|
3175
|
-
},
|
|
3176
|
-
{
|
|
3177
|
-
open: true,
|
|
3178
|
-
variant: 'outline',
|
|
3179
|
-
class: ['border-primary'],
|
|
3180
|
-
},
|
|
3181
|
-
],
|
|
3182
|
-
defaultVariants: {
|
|
3183
|
-
variant: 'default',
|
|
3184
|
-
size: 'default',
|
|
3185
|
-
state: 'default',
|
|
3186
|
-
open: false,
|
|
3187
|
-
},
|
|
3188
|
-
});
|
|
3189
|
-
/**
|
|
3190
|
-
* CVA variants for the disabled state of datepicker trigger.
|
|
3191
|
-
*
|
|
3192
|
-
* @tokens `--color-disabled`, `--color-disabled-foreground`
|
|
3193
|
-
*/
|
|
3194
|
-
const datepickerDisabledVariants = cva([
|
|
3195
|
-
'cursor-not-allowed',
|
|
3196
|
-
'bg-disabled',
|
|
3197
|
-
'text-disabled-foreground',
|
|
3198
|
-
'hover:border-input-border',
|
|
3199
|
-
'pointer-events-none',
|
|
3200
|
-
]);
|
|
3201
|
-
/**
|
|
3202
|
-
* CVA variants for the datepicker input field.
|
|
3203
|
-
*
|
|
3204
|
-
* @tokens `--color-input-foreground`, `--color-input-placeholder`
|
|
3205
|
-
*/
|
|
3206
|
-
const datepickerInputVariants = cva([
|
|
3207
|
-
'flex-1',
|
|
3208
|
-
'bg-transparent',
|
|
3209
|
-
'outline-none',
|
|
3210
|
-
'placeholder:text-input-placeholder',
|
|
3211
|
-
'disabled:cursor-not-allowed',
|
|
3212
|
-
'min-w-0',
|
|
3213
|
-
'truncate',
|
|
3214
|
-
], {
|
|
3215
|
-
variants: {
|
|
3216
|
-
size: {
|
|
3217
|
-
sm: ['text-xs'],
|
|
3218
|
-
default: ['text-sm'],
|
|
3219
|
-
lg: ['text-base'],
|
|
3220
|
-
},
|
|
3221
|
-
},
|
|
3222
|
-
defaultVariants: {
|
|
3223
|
-
size: 'default',
|
|
3224
|
-
},
|
|
3225
|
-
});
|
|
3226
|
-
/**
|
|
3227
|
-
* CVA variants for the calendar icon button.
|
|
3228
|
-
*
|
|
3229
|
-
* @tokens `--color-ring`, `--color-muted-foreground`, `--radius-interactive-sm`
|
|
3230
|
-
*/
|
|
3231
|
-
const datepickerIconVariants = cva([
|
|
3232
|
-
'inline-flex',
|
|
3233
|
-
'items-center',
|
|
3234
|
-
'justify-center',
|
|
3235
|
-
'shrink-0',
|
|
3236
|
-
'text-muted-foreground',
|
|
3237
|
-
'transition-colors',
|
|
3238
|
-
'hover:text-foreground',
|
|
3239
|
-
'focus-visible:outline-[1px]',
|
|
3240
|
-
'focus-visible:outline-offset-2',
|
|
3241
|
-
'focus-visible:outline-ring',
|
|
3242
|
-
'rounded-interactive-sm',
|
|
3243
|
-
], {
|
|
3244
|
-
variants: {
|
|
3245
|
-
size: {
|
|
3246
|
-
sm: ['h-4', 'w-4'],
|
|
3247
|
-
default: ['h-5', 'w-5'],
|
|
3248
|
-
lg: ['h-6', 'w-6'],
|
|
3249
|
-
},
|
|
3250
|
-
},
|
|
3251
|
-
defaultVariants: {
|
|
3252
|
-
size: 'default',
|
|
3253
|
-
},
|
|
3254
|
-
});
|
|
3255
|
-
/**
|
|
3256
|
-
* CVA variants for the clear button.
|
|
3257
|
-
*
|
|
3258
|
-
* @tokens `--color-ring`, `--color-muted-foreground`, `--color-foreground`, `--radius-interactive-sm`
|
|
3259
|
-
*/
|
|
3260
|
-
const datepickerClearVariants = cva([
|
|
3261
|
-
'inline-flex',
|
|
3262
|
-
'items-center',
|
|
3263
|
-
'justify-center',
|
|
3264
|
-
'rounded-interactive-sm',
|
|
3265
|
-
'text-muted-foreground',
|
|
3266
|
-
'transition-colors',
|
|
3267
|
-
'hover:text-foreground',
|
|
3268
|
-
'focus-visible:outline-[1px]',
|
|
3269
|
-
'focus-visible:outline-offset-2',
|
|
3270
|
-
'focus-visible:outline-ring',
|
|
3271
|
-
'shrink-0',
|
|
3272
|
-
], {
|
|
3273
|
-
variants: {
|
|
3274
|
-
size: {
|
|
3275
|
-
sm: ['h-4', 'w-4'],
|
|
3276
|
-
default: ['h-5', 'w-5'],
|
|
3277
|
-
lg: ['h-6', 'w-6'],
|
|
3278
|
-
},
|
|
3279
|
-
},
|
|
3280
|
-
defaultVariants: {
|
|
3281
|
-
size: 'default',
|
|
3282
|
-
},
|
|
3283
|
-
});
|
|
3284
|
-
/**
|
|
3285
|
-
* CVA variants for the datepicker panel (overlay).
|
|
3286
|
-
*
|
|
3287
|
-
* @tokens `--color-popover`, `--color-popover-foreground`, `--color-border-subtle`, `--radius-overlay`
|
|
3288
|
-
*/
|
|
3289
|
-
const datepickerPanelVariants = cva([
|
|
3290
|
-
'z-50',
|
|
3291
|
-
'overflow-hidden',
|
|
3292
|
-
'rounded-overlay',
|
|
3293
|
-
'border',
|
|
3294
|
-
'border-border-subtle',
|
|
3295
|
-
'bg-popover',
|
|
3296
|
-
'text-popover-foreground',
|
|
3297
|
-
'shadow-lg',
|
|
3298
|
-
'outline-none',
|
|
3299
|
-
], {
|
|
3300
|
-
variants: {
|
|
3301
|
-
size: {
|
|
3302
|
-
sm: ['p-2', 'text-xs'],
|
|
3303
|
-
default: ['p-3', 'text-sm'],
|
|
3304
|
-
lg: ['p-4', 'text-base'],
|
|
3305
|
-
},
|
|
3306
|
-
},
|
|
3307
|
-
defaultVariants: {
|
|
3308
|
-
size: 'default',
|
|
3309
|
-
},
|
|
3310
|
-
});
|
|
3311
|
-
/**
|
|
3312
|
-
* CVA variants for the footer section of the datepicker panel.
|
|
3313
|
-
*
|
|
3314
|
-
* @tokens `--color-border-subtle`
|
|
3315
|
-
*/
|
|
3316
|
-
const datepickerFooterVariants = cva([
|
|
3317
|
-
'flex',
|
|
3318
|
-
'items-center',
|
|
3319
|
-
'justify-between',
|
|
3320
|
-
'border-t',
|
|
3321
|
-
'border-border-subtle',
|
|
3322
|
-
'mt-3',
|
|
3323
|
-
'pt-3',
|
|
3324
|
-
], {
|
|
3325
|
-
variants: {
|
|
3326
|
-
size: {
|
|
3327
|
-
sm: ['mt-2', 'pt-2', 'gap-1'],
|
|
3328
|
-
default: ['mt-3', 'pt-3', 'gap-2'],
|
|
3329
|
-
lg: ['mt-4', 'pt-4', 'gap-3'],
|
|
3330
|
-
},
|
|
3331
|
-
},
|
|
3332
|
-
defaultVariants: {
|
|
3333
|
-
size: 'default',
|
|
3334
|
-
},
|
|
3335
|
-
});
|
|
3336
|
-
/**
|
|
3337
|
-
* CVA variants for the footer buttons.
|
|
3338
|
-
*
|
|
3339
|
-
* @tokens `--color-primary`, `--color-primary-foreground`, `--color-primary-hover`,
|
|
3340
|
-
* `--color-muted`, `--color-muted-foreground`, `--color-muted-hover`, `--radius-control-sm`
|
|
3341
|
-
*/
|
|
3342
|
-
const datepickerFooterButtonVariants = cva([
|
|
3343
|
-
'inline-flex',
|
|
3344
|
-
'items-center',
|
|
3345
|
-
'justify-center',
|
|
3346
|
-
'rounded-control-sm',
|
|
3347
|
-
'font-medium',
|
|
3348
|
-
'transition-colors',
|
|
3349
|
-
'focus-visible:outline-[1px]',
|
|
3350
|
-
'focus-visible:outline-offset-2',
|
|
3351
|
-
'focus-visible:outline-ring',
|
|
3352
|
-
], {
|
|
3353
|
-
variants: {
|
|
3354
|
-
size: {
|
|
3355
|
-
sm: ['h-7', 'px-2', 'text-xs'],
|
|
3356
|
-
default: ['h-8', 'px-3', 'text-sm'],
|
|
3357
|
-
lg: ['h-9', 'px-4', 'text-base'],
|
|
3358
|
-
},
|
|
3359
|
-
variant: {
|
|
3360
|
-
primary: [
|
|
3361
|
-
'bg-primary',
|
|
3362
|
-
'text-primary-foreground',
|
|
3363
|
-
'hover:bg-primary-hover',
|
|
3364
|
-
],
|
|
3365
|
-
secondary: [
|
|
3366
|
-
'bg-muted',
|
|
3367
|
-
'text-muted-foreground',
|
|
3368
|
-
'hover:bg-muted-hover',
|
|
3369
|
-
],
|
|
3370
|
-
},
|
|
3371
|
-
},
|
|
3372
|
-
defaultVariants: {
|
|
3373
|
-
size: 'default',
|
|
3374
|
-
variant: 'secondary',
|
|
3375
|
-
},
|
|
3376
|
-
});
|
|
3377
|
-
/**
|
|
3378
|
-
* CVA variants for the range separator.
|
|
3379
|
-
*
|
|
3380
|
-
* @tokens `--color-muted-foreground`
|
|
3381
|
-
*/
|
|
3382
|
-
const datepickerRangeSeparatorVariants = cva([
|
|
3383
|
-
'inline-flex',
|
|
3384
|
-
'items-center',
|
|
3385
|
-
'justify-center',
|
|
3386
|
-
'text-muted-foreground',
|
|
3387
|
-
'shrink-0',
|
|
3388
|
-
], {
|
|
3389
|
-
variants: {
|
|
3390
|
-
size: {
|
|
3391
|
-
sm: ['px-1', 'text-xs'],
|
|
3392
|
-
default: ['px-2', 'text-sm'],
|
|
3393
|
-
lg: ['px-3', 'text-base'],
|
|
3394
|
-
},
|
|
3395
|
-
},
|
|
3396
|
-
defaultVariants: {
|
|
3397
|
-
size: 'default',
|
|
3398
|
-
},
|
|
3399
|
-
});
|
|
3400
|
-
|
|
3401
|
-
/**
|
|
3402
|
-
* CVA variants for the time picker container.
|
|
3403
|
-
*
|
|
3404
|
-
* @tokens `--color-input-background`, `--color-input-foreground`, `--color-input-border`,
|
|
3405
|
-
* `--color-ring`, `--color-warn`, `--color-success`, `--radius-input`
|
|
3406
|
-
*/
|
|
3407
|
-
const timepickerContainerVariants = cva([
|
|
3408
|
-
'inline-flex',
|
|
3409
|
-
'items-center',
|
|
3410
|
-
'gap-1',
|
|
3411
|
-
'rounded-input',
|
|
3412
|
-
'transition-colors',
|
|
3413
|
-
'duration-150',
|
|
3414
|
-
], {
|
|
3415
|
-
variants: {
|
|
3416
|
-
variant: {
|
|
3417
|
-
standalone: [
|
|
3418
|
-
'border',
|
|
3419
|
-
'border-input-border',
|
|
3420
|
-
'bg-input-background',
|
|
3421
|
-
'text-input-foreground',
|
|
3422
|
-
'focus-within:outline-[1px]',
|
|
3423
|
-
'focus-within:outline-offset-2',
|
|
3424
|
-
'focus-within:outline-ring',
|
|
3425
|
-
],
|
|
3426
|
-
embedded: [
|
|
3427
|
-
'border-transparent',
|
|
3428
|
-
'bg-transparent',
|
|
3429
|
-
'text-foreground',
|
|
3430
|
-
],
|
|
3431
|
-
},
|
|
3432
|
-
size: {
|
|
3433
|
-
sm: ['h-8', 'px-2', 'text-xs', 'gap-0.5'],
|
|
3434
|
-
default: ['h-10', 'px-3', 'text-sm', 'gap-1'],
|
|
3435
|
-
lg: ['h-12', 'px-4', 'text-base', 'gap-1.5'],
|
|
3436
|
-
},
|
|
3437
|
-
state: {
|
|
3438
|
-
default: [],
|
|
3439
|
-
error: [
|
|
3440
|
-
'border-warn',
|
|
3441
|
-
'focus-within:outline-warn',
|
|
3442
|
-
],
|
|
3443
|
-
success: [
|
|
3444
|
-
'border-success',
|
|
3445
|
-
'focus-within:outline-success',
|
|
3446
|
-
],
|
|
3447
|
-
},
|
|
3448
|
-
},
|
|
3449
|
-
compoundVariants: [
|
|
3450
|
-
{
|
|
3451
|
-
variant: 'embedded',
|
|
3452
|
-
state: 'error',
|
|
3453
|
-
class: [],
|
|
3454
|
-
},
|
|
3455
|
-
{
|
|
3456
|
-
variant: 'embedded',
|
|
3457
|
-
state: 'success',
|
|
3458
|
-
class: [],
|
|
3459
|
-
},
|
|
3460
|
-
],
|
|
3461
|
-
defaultVariants: {
|
|
3462
|
-
variant: 'standalone',
|
|
3463
|
-
size: 'default',
|
|
3464
|
-
state: 'default',
|
|
3465
|
-
},
|
|
3466
|
-
});
|
|
3467
|
-
/**
|
|
3468
|
-
* CVA variants for the disabled state of time picker.
|
|
3469
|
-
*
|
|
3470
|
-
* @tokens `--color-disabled`, `--color-disabled-foreground`
|
|
3471
|
-
*/
|
|
3472
|
-
const timepickerDisabledVariants = cva([
|
|
3473
|
-
'cursor-not-allowed',
|
|
3474
|
-
'bg-disabled',
|
|
3475
|
-
'text-disabled-foreground',
|
|
3476
|
-
'pointer-events-none',
|
|
3477
|
-
]);
|
|
3478
|
-
/**
|
|
3479
|
-
* CVA variants for each time segment input.
|
|
3480
|
-
*
|
|
3481
|
-
* @tokens `--color-primary-subtle`, `--color-primary-subtle-foreground`, `--radius-interactive-sm`
|
|
3482
|
-
*/
|
|
3483
|
-
const timepickerSegmentVariants = cva([
|
|
3484
|
-
'bg-transparent',
|
|
3485
|
-
'outline-none',
|
|
3486
|
-
'text-center',
|
|
3487
|
-
'font-mono',
|
|
3488
|
-
'tabular-nums',
|
|
3489
|
-
'select-all',
|
|
3490
|
-
'focus:bg-primary-subtle',
|
|
3491
|
-
'focus:text-primary-subtle-foreground',
|
|
3492
|
-
'focus:rounded-interactive-sm',
|
|
3493
|
-
], {
|
|
3494
|
-
variants: {
|
|
3495
|
-
size: {
|
|
3496
|
-
sm: ['w-5', 'text-xs'],
|
|
3497
|
-
default: ['w-7', 'text-sm'],
|
|
3498
|
-
lg: ['w-9', 'text-base'],
|
|
3499
|
-
},
|
|
3500
|
-
},
|
|
3501
|
-
defaultVariants: {
|
|
3502
|
-
size: 'default',
|
|
3503
|
-
},
|
|
3504
|
-
});
|
|
3505
|
-
/**
|
|
3506
|
-
* CVA variants for the colon separator.
|
|
3507
|
-
*
|
|
3508
|
-
* @tokens `--color-muted-foreground`
|
|
3509
|
-
*/
|
|
3510
|
-
const timepickerSeparatorVariants = cva([
|
|
3511
|
-
'text-muted-foreground',
|
|
3512
|
-
'select-none',
|
|
3513
|
-
'font-mono',
|
|
3514
|
-
], {
|
|
3515
|
-
variants: {
|
|
3516
|
-
size: {
|
|
3517
|
-
sm: ['text-xs'],
|
|
3518
|
-
default: ['text-sm'],
|
|
3519
|
-
lg: ['text-base'],
|
|
3520
|
-
},
|
|
3521
|
-
},
|
|
3522
|
-
defaultVariants: {
|
|
3523
|
-
size: 'default',
|
|
3524
|
-
},
|
|
3525
|
-
});
|
|
3526
|
-
/**
|
|
3527
|
-
* CVA variants for the AM/PM toggle button.
|
|
3528
|
-
*
|
|
3529
|
-
* @tokens `--color-muted`, `--color-muted-foreground`, `--color-muted-hover`, `--color-ring`,
|
|
3530
|
-
* `--radius-control-sm`
|
|
3531
|
-
*/
|
|
3532
|
-
const timepickerPeriodVariants = cva([
|
|
3533
|
-
'inline-flex',
|
|
3534
|
-
'items-center',
|
|
3535
|
-
'justify-center',
|
|
3536
|
-
'rounded-control-sm',
|
|
3537
|
-
'font-medium',
|
|
3538
|
-
'transition-colors',
|
|
3539
|
-
'select-none',
|
|
3540
|
-
'bg-muted',
|
|
3541
|
-
'text-muted-foreground',
|
|
3542
|
-
'hover:bg-muted-hover',
|
|
3543
|
-
'focus-visible:outline-[1px]',
|
|
3544
|
-
'focus-visible:outline-offset-2',
|
|
3545
|
-
'focus-visible:outline-ring',
|
|
3546
|
-
], {
|
|
3547
|
-
variants: {
|
|
3548
|
-
size: {
|
|
3549
|
-
sm: ['h-5', 'px-1', 'text-xs', 'ml-0.5'],
|
|
3550
|
-
default: ['h-6', 'px-1.5', 'text-xs', 'ml-1'],
|
|
3551
|
-
lg: ['h-7', 'px-2', 'text-sm', 'ml-1.5'],
|
|
3552
|
-
},
|
|
3553
|
-
},
|
|
3554
|
-
defaultVariants: {
|
|
3555
|
-
size: 'default',
|
|
3556
|
-
},
|
|
3557
|
-
});
|
|
3558
|
-
/**
|
|
3559
|
-
* CVA variants for the time section divider in datepicker panel.
|
|
3560
|
-
*
|
|
3561
|
-
* @tokens `--color-border-subtle`
|
|
3562
|
-
*/
|
|
3563
|
-
const timepickerSectionVariants = cva([
|
|
3564
|
-
'flex',
|
|
3565
|
-
'items-center',
|
|
3566
|
-
'justify-center',
|
|
3567
|
-
'border-t',
|
|
3568
|
-
'border-border-subtle',
|
|
3569
|
-
], {
|
|
3570
|
-
variants: {
|
|
3571
|
-
size: {
|
|
3572
|
-
sm: ['pt-2', 'mt-2'],
|
|
3573
|
-
default: ['pt-3', 'mt-3'],
|
|
3574
|
-
lg: ['pt-4', 'mt-4'],
|
|
3575
|
-
},
|
|
3576
|
-
},
|
|
3577
|
-
defaultVariants: {
|
|
3578
|
-
size: 'default',
|
|
3579
|
-
},
|
|
3580
|
-
});
|
|
3581
|
-
/**
|
|
3582
|
-
* CVA variants for time labels in date range picker.
|
|
3583
|
-
*
|
|
3584
|
-
* @tokens `--color-muted-foreground`
|
|
3585
|
-
*/
|
|
3586
|
-
const timepickerLabelVariants = cva([
|
|
3587
|
-
'text-muted-foreground',
|
|
3588
|
-
'font-medium',
|
|
3589
|
-
], {
|
|
3590
|
-
variants: {
|
|
3591
|
-
size: {
|
|
3592
|
-
sm: ['text-xs'],
|
|
3593
|
-
default: ['text-xs'],
|
|
3594
|
-
lg: ['text-sm'],
|
|
3595
|
-
},
|
|
3596
|
-
},
|
|
3597
|
-
defaultVariants: {
|
|
3598
|
-
size: 'default',
|
|
3599
|
-
},
|
|
3600
|
-
});
|
|
3601
|
-
|
|
3602
|
-
/**
|
|
3603
|
-
* Types and interfaces for the TimePicker component.
|
|
3604
|
-
*/
|
|
3605
|
-
/** Creates a ComTimeValue */
|
|
3606
|
-
function createTimeValue(hours = 0, minutes = 0, seconds = 0) {
|
|
3607
|
-
return { hours, minutes, seconds };
|
|
3608
|
-
}
|
|
3609
|
-
/**
|
|
3610
|
-
* Compares two ComTimeValue objects.
|
|
3611
|
-
* @returns negative if a < b, 0 if equal, positive if a > b
|
|
3612
|
-
*/
|
|
3613
|
-
function compareTime(a, b) {
|
|
3614
|
-
const diff = a.hours * 3600 + a.minutes * 60 + a.seconds - (b.hours * 3600 + b.minutes * 60 + b.seconds);
|
|
3615
|
-
return diff;
|
|
3616
|
-
}
|
|
3617
|
-
/** Generates a unique ID for time picker instances */
|
|
3618
|
-
let timePickerIdCounter = 0;
|
|
3619
|
-
function generateTimePickerId() {
|
|
3620
|
-
return `com-time-picker-${timePickerIdCounter++}`;
|
|
3621
|
-
}
|
|
3622
|
-
|
|
3623
|
-
/**
|
|
3624
|
-
* Time picker component with segmented numeric input fields.
|
|
3625
|
-
* Supports standalone usage with ControlValueAccessor and embedded usage
|
|
3626
|
-
* within datepicker/date-range-picker panels.
|
|
3627
|
-
*
|
|
3628
|
-
* Visual layout: `[HH] : [MM] : [SS] [AM|PM]`
|
|
3629
|
-
*
|
|
3630
|
-
* @tokens `--color-input-background`, `--color-input-foreground`, `--color-input-border`,
|
|
3631
|
-
* `--color-ring`, `--color-primary-subtle`, `--color-primary-subtle-foreground`,
|
|
3632
|
-
* `--color-muted`, `--color-muted-foreground`, `--color-muted-hover`,
|
|
3633
|
-
* `--color-disabled`, `--color-disabled-foreground`,
|
|
3634
|
-
* `--color-warn`, `--color-success`, `--color-border`
|
|
3635
|
-
*
|
|
3636
|
-
* @example
|
|
3637
|
-
* ```html
|
|
3638
|
-
* <!-- Standalone with reactive forms -->
|
|
3639
|
-
* <com-time-picker formControlName="startTime" />
|
|
3640
|
-
*
|
|
3641
|
-
* <!-- 12-hour format with seconds -->
|
|
3642
|
-
* <com-time-picker formControlName="alarm" [use12HourFormat]="true" [showSeconds]="true" />
|
|
3643
|
-
*
|
|
3644
|
-
* <!-- 15-minute steps -->
|
|
3645
|
-
* <com-time-picker formControlName="meeting" [minuteStep]="15" />
|
|
3646
|
-
*
|
|
3647
|
-
* <!-- Embedded inside datepicker panel -->
|
|
3648
|
-
* <com-time-picker variant="embedded" [value]="time" (timeChange)="onTime($event)" />
|
|
3649
|
-
* ```
|
|
3650
|
-
*/
|
|
3651
|
-
class ComTimePicker {
|
|
3652
|
-
localeId = inject(LOCALE_ID);
|
|
3653
|
-
ngControl = inject(NgControl, { optional: true, self: true });
|
|
3654
|
-
timepickerId = generateTimePickerId();
|
|
3655
|
-
hoursInputRef = viewChild('hoursInput', ...(ngDevMode ? [{ debugName: "hoursInputRef" }] : []));
|
|
3656
|
-
minutesInputRef = viewChild('minutesInput', ...(ngDevMode ? [{ debugName: "minutesInputRef" }] : []));
|
|
3657
|
-
secondsInputRef = viewChild('secondsInput', ...(ngDevMode ? [{ debugName: "secondsInputRef" }] : []));
|
|
3658
|
-
periodButtonRef = viewChild('periodButton', ...(ngDevMode ? [{ debugName: "periodButtonRef" }] : []));
|
|
3659
|
-
// ============ INPUTS ============
|
|
3660
|
-
/** Current time value. */
|
|
3661
|
-
value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
3662
|
-
/** Whether the time picker is disabled. */
|
|
3663
|
-
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
3664
|
-
/** Whether the time picker is required. */
|
|
3665
|
-
required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
|
|
3666
|
-
/** Whether to show the seconds segment. */
|
|
3667
|
-
showSeconds = input(false, ...(ngDevMode ? [{ debugName: "showSeconds" }] : []));
|
|
3668
|
-
/** 12h vs 24h format. `null` = auto-detect from locale. */
|
|
3669
|
-
use12HourFormat = input(null, ...(ngDevMode ? [{ debugName: "use12HourFormat" }] : []));
|
|
3670
|
-
/** Step interval for minutes. */
|
|
3671
|
-
minuteStep = input(1, ...(ngDevMode ? [{ debugName: "minuteStep" }] : []));
|
|
3672
|
-
/** Step interval for seconds. */
|
|
3673
|
-
secondStep = input(1, ...(ngDevMode ? [{ debugName: "secondStep" }] : []));
|
|
3674
|
-
/** Minimum selectable time. */
|
|
3675
|
-
minTime = input(null, ...(ngDevMode ? [{ debugName: "minTime" }] : []));
|
|
3676
|
-
/** Maximum selectable time. */
|
|
3677
|
-
maxTime = input(null, ...(ngDevMode ? [{ debugName: "maxTime" }] : []));
|
|
3678
|
-
/** Visual variant. */
|
|
3679
|
-
variant = input('standalone', ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
3680
|
-
/** Size variant. */
|
|
3681
|
-
size = input('default', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
3682
|
-
/** Validation state. */
|
|
3683
|
-
state = input('default', ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
3684
|
-
/** Accessible label for the group. */
|
|
3685
|
-
ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
3686
|
-
/** Additional CSS classes. */
|
|
3687
|
-
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : {}), alias: 'class' });
|
|
3688
|
-
/** Placeholder text for empty segments. */
|
|
3689
|
-
placeholder = input('--', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
3690
|
-
// ============ OUTPUTS ============
|
|
3691
|
-
/** Emitted when time value changes. */
|
|
3692
|
-
timeChange = output();
|
|
3693
|
-
// ============ INTERNAL STATE ============
|
|
3694
|
-
/** Internal value state. */
|
|
3695
|
-
internalValue = linkedSignal(() => this.value() ?? null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
|
|
3696
|
-
/** Which segment is currently focused. */
|
|
3697
|
-
activeSegment = signal(null, ...(ngDevMode ? [{ debugName: "activeSegment" }] : []));
|
|
3698
|
-
/** Pending typed digits for auto-advance. */
|
|
3699
|
-
pendingDigits = signal('', ...(ngDevMode ? [{ debugName: "pendingDigits" }] : []));
|
|
3700
|
-
/** Live announcements for screen readers. */
|
|
3701
|
-
liveAnnouncement = signal('', ...(ngDevMode ? [{ debugName: "liveAnnouncement" }] : []));
|
|
3702
|
-
// ============ COMPUTED STATE ============
|
|
3703
|
-
/** Whether to use 12-hour format. */
|
|
3704
|
-
is12Hour = computed(() => {
|
|
3705
|
-
const explicit = this.use12HourFormat();
|
|
3706
|
-
if (explicit !== null)
|
|
3707
|
-
return explicit;
|
|
3708
|
-
try {
|
|
3709
|
-
const options = new Intl.DateTimeFormat(this.localeId, { hour: 'numeric' }).resolvedOptions();
|
|
3710
|
-
return options.hour12 === true;
|
|
3711
|
-
}
|
|
3712
|
-
catch {
|
|
3713
|
-
return false;
|
|
3714
|
-
}
|
|
3715
|
-
}, ...(ngDevMode ? [{ debugName: "is12Hour" }] : []));
|
|
3716
|
-
/** Current period (AM/PM). */
|
|
3717
|
-
period = computed(() => {
|
|
3718
|
-
const value = this.internalValue();
|
|
3719
|
-
if (!value)
|
|
3720
|
-
return 'AM';
|
|
3721
|
-
return value.hours >= 12 ? 'PM' : 'AM';
|
|
3722
|
-
}, ...(ngDevMode ? [{ debugName: "period" }] : []));
|
|
3723
|
-
/** Display hours (converted from 24h to 12h when needed). */
|
|
3724
|
-
displayHours = computed(() => {
|
|
3725
|
-
const value = this.internalValue();
|
|
3726
|
-
if (!value)
|
|
3727
|
-
return null;
|
|
3728
|
-
if (!this.is12Hour())
|
|
3729
|
-
return value.hours;
|
|
3730
|
-
const h = value.hours % 12;
|
|
3731
|
-
return h === 0 ? 12 : h;
|
|
3732
|
-
}, ...(ngDevMode ? [{ debugName: "displayHours" }] : []));
|
|
3733
|
-
/** Formatted hours string. */
|
|
3734
|
-
formattedHours = computed(() => {
|
|
3735
|
-
const h = this.displayHours();
|
|
3736
|
-
if (h === null)
|
|
3737
|
-
return '';
|
|
3738
|
-
return h.toString().padStart(2, '0');
|
|
3739
|
-
}, ...(ngDevMode ? [{ debugName: "formattedHours" }] : []));
|
|
3740
|
-
/** Formatted minutes string. */
|
|
3741
|
-
formattedMinutes = computed(() => {
|
|
3742
|
-
const value = this.internalValue();
|
|
3743
|
-
if (!value)
|
|
3744
|
-
return '';
|
|
3745
|
-
return value.minutes.toString().padStart(2, '0');
|
|
3746
|
-
}, ...(ngDevMode ? [{ debugName: "formattedMinutes" }] : []));
|
|
3747
|
-
/** Formatted seconds string. */
|
|
3748
|
-
formattedSeconds = computed(() => {
|
|
3749
|
-
const value = this.internalValue();
|
|
3750
|
-
if (!value)
|
|
3751
|
-
return '';
|
|
3752
|
-
return value.seconds.toString().padStart(2, '0');
|
|
3753
|
-
}, ...(ngDevMode ? [{ debugName: "formattedSeconds" }] : []));
|
|
3754
|
-
/** Container classes. */
|
|
3755
|
-
containerClasses = computed(() => {
|
|
3756
|
-
const base = timepickerContainerVariants({
|
|
3757
|
-
variant: this.variant(),
|
|
3758
|
-
size: this.size(),
|
|
3759
|
-
state: this.state(),
|
|
3760
|
-
});
|
|
3761
|
-
const disabled = this.disabled() ? timepickerDisabledVariants() : '';
|
|
3762
|
-
return joinClasses(base, disabled, this.userClass());
|
|
3763
|
-
}, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
3764
|
-
/** Segment input classes. */
|
|
3765
|
-
segmentClasses = computed(() => {
|
|
3766
|
-
return timepickerSegmentVariants({ size: this.size() });
|
|
3767
|
-
}, ...(ngDevMode ? [{ debugName: "segmentClasses" }] : []));
|
|
3768
|
-
/** Separator classes. */
|
|
3769
|
-
separatorClasses = computed(() => {
|
|
3770
|
-
return timepickerSeparatorVariants({ size: this.size() });
|
|
3771
|
-
}, ...(ngDevMode ? [{ debugName: "separatorClasses" }] : []));
|
|
3772
|
-
/** Period button classes. */
|
|
3773
|
-
periodClasses = computed(() => {
|
|
3774
|
-
return timepickerPeriodVariants({ size: this.size() });
|
|
3775
|
-
}, ...(ngDevMode ? [{ debugName: "periodClasses" }] : []));
|
|
3776
|
-
// ============ CVA CALLBACKS ============
|
|
3777
|
-
onChange = () => { };
|
|
3778
|
-
onTouched = () => { };
|
|
3779
|
-
onValidatorChange = () => { };
|
|
3780
|
-
constructor() {
|
|
3781
|
-
if (this.ngControl) {
|
|
3782
|
-
this.ngControl.valueAccessor = this;
|
|
3783
|
-
}
|
|
3784
|
-
}
|
|
3785
|
-
// ============ CVA IMPLEMENTATION ============
|
|
3786
|
-
writeValue(value) {
|
|
3787
|
-
this.internalValue.set(value);
|
|
3788
|
-
}
|
|
3789
|
-
registerOnChange(fn) {
|
|
3790
|
-
this.onChange = fn;
|
|
3791
|
-
}
|
|
3792
|
-
registerOnTouched(fn) {
|
|
3793
|
-
this.onTouched = fn;
|
|
3794
|
-
}
|
|
3795
|
-
setDisabledState(_isDisabled) {
|
|
3796
|
-
// Disabled state is handled via the disabled input
|
|
3797
|
-
}
|
|
3798
|
-
// ============ VALIDATOR IMPLEMENTATION ============
|
|
3799
|
-
validate() {
|
|
3800
|
-
const value = this.internalValue();
|
|
3801
|
-
if (this.required() && !value) {
|
|
3802
|
-
return { required: true };
|
|
3803
|
-
}
|
|
3804
|
-
if (value) {
|
|
3805
|
-
const minTime = this.minTime();
|
|
3806
|
-
if (minTime && compareTime(value, minTime) < 0) {
|
|
3807
|
-
return { minTime: { min: minTime, actual: value } };
|
|
3808
|
-
}
|
|
3809
|
-
const maxTime = this.maxTime();
|
|
3810
|
-
if (maxTime && compareTime(value, maxTime) > 0) {
|
|
3811
|
-
return { maxTime: { max: maxTime, actual: value } };
|
|
3812
|
-
}
|
|
3813
|
-
}
|
|
3814
|
-
return null;
|
|
3815
|
-
}
|
|
3816
|
-
registerOnValidatorChange(fn) {
|
|
3817
|
-
this.onValidatorChange = fn;
|
|
3818
|
-
}
|
|
3819
|
-
// ============ EVENT HANDLERS ============
|
|
3820
|
-
onSegmentFocus(segment) {
|
|
3821
|
-
this.activeSegment.set(segment);
|
|
3822
|
-
this.pendingDigits.set('');
|
|
3823
|
-
}
|
|
3824
|
-
onSegmentBlur(segment) {
|
|
3825
|
-
this.activeSegment.set(null);
|
|
3826
|
-
this.pendingDigits.set('');
|
|
3827
|
-
this.snapToStep(segment);
|
|
3828
|
-
this.onTouched();
|
|
3829
|
-
}
|
|
3830
|
-
onSegmentInput(event, segment) {
|
|
3831
|
-
// Prevent default browser input handling — we manage value via keydown
|
|
3832
|
-
const input = event.target;
|
|
3833
|
-
const value = this.internalValue();
|
|
3834
|
-
// Restore the formatted value to prevent browser from changing display
|
|
3835
|
-
if (segment === 'hours') {
|
|
3836
|
-
input.value = this.formattedHours();
|
|
3837
|
-
}
|
|
3838
|
-
else if (segment === 'minutes') {
|
|
3839
|
-
input.value = this.formattedMinutes();
|
|
3840
|
-
}
|
|
3841
|
-
else {
|
|
3842
|
-
input.value = this.formattedSeconds();
|
|
3843
|
-
}
|
|
3844
|
-
}
|
|
3845
|
-
onSegmentKeydown(event, segment) {
|
|
3846
|
-
switch (event.key) {
|
|
3847
|
-
case 'ArrowUp':
|
|
3848
|
-
event.preventDefault();
|
|
3849
|
-
this.incrementSegment(segment, 1);
|
|
3850
|
-
break;
|
|
3851
|
-
case 'ArrowDown':
|
|
3852
|
-
event.preventDefault();
|
|
3853
|
-
this.incrementSegment(segment, -1);
|
|
3854
|
-
break;
|
|
3855
|
-
case 'ArrowRight':
|
|
3856
|
-
event.preventDefault();
|
|
3857
|
-
this.focusNextSegment(segment);
|
|
3858
|
-
break;
|
|
3859
|
-
case 'ArrowLeft':
|
|
3860
|
-
event.preventDefault();
|
|
3861
|
-
this.focusPrevSegment(segment);
|
|
3862
|
-
break;
|
|
3863
|
-
case 'Home':
|
|
3864
|
-
event.preventDefault();
|
|
3865
|
-
this.setSegmentToMin(segment);
|
|
3866
|
-
break;
|
|
3867
|
-
case 'End':
|
|
3868
|
-
event.preventDefault();
|
|
3869
|
-
this.setSegmentToMax(segment);
|
|
3870
|
-
break;
|
|
3871
|
-
case 'Backspace':
|
|
3872
|
-
case 'Delete':
|
|
3873
|
-
event.preventDefault();
|
|
3874
|
-
this.pendingDigits.set('');
|
|
3875
|
-
break;
|
|
3876
|
-
default:
|
|
3877
|
-
if (/^[0-9]$/.test(event.key)) {
|
|
3878
|
-
event.preventDefault();
|
|
3879
|
-
this.handleDigitInput(event.key, segment);
|
|
3880
|
-
}
|
|
3881
|
-
break;
|
|
3882
|
-
}
|
|
3883
|
-
}
|
|
3884
|
-
onPeriodKeydown(event) {
|
|
3885
|
-
switch (event.key) {
|
|
3886
|
-
case 'ArrowUp':
|
|
3887
|
-
case 'ArrowDown':
|
|
3888
|
-
event.preventDefault();
|
|
3889
|
-
this.togglePeriod();
|
|
3890
|
-
break;
|
|
3891
|
-
case 'ArrowLeft':
|
|
3892
|
-
event.preventDefault();
|
|
3893
|
-
this.focusPrevSegment('period');
|
|
3894
|
-
break;
|
|
3895
|
-
case 'a':
|
|
3896
|
-
case 'A':
|
|
3897
|
-
event.preventDefault();
|
|
3898
|
-
this.setPeriod('AM');
|
|
3899
|
-
break;
|
|
3900
|
-
case 'p':
|
|
3901
|
-
case 'P':
|
|
3902
|
-
event.preventDefault();
|
|
3903
|
-
this.setPeriod('PM');
|
|
3904
|
-
break;
|
|
3905
|
-
}
|
|
3906
|
-
}
|
|
3907
|
-
togglePeriod() {
|
|
3908
|
-
const value = this.internalValue();
|
|
3909
|
-
if (!value) {
|
|
3910
|
-
this.updateValue({ hours: 12, minutes: 0, seconds: 0 });
|
|
3911
|
-
return;
|
|
3912
|
-
}
|
|
3913
|
-
const newHours = value.hours >= 12 ? value.hours - 12 : value.hours + 12;
|
|
3914
|
-
this.updateValue({ ...value, hours: newHours });
|
|
3915
|
-
}
|
|
3916
|
-
// ============ PRIVATE METHODS ============
|
|
3917
|
-
setPeriod(period) {
|
|
3918
|
-
const value = this.internalValue();
|
|
3919
|
-
if (!value) {
|
|
3920
|
-
const hours = period === 'AM' ? 0 : 12;
|
|
3921
|
-
this.updateValue({ hours, minutes: 0, seconds: 0 });
|
|
3922
|
-
return;
|
|
3923
|
-
}
|
|
3924
|
-
const currentPeriod = this.period();
|
|
3925
|
-
if (currentPeriod === period)
|
|
3926
|
-
return;
|
|
3927
|
-
const newHours = period === 'AM' ? value.hours - 12 : value.hours + 12;
|
|
3928
|
-
this.updateValue({ ...value, hours: newHours });
|
|
3929
|
-
}
|
|
3930
|
-
incrementSegment(segment, direction) {
|
|
3931
|
-
const value = this.internalValue() ?? { hours: 0, minutes: 0, seconds: 0 };
|
|
3932
|
-
const step = segment === 'minutes' ? this.minuteStep() : segment === 'seconds' ? this.secondStep() : 1;
|
|
3933
|
-
const delta = step * direction;
|
|
3934
|
-
let newValue;
|
|
3935
|
-
switch (segment) {
|
|
3936
|
-
case 'hours': {
|
|
3937
|
-
const max = this.is12Hour() ? 12 : 23;
|
|
3938
|
-
const min = this.is12Hour() ? 1 : 0;
|
|
3939
|
-
let h = this.is12Hour() ? (this.displayHours() ?? min) : value.hours;
|
|
3940
|
-
h += delta;
|
|
3941
|
-
// Wrap
|
|
3942
|
-
if (this.is12Hour()) {
|
|
3943
|
-
if (h > max)
|
|
3944
|
-
h = min;
|
|
3945
|
-
if (h < min)
|
|
3946
|
-
h = max;
|
|
3947
|
-
// Convert back to 24h
|
|
3948
|
-
const isPM = this.period() === 'PM';
|
|
3949
|
-
let h24 = h === 12 ? 0 : h;
|
|
3950
|
-
if (isPM)
|
|
3951
|
-
h24 += 12;
|
|
3952
|
-
newValue = { ...value, hours: h24 };
|
|
3953
|
-
}
|
|
3954
|
-
else {
|
|
3955
|
-
if (h > 23)
|
|
3956
|
-
h = 0;
|
|
3957
|
-
if (h < 0)
|
|
3958
|
-
h = 23;
|
|
3959
|
-
newValue = { ...value, hours: h };
|
|
3960
|
-
}
|
|
3961
|
-
break;
|
|
3962
|
-
}
|
|
3963
|
-
case 'minutes': {
|
|
3964
|
-
let m = value.minutes + delta;
|
|
3965
|
-
if (m > 59)
|
|
3966
|
-
m = 0;
|
|
3967
|
-
if (m < 0)
|
|
3968
|
-
m = 59;
|
|
3969
|
-
newValue = { ...value, minutes: m };
|
|
3970
|
-
break;
|
|
3971
|
-
}
|
|
3972
|
-
case 'seconds': {
|
|
3973
|
-
let s = value.seconds + delta;
|
|
3974
|
-
if (s > 59)
|
|
3975
|
-
s = 0;
|
|
3976
|
-
if (s < 0)
|
|
3977
|
-
s = 59;
|
|
3978
|
-
newValue = { ...value, seconds: s };
|
|
3979
|
-
break;
|
|
3980
|
-
}
|
|
3981
|
-
}
|
|
3982
|
-
this.updateValue(newValue);
|
|
3983
|
-
}
|
|
3984
|
-
handleDigitInput(digit, segment) {
|
|
3985
|
-
const pending = this.pendingDigits() + digit;
|
|
3986
|
-
const value = this.internalValue() ?? { hours: 0, minutes: 0, seconds: 0 };
|
|
3987
|
-
let parsed = parseInt(pending, 10);
|
|
3988
|
-
switch (segment) {
|
|
3989
|
-
case 'hours': {
|
|
3990
|
-
const max = this.is12Hour() ? 12 : 23;
|
|
3991
|
-
const min = this.is12Hour() ? 1 : 0;
|
|
3992
|
-
if (parsed > max)
|
|
3993
|
-
parsed = parseInt(digit, 10);
|
|
3994
|
-
if (parsed < min && pending.length >= 2)
|
|
3995
|
-
parsed = min;
|
|
3996
|
-
// Convert to 24h if 12h mode
|
|
3997
|
-
let h24 = parsed;
|
|
3998
|
-
if (this.is12Hour()) {
|
|
3999
|
-
const isPM = this.period() === 'PM';
|
|
4000
|
-
h24 = parsed === 12 ? 0 : parsed;
|
|
4001
|
-
if (isPM)
|
|
4002
|
-
h24 += 12;
|
|
4003
|
-
}
|
|
4004
|
-
this.updateValue({ ...value, hours: h24 });
|
|
4005
|
-
break;
|
|
4006
|
-
}
|
|
4007
|
-
case 'minutes': {
|
|
4008
|
-
if (parsed > 59)
|
|
4009
|
-
parsed = parseInt(digit, 10);
|
|
4010
|
-
this.updateValue({ ...value, minutes: parsed });
|
|
4011
|
-
break;
|
|
4012
|
-
}
|
|
4013
|
-
case 'seconds': {
|
|
4014
|
-
if (parsed > 59)
|
|
4015
|
-
parsed = parseInt(digit, 10);
|
|
4016
|
-
this.updateValue({ ...value, seconds: parsed });
|
|
4017
|
-
break;
|
|
4018
|
-
}
|
|
4019
|
-
}
|
|
4020
|
-
// Auto-advance after 2 digits
|
|
4021
|
-
if (pending.length >= 2) {
|
|
4022
|
-
this.pendingDigits.set('');
|
|
4023
|
-
this.focusNextSegment(segment);
|
|
4024
|
-
}
|
|
4025
|
-
else {
|
|
4026
|
-
this.pendingDigits.set(pending);
|
|
4027
|
-
}
|
|
4028
|
-
}
|
|
4029
|
-
snapToStep(segment) {
|
|
4030
|
-
const value = this.internalValue();
|
|
4031
|
-
if (!value)
|
|
4032
|
-
return;
|
|
4033
|
-
if (segment === 'minutes' && this.minuteStep() > 1) {
|
|
4034
|
-
const step = this.minuteStep();
|
|
4035
|
-
const snapped = Math.round(value.minutes / step) * step;
|
|
4036
|
-
const clamped = Math.min(snapped, 59);
|
|
4037
|
-
if (clamped !== value.minutes) {
|
|
4038
|
-
this.updateValue({ ...value, minutes: clamped });
|
|
4039
|
-
}
|
|
4040
|
-
}
|
|
4041
|
-
if (segment === 'seconds' && this.secondStep() > 1) {
|
|
4042
|
-
const step = this.secondStep();
|
|
4043
|
-
const snapped = Math.round(value.seconds / step) * step;
|
|
4044
|
-
const clamped = Math.min(snapped, 59);
|
|
4045
|
-
if (clamped !== value.seconds) {
|
|
4046
|
-
this.updateValue({ ...value, seconds: clamped });
|
|
4047
|
-
}
|
|
4048
|
-
}
|
|
4049
|
-
}
|
|
4050
|
-
setSegmentToMin(segment) {
|
|
4051
|
-
const value = this.internalValue() ?? { hours: 0, minutes: 0, seconds: 0 };
|
|
4052
|
-
switch (segment) {
|
|
4053
|
-
case 'hours': {
|
|
4054
|
-
if (this.is12Hour()) {
|
|
4055
|
-
// Min display is 1; convert to 24h
|
|
4056
|
-
const isPM = this.period() === 'PM';
|
|
4057
|
-
const h24 = isPM ? 13 : 1;
|
|
4058
|
-
this.updateValue({ ...value, hours: h24 });
|
|
4059
|
-
}
|
|
4060
|
-
else {
|
|
4061
|
-
this.updateValue({ ...value, hours: 0 });
|
|
4062
|
-
}
|
|
4063
|
-
break;
|
|
4064
|
-
}
|
|
4065
|
-
case 'minutes':
|
|
4066
|
-
this.updateValue({ ...value, minutes: 0 });
|
|
4067
|
-
break;
|
|
4068
|
-
case 'seconds':
|
|
4069
|
-
this.updateValue({ ...value, seconds: 0 });
|
|
4070
|
-
break;
|
|
4071
|
-
}
|
|
4072
|
-
}
|
|
4073
|
-
setSegmentToMax(segment) {
|
|
4074
|
-
const value = this.internalValue() ?? { hours: 0, minutes: 0, seconds: 0 };
|
|
4075
|
-
switch (segment) {
|
|
4076
|
-
case 'hours': {
|
|
4077
|
-
if (this.is12Hour()) {
|
|
4078
|
-
// Max display is 12; 12 in 12h = 0 in 24h (for AM) or 12 (for PM)
|
|
4079
|
-
const isPM = this.period() === 'PM';
|
|
4080
|
-
const h24 = isPM ? 12 : 0;
|
|
4081
|
-
this.updateValue({ ...value, hours: h24 });
|
|
4082
|
-
}
|
|
4083
|
-
else {
|
|
4084
|
-
this.updateValue({ ...value, hours: 23 });
|
|
4085
|
-
}
|
|
4086
|
-
break;
|
|
4087
|
-
}
|
|
4088
|
-
case 'minutes':
|
|
4089
|
-
this.updateValue({ ...value, minutes: 59 });
|
|
4090
|
-
break;
|
|
4091
|
-
case 'seconds':
|
|
4092
|
-
this.updateValue({ ...value, seconds: 59 });
|
|
4093
|
-
break;
|
|
4094
|
-
}
|
|
4095
|
-
}
|
|
4096
|
-
focusNextSegment(current) {
|
|
4097
|
-
switch (current) {
|
|
4098
|
-
case 'hours':
|
|
4099
|
-
this.minutesInputRef()?.nativeElement.focus();
|
|
4100
|
-
break;
|
|
4101
|
-
case 'minutes':
|
|
4102
|
-
if (this.showSeconds()) {
|
|
4103
|
-
this.secondsInputRef()?.nativeElement.focus();
|
|
4104
|
-
}
|
|
4105
|
-
else if (this.is12Hour()) {
|
|
4106
|
-
this.periodButtonRef()?.nativeElement.focus();
|
|
4107
|
-
}
|
|
4108
|
-
break;
|
|
4109
|
-
case 'seconds':
|
|
4110
|
-
if (this.is12Hour()) {
|
|
4111
|
-
this.periodButtonRef()?.nativeElement.focus();
|
|
4112
|
-
}
|
|
4113
|
-
break;
|
|
4114
|
-
}
|
|
4115
|
-
}
|
|
4116
|
-
focusPrevSegment(current) {
|
|
4117
|
-
switch (current) {
|
|
4118
|
-
case 'minutes':
|
|
4119
|
-
this.hoursInputRef()?.nativeElement.focus();
|
|
4120
|
-
break;
|
|
4121
|
-
case 'seconds':
|
|
4122
|
-
this.minutesInputRef()?.nativeElement.focus();
|
|
4123
|
-
break;
|
|
4124
|
-
case 'period':
|
|
4125
|
-
if (this.showSeconds()) {
|
|
4126
|
-
this.secondsInputRef()?.nativeElement.focus();
|
|
4127
|
-
}
|
|
4128
|
-
else {
|
|
4129
|
-
this.minutesInputRef()?.nativeElement.focus();
|
|
4130
|
-
}
|
|
4131
|
-
break;
|
|
4132
|
-
}
|
|
4133
|
-
}
|
|
4134
|
-
updateValue(value) {
|
|
4135
|
-
this.internalValue.set(value);
|
|
4136
|
-
this.onChange(value);
|
|
4137
|
-
this.timeChange.emit(value);
|
|
4138
|
-
this.onValidatorChange();
|
|
4139
|
-
if (value) {
|
|
4140
|
-
const h = this.is12Hour()
|
|
4141
|
-
? `${(value.hours % 12 || 12)}:${value.minutes.toString().padStart(2, '0')}${this.showSeconds() ? ':' + value.seconds.toString().padStart(2, '0') : ''} ${value.hours >= 12 ? 'PM' : 'AM'}`
|
|
4142
|
-
: `${value.hours.toString().padStart(2, '0')}:${value.minutes.toString().padStart(2, '0')}${this.showSeconds() ? ':' + value.seconds.toString().padStart(2, '0') : ''}`;
|
|
4143
|
-
this.liveAnnouncement.set(`Time set to ${h}`);
|
|
4144
|
-
}
|
|
4145
|
-
}
|
|
4146
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComTimePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4147
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComTimePicker, isStandalone: true, selector: "com-time-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, use12HourFormat: { classPropertyName: "use12HourFormat", publicName: "use12HourFormat", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null }, secondStep: { classPropertyName: "secondStep", publicName: "secondStep", isSignal: true, isRequired: false, transformFunction: null }, minTime: { classPropertyName: "minTime", publicName: "minTime", isSignal: true, isRequired: false, transformFunction: null }, maxTime: { classPropertyName: "maxTime", publicName: "maxTime", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { timeChange: "timeChange" }, host: { properties: { "class.com-time-picker-disabled": "disabled()", "attr.role": "\"group\"", "attr.aria-label": "ariaLabel() || \"Time picker\"", "attr.aria-disabled": "disabled() || null" }, classAttribute: "com-time-picker-host inline-block" }, viewQueries: [{ propertyName: "hoursInputRef", first: true, predicate: ["hoursInput"], descendants: true, isSignal: true }, { propertyName: "minutesInputRef", first: true, predicate: ["minutesInput"], descendants: true, isSignal: true }, { propertyName: "secondsInputRef", first: true, predicate: ["secondsInput"], descendants: true, isSignal: true }, { propertyName: "periodButtonRef", first: true, predicate: ["periodButton"], descendants: true, isSignal: true }], exportAs: ["comTimePicker"], ngImport: i0, template: `
|
|
4148
|
-
<div [class]="containerClasses()">
|
|
4149
|
-
<!-- Hours -->
|
|
4150
|
-
<input
|
|
4151
|
-
#hoursInput
|
|
4152
|
-
type="text"
|
|
4153
|
-
inputmode="numeric"
|
|
4154
|
-
role="spinbutton"
|
|
4155
|
-
[class]="segmentClasses()"
|
|
4156
|
-
[attr.aria-label]="'Hours'"
|
|
4157
|
-
[attr.aria-valuenow]="displayHours()"
|
|
4158
|
-
[attr.aria-valuemin]="is12Hour() ? 1 : 0"
|
|
4159
|
-
[attr.aria-valuemax]="is12Hour() ? 12 : 23"
|
|
4160
|
-
[value]="formattedHours()"
|
|
4161
|
-
[placeholder]="placeholder()"
|
|
4162
|
-
[disabled]="disabled()"
|
|
4163
|
-
maxlength="2"
|
|
4164
|
-
(keydown)="onSegmentKeydown($event, 'hours')"
|
|
4165
|
-
(input)="onSegmentInput($event, 'hours')"
|
|
4166
|
-
(focus)="onSegmentFocus('hours')"
|
|
4167
|
-
(blur)="onSegmentBlur('hours')"
|
|
4168
|
-
/>
|
|
4169
|
-
|
|
4170
|
-
<span [class]="separatorClasses()" aria-hidden="true">:</span>
|
|
4171
|
-
|
|
4172
|
-
<!-- Minutes -->
|
|
4173
|
-
<input
|
|
4174
|
-
#minutesInput
|
|
4175
|
-
type="text"
|
|
4176
|
-
inputmode="numeric"
|
|
4177
|
-
role="spinbutton"
|
|
4178
|
-
[class]="segmentClasses()"
|
|
4179
|
-
[attr.aria-label]="'Minutes'"
|
|
4180
|
-
[attr.aria-valuenow]="internalValue()?.minutes ?? null"
|
|
4181
|
-
[attr.aria-valuemin]="0"
|
|
4182
|
-
[attr.aria-valuemax]="59"
|
|
4183
|
-
[value]="formattedMinutes()"
|
|
4184
|
-
[placeholder]="placeholder()"
|
|
4185
|
-
[disabled]="disabled()"
|
|
4186
|
-
maxlength="2"
|
|
4187
|
-
(keydown)="onSegmentKeydown($event, 'minutes')"
|
|
4188
|
-
(input)="onSegmentInput($event, 'minutes')"
|
|
4189
|
-
(focus)="onSegmentFocus('minutes')"
|
|
4190
|
-
(blur)="onSegmentBlur('minutes')"
|
|
4191
|
-
/>
|
|
4192
|
-
|
|
4193
|
-
@if (showSeconds()) {
|
|
4194
|
-
<span [class]="separatorClasses()" aria-hidden="true">:</span>
|
|
4195
|
-
|
|
4196
|
-
<!-- Seconds -->
|
|
4197
|
-
<input
|
|
4198
|
-
#secondsInput
|
|
4199
|
-
type="text"
|
|
4200
|
-
inputmode="numeric"
|
|
4201
|
-
role="spinbutton"
|
|
4202
|
-
[class]="segmentClasses()"
|
|
4203
|
-
[attr.aria-label]="'Seconds'"
|
|
4204
|
-
[attr.aria-valuenow]="internalValue()?.seconds ?? null"
|
|
4205
|
-
[attr.aria-valuemin]="0"
|
|
4206
|
-
[attr.aria-valuemax]="59"
|
|
4207
|
-
[value]="formattedSeconds()"
|
|
4208
|
-
[placeholder]="placeholder()"
|
|
4209
|
-
[disabled]="disabled()"
|
|
4210
|
-
maxlength="2"
|
|
4211
|
-
(keydown)="onSegmentKeydown($event, 'seconds')"
|
|
4212
|
-
(input)="onSegmentInput($event, 'seconds')"
|
|
4213
|
-
(focus)="onSegmentFocus('seconds')"
|
|
4214
|
-
(blur)="onSegmentBlur('seconds')"
|
|
4215
|
-
/>
|
|
4216
|
-
}
|
|
4217
|
-
|
|
4218
|
-
@if (is12Hour()) {
|
|
4219
|
-
<button
|
|
4220
|
-
#periodButton
|
|
4221
|
-
type="button"
|
|
4222
|
-
[class]="periodClasses()"
|
|
4223
|
-
[attr.aria-label]="'Toggle AM/PM, currently ' + period()"
|
|
4224
|
-
[disabled]="disabled()"
|
|
4225
|
-
(click)="togglePeriod()"
|
|
4226
|
-
(keydown)="onPeriodKeydown($event)"
|
|
4227
|
-
>
|
|
4228
|
-
{{ period() }}
|
|
4229
|
-
</button>
|
|
4230
|
-
}
|
|
4231
|
-
</div>
|
|
4232
|
-
|
|
4233
|
-
<div class="sr-only" aria-live="polite" aria-atomic="true">
|
|
4234
|
-
{{ liveAnnouncement() }}
|
|
4235
|
-
</div>
|
|
4236
|
-
`, isInline: true, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4237
|
-
}
|
|
4238
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComTimePicker, decorators: [{
|
|
4239
|
-
type: Component,
|
|
4240
|
-
args: [{ selector: 'com-time-picker', exportAs: 'comTimePicker', template: `
|
|
4241
|
-
<div [class]="containerClasses()">
|
|
4242
|
-
<!-- Hours -->
|
|
4243
|
-
<input
|
|
4244
|
-
#hoursInput
|
|
4245
|
-
type="text"
|
|
4246
|
-
inputmode="numeric"
|
|
4247
|
-
role="spinbutton"
|
|
4248
|
-
[class]="segmentClasses()"
|
|
4249
|
-
[attr.aria-label]="'Hours'"
|
|
4250
|
-
[attr.aria-valuenow]="displayHours()"
|
|
4251
|
-
[attr.aria-valuemin]="is12Hour() ? 1 : 0"
|
|
4252
|
-
[attr.aria-valuemax]="is12Hour() ? 12 : 23"
|
|
4253
|
-
[value]="formattedHours()"
|
|
4254
|
-
[placeholder]="placeholder()"
|
|
4255
|
-
[disabled]="disabled()"
|
|
4256
|
-
maxlength="2"
|
|
4257
|
-
(keydown)="onSegmentKeydown($event, 'hours')"
|
|
4258
|
-
(input)="onSegmentInput($event, 'hours')"
|
|
4259
|
-
(focus)="onSegmentFocus('hours')"
|
|
4260
|
-
(blur)="onSegmentBlur('hours')"
|
|
4261
|
-
/>
|
|
4262
|
-
|
|
4263
|
-
<span [class]="separatorClasses()" aria-hidden="true">:</span>
|
|
4264
|
-
|
|
4265
|
-
<!-- Minutes -->
|
|
4266
|
-
<input
|
|
4267
|
-
#minutesInput
|
|
4268
|
-
type="text"
|
|
4269
|
-
inputmode="numeric"
|
|
4270
|
-
role="spinbutton"
|
|
4271
|
-
[class]="segmentClasses()"
|
|
4272
|
-
[attr.aria-label]="'Minutes'"
|
|
4273
|
-
[attr.aria-valuenow]="internalValue()?.minutes ?? null"
|
|
4274
|
-
[attr.aria-valuemin]="0"
|
|
4275
|
-
[attr.aria-valuemax]="59"
|
|
4276
|
-
[value]="formattedMinutes()"
|
|
4277
|
-
[placeholder]="placeholder()"
|
|
4278
|
-
[disabled]="disabled()"
|
|
4279
|
-
maxlength="2"
|
|
4280
|
-
(keydown)="onSegmentKeydown($event, 'minutes')"
|
|
4281
|
-
(input)="onSegmentInput($event, 'minutes')"
|
|
4282
|
-
(focus)="onSegmentFocus('minutes')"
|
|
4283
|
-
(blur)="onSegmentBlur('minutes')"
|
|
4284
|
-
/>
|
|
4285
|
-
|
|
4286
|
-
@if (showSeconds()) {
|
|
4287
|
-
<span [class]="separatorClasses()" aria-hidden="true">:</span>
|
|
4288
|
-
|
|
4289
|
-
<!-- Seconds -->
|
|
4290
|
-
<input
|
|
4291
|
-
#secondsInput
|
|
4292
|
-
type="text"
|
|
4293
|
-
inputmode="numeric"
|
|
4294
|
-
role="spinbutton"
|
|
4295
|
-
[class]="segmentClasses()"
|
|
4296
|
-
[attr.aria-label]="'Seconds'"
|
|
4297
|
-
[attr.aria-valuenow]="internalValue()?.seconds ?? null"
|
|
4298
|
-
[attr.aria-valuemin]="0"
|
|
4299
|
-
[attr.aria-valuemax]="59"
|
|
4300
|
-
[value]="formattedSeconds()"
|
|
4301
|
-
[placeholder]="placeholder()"
|
|
4302
|
-
[disabled]="disabled()"
|
|
4303
|
-
maxlength="2"
|
|
4304
|
-
(keydown)="onSegmentKeydown($event, 'seconds')"
|
|
4305
|
-
(input)="onSegmentInput($event, 'seconds')"
|
|
4306
|
-
(focus)="onSegmentFocus('seconds')"
|
|
4307
|
-
(blur)="onSegmentBlur('seconds')"
|
|
4308
|
-
/>
|
|
4309
|
-
}
|
|
4310
|
-
|
|
4311
|
-
@if (is12Hour()) {
|
|
4312
|
-
<button
|
|
4313
|
-
#periodButton
|
|
4314
|
-
type="button"
|
|
4315
|
-
[class]="periodClasses()"
|
|
4316
|
-
[attr.aria-label]="'Toggle AM/PM, currently ' + period()"
|
|
4317
|
-
[disabled]="disabled()"
|
|
4318
|
-
(click)="togglePeriod()"
|
|
4319
|
-
(keydown)="onPeriodKeydown($event)"
|
|
4320
|
-
>
|
|
4321
|
-
{{ period() }}
|
|
4322
|
-
</button>
|
|
4323
|
-
}
|
|
4324
|
-
</div>
|
|
4325
|
-
|
|
4326
|
-
<div class="sr-only" aria-live="polite" aria-atomic="true">
|
|
4327
|
-
{{ liveAnnouncement() }}
|
|
4328
|
-
</div>
|
|
4329
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
4330
|
-
class: 'com-time-picker-host inline-block',
|
|
4331
|
-
'[class.com-time-picker-disabled]': 'disabled()',
|
|
4332
|
-
'[attr.role]': '"group"',
|
|
4333
|
-
'[attr.aria-label]': 'ariaLabel() || "Time picker"',
|
|
4334
|
-
'[attr.aria-disabled]': 'disabled() || null',
|
|
4335
|
-
}, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
|
|
4336
|
-
}], ctorParameters: () => [], propDecorators: { hoursInputRef: [{ type: i0.ViewChild, args: ['hoursInput', { isSignal: true }] }], minutesInputRef: [{ type: i0.ViewChild, args: ['minutesInput', { isSignal: true }] }], secondsInputRef: [{ type: i0.ViewChild, args: ['secondsInput', { isSignal: true }] }], periodButtonRef: [{ type: i0.ViewChild, args: ['periodButton', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], use12HourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "use12HourFormat", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], secondStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondStep", required: false }] }], minTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "minTime", required: false }] }], maxTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxTime", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], timeChange: [{ type: i0.Output, args: ["timeChange"] }] } });
|
|
4337
|
-
|
|
4338
|
-
/** Default position for the datepicker panel. */
|
|
4339
|
-
const DEFAULT_POSITIONS$1 = [
|
|
4340
|
-
// Below trigger, aligned start
|
|
4341
|
-
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
|
|
4342
|
-
// Above trigger, aligned start
|
|
4343
|
-
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
|
|
4344
|
-
// Below trigger, aligned end
|
|
4345
|
-
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 4 },
|
|
4346
|
-
// Above trigger, aligned end
|
|
4347
|
-
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -4 },
|
|
4348
|
-
];
|
|
4349
|
-
/**
|
|
4350
|
-
* Single date picker component with calendar popup.
|
|
4351
|
-
* Implements ControlValueAccessor for Reactive Forms and Template-driven Forms.
|
|
4352
|
-
*
|
|
4353
|
-
* @tokens `--color-input-background`, `--color-input-foreground`, `--color-input-border`,
|
|
4354
|
-
* `--color-input-placeholder`, `--color-ring`, `--color-muted`, `--color-muted-foreground`,
|
|
4355
|
-
* `--color-popover`, `--color-popover-foreground`, `--color-border-subtle`,
|
|
4356
|
-
* `--color-primary`, `--color-primary-foreground`, `--color-primary-hover`,
|
|
4357
|
-
* `--color-warn`, `--color-success`, `--color-disabled`, `--color-disabled-foreground`
|
|
4358
|
-
*
|
|
4359
|
-
* @example
|
|
4360
|
-
* ```html
|
|
4361
|
-
* <com-datepicker
|
|
4362
|
-
* formControlName="birthDate"
|
|
4363
|
-
* placeholder="Select date..."
|
|
4364
|
-
* [min]="minDate"
|
|
4365
|
-
* [max]="maxDate"
|
|
4366
|
-
* [showTodayButton]="true"
|
|
4367
|
-
* [showClearButton]="true"
|
|
4368
|
-
* />
|
|
4369
|
-
* ```
|
|
4370
|
-
*/
|
|
4371
|
-
class ComDatepicker {
|
|
4372
|
-
elementRef = inject(ElementRef);
|
|
4373
|
-
destroyRef = inject(DestroyRef);
|
|
4374
|
-
overlay = inject(Overlay);
|
|
4375
|
-
viewContainerRef = inject(ViewContainerRef);
|
|
4376
|
-
document = inject(DOCUMENT);
|
|
4377
|
-
dateAdapter = inject(DATE_ADAPTER);
|
|
4378
|
-
/** Optional NgControl for form integration. */
|
|
4379
|
-
ngControl = inject(NgControl, { optional: true, self: true });
|
|
4380
|
-
/** Reference to the trigger element. */
|
|
4381
|
-
triggerRef = viewChild.required('triggerElement');
|
|
4382
|
-
/** Reference to the input element. */
|
|
4383
|
-
inputRef = viewChild.required('inputElement');
|
|
4384
|
-
/** Reference to the panel template. */
|
|
4385
|
-
panelTemplateRef = viewChild.required('panelTemplate');
|
|
4386
|
-
/** Overlay reference. */
|
|
4387
|
-
overlayRef = null;
|
|
4388
|
-
/** Unique ID for the datepicker. */
|
|
4389
|
-
datepickerId = generateDatepickerId();
|
|
4390
|
-
// ============ INPUTS ============
|
|
4391
|
-
/** Current value. */
|
|
4392
|
-
value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
4393
|
-
/** Minimum selectable date. */
|
|
4394
|
-
min = input(null, ...(ngDevMode ? [{ debugName: "min" }] : []));
|
|
4395
|
-
/** Maximum selectable date. */
|
|
4396
|
-
max = input(null, ...(ngDevMode ? [{ debugName: "max" }] : []));
|
|
4397
|
-
/** Custom filter function to disable specific dates. */
|
|
4398
|
-
dateFilter = input(null, ...(ngDevMode ? [{ debugName: "dateFilter" }] : []));
|
|
4399
|
-
/** Date the calendar opens to (defaults to selected or today). */
|
|
4400
|
-
startAt = input(null, ...(ngDevMode ? [{ debugName: "startAt" }] : []));
|
|
4401
|
-
/** Initial calendar view. */
|
|
4402
|
-
startView = input('month', ...(ngDevMode ? [{ debugName: "startView" }] : []));
|
|
4403
|
-
/** First day of week override (0=Sun, 1=Mon, ..., 6=Sat). */
|
|
4404
|
-
firstDayOfWeek = input(null, ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : []));
|
|
4405
|
-
/** Placeholder text. */
|
|
4406
|
-
placeholder = input('Select date...', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
4407
|
-
/** Whether the datepicker is disabled. */
|
|
4408
|
-
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
4409
|
-
/** Whether the datepicker is required. */
|
|
4410
|
-
required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
|
|
4411
|
-
/** Display format for the date. */
|
|
4412
|
-
dateFormat = input('medium', ...(ngDevMode ? [{ debugName: "dateFormat" }] : []));
|
|
4413
|
-
/** Show a clear button in the trigger. */
|
|
4414
|
-
showClearButton = input(false, ...(ngDevMode ? [{ debugName: "showClearButton" }] : []));
|
|
4415
|
-
/** Show a today button in the footer. */
|
|
4416
|
-
showTodayButton = input(false, ...(ngDevMode ? [{ debugName: "showTodayButton" }] : []));
|
|
4417
|
-
/** Show a clear button in the footer. */
|
|
4418
|
-
showFooterClearButton = input(false, ...(ngDevMode ? [{ debugName: "showFooterClearButton" }] : []));
|
|
4419
|
-
/** Don't auto-close on selection. */
|
|
4420
|
-
keepOpen = input(false, ...(ngDevMode ? [{ debugName: "keepOpen" }] : []));
|
|
4421
|
-
/** Allow manual text input. */
|
|
4422
|
-
allowManualInput = input(true, ...(ngDevMode ? [{ debugName: "allowManualInput" }] : []));
|
|
4423
|
-
/** Additional CSS classes for the panel. */
|
|
4424
|
-
panelClass = input('', ...(ngDevMode ? [{ debugName: "panelClass" }] : []));
|
|
4425
|
-
/** Panel width strategy. */
|
|
4426
|
-
panelWidth = input('auto', ...(ngDevMode ? [{ debugName: "panelWidth" }] : []));
|
|
4427
|
-
/** CVA variant for trigger styling. */
|
|
4428
|
-
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
4429
|
-
/** Size variant. */
|
|
4430
|
-
size = input('default', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
4431
|
-
/** Validation state. */
|
|
4432
|
-
state = input('default', ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
4433
|
-
/** Additional CSS classes for the trigger. */
|
|
4434
|
-
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : {}), alias: 'class' });
|
|
4435
|
-
/** Accessible label for the input. */
|
|
4436
|
-
ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
4437
|
-
/** ID of element describing the input. */
|
|
4438
|
-
ariaDescribedBy = input(null, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
|
|
4439
|
-
/** Whether to show the time picker below the calendar. */
|
|
4440
|
-
showTimePicker = input(false, ...(ngDevMode ? [{ debugName: "showTimePicker" }] : []));
|
|
4441
|
-
/** 12h vs 24h format for the time picker. `null` = auto-detect. */
|
|
4442
|
-
use12HourFormat = input(null, ...(ngDevMode ? [{ debugName: "use12HourFormat" }] : []));
|
|
4443
|
-
/** Whether the time picker shows seconds. */
|
|
4444
|
-
showSeconds = input(false, ...(ngDevMode ? [{ debugName: "showSeconds" }] : []));
|
|
4445
|
-
/** Step interval for minutes in the time picker. */
|
|
4446
|
-
minuteStep = input(1, ...(ngDevMode ? [{ debugName: "minuteStep" }] : []));
|
|
4447
|
-
// ============ OUTPUTS ============
|
|
4448
|
-
/** Emitted when a date is selected. */
|
|
4449
|
-
dateChange = output();
|
|
4450
|
-
/** Emitted when the panel opens. */
|
|
4451
|
-
opened = output();
|
|
4452
|
-
/** Emitted when the panel closes. */
|
|
4453
|
-
closed = output();
|
|
4454
|
-
// ============ INTERNAL STATE ============
|
|
4455
|
-
/** Whether the panel is open. */
|
|
4456
|
-
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
4457
|
-
/** Internal value state (managed by CVA or input). */
|
|
4458
|
-
internalValue = linkedSignal(() => this.value() ?? null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
|
|
4459
|
-
/** Calendar active date for navigation. */
|
|
4460
|
-
calendarActiveDate = signal(this.dateAdapter.today(), ...(ngDevMode ? [{ debugName: "calendarActiveDate" }] : []));
|
|
4461
|
-
/** Live announcements for screen readers. */
|
|
4462
|
-
liveAnnouncement = signal('', ...(ngDevMode ? [{ debugName: "liveAnnouncement" }] : []));
|
|
4463
|
-
// ============ COMPUTED STATE ============
|
|
4464
|
-
/** Input element ID. */
|
|
4465
|
-
inputId = computed(() => `${this.datepickerId}-input`, ...(ngDevMode ? [{ debugName: "inputId" }] : []));
|
|
4466
|
-
/** Panel element ID. */
|
|
4467
|
-
panelId = computed(() => `${this.datepickerId}-panel`, ...(ngDevMode ? [{ debugName: "panelId" }] : []));
|
|
4468
|
-
/** Whether the datepicker has a value. */
|
|
4469
|
-
hasValue = computed(() => this.internalValue() !== null, ...(ngDevMode ? [{ debugName: "hasValue" }] : []));
|
|
4470
|
-
/** Icon size based on datepicker size. */
|
|
4471
|
-
iconSize = computed(() => {
|
|
4472
|
-
const sizeMap = {
|
|
4473
|
-
sm: 'sm',
|
|
4474
|
-
default: 'md',
|
|
4475
|
-
lg: 'lg',
|
|
4476
|
-
};
|
|
4477
|
-
return sizeMap[this.size()];
|
|
4478
|
-
}, ...(ngDevMode ? [{ debugName: "iconSize" }] : []));
|
|
4479
|
-
/** Formatted display value. */
|
|
4480
|
-
displayValue = computed(() => {
|
|
4481
|
-
const value = this.internalValue();
|
|
4482
|
-
if (!value)
|
|
4483
|
-
return '';
|
|
4484
|
-
return this.dateAdapter.format(value, this.effectiveDateFormat());
|
|
4485
|
-
}, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
|
|
4486
|
-
/** Computed trigger classes. */
|
|
4487
|
-
triggerClasses = computed(() => {
|
|
4488
|
-
const baseClasses = datepickerTriggerVariants({
|
|
4489
|
-
variant: this.variant(),
|
|
4490
|
-
size: this.size(),
|
|
4491
|
-
state: this.state(),
|
|
4492
|
-
open: this.isOpen(),
|
|
4493
|
-
});
|
|
4494
|
-
const disabledClasses = this.disabled() ? datepickerDisabledVariants() : '';
|
|
4495
|
-
return joinClasses(baseClasses, disabledClasses, this.userClass());
|
|
4496
|
-
}, ...(ngDevMode ? [{ debugName: "triggerClasses" }] : []));
|
|
4497
|
-
/** Computed input classes. */
|
|
4498
|
-
inputClasses = computed(() => {
|
|
4499
|
-
return datepickerInputVariants({ size: this.size() });
|
|
4500
|
-
}, ...(ngDevMode ? [{ debugName: "inputClasses" }] : []));
|
|
4501
|
-
/** Computed icon classes. */
|
|
4502
|
-
iconClasses = computed(() => {
|
|
4503
|
-
return datepickerIconVariants({ size: this.size() });
|
|
4504
|
-
}, ...(ngDevMode ? [{ debugName: "iconClasses" }] : []));
|
|
4505
|
-
/** Computed clear button classes. */
|
|
4506
|
-
clearClasses = computed(() => {
|
|
4507
|
-
return datepickerClearVariants({ size: this.size() });
|
|
4508
|
-
}, ...(ngDevMode ? [{ debugName: "clearClasses" }] : []));
|
|
4509
|
-
/** Computed panel classes. */
|
|
4510
|
-
panelClasses = computed(() => {
|
|
4511
|
-
const baseClasses = datepickerPanelVariants({ size: this.size() });
|
|
4512
|
-
return joinClasses(baseClasses, this.panelClass());
|
|
4513
|
-
}, ...(ngDevMode ? [{ debugName: "panelClasses" }] : []));
|
|
4514
|
-
/** Computed footer classes. */
|
|
4515
|
-
footerClasses = computed(() => {
|
|
4516
|
-
return datepickerFooterVariants({ size: this.size() });
|
|
4517
|
-
}, ...(ngDevMode ? [{ debugName: "footerClasses" }] : []));
|
|
4518
|
-
/** Computed today button classes. */
|
|
4519
|
-
todayButtonClasses = computed(() => {
|
|
4520
|
-
return datepickerFooterButtonVariants({ size: this.size(), variant: 'primary' });
|
|
4521
|
-
}, ...(ngDevMode ? [{ debugName: "todayButtonClasses" }] : []));
|
|
4522
|
-
/** Computed clear button classes (footer). */
|
|
4523
|
-
clearButtonClasses = computed(() => {
|
|
4524
|
-
return datepickerFooterButtonVariants({ size: this.size(), variant: 'secondary' });
|
|
4525
|
-
}, ...(ngDevMode ? [{ debugName: "clearButtonClasses" }] : []));
|
|
4526
|
-
/** Time section divider classes. */
|
|
4527
|
-
timeSectionClasses = computed(() => {
|
|
4528
|
-
return timepickerSectionVariants({ size: this.size() });
|
|
4529
|
-
}, ...(ngDevMode ? [{ debugName: "timeSectionClasses" }] : []));
|
|
4530
|
-
/** Time value derived from the current date value. */
|
|
4531
|
-
timeValue = computed(() => {
|
|
4532
|
-
const date = this.internalValue();
|
|
4533
|
-
if (!date)
|
|
4534
|
-
return null;
|
|
4535
|
-
return createTimeValue(this.dateAdapter.getHours(date), this.dateAdapter.getMinutes(date), this.dateAdapter.getSeconds(date));
|
|
4536
|
-
}, ...(ngDevMode ? [{ debugName: "timeValue" }] : []));
|
|
4537
|
-
/** Effective display format — switches to dateTime when time picker is shown. */
|
|
4538
|
-
effectiveDateFormat = computed(() => {
|
|
4539
|
-
if (this.showTimePicker()) {
|
|
4540
|
-
return this.showSeconds() ? 'dateTimeLong' : 'dateTimeMedium';
|
|
4541
|
-
}
|
|
4542
|
-
return this.dateFormat();
|
|
4543
|
-
}, ...(ngDevMode ? [{ debugName: "effectiveDateFormat" }] : []));
|
|
4544
|
-
/** Whether the panel should stay open (keepOpen or time picker shown). */
|
|
4545
|
-
effectiveKeepOpen = computed(() => {
|
|
4546
|
-
return this.keepOpen() || this.showTimePicker();
|
|
4547
|
-
}, ...(ngDevMode ? [{ debugName: "effectiveKeepOpen" }] : []));
|
|
4548
|
-
// ============ CVA CALLBACKS ============
|
|
4549
|
-
onChange = () => { };
|
|
4550
|
-
onTouched = () => { };
|
|
4551
|
-
onValidatorChange = () => { };
|
|
4552
|
-
constructor() {
|
|
4553
|
-
// Wire up NgControl if present
|
|
4554
|
-
if (this.ngControl) {
|
|
4555
|
-
this.ngControl.valueAccessor = this;
|
|
4556
|
-
}
|
|
4557
|
-
// Sync calendar active date with internal value or startAt
|
|
4558
|
-
effect(() => {
|
|
4559
|
-
const value = this.internalValue();
|
|
4560
|
-
const startAt = this.startAt();
|
|
4561
|
-
if (value) {
|
|
4562
|
-
this.calendarActiveDate.set(value);
|
|
4563
|
-
}
|
|
4564
|
-
else if (startAt) {
|
|
4565
|
-
this.calendarActiveDate.set(startAt);
|
|
4566
|
-
}
|
|
4567
|
-
else {
|
|
4568
|
-
this.calendarActiveDate.set(this.dateAdapter.today());
|
|
4569
|
-
}
|
|
4570
|
-
}, {});
|
|
4571
|
-
}
|
|
4572
|
-
ngOnDestroy() {
|
|
4573
|
-
this.destroyOverlay();
|
|
4574
|
-
}
|
|
4575
|
-
// ============ CVA IMPLEMENTATION ============
|
|
4576
|
-
writeValue(value) {
|
|
4577
|
-
this.internalValue.set(value);
|
|
4578
|
-
}
|
|
4579
|
-
registerOnChange(fn) {
|
|
4580
|
-
this.onChange = fn;
|
|
4581
|
-
}
|
|
4582
|
-
registerOnTouched(fn) {
|
|
4583
|
-
this.onTouched = fn;
|
|
4584
|
-
}
|
|
4585
|
-
setDisabledState(_isDisabled) {
|
|
4586
|
-
// Disabled state is handled via the disabled input
|
|
4587
|
-
}
|
|
4588
|
-
// ============ VALIDATOR IMPLEMENTATION ============
|
|
4589
|
-
validate() {
|
|
4590
|
-
const value = this.internalValue();
|
|
4591
|
-
// Required validation
|
|
4592
|
-
if (this.required() && !value) {
|
|
4593
|
-
return { required: true };
|
|
4594
|
-
}
|
|
4595
|
-
if (value) {
|
|
4596
|
-
// Min validation
|
|
4597
|
-
const min = this.min();
|
|
4598
|
-
if (min && this.dateAdapter.compareDate(value, min) < 0) {
|
|
4599
|
-
return { minDate: { min, actual: value } };
|
|
4600
|
-
}
|
|
4601
|
-
// Max validation
|
|
4602
|
-
const max = this.max();
|
|
4603
|
-
if (max && this.dateAdapter.compareDate(value, max) > 0) {
|
|
4604
|
-
return { maxDate: { max, actual: value } };
|
|
4605
|
-
}
|
|
4606
|
-
// Date filter validation
|
|
4607
|
-
const dateFilter = this.dateFilter();
|
|
4608
|
-
if (dateFilter && !dateFilter(value)) {
|
|
4609
|
-
return { dateFilter: true };
|
|
4610
|
-
}
|
|
4611
|
-
}
|
|
4612
|
-
return null;
|
|
4613
|
-
}
|
|
4614
|
-
registerOnValidatorChange(fn) {
|
|
4615
|
-
this.onValidatorChange = fn;
|
|
4616
|
-
}
|
|
4617
|
-
// ============ PUBLIC METHODS ============
|
|
4618
|
-
/** Opens the datepicker panel. */
|
|
4619
|
-
open() {
|
|
4620
|
-
if (this.disabled() || this.isOpen()) {
|
|
4621
|
-
return;
|
|
4622
|
-
}
|
|
4623
|
-
this.createOverlay();
|
|
4624
|
-
this.isOpen.set(true);
|
|
4625
|
-
this.opened.emit();
|
|
4626
|
-
this.announce('Calendar opened');
|
|
4627
|
-
}
|
|
4628
|
-
/** Closes the datepicker panel. */
|
|
4629
|
-
close() {
|
|
4630
|
-
if (!this.isOpen()) {
|
|
4631
|
-
return;
|
|
4632
|
-
}
|
|
4633
|
-
this.destroyOverlay();
|
|
4634
|
-
this.isOpen.set(false);
|
|
4635
|
-
this.closed.emit();
|
|
4636
|
-
this.onTouched();
|
|
4637
|
-
// Return focus to trigger
|
|
4638
|
-
this.inputRef().nativeElement.focus();
|
|
4639
|
-
}
|
|
4640
|
-
/** Toggles the datepicker panel. */
|
|
4641
|
-
toggle() {
|
|
4642
|
-
if (this.isOpen()) {
|
|
4643
|
-
this.close();
|
|
4644
|
-
}
|
|
4645
|
-
else {
|
|
4646
|
-
this.open();
|
|
4647
|
-
}
|
|
4648
|
-
}
|
|
4649
|
-
/** Clears the selected date. */
|
|
4650
|
-
clear(event) {
|
|
4651
|
-
event?.preventDefault();
|
|
4652
|
-
event?.stopPropagation();
|
|
4653
|
-
this.updateValue(null);
|
|
4654
|
-
this.announce('Date cleared');
|
|
4655
|
-
}
|
|
4656
|
-
/** Selects today's date. */
|
|
4657
|
-
selectToday() {
|
|
4658
|
-
const today = this.dateAdapter.today();
|
|
4659
|
-
this.updateValue(today);
|
|
4660
|
-
if (!this.effectiveKeepOpen()) {
|
|
4661
|
-
this.close();
|
|
4662
|
-
}
|
|
4663
|
-
}
|
|
4664
|
-
// ============ EVENT HANDLERS ============
|
|
4665
|
-
onTriggerClick() {
|
|
4666
|
-
if (!this.disabled()) {
|
|
4667
|
-
this.toggle();
|
|
4668
|
-
}
|
|
4669
|
-
}
|
|
4670
|
-
onTriggerKeydown(event) {
|
|
4671
|
-
switch (event.key) {
|
|
4672
|
-
case 'ArrowDown':
|
|
4673
|
-
case 'ArrowUp':
|
|
4674
|
-
event.preventDefault();
|
|
4675
|
-
this.open();
|
|
4676
|
-
break;
|
|
4677
|
-
case 'Escape':
|
|
4678
|
-
if (this.isOpen()) {
|
|
4679
|
-
event.preventDefault();
|
|
4680
|
-
this.close();
|
|
4681
|
-
}
|
|
4682
|
-
break;
|
|
4683
|
-
}
|
|
4684
|
-
}
|
|
4685
|
-
onInputKeydown(event) {
|
|
4686
|
-
switch (event.key) {
|
|
4687
|
-
case 'Enter':
|
|
4688
|
-
event.preventDefault();
|
|
4689
|
-
if (this.isOpen()) {
|
|
4690
|
-
// Commit manual input
|
|
4691
|
-
this.parseAndSetValue(this.inputRef().nativeElement.value);
|
|
4692
|
-
}
|
|
4693
|
-
else {
|
|
4694
|
-
this.open();
|
|
4695
|
-
}
|
|
4696
|
-
break;
|
|
4697
|
-
case 'Escape':
|
|
4698
|
-
if (this.isOpen()) {
|
|
4699
|
-
event.preventDefault();
|
|
4700
|
-
this.close();
|
|
4701
|
-
}
|
|
4702
|
-
break;
|
|
4703
|
-
case 'ArrowDown':
|
|
4704
|
-
if (!this.isOpen()) {
|
|
4705
|
-
event.preventDefault();
|
|
4706
|
-
this.open();
|
|
4707
|
-
}
|
|
4708
|
-
break;
|
|
4709
|
-
}
|
|
4710
|
-
}
|
|
4711
|
-
onInputChange(event) {
|
|
4712
|
-
if (!this.allowManualInput()) {
|
|
4713
|
-
return;
|
|
4714
|
-
}
|
|
4715
|
-
const input = event.target;
|
|
4716
|
-
// Debounce or wait for blur/enter to actually parse
|
|
4717
|
-
// For now, we just allow typing without immediate parsing
|
|
4718
|
-
}
|
|
4719
|
-
onInputBlur() {
|
|
4720
|
-
if (this.allowManualInput()) {
|
|
4721
|
-
this.parseAndSetValue(this.inputRef().nativeElement.value);
|
|
4722
|
-
}
|
|
4723
|
-
this.onTouched();
|
|
4724
|
-
}
|
|
4725
|
-
onPanelKeydown(event) {
|
|
4726
|
-
switch (event.key) {
|
|
4727
|
-
case 'Escape':
|
|
4728
|
-
event.preventDefault();
|
|
4729
|
-
this.close();
|
|
4730
|
-
break;
|
|
4731
|
-
}
|
|
4732
|
-
}
|
|
4733
|
-
onDateSelected(date) {
|
|
4734
|
-
// Preserve time when selecting a new date if time picker is shown
|
|
4735
|
-
if (this.showTimePicker()) {
|
|
4736
|
-
const currentValue = this.internalValue();
|
|
4737
|
-
if (currentValue) {
|
|
4738
|
-
const withTime = this.dateAdapter.setTime(date, this.dateAdapter.getHours(currentValue), this.dateAdapter.getMinutes(currentValue), this.dateAdapter.getSeconds(currentValue));
|
|
4739
|
-
this.updateValue(withTime);
|
|
4740
|
-
}
|
|
4741
|
-
else {
|
|
4742
|
-
this.updateValue(date);
|
|
4743
|
-
}
|
|
4744
|
-
}
|
|
4745
|
-
else {
|
|
4746
|
-
this.updateValue(date);
|
|
4747
|
-
}
|
|
4748
|
-
if (!this.effectiveKeepOpen()) {
|
|
4749
|
-
this.close();
|
|
4750
|
-
}
|
|
4751
|
-
this.announce(`Selected ${this.dateAdapter.format(date, 'long')}`);
|
|
4752
|
-
}
|
|
4753
|
-
onTimeChange(time) {
|
|
4754
|
-
if (!time)
|
|
4755
|
-
return;
|
|
4756
|
-
const current = this.internalValue() ?? this.dateAdapter.today();
|
|
4757
|
-
const updated = this.dateAdapter.setTime(current, time.hours, time.minutes, time.seconds);
|
|
4758
|
-
this.updateValue(updated);
|
|
4759
|
-
}
|
|
4760
|
-
onActiveDateChange(date) {
|
|
4761
|
-
this.calendarActiveDate.set(date);
|
|
4762
|
-
}
|
|
4763
|
-
// ============ PRIVATE METHODS ============
|
|
4764
|
-
createOverlay() {
|
|
4765
|
-
if (this.overlayRef) {
|
|
4766
|
-
return;
|
|
4767
|
-
}
|
|
4768
|
-
const hostEl = this.elementRef.nativeElement;
|
|
4769
|
-
const positionStrategy = this.overlay
|
|
4770
|
-
.position()
|
|
4771
|
-
.flexibleConnectedTo(hostEl)
|
|
4772
|
-
.withPositions(DEFAULT_POSITIONS$1)
|
|
4773
|
-
.withFlexibleDimensions(false)
|
|
4774
|
-
.withPush(true);
|
|
4775
|
-
this.overlayRef = this.overlay.create({
|
|
4776
|
-
positionStrategy,
|
|
4777
|
-
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
4778
|
-
hasBackdrop: true,
|
|
4779
|
-
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
4780
|
-
});
|
|
4781
|
-
// Attach panel template
|
|
4782
|
-
const portal = new TemplatePortal(this.panelTemplateRef(), this.viewContainerRef);
|
|
4783
|
-
this.overlayRef.attach(portal);
|
|
4784
|
-
// Close on backdrop click
|
|
4785
|
-
this.overlayRef
|
|
4786
|
-
.backdropClick()
|
|
4787
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
4788
|
-
.subscribe(() => this.close());
|
|
4789
|
-
// Close on outside click
|
|
4790
|
-
this.overlayRef
|
|
4791
|
-
.outsidePointerEvents()
|
|
4792
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
4793
|
-
.subscribe(() => this.close());
|
|
4794
|
-
}
|
|
4795
|
-
destroyOverlay() {
|
|
4796
|
-
if (this.overlayRef) {
|
|
4797
|
-
this.overlayRef.dispose();
|
|
4798
|
-
this.overlayRef = null;
|
|
4799
|
-
}
|
|
4800
|
-
}
|
|
4801
|
-
updateValue(value) {
|
|
4802
|
-
this.internalValue.set(value);
|
|
4803
|
-
this.onChange(value);
|
|
4804
|
-
this.dateChange.emit(value);
|
|
4805
|
-
this.onValidatorChange();
|
|
4806
|
-
}
|
|
4807
|
-
parseAndSetValue(inputValue) {
|
|
4808
|
-
if (!inputValue.trim()) {
|
|
4809
|
-
// Empty input - clear if allowed
|
|
4810
|
-
if (this.hasValue()) {
|
|
4811
|
-
this.updateValue(null);
|
|
4812
|
-
}
|
|
4813
|
-
return;
|
|
4814
|
-
}
|
|
4815
|
-
const parsed = this.dateAdapter.parse(inputValue, this.effectiveDateFormat());
|
|
4816
|
-
if (parsed && this.dateAdapter.isValid(parsed)) {
|
|
4817
|
-
// Validate against min/max/filter
|
|
4818
|
-
if (this.isDateValid(parsed)) {
|
|
4819
|
-
this.updateValue(parsed);
|
|
4820
|
-
}
|
|
4821
|
-
else {
|
|
4822
|
-
// Invalid date - revert to current value
|
|
4823
|
-
this.inputRef().nativeElement.value = this.displayValue();
|
|
4824
|
-
}
|
|
4825
|
-
}
|
|
4826
|
-
else {
|
|
4827
|
-
// Parse failed - revert to current value
|
|
4828
|
-
this.inputRef().nativeElement.value = this.displayValue();
|
|
4829
|
-
}
|
|
4830
|
-
}
|
|
4831
|
-
isDateValid(date) {
|
|
4832
|
-
const min = this.min();
|
|
4833
|
-
const max = this.max();
|
|
4834
|
-
const filter = this.dateFilter();
|
|
4835
|
-
if (min && this.dateAdapter.compareDate(date, min) < 0) {
|
|
4836
|
-
return false;
|
|
4837
|
-
}
|
|
4838
|
-
if (max && this.dateAdapter.compareDate(date, max) > 0) {
|
|
4839
|
-
return false;
|
|
4840
|
-
}
|
|
4841
|
-
if (filter && !filter(date)) {
|
|
4842
|
-
return false;
|
|
4843
|
-
}
|
|
4844
|
-
return true;
|
|
4845
|
-
}
|
|
4846
|
-
announce(message) {
|
|
4847
|
-
this.liveAnnouncement.set(message);
|
|
4848
|
-
}
|
|
4849
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComDatepicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4850
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComDatepicker, isStandalone: true, selector: "com-datepicker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", isSignal: true, isRequired: false, transformFunction: null }, startView: { classPropertyName: "startView", publicName: "startView", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, showTodayButton: { classPropertyName: "showTodayButton", publicName: "showTodayButton", isSignal: true, isRequired: false, transformFunction: null }, showFooterClearButton: { classPropertyName: "showFooterClearButton", publicName: "showFooterClearButton", isSignal: true, isRequired: false, transformFunction: null }, keepOpen: { classPropertyName: "keepOpen", publicName: "keepOpen", isSignal: true, isRequired: false, transformFunction: null }, allowManualInput: { classPropertyName: "allowManualInput", publicName: "allowManualInput", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, panelWidth: { classPropertyName: "panelWidth", publicName: "panelWidth", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, showTimePicker: { classPropertyName: "showTimePicker", publicName: "showTimePicker", isSignal: true, isRequired: false, transformFunction: null }, use12HourFormat: { classPropertyName: "use12HourFormat", publicName: "use12HourFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dateChange: "dateChange", opened: "opened", closed: "closed" }, host: { properties: { "class.com-datepicker-disabled": "disabled()", "class.com-datepicker-open": "isOpen()" }, classAttribute: "com-datepicker-host inline-block" }, providers: [
|
|
4851
|
-
SingleSelectionStrategy,
|
|
4852
|
-
{ provide: CALENDAR_SELECTION_STRATEGY, useExisting: SingleSelectionStrategy },
|
|
4853
|
-
], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerElement"], descendants: true, isSignal: true }, { propertyName: "inputRef", first: true, predicate: ["inputElement"], descendants: true, isSignal: true }, { propertyName: "panelTemplateRef", first: true, predicate: ["panelTemplate"], descendants: true, isSignal: true }], exportAs: ["comDatepicker"], ngImport: i0, template: `
|
|
4854
|
-
<!-- Trigger container -->
|
|
4855
|
-
<div
|
|
4856
|
-
#triggerElement
|
|
4857
|
-
[class]="triggerClasses()"
|
|
4858
|
-
[attr.aria-expanded]="isOpen()"
|
|
4859
|
-
[attr.aria-haspopup]="'dialog'"
|
|
4860
|
-
[attr.aria-owns]="panelId()"
|
|
4861
|
-
[attr.aria-disabled]="disabled() || null"
|
|
4862
|
-
(click)="onTriggerClick()"
|
|
4863
|
-
(keydown)="onTriggerKeydown($event)"
|
|
4864
|
-
>
|
|
4865
|
-
<!-- Date input display -->
|
|
4866
|
-
<input
|
|
4867
|
-
#inputElement
|
|
4868
|
-
type="text"
|
|
4869
|
-
[class]="inputClasses()"
|
|
4870
|
-
[value]="displayValue()"
|
|
4871
|
-
[placeholder]="placeholder()"
|
|
4872
|
-
[disabled]="disabled()"
|
|
4873
|
-
[readonly]="!allowManualInput()"
|
|
4874
|
-
[attr.id]="inputId()"
|
|
4875
|
-
[attr.aria-label]="ariaLabel() || placeholder()"
|
|
4876
|
-
[attr.aria-describedby]="ariaDescribedBy() || null"
|
|
4877
|
-
[attr.aria-invalid]="state() === 'error' || null"
|
|
4878
|
-
[attr.aria-required]="required() || null"
|
|
4879
|
-
(input)="onInputChange($event)"
|
|
4880
|
-
(blur)="onInputBlur()"
|
|
4881
|
-
(keydown)="onInputKeydown($event)"
|
|
4882
|
-
/>
|
|
4883
|
-
|
|
4884
|
-
<!-- Clear button -->
|
|
4885
|
-
@if (showClearButton() && hasValue() && !disabled()) {
|
|
4886
|
-
<button
|
|
4887
|
-
type="button"
|
|
4888
|
-
[class]="clearClasses()"
|
|
4889
|
-
[attr.aria-label]="'Clear date'"
|
|
4890
|
-
(click)="clear($event)"
|
|
4891
|
-
>
|
|
4892
|
-
<com-icon name="x" [size]="iconSize()" />
|
|
4893
|
-
</button>
|
|
4894
|
-
}
|
|
4895
|
-
|
|
4896
|
-
<!-- Calendar icon -->
|
|
4897
|
-
<button
|
|
4898
|
-
type="button"
|
|
4899
|
-
[class]="iconClasses()"
|
|
4900
|
-
[attr.aria-label]="isOpen() ? 'Close calendar' : 'Open calendar'"
|
|
4901
|
-
[disabled]="disabled()"
|
|
4902
|
-
tabindex="-1"
|
|
4903
|
-
>
|
|
4904
|
-
<com-icon name="calendar" [size]="iconSize()" />
|
|
4905
|
-
</button>
|
|
4906
|
-
</div>
|
|
4907
|
-
|
|
4908
|
-
<!-- Panel template (rendered in overlay) -->
|
|
4909
|
-
<ng-template #panelTemplate>
|
|
4910
|
-
<div
|
|
4911
|
-
[class]="panelClasses()"
|
|
4912
|
-
[attr.id]="panelId()"
|
|
4913
|
-
role="dialog"
|
|
4914
|
-
aria-modal="true"
|
|
4915
|
-
[attr.aria-label]="'Choose date'"
|
|
4916
|
-
(keydown)="onPanelKeydown($event)"
|
|
4917
|
-
cdkTrapFocus
|
|
4918
|
-
[cdkTrapFocusAutoCapture]="true"
|
|
4919
|
-
>
|
|
4920
|
-
<com-calendar
|
|
4921
|
-
[activeDate]="calendarActiveDate()"
|
|
4922
|
-
[selected]="internalValue()"
|
|
4923
|
-
[minDate]="min()"
|
|
4924
|
-
[maxDate]="max()"
|
|
4925
|
-
[dateFilter]="dateFilter()"
|
|
4926
|
-
[startView]="startView()"
|
|
4927
|
-
[firstDayOfWeek]="firstDayOfWeek()"
|
|
4928
|
-
[bordered]="false"
|
|
4929
|
-
(selectedChange)="onDateSelected($event)"
|
|
4930
|
-
(activeDateChange)="onActiveDateChange($event)"
|
|
4931
|
-
/>
|
|
4932
|
-
|
|
4933
|
-
@if (showTimePicker()) {
|
|
4934
|
-
<div [class]="timeSectionClasses()">
|
|
4935
|
-
<com-time-picker
|
|
4936
|
-
variant="embedded"
|
|
4937
|
-
[size]="size()"
|
|
4938
|
-
[value]="timeValue()"
|
|
4939
|
-
[use12HourFormat]="use12HourFormat()"
|
|
4940
|
-
[showSeconds]="showSeconds()"
|
|
4941
|
-
[minuteStep]="minuteStep()"
|
|
4942
|
-
[disabled]="disabled()"
|
|
4943
|
-
(timeChange)="onTimeChange($event)"
|
|
4944
|
-
/>
|
|
4945
|
-
</div>
|
|
4946
|
-
}
|
|
4947
|
-
|
|
4948
|
-
@if (showTodayButton() || showFooterClearButton() || showTimePicker()) {
|
|
4949
|
-
<div [class]="footerClasses()">
|
|
4950
|
-
@if (showTodayButton()) {
|
|
4951
|
-
<button
|
|
4952
|
-
type="button"
|
|
4953
|
-
[class]="todayButtonClasses()"
|
|
4954
|
-
(click)="selectToday()"
|
|
4955
|
-
>
|
|
4956
|
-
Today
|
|
4957
|
-
</button>
|
|
4958
|
-
}
|
|
4959
|
-
@if (showFooterClearButton()) {
|
|
4960
|
-
<button
|
|
4961
|
-
type="button"
|
|
4962
|
-
[class]="clearButtonClasses()"
|
|
4963
|
-
(click)="clear($event)"
|
|
4964
|
-
>
|
|
4965
|
-
Clear
|
|
4966
|
-
</button>
|
|
4967
|
-
}
|
|
4968
|
-
@if (showTimePicker()) {
|
|
4969
|
-
<button
|
|
4970
|
-
type="button"
|
|
4971
|
-
[class]="todayButtonClasses()"
|
|
4972
|
-
(click)="close()"
|
|
4973
|
-
>
|
|
4974
|
-
Done
|
|
4975
|
-
</button>
|
|
4976
|
-
}
|
|
4977
|
-
</div>
|
|
4978
|
-
}
|
|
4979
|
-
</div>
|
|
4980
|
-
</ng-template>
|
|
4981
|
-
|
|
4982
|
-
<!-- Live announcer region -->
|
|
4983
|
-
<div class="sr-only" aria-live="polite" aria-atomic="true">
|
|
4984
|
-
{{ liveAnnouncement() }}
|
|
4985
|
-
</div>
|
|
4986
|
-
`, isInline: true, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: ComCalendar, selector: "com-calendar", inputs: ["activeDate", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "bordered", "startView", "firstDayOfWeek", "monthColumns", "cellTemplate"], outputs: ["selectedChange", "viewChanged", "activeDateChange"] }, { kind: "component", type: ComIcon, selector: "com-icon", inputs: ["name", "img", "color", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { kind: "component", type: ComTimePicker, selector: "com-time-picker", inputs: ["value", "disabled", "required", "showSeconds", "use12HourFormat", "minuteStep", "secondStep", "minTime", "maxTime", "variant", "size", "state", "ariaLabel", "class", "placeholder"], outputs: ["timeChange"], exportAs: ["comTimePicker"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4987
|
-
}
|
|
4988
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComDatepicker, decorators: [{
|
|
4989
|
-
type: Component,
|
|
4990
|
-
args: [{ selector: 'com-datepicker', exportAs: 'comDatepicker', template: `
|
|
4991
|
-
<!-- Trigger container -->
|
|
4992
|
-
<div
|
|
4993
|
-
#triggerElement
|
|
4994
|
-
[class]="triggerClasses()"
|
|
4995
|
-
[attr.aria-expanded]="isOpen()"
|
|
4996
|
-
[attr.aria-haspopup]="'dialog'"
|
|
4997
|
-
[attr.aria-owns]="panelId()"
|
|
4998
|
-
[attr.aria-disabled]="disabled() || null"
|
|
4999
|
-
(click)="onTriggerClick()"
|
|
5000
|
-
(keydown)="onTriggerKeydown($event)"
|
|
5001
|
-
>
|
|
5002
|
-
<!-- Date input display -->
|
|
5003
|
-
<input
|
|
5004
|
-
#inputElement
|
|
5005
|
-
type="text"
|
|
5006
|
-
[class]="inputClasses()"
|
|
5007
|
-
[value]="displayValue()"
|
|
5008
|
-
[placeholder]="placeholder()"
|
|
5009
|
-
[disabled]="disabled()"
|
|
5010
|
-
[readonly]="!allowManualInput()"
|
|
5011
|
-
[attr.id]="inputId()"
|
|
5012
|
-
[attr.aria-label]="ariaLabel() || placeholder()"
|
|
5013
|
-
[attr.aria-describedby]="ariaDescribedBy() || null"
|
|
5014
|
-
[attr.aria-invalid]="state() === 'error' || null"
|
|
5015
|
-
[attr.aria-required]="required() || null"
|
|
5016
|
-
(input)="onInputChange($event)"
|
|
5017
|
-
(blur)="onInputBlur()"
|
|
5018
|
-
(keydown)="onInputKeydown($event)"
|
|
5019
|
-
/>
|
|
5020
|
-
|
|
5021
|
-
<!-- Clear button -->
|
|
5022
|
-
@if (showClearButton() && hasValue() && !disabled()) {
|
|
5023
|
-
<button
|
|
5024
|
-
type="button"
|
|
5025
|
-
[class]="clearClasses()"
|
|
5026
|
-
[attr.aria-label]="'Clear date'"
|
|
5027
|
-
(click)="clear($event)"
|
|
5028
|
-
>
|
|
5029
|
-
<com-icon name="x" [size]="iconSize()" />
|
|
5030
|
-
</button>
|
|
5031
|
-
}
|
|
5032
|
-
|
|
5033
|
-
<!-- Calendar icon -->
|
|
5034
|
-
<button
|
|
5035
|
-
type="button"
|
|
5036
|
-
[class]="iconClasses()"
|
|
5037
|
-
[attr.aria-label]="isOpen() ? 'Close calendar' : 'Open calendar'"
|
|
5038
|
-
[disabled]="disabled()"
|
|
5039
|
-
tabindex="-1"
|
|
5040
|
-
>
|
|
5041
|
-
<com-icon name="calendar" [size]="iconSize()" />
|
|
5042
|
-
</button>
|
|
5043
|
-
</div>
|
|
5044
|
-
|
|
5045
|
-
<!-- Panel template (rendered in overlay) -->
|
|
5046
|
-
<ng-template #panelTemplate>
|
|
5047
|
-
<div
|
|
5048
|
-
[class]="panelClasses()"
|
|
5049
|
-
[attr.id]="panelId()"
|
|
5050
|
-
role="dialog"
|
|
5051
|
-
aria-modal="true"
|
|
5052
|
-
[attr.aria-label]="'Choose date'"
|
|
5053
|
-
(keydown)="onPanelKeydown($event)"
|
|
5054
|
-
cdkTrapFocus
|
|
5055
|
-
[cdkTrapFocusAutoCapture]="true"
|
|
5056
|
-
>
|
|
5057
|
-
<com-calendar
|
|
5058
|
-
[activeDate]="calendarActiveDate()"
|
|
5059
|
-
[selected]="internalValue()"
|
|
5060
|
-
[minDate]="min()"
|
|
5061
|
-
[maxDate]="max()"
|
|
5062
|
-
[dateFilter]="dateFilter()"
|
|
5063
|
-
[startView]="startView()"
|
|
5064
|
-
[firstDayOfWeek]="firstDayOfWeek()"
|
|
5065
|
-
[bordered]="false"
|
|
5066
|
-
(selectedChange)="onDateSelected($event)"
|
|
5067
|
-
(activeDateChange)="onActiveDateChange($event)"
|
|
5068
|
-
/>
|
|
5069
|
-
|
|
5070
|
-
@if (showTimePicker()) {
|
|
5071
|
-
<div [class]="timeSectionClasses()">
|
|
5072
|
-
<com-time-picker
|
|
5073
|
-
variant="embedded"
|
|
5074
|
-
[size]="size()"
|
|
5075
|
-
[value]="timeValue()"
|
|
5076
|
-
[use12HourFormat]="use12HourFormat()"
|
|
5077
|
-
[showSeconds]="showSeconds()"
|
|
5078
|
-
[minuteStep]="minuteStep()"
|
|
5079
|
-
[disabled]="disabled()"
|
|
5080
|
-
(timeChange)="onTimeChange($event)"
|
|
5081
|
-
/>
|
|
5082
|
-
</div>
|
|
5083
|
-
}
|
|
5084
|
-
|
|
5085
|
-
@if (showTodayButton() || showFooterClearButton() || showTimePicker()) {
|
|
5086
|
-
<div [class]="footerClasses()">
|
|
5087
|
-
@if (showTodayButton()) {
|
|
5088
|
-
<button
|
|
5089
|
-
type="button"
|
|
5090
|
-
[class]="todayButtonClasses()"
|
|
5091
|
-
(click)="selectToday()"
|
|
5092
|
-
>
|
|
5093
|
-
Today
|
|
5094
|
-
</button>
|
|
5095
|
-
}
|
|
5096
|
-
@if (showFooterClearButton()) {
|
|
5097
|
-
<button
|
|
5098
|
-
type="button"
|
|
5099
|
-
[class]="clearButtonClasses()"
|
|
5100
|
-
(click)="clear($event)"
|
|
5101
|
-
>
|
|
5102
|
-
Clear
|
|
5103
|
-
</button>
|
|
5104
|
-
}
|
|
5105
|
-
@if (showTimePicker()) {
|
|
5106
|
-
<button
|
|
5107
|
-
type="button"
|
|
5108
|
-
[class]="todayButtonClasses()"
|
|
5109
|
-
(click)="close()"
|
|
5110
|
-
>
|
|
5111
|
-
Done
|
|
5112
|
-
</button>
|
|
5113
|
-
}
|
|
5114
|
-
</div>
|
|
5115
|
-
}
|
|
5116
|
-
</div>
|
|
5117
|
-
</ng-template>
|
|
5118
|
-
|
|
5119
|
-
<!-- Live announcer region -->
|
|
5120
|
-
<div class="sr-only" aria-live="polite" aria-atomic="true">
|
|
5121
|
-
{{ liveAnnouncement() }}
|
|
5122
|
-
</div>
|
|
5123
|
-
`, imports: [
|
|
5124
|
-
OverlayModule,
|
|
5125
|
-
A11yModule,
|
|
5126
|
-
ComCalendar,
|
|
5127
|
-
ComIcon,
|
|
5128
|
-
ComTimePicker,
|
|
5129
|
-
], providers: [
|
|
5130
|
-
SingleSelectionStrategy,
|
|
5131
|
-
{ provide: CALENDAR_SELECTION_STRATEGY, useExisting: SingleSelectionStrategy },
|
|
5132
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
5133
|
-
class: 'com-datepicker-host inline-block',
|
|
5134
|
-
'[class.com-datepicker-disabled]': 'disabled()',
|
|
5135
|
-
'[class.com-datepicker-open]': 'isOpen()',
|
|
5136
|
-
}, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
|
|
5137
|
-
}], ctorParameters: () => [], propDecorators: { triggerRef: [{ type: i0.ViewChild, args: ['triggerElement', { isSignal: true }] }], inputRef: [{ type: i0.ViewChild, args: ['inputElement', { isSignal: true }] }], panelTemplateRef: [{ type: i0.ViewChild, args: ['panelTemplate', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], startView: [{ type: i0.Input, args: [{ isSignal: true, alias: "startView", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], showClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], showTodayButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTodayButton", required: false }] }], showFooterClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooterClearButton", required: false }] }], keepOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepOpen", required: false }] }], allowManualInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowManualInput", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], panelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWidth", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], showTimePicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTimePicker", required: false }] }], use12HourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "use12HourFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], dateChange: [{ type: i0.Output, args: ["dateChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
5138
|
-
|
|
5139
|
-
/** Default position for the datepicker panel. */
|
|
5140
|
-
const DEFAULT_POSITIONS = [
|
|
5141
|
-
// Below trigger, aligned start
|
|
5142
|
-
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
|
|
5143
|
-
// Above trigger, aligned start
|
|
5144
|
-
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
|
|
5145
|
-
// Below trigger, aligned end
|
|
5146
|
-
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 4 },
|
|
5147
|
-
// Above trigger, aligned end
|
|
5148
|
-
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -4 },
|
|
5149
|
-
];
|
|
5150
|
-
/**
|
|
5151
|
-
* Date range picker component with calendar popup.
|
|
5152
|
-
* Allows selecting a start and end date via a two-click interaction.
|
|
5153
|
-
* Implements ControlValueAccessor for Reactive Forms and Template-driven Forms.
|
|
5154
|
-
*
|
|
5155
|
-
* @tokens `--color-input-background`, `--color-input-foreground`, `--color-input-border`,
|
|
5156
|
-
* `--color-input-placeholder`, `--color-ring`, `--color-muted`, `--color-muted-foreground`,
|
|
5157
|
-
* `--color-popover`, `--color-popover-foreground`, `--color-border-subtle`,
|
|
5158
|
-
* `--color-primary`, `--color-primary-foreground`, `--color-primary-hover`,
|
|
5159
|
-
* `--color-warn`, `--color-success`, `--color-disabled`, `--color-disabled-foreground`
|
|
5160
|
-
*
|
|
5161
|
-
* @example
|
|
5162
|
-
* ```html
|
|
5163
|
-
* <com-date-range-picker
|
|
5164
|
-
* formControlName="dateRange"
|
|
5165
|
-
* startPlaceholder="Start date"
|
|
5166
|
-
* endPlaceholder="End date"
|
|
5167
|
-
* [min]="minDate"
|
|
5168
|
-
* [max]="maxDate"
|
|
5169
|
-
* [showTodayButton]="true"
|
|
5170
|
-
* />
|
|
5171
|
-
* ```
|
|
5172
|
-
*/
|
|
5173
|
-
class ComDateRangePicker {
|
|
5174
|
-
elementRef = inject(ElementRef);
|
|
5175
|
-
destroyRef = inject(DestroyRef);
|
|
5176
|
-
overlay = inject(Overlay);
|
|
5177
|
-
viewContainerRef = inject(ViewContainerRef);
|
|
5178
|
-
document = inject(DOCUMENT);
|
|
5179
|
-
dateAdapter = inject(DATE_ADAPTER);
|
|
5180
|
-
/** Optional NgControl for form integration. */
|
|
5181
|
-
ngControl = inject(NgControl, { optional: true, self: true });
|
|
5182
|
-
/** Reference to the trigger element. */
|
|
5183
|
-
triggerRef = viewChild.required('triggerElement');
|
|
5184
|
-
/** Reference to the start input element. */
|
|
5185
|
-
startInputRef = viewChild.required('startInputElement');
|
|
5186
|
-
/** Reference to the end input element. */
|
|
5187
|
-
endInputRef = viewChild.required('endInputElement');
|
|
5188
|
-
/** Reference to the panel template. */
|
|
5189
|
-
panelTemplateRef = viewChild.required('panelTemplate');
|
|
5190
|
-
/** Overlay reference. */
|
|
5191
|
-
overlayRef = null;
|
|
5192
|
-
/** Unique ID for the datepicker. */
|
|
5193
|
-
datepickerId = generateDatepickerId();
|
|
5194
|
-
// ============ INPUTS ============
|
|
5195
|
-
/** Current value. */
|
|
5196
|
-
value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
5197
|
-
/** Minimum selectable date. */
|
|
5198
|
-
min = input(null, ...(ngDevMode ? [{ debugName: "min" }] : []));
|
|
5199
|
-
/** Maximum selectable date. */
|
|
5200
|
-
max = input(null, ...(ngDevMode ? [{ debugName: "max" }] : []));
|
|
5201
|
-
/** Custom filter function to disable specific dates. */
|
|
5202
|
-
dateFilter = input(null, ...(ngDevMode ? [{ debugName: "dateFilter" }] : []));
|
|
5203
|
-
/** Date the calendar opens to (defaults to start date or today). */
|
|
5204
|
-
startAt = input(null, ...(ngDevMode ? [{ debugName: "startAt" }] : []));
|
|
5205
|
-
/** Initial calendar view. */
|
|
5206
|
-
startView = input('month', ...(ngDevMode ? [{ debugName: "startView" }] : []));
|
|
5207
|
-
/** First day of week override (0=Sun, 1=Mon, ..., 6=Sat). */
|
|
5208
|
-
firstDayOfWeek = input(null, ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : []));
|
|
5209
|
-
/** Placeholder text for start date. */
|
|
5210
|
-
startPlaceholder = input('Start date', ...(ngDevMode ? [{ debugName: "startPlaceholder" }] : []));
|
|
5211
|
-
/** Placeholder text for end date. */
|
|
5212
|
-
endPlaceholder = input('End date', ...(ngDevMode ? [{ debugName: "endPlaceholder" }] : []));
|
|
5213
|
-
/** Whether the datepicker is disabled. */
|
|
5214
|
-
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
5215
|
-
/** Whether the datepicker is required. */
|
|
5216
|
-
required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
|
|
5217
|
-
/** Display format for the date. */
|
|
5218
|
-
dateFormat = input('medium', ...(ngDevMode ? [{ debugName: "dateFormat" }] : []));
|
|
5219
|
-
/** Show a clear button in the trigger. */
|
|
5220
|
-
showClearButton = input(false, ...(ngDevMode ? [{ debugName: "showClearButton" }] : []));
|
|
5221
|
-
/** Show a today button in the footer. */
|
|
5222
|
-
showTodayButton = input(false, ...(ngDevMode ? [{ debugName: "showTodayButton" }] : []));
|
|
5223
|
-
/** Show a clear button in the footer. */
|
|
5224
|
-
showFooterClearButton = input(false, ...(ngDevMode ? [{ debugName: "showFooterClearButton" }] : []));
|
|
5225
|
-
/** Don't auto-close on complete range selection. */
|
|
5226
|
-
keepOpen = input(false, ...(ngDevMode ? [{ debugName: "keepOpen" }] : []));
|
|
5227
|
-
/** Allow manual text input. */
|
|
5228
|
-
allowManualInput = input(true, ...(ngDevMode ? [{ debugName: "allowManualInput" }] : []));
|
|
5229
|
-
/** Additional CSS classes for the panel. */
|
|
5230
|
-
panelClass = input('', ...(ngDevMode ? [{ debugName: "panelClass" }] : []));
|
|
5231
|
-
/** Panel width strategy. */
|
|
5232
|
-
panelWidth = input('auto', ...(ngDevMode ? [{ debugName: "panelWidth" }] : []));
|
|
5233
|
-
/** CVA variant for trigger styling. */
|
|
5234
|
-
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
5235
|
-
/** Size variant. */
|
|
5236
|
-
size = input('default', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
5237
|
-
/** Validation state. */
|
|
5238
|
-
state = input('default', ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
5239
|
-
/** Additional CSS classes for the trigger. */
|
|
5240
|
-
userClass = input('', { ...(ngDevMode ? { debugName: "userClass" } : {}), alias: 'class' });
|
|
5241
|
-
/** Accessible label for the start input. */
|
|
5242
|
-
startAriaLabel = input(null, ...(ngDevMode ? [{ debugName: "startAriaLabel" }] : []));
|
|
5243
|
-
/** Accessible label for the end input. */
|
|
5244
|
-
endAriaLabel = input(null, ...(ngDevMode ? [{ debugName: "endAriaLabel" }] : []));
|
|
5245
|
-
/** Whether to show time pickers below the calendar. */
|
|
5246
|
-
showTimePicker = input(false, ...(ngDevMode ? [{ debugName: "showTimePicker" }] : []));
|
|
5247
|
-
/** 12h vs 24h format for the time pickers. `null` = auto-detect. */
|
|
5248
|
-
use12HourFormat = input(null, ...(ngDevMode ? [{ debugName: "use12HourFormat" }] : []));
|
|
5249
|
-
/** Whether the time pickers show seconds. */
|
|
5250
|
-
showSeconds = input(false, ...(ngDevMode ? [{ debugName: "showSeconds" }] : []));
|
|
5251
|
-
/** Step interval for minutes in the time pickers. */
|
|
5252
|
-
minuteStep = input(1, ...(ngDevMode ? [{ debugName: "minuteStep" }] : []));
|
|
5253
|
-
// ============ OUTPUTS ============
|
|
5254
|
-
/** Emitted when a complete range is selected. */
|
|
5255
|
-
rangeChange = output();
|
|
5256
|
-
/** Emitted when the panel opens. */
|
|
5257
|
-
opened = output();
|
|
5258
|
-
/** Emitted when the panel closes. */
|
|
5259
|
-
closed = output();
|
|
5260
|
-
// ============ INTERNAL STATE ============
|
|
5261
|
-
/** Whether the panel is open. */
|
|
5262
|
-
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
5263
|
-
/** Which input is currently focused. */
|
|
5264
|
-
activeInput = signal(null, ...(ngDevMode ? [{ debugName: "activeInput" }] : []));
|
|
5265
|
-
/** Internal value state (managed by CVA or input). */
|
|
5266
|
-
internalValue = linkedSignal(() => this.value() ?? null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
|
|
5267
|
-
/** Calendar active date for navigation. */
|
|
5268
|
-
calendarActiveDate = signal(this.dateAdapter.today(), ...(ngDevMode ? [{ debugName: "calendarActiveDate" }] : []));
|
|
5269
|
-
/** Live announcements for screen readers. */
|
|
5270
|
-
liveAnnouncement = signal('', ...(ngDevMode ? [{ debugName: "liveAnnouncement" }] : []));
|
|
5271
|
-
// ============ COMPUTED STATE ============
|
|
5272
|
-
/** Start input element ID. */
|
|
5273
|
-
startInputId = computed(() => `${this.datepickerId}-start`, ...(ngDevMode ? [{ debugName: "startInputId" }] : []));
|
|
5274
|
-
/** End input element ID. */
|
|
5275
|
-
endInputId = computed(() => `${this.datepickerId}-end`, ...(ngDevMode ? [{ debugName: "endInputId" }] : []));
|
|
5276
|
-
/** Panel element ID. */
|
|
5277
|
-
panelId = computed(() => `${this.datepickerId}-panel`, ...(ngDevMode ? [{ debugName: "panelId" }] : []));
|
|
5278
|
-
/** Whether the datepicker has a value. */
|
|
5279
|
-
hasValue = computed(() => {
|
|
5280
|
-
const value = this.internalValue();
|
|
5281
|
-
return value !== null && (value.start !== null || value.end !== null);
|
|
5282
|
-
}, ...(ngDevMode ? [{ debugName: "hasValue" }] : []));
|
|
5283
|
-
/** Icon size based on datepicker size. */
|
|
5284
|
-
iconSize = computed(() => {
|
|
5285
|
-
const sizeMap = {
|
|
5286
|
-
sm: 'sm',
|
|
5287
|
-
default: 'md',
|
|
5288
|
-
lg: 'lg',
|
|
5289
|
-
};
|
|
5290
|
-
return sizeMap[this.size()];
|
|
5291
|
-
}, ...(ngDevMode ? [{ debugName: "iconSize" }] : []));
|
|
5292
|
-
/** Calendar selection (converts DateRangeValue to DateRange for calendar). */
|
|
5293
|
-
calendarSelection = computed(() => {
|
|
5294
|
-
const value = this.internalValue();
|
|
5295
|
-
if (!value)
|
|
5296
|
-
return null;
|
|
5297
|
-
return { start: value.start, end: value.end };
|
|
5298
|
-
}, ...(ngDevMode ? [{ debugName: "calendarSelection" }] : []));
|
|
5299
|
-
/** Formatted start display value. */
|
|
5300
|
-
startDisplayValue = computed(() => {
|
|
5301
|
-
const value = this.internalValue();
|
|
5302
|
-
if (!value?.start)
|
|
5303
|
-
return '';
|
|
5304
|
-
return this.dateAdapter.format(value.start, this.effectiveDateFormat());
|
|
5305
|
-
}, ...(ngDevMode ? [{ debugName: "startDisplayValue" }] : []));
|
|
5306
|
-
/** Formatted end display value. */
|
|
5307
|
-
endDisplayValue = computed(() => {
|
|
5308
|
-
const value = this.internalValue();
|
|
5309
|
-
if (!value?.end)
|
|
5310
|
-
return '';
|
|
5311
|
-
return this.dateAdapter.format(value.end, this.effectiveDateFormat());
|
|
5312
|
-
}, ...(ngDevMode ? [{ debugName: "endDisplayValue" }] : []));
|
|
5313
|
-
/** Computed trigger classes. */
|
|
5314
|
-
triggerClasses = computed(() => {
|
|
5315
|
-
const baseClasses = datepickerTriggerVariants({
|
|
5316
|
-
variant: this.variant(),
|
|
5317
|
-
size: this.size(),
|
|
5318
|
-
state: this.state(),
|
|
5319
|
-
open: this.isOpen(),
|
|
5320
|
-
});
|
|
5321
|
-
const disabledClasses = this.disabled() ? datepickerDisabledVariants() : '';
|
|
5322
|
-
return joinClasses(baseClasses, disabledClasses, this.userClass());
|
|
5323
|
-
}, ...(ngDevMode ? [{ debugName: "triggerClasses" }] : []));
|
|
5324
|
-
/** Computed input classes. */
|
|
5325
|
-
inputClasses = computed(() => {
|
|
5326
|
-
return datepickerInputVariants({ size: this.size() });
|
|
5327
|
-
}, ...(ngDevMode ? [{ debugName: "inputClasses" }] : []));
|
|
5328
|
-
/** Computed separator classes. */
|
|
5329
|
-
separatorClasses = computed(() => {
|
|
5330
|
-
return datepickerRangeSeparatorVariants({ size: this.size() });
|
|
5331
|
-
}, ...(ngDevMode ? [{ debugName: "separatorClasses" }] : []));
|
|
5332
|
-
/** Computed icon classes. */
|
|
5333
|
-
iconClasses = computed(() => {
|
|
5334
|
-
return datepickerIconVariants({ size: this.size() });
|
|
5335
|
-
}, ...(ngDevMode ? [{ debugName: "iconClasses" }] : []));
|
|
5336
|
-
/** Computed clear button classes. */
|
|
5337
|
-
clearClasses = computed(() => {
|
|
5338
|
-
return datepickerClearVariants({ size: this.size() });
|
|
5339
|
-
}, ...(ngDevMode ? [{ debugName: "clearClasses" }] : []));
|
|
5340
|
-
/** Computed panel classes. */
|
|
5341
|
-
panelClasses = computed(() => {
|
|
5342
|
-
const baseClasses = datepickerPanelVariants({ size: this.size() });
|
|
5343
|
-
return joinClasses(baseClasses, this.panelClass());
|
|
5344
|
-
}, ...(ngDevMode ? [{ debugName: "panelClasses" }] : []));
|
|
5345
|
-
/** Computed footer classes. */
|
|
5346
|
-
footerClasses = computed(() => {
|
|
5347
|
-
return datepickerFooterVariants({ size: this.size() });
|
|
5348
|
-
}, ...(ngDevMode ? [{ debugName: "footerClasses" }] : []));
|
|
5349
|
-
/** Computed today button classes. */
|
|
5350
|
-
todayButtonClasses = computed(() => {
|
|
5351
|
-
return datepickerFooterButtonVariants({ size: this.size(), variant: 'primary' });
|
|
5352
|
-
}, ...(ngDevMode ? [{ debugName: "todayButtonClasses" }] : []));
|
|
5353
|
-
/** Computed clear button classes (footer). */
|
|
5354
|
-
clearButtonClasses = computed(() => {
|
|
5355
|
-
return datepickerFooterButtonVariants({ size: this.size(), variant: 'secondary' });
|
|
5356
|
-
}, ...(ngDevMode ? [{ debugName: "clearButtonClasses" }] : []));
|
|
5357
|
-
/** Time section divider classes. */
|
|
5358
|
-
timeSectionClasses = computed(() => {
|
|
5359
|
-
return timepickerSectionVariants({ size: this.size() });
|
|
5360
|
-
}, ...(ngDevMode ? [{ debugName: "timeSectionClasses" }] : []));
|
|
5361
|
-
/** Time label classes. */
|
|
5362
|
-
timeLabelClasses = computed(() => {
|
|
5363
|
-
return timepickerLabelVariants({ size: this.size() });
|
|
5364
|
-
}, ...(ngDevMode ? [{ debugName: "timeLabelClasses" }] : []));
|
|
5365
|
-
/** Start time value derived from the start date. */
|
|
5366
|
-
startTimeValue = computed(() => {
|
|
5367
|
-
const value = this.internalValue();
|
|
5368
|
-
if (!value?.start)
|
|
5369
|
-
return null;
|
|
5370
|
-
return createTimeValue(this.dateAdapter.getHours(value.start), this.dateAdapter.getMinutes(value.start), this.dateAdapter.getSeconds(value.start));
|
|
5371
|
-
}, ...(ngDevMode ? [{ debugName: "startTimeValue" }] : []));
|
|
5372
|
-
/** End time value derived from the end date. */
|
|
5373
|
-
endTimeValue = computed(() => {
|
|
5374
|
-
const value = this.internalValue();
|
|
5375
|
-
if (!value?.end)
|
|
5376
|
-
return null;
|
|
5377
|
-
return createTimeValue(this.dateAdapter.getHours(value.end), this.dateAdapter.getMinutes(value.end), this.dateAdapter.getSeconds(value.end));
|
|
5378
|
-
}, ...(ngDevMode ? [{ debugName: "endTimeValue" }] : []));
|
|
5379
|
-
/** Effective display format — switches to dateTime when time picker is shown. */
|
|
5380
|
-
effectiveDateFormat = computed(() => {
|
|
5381
|
-
if (this.showTimePicker()) {
|
|
5382
|
-
return this.showSeconds() ? 'dateTimeLong' : 'dateTimeMedium';
|
|
5383
|
-
}
|
|
5384
|
-
return this.dateFormat();
|
|
5385
|
-
}, ...(ngDevMode ? [{ debugName: "effectiveDateFormat" }] : []));
|
|
5386
|
-
/** Whether the panel should stay open (keepOpen or time picker shown). */
|
|
5387
|
-
effectiveKeepOpen = computed(() => {
|
|
5388
|
-
return this.keepOpen() || this.showTimePicker();
|
|
5389
|
-
}, ...(ngDevMode ? [{ debugName: "effectiveKeepOpen" }] : []));
|
|
5390
|
-
// ============ CVA CALLBACKS ============
|
|
5391
|
-
onChange = () => { };
|
|
5392
|
-
onTouched = () => { };
|
|
5393
|
-
onValidatorChange = () => { };
|
|
5394
|
-
constructor() {
|
|
5395
|
-
// Wire up NgControl if present
|
|
5396
|
-
if (this.ngControl) {
|
|
5397
|
-
this.ngControl.valueAccessor = this;
|
|
5398
|
-
}
|
|
5399
|
-
// Sync calendar active date with internal value or startAt
|
|
5400
|
-
effect(() => {
|
|
5401
|
-
const value = this.internalValue();
|
|
5402
|
-
const startAt = this.startAt();
|
|
5403
|
-
if (value?.start) {
|
|
5404
|
-
this.calendarActiveDate.set(value.start);
|
|
5405
|
-
}
|
|
5406
|
-
else if (startAt) {
|
|
5407
|
-
this.calendarActiveDate.set(startAt);
|
|
5408
|
-
}
|
|
5409
|
-
else {
|
|
5410
|
-
this.calendarActiveDate.set(this.dateAdapter.today());
|
|
5411
|
-
}
|
|
5412
|
-
}, {});
|
|
5413
|
-
}
|
|
5414
|
-
ngOnDestroy() {
|
|
5415
|
-
this.destroyOverlay();
|
|
5416
|
-
}
|
|
5417
|
-
// ============ CVA IMPLEMENTATION ============
|
|
5418
|
-
writeValue(value) {
|
|
5419
|
-
this.internalValue.set(value);
|
|
5420
|
-
}
|
|
5421
|
-
registerOnChange(fn) {
|
|
5422
|
-
this.onChange = fn;
|
|
5423
|
-
}
|
|
5424
|
-
registerOnTouched(fn) {
|
|
5425
|
-
this.onTouched = fn;
|
|
5426
|
-
}
|
|
5427
|
-
setDisabledState(_isDisabled) {
|
|
5428
|
-
// Disabled state is handled via the disabled input
|
|
5429
|
-
}
|
|
5430
|
-
// ============ VALIDATOR IMPLEMENTATION ============
|
|
5431
|
-
validate() {
|
|
5432
|
-
const value = this.internalValue();
|
|
5433
|
-
// Required validation
|
|
5434
|
-
if (this.required() && (!value || (!value.start && !value.end))) {
|
|
5435
|
-
return { required: true };
|
|
5436
|
-
}
|
|
5437
|
-
if (value) {
|
|
5438
|
-
const { start, end } = value;
|
|
5439
|
-
const min = this.min();
|
|
5440
|
-
const max = this.max();
|
|
5441
|
-
const dateFilter = this.dateFilter();
|
|
5442
|
-
// Min validation for start
|
|
5443
|
-
if (start && min && this.dateAdapter.compareDate(start, min) < 0) {
|
|
5444
|
-
return { minDate: { min, actual: start } };
|
|
5445
|
-
}
|
|
5446
|
-
// Max validation for end
|
|
5447
|
-
if (end && max && this.dateAdapter.compareDate(end, max) > 0) {
|
|
5448
|
-
return { maxDate: { max, actual: end } };
|
|
5449
|
-
}
|
|
5450
|
-
// Date filter validation
|
|
5451
|
-
if (start && dateFilter && !dateFilter(start)) {
|
|
5452
|
-
return { dateFilter: { date: start } };
|
|
5453
|
-
}
|
|
5454
|
-
if (end && dateFilter && !dateFilter(end)) {
|
|
5455
|
-
return { dateFilter: { date: end } };
|
|
5456
|
-
}
|
|
5457
|
-
// Range validation (start must be before or equal to end)
|
|
5458
|
-
if (start && end && this.dateAdapter.compareDate(start, end) > 0) {
|
|
5459
|
-
return { rangeInvalid: { start, end } };
|
|
5460
|
-
}
|
|
5461
|
-
}
|
|
5462
|
-
return null;
|
|
5463
|
-
}
|
|
5464
|
-
registerOnValidatorChange(fn) {
|
|
5465
|
-
this.onValidatorChange = fn;
|
|
5466
|
-
}
|
|
5467
|
-
// ============ PUBLIC METHODS ============
|
|
5468
|
-
/** Opens the datepicker panel. */
|
|
5469
|
-
open() {
|
|
5470
|
-
if (this.disabled() || this.isOpen()) {
|
|
5471
|
-
return;
|
|
5472
|
-
}
|
|
5473
|
-
this.createOverlay();
|
|
5474
|
-
this.isOpen.set(true);
|
|
5475
|
-
this.opened.emit();
|
|
5476
|
-
this.announce('Calendar opened. Select a start date.');
|
|
5477
|
-
}
|
|
5478
|
-
/** Closes the datepicker panel. */
|
|
5479
|
-
close() {
|
|
5480
|
-
if (!this.isOpen()) {
|
|
5481
|
-
return;
|
|
5482
|
-
}
|
|
5483
|
-
this.destroyOverlay();
|
|
5484
|
-
this.isOpen.set(false);
|
|
5485
|
-
this.closed.emit();
|
|
5486
|
-
this.onTouched();
|
|
5487
|
-
// Return focus to appropriate input
|
|
5488
|
-
const activeInput = this.activeInput();
|
|
5489
|
-
if (activeInput === 'end') {
|
|
5490
|
-
this.endInputRef().nativeElement.focus();
|
|
5491
|
-
}
|
|
5492
|
-
else {
|
|
5493
|
-
this.startInputRef().nativeElement.focus();
|
|
5494
|
-
}
|
|
5495
|
-
}
|
|
5496
|
-
/** Toggles the datepicker panel. */
|
|
5497
|
-
toggle() {
|
|
5498
|
-
if (this.isOpen()) {
|
|
5499
|
-
this.close();
|
|
5500
|
-
}
|
|
5501
|
-
else {
|
|
5502
|
-
this.open();
|
|
5503
|
-
}
|
|
5504
|
-
}
|
|
5505
|
-
/** Clears the selected date range. */
|
|
5506
|
-
clear(event) {
|
|
5507
|
-
event?.preventDefault();
|
|
5508
|
-
event?.stopPropagation();
|
|
5509
|
-
this.updateValue(null);
|
|
5510
|
-
this.announce('Date range cleared');
|
|
5511
|
-
}
|
|
5512
|
-
/** Selects today's date as the start date. */
|
|
5513
|
-
selectToday() {
|
|
5514
|
-
const today = this.dateAdapter.today();
|
|
5515
|
-
const currentValue = this.internalValue();
|
|
5516
|
-
// Set today as start if no start, or as end if we have a start
|
|
5517
|
-
if (!currentValue?.start) {
|
|
5518
|
-
this.updateValue(createDateRangeValue(today, null));
|
|
5519
|
-
this.announce('Start date set to today');
|
|
5520
|
-
}
|
|
5521
|
-
else if (!currentValue.end) {
|
|
5522
|
-
// Ensure proper ordering
|
|
5523
|
-
const newRange = this.dateAdapter.compareDate(today, currentValue.start) < 0
|
|
5524
|
-
? createDateRangeValue(today, currentValue.start)
|
|
5525
|
-
: createDateRangeValue(currentValue.start, today);
|
|
5526
|
-
this.updateValue(newRange);
|
|
5527
|
-
if (!this.effectiveKeepOpen()) {
|
|
5528
|
-
this.close();
|
|
5529
|
-
}
|
|
5530
|
-
}
|
|
5531
|
-
}
|
|
5532
|
-
// ============ EVENT HANDLERS ============
|
|
5533
|
-
onTriggerClick() {
|
|
5534
|
-
if (!this.disabled() && !this.isOpen()) {
|
|
5535
|
-
this.open();
|
|
5536
|
-
}
|
|
5537
|
-
}
|
|
5538
|
-
onTriggerKeydown(event) {
|
|
5539
|
-
switch (event.key) {
|
|
5540
|
-
case 'Escape':
|
|
5541
|
-
if (this.isOpen()) {
|
|
5542
|
-
event.preventDefault();
|
|
5543
|
-
this.close();
|
|
5544
|
-
}
|
|
5545
|
-
break;
|
|
5546
|
-
}
|
|
5547
|
-
}
|
|
5548
|
-
onStartInputFocus() {
|
|
5549
|
-
this.activeInput.set('start');
|
|
5550
|
-
}
|
|
5551
|
-
onEndInputFocus() {
|
|
5552
|
-
this.activeInput.set('end');
|
|
5553
|
-
}
|
|
5554
|
-
onInputKeydown(event, inputType) {
|
|
5555
|
-
switch (event.key) {
|
|
5556
|
-
case 'Enter':
|
|
5557
|
-
event.preventDefault();
|
|
5558
|
-
if (this.isOpen()) {
|
|
5559
|
-
// Commit manual input
|
|
5560
|
-
if (inputType === 'start') {
|
|
5561
|
-
this.parseAndSetStart(this.startInputRef().nativeElement.value);
|
|
5562
|
-
}
|
|
5563
|
-
else {
|
|
5564
|
-
this.parseAndSetEnd(this.endInputRef().nativeElement.value);
|
|
5565
|
-
}
|
|
5566
|
-
}
|
|
5567
|
-
else {
|
|
5568
|
-
this.open();
|
|
5569
|
-
}
|
|
5570
|
-
break;
|
|
5571
|
-
case 'Escape':
|
|
5572
|
-
if (this.isOpen()) {
|
|
5573
|
-
event.preventDefault();
|
|
5574
|
-
this.close();
|
|
5575
|
-
}
|
|
5576
|
-
break;
|
|
5577
|
-
case 'ArrowDown':
|
|
5578
|
-
if (!this.isOpen()) {
|
|
5579
|
-
event.preventDefault();
|
|
5580
|
-
this.open();
|
|
5581
|
-
}
|
|
5582
|
-
break;
|
|
5583
|
-
case 'Tab':
|
|
5584
|
-
// Allow natural tab navigation between inputs
|
|
5585
|
-
break;
|
|
5586
|
-
}
|
|
5587
|
-
}
|
|
5588
|
-
onStartInputChange(_event) {
|
|
5589
|
-
// Debounced in blur handler
|
|
5590
|
-
}
|
|
5591
|
-
onEndInputChange(_event) {
|
|
5592
|
-
// Debounced in blur handler
|
|
5593
|
-
}
|
|
5594
|
-
onStartInputBlur() {
|
|
5595
|
-
if (this.allowManualInput()) {
|
|
5596
|
-
this.parseAndSetStart(this.startInputRef().nativeElement.value);
|
|
5597
|
-
}
|
|
5598
|
-
this.onTouched();
|
|
5599
|
-
}
|
|
5600
|
-
onEndInputBlur() {
|
|
5601
|
-
if (this.allowManualInput()) {
|
|
5602
|
-
this.parseAndSetEnd(this.endInputRef().nativeElement.value);
|
|
5603
|
-
}
|
|
5604
|
-
this.onTouched();
|
|
5605
|
-
}
|
|
5606
|
-
onPanelKeydown(event) {
|
|
5607
|
-
switch (event.key) {
|
|
5608
|
-
case 'Escape':
|
|
5609
|
-
event.preventDefault();
|
|
5610
|
-
this.close();
|
|
5611
|
-
break;
|
|
5612
|
-
}
|
|
5613
|
-
}
|
|
5614
|
-
onCalendarSelectionChange(selection) {
|
|
5615
|
-
// The calendar emits the selection from the strategy
|
|
5616
|
-
const range = selection;
|
|
5617
|
-
if (range) {
|
|
5618
|
-
const newValue = createDateRangeValue(range.start, range.end);
|
|
5619
|
-
this.updateValue(newValue);
|
|
5620
|
-
if (range.start && range.end) {
|
|
5621
|
-
// Complete range selected
|
|
5622
|
-
this.announce(`Range selected: ${this.formatDate(range.start)} to ${this.formatDate(range.end)}`);
|
|
5623
|
-
if (!this.effectiveKeepOpen()) {
|
|
5624
|
-
this.close();
|
|
5625
|
-
}
|
|
5626
|
-
}
|
|
5627
|
-
else if (range.start) {
|
|
5628
|
-
this.announce(`Start date selected: ${this.formatDate(range.start)}. Now select end date.`);
|
|
5629
|
-
}
|
|
5630
|
-
}
|
|
5631
|
-
}
|
|
5632
|
-
onActiveDateChange(date) {
|
|
5633
|
-
this.calendarActiveDate.set(date);
|
|
5634
|
-
}
|
|
5635
|
-
onStartTimeChange(time) {
|
|
5636
|
-
if (!time)
|
|
5637
|
-
return;
|
|
5638
|
-
const value = this.internalValue();
|
|
5639
|
-
const startDate = value?.start ?? this.dateAdapter.today();
|
|
5640
|
-
const updated = this.dateAdapter.setTime(startDate, time.hours, time.minutes, time.seconds);
|
|
5641
|
-
this.updateValue(createDateRangeValue(updated, value?.end ?? null));
|
|
5642
|
-
}
|
|
5643
|
-
onEndTimeChange(time) {
|
|
5644
|
-
if (!time)
|
|
5645
|
-
return;
|
|
5646
|
-
const value = this.internalValue();
|
|
5647
|
-
const endDate = value?.end ?? this.dateAdapter.today();
|
|
5648
|
-
const updated = this.dateAdapter.setTime(endDate, time.hours, time.minutes, time.seconds);
|
|
5649
|
-
this.updateValue(createDateRangeValue(value?.start ?? null, updated));
|
|
5650
|
-
}
|
|
5651
|
-
// ============ PRIVATE METHODS ============
|
|
5652
|
-
createOverlay() {
|
|
5653
|
-
if (this.overlayRef) {
|
|
5654
|
-
return;
|
|
5655
|
-
}
|
|
5656
|
-
const hostEl = this.elementRef.nativeElement;
|
|
5657
|
-
const positionStrategy = this.overlay
|
|
5658
|
-
.position()
|
|
5659
|
-
.flexibleConnectedTo(hostEl)
|
|
5660
|
-
.withPositions(DEFAULT_POSITIONS)
|
|
5661
|
-
.withFlexibleDimensions(false)
|
|
5662
|
-
.withPush(true);
|
|
5663
|
-
this.overlayRef = this.overlay.create({
|
|
5664
|
-
positionStrategy,
|
|
5665
|
-
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
5666
|
-
hasBackdrop: true,
|
|
5667
|
-
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
5668
|
-
});
|
|
5669
|
-
// Attach panel template
|
|
5670
|
-
const portal = new TemplatePortal(this.panelTemplateRef(), this.viewContainerRef);
|
|
5671
|
-
this.overlayRef.attach(portal);
|
|
5672
|
-
// Close on backdrop click
|
|
5673
|
-
this.overlayRef
|
|
5674
|
-
.backdropClick()
|
|
5675
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
5676
|
-
.subscribe(() => this.close());
|
|
5677
|
-
// Close on outside click
|
|
5678
|
-
this.overlayRef
|
|
5679
|
-
.outsidePointerEvents()
|
|
5680
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
5681
|
-
.subscribe(() => this.close());
|
|
5682
|
-
}
|
|
5683
|
-
destroyOverlay() {
|
|
5684
|
-
if (this.overlayRef) {
|
|
5685
|
-
this.overlayRef.dispose();
|
|
5686
|
-
this.overlayRef = null;
|
|
5687
|
-
}
|
|
5688
|
-
}
|
|
5689
|
-
updateValue(value) {
|
|
5690
|
-
this.internalValue.set(value);
|
|
5691
|
-
this.onChange(value);
|
|
5692
|
-
this.rangeChange.emit(value);
|
|
5693
|
-
this.onValidatorChange();
|
|
5694
|
-
}
|
|
5695
|
-
parseAndSetStart(inputValue) {
|
|
5696
|
-
const currentValue = this.internalValue();
|
|
5697
|
-
if (!inputValue.trim()) {
|
|
5698
|
-
// Clear start date
|
|
5699
|
-
if (currentValue?.start) {
|
|
5700
|
-
this.updateValue(createDateRangeValue(null, currentValue.end));
|
|
5701
|
-
}
|
|
5702
|
-
return;
|
|
5703
|
-
}
|
|
5704
|
-
const parsed = this.dateAdapter.parse(inputValue, this.effectiveDateFormat());
|
|
5705
|
-
if (parsed && this.dateAdapter.isValid(parsed) && this.isDateValid(parsed)) {
|
|
5706
|
-
// Ensure start <= end
|
|
5707
|
-
if (currentValue?.end && this.dateAdapter.compareDate(parsed, currentValue.end) > 0) {
|
|
5708
|
-
// Swap dates
|
|
5709
|
-
this.updateValue(createDateRangeValue(currentValue.end, parsed));
|
|
5710
|
-
}
|
|
5711
|
-
else {
|
|
5712
|
-
this.updateValue(createDateRangeValue(parsed, currentValue?.end ?? null));
|
|
5713
|
-
}
|
|
5714
|
-
}
|
|
5715
|
-
else {
|
|
5716
|
-
// Revert to current value
|
|
5717
|
-
this.startInputRef().nativeElement.value = this.startDisplayValue();
|
|
5718
|
-
}
|
|
5719
|
-
}
|
|
5720
|
-
parseAndSetEnd(inputValue) {
|
|
5721
|
-
const currentValue = this.internalValue();
|
|
5722
|
-
if (!inputValue.trim()) {
|
|
5723
|
-
// Clear end date
|
|
5724
|
-
if (currentValue?.end) {
|
|
5725
|
-
this.updateValue(createDateRangeValue(currentValue.start, null));
|
|
5726
|
-
}
|
|
5727
|
-
return;
|
|
5728
|
-
}
|
|
5729
|
-
const parsed = this.dateAdapter.parse(inputValue, this.effectiveDateFormat());
|
|
5730
|
-
if (parsed && this.dateAdapter.isValid(parsed) && this.isDateValid(parsed)) {
|
|
5731
|
-
// Ensure start <= end
|
|
5732
|
-
if (currentValue?.start && this.dateAdapter.compareDate(parsed, currentValue.start) < 0) {
|
|
5733
|
-
// Swap dates
|
|
5734
|
-
this.updateValue(createDateRangeValue(parsed, currentValue.start));
|
|
5735
|
-
}
|
|
5736
|
-
else {
|
|
5737
|
-
this.updateValue(createDateRangeValue(currentValue?.start ?? null, parsed));
|
|
5738
|
-
}
|
|
5739
|
-
}
|
|
5740
|
-
else {
|
|
5741
|
-
// Revert to current value
|
|
5742
|
-
this.endInputRef().nativeElement.value = this.endDisplayValue();
|
|
5743
|
-
}
|
|
5744
|
-
}
|
|
5745
|
-
isDateValid(date) {
|
|
5746
|
-
const min = this.min();
|
|
5747
|
-
const max = this.max();
|
|
5748
|
-
const filter = this.dateFilter();
|
|
5749
|
-
if (min && this.dateAdapter.compareDate(date, min) < 0) {
|
|
5750
|
-
return false;
|
|
5751
|
-
}
|
|
5752
|
-
if (max && this.dateAdapter.compareDate(date, max) > 0) {
|
|
5753
|
-
return false;
|
|
5754
|
-
}
|
|
5755
|
-
if (filter && !filter(date)) {
|
|
5756
|
-
return false;
|
|
5757
|
-
}
|
|
5758
|
-
return true;
|
|
5759
|
-
}
|
|
5760
|
-
formatDate(date) {
|
|
5761
|
-
return this.dateAdapter.format(date, 'long');
|
|
5762
|
-
}
|
|
5763
|
-
announce(message) {
|
|
5764
|
-
this.liveAnnouncement.set(message);
|
|
5765
|
-
}
|
|
5766
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComDateRangePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5767
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: ComDateRangePicker, isStandalone: true, selector: "com-date-range-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", isSignal: true, isRequired: false, transformFunction: null }, startView: { classPropertyName: "startView", publicName: "startView", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, startPlaceholder: { classPropertyName: "startPlaceholder", publicName: "startPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, endPlaceholder: { classPropertyName: "endPlaceholder", publicName: "endPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, dateFormat: { classPropertyName: "dateFormat", publicName: "dateFormat", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, showTodayButton: { classPropertyName: "showTodayButton", publicName: "showTodayButton", isSignal: true, isRequired: false, transformFunction: null }, showFooterClearButton: { classPropertyName: "showFooterClearButton", publicName: "showFooterClearButton", isSignal: true, isRequired: false, transformFunction: null }, keepOpen: { classPropertyName: "keepOpen", publicName: "keepOpen", isSignal: true, isRequired: false, transformFunction: null }, allowManualInput: { classPropertyName: "allowManualInput", publicName: "allowManualInput", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, panelWidth: { classPropertyName: "panelWidth", publicName: "panelWidth", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, startAriaLabel: { classPropertyName: "startAriaLabel", publicName: "startAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, endAriaLabel: { classPropertyName: "endAriaLabel", publicName: "endAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, showTimePicker: { classPropertyName: "showTimePicker", publicName: "showTimePicker", isSignal: true, isRequired: false, transformFunction: null }, use12HourFormat: { classPropertyName: "use12HourFormat", publicName: "use12HourFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rangeChange: "rangeChange", opened: "opened", closed: "closed" }, host: { properties: { "class.com-date-range-picker-disabled": "disabled()", "class.com-date-range-picker-open": "isOpen()" }, classAttribute: "com-date-range-picker-host inline-block" }, providers: [
|
|
5768
|
-
RangeSelectionStrategy,
|
|
5769
|
-
{ provide: CALENDAR_SELECTION_STRATEGY, useExisting: RangeSelectionStrategy },
|
|
5770
|
-
], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerElement"], descendants: true, isSignal: true }, { propertyName: "startInputRef", first: true, predicate: ["startInputElement"], descendants: true, isSignal: true }, { propertyName: "endInputRef", first: true, predicate: ["endInputElement"], descendants: true, isSignal: true }, { propertyName: "panelTemplateRef", first: true, predicate: ["panelTemplate"], descendants: true, isSignal: true }], exportAs: ["comDateRangePicker"], ngImport: i0, template: `
|
|
5771
|
-
<!-- Trigger container -->
|
|
5772
|
-
<div
|
|
5773
|
-
#triggerElement
|
|
5774
|
-
[class]="triggerClasses()"
|
|
5775
|
-
[attr.aria-expanded]="isOpen()"
|
|
5776
|
-
[attr.aria-haspopup]="'dialog'"
|
|
5777
|
-
[attr.aria-owns]="panelId()"
|
|
5778
|
-
[attr.aria-disabled]="disabled() || null"
|
|
5779
|
-
(click)="onTriggerClick()"
|
|
5780
|
-
(keydown)="onTriggerKeydown($event)"
|
|
5781
|
-
>
|
|
5782
|
-
<!-- Start date input -->
|
|
5783
|
-
<input
|
|
5784
|
-
#startInputElement
|
|
5785
|
-
type="text"
|
|
5786
|
-
[class]="inputClasses()"
|
|
5787
|
-
[value]="startDisplayValue()"
|
|
5788
|
-
[placeholder]="startPlaceholder()"
|
|
5789
|
-
[disabled]="disabled()"
|
|
5790
|
-
[readonly]="!allowManualInput()"
|
|
5791
|
-
[attr.id]="startInputId()"
|
|
5792
|
-
[attr.aria-label]="startAriaLabel() || startPlaceholder()"
|
|
5793
|
-
[attr.aria-invalid]="state() === 'error' || null"
|
|
5794
|
-
[attr.aria-required]="required() || null"
|
|
5795
|
-
(focus)="onStartInputFocus()"
|
|
5796
|
-
(input)="onStartInputChange($event)"
|
|
5797
|
-
(blur)="onStartInputBlur()"
|
|
5798
|
-
(keydown)="onInputKeydown($event, 'start')"
|
|
5799
|
-
/>
|
|
5800
|
-
|
|
5801
|
-
<!-- Range separator -->
|
|
5802
|
-
<span [class]="separatorClasses()">
|
|
5803
|
-
<com-icon name="arrow-right" [size]="iconSize()" />
|
|
5804
|
-
</span>
|
|
5805
|
-
|
|
5806
|
-
<!-- End date input -->
|
|
5807
|
-
<input
|
|
5808
|
-
#endInputElement
|
|
5809
|
-
type="text"
|
|
5810
|
-
[class]="inputClasses()"
|
|
5811
|
-
[value]="endDisplayValue()"
|
|
5812
|
-
[placeholder]="endPlaceholder()"
|
|
5813
|
-
[disabled]="disabled()"
|
|
5814
|
-
[readonly]="!allowManualInput()"
|
|
5815
|
-
[attr.id]="endInputId()"
|
|
5816
|
-
[attr.aria-label]="endAriaLabel() || endPlaceholder()"
|
|
5817
|
-
[attr.aria-invalid]="state() === 'error' || null"
|
|
5818
|
-
(focus)="onEndInputFocus()"
|
|
5819
|
-
(input)="onEndInputChange($event)"
|
|
5820
|
-
(blur)="onEndInputBlur()"
|
|
5821
|
-
(keydown)="onInputKeydown($event, 'end')"
|
|
5822
|
-
/>
|
|
5823
|
-
|
|
5824
|
-
<!-- Clear button -->
|
|
5825
|
-
@if (showClearButton() && hasValue() && !disabled()) {
|
|
5826
|
-
<button
|
|
5827
|
-
type="button"
|
|
5828
|
-
[class]="clearClasses()"
|
|
5829
|
-
[attr.aria-label]="'Clear date range'"
|
|
5830
|
-
(click)="clear($event)"
|
|
5831
|
-
>
|
|
5832
|
-
<com-icon name="x" [size]="iconSize()" />
|
|
5833
|
-
</button>
|
|
5834
|
-
}
|
|
5835
|
-
|
|
5836
|
-
<!-- Calendar icon -->
|
|
5837
|
-
<button
|
|
5838
|
-
type="button"
|
|
5839
|
-
[class]="iconClasses()"
|
|
5840
|
-
[attr.aria-label]="isOpen() ? 'Close calendar' : 'Open calendar'"
|
|
5841
|
-
[disabled]="disabled()"
|
|
5842
|
-
tabindex="-1"
|
|
5843
|
-
>
|
|
5844
|
-
<com-icon name="calendar" [size]="iconSize()" />
|
|
5845
|
-
</button>
|
|
5846
|
-
</div>
|
|
5847
|
-
|
|
5848
|
-
<!-- Panel template (rendered in overlay) -->
|
|
5849
|
-
<ng-template #panelTemplate>
|
|
5850
|
-
<div
|
|
5851
|
-
[class]="panelClasses()"
|
|
5852
|
-
[attr.id]="panelId()"
|
|
5853
|
-
role="dialog"
|
|
5854
|
-
aria-modal="true"
|
|
5855
|
-
[attr.aria-label]="'Choose date range'"
|
|
5856
|
-
(keydown)="onPanelKeydown($event)"
|
|
5857
|
-
cdkTrapFocus
|
|
5858
|
-
[cdkTrapFocusAutoCapture]="true"
|
|
5859
|
-
>
|
|
5860
|
-
<com-calendar
|
|
5861
|
-
[activeDate]="calendarActiveDate()"
|
|
5862
|
-
[selected]="calendarSelection()"
|
|
5863
|
-
[minDate]="min()"
|
|
5864
|
-
[maxDate]="max()"
|
|
5865
|
-
[dateFilter]="dateFilter()"
|
|
5866
|
-
[startView]="startView()"
|
|
5867
|
-
[firstDayOfWeek]="firstDayOfWeek()"
|
|
5868
|
-
[monthColumns]="2"
|
|
5869
|
-
[bordered]="false"
|
|
5870
|
-
(selectedChange)="onCalendarSelectionChange($event)"
|
|
5871
|
-
(activeDateChange)="onActiveDateChange($event)"
|
|
5872
|
-
/>
|
|
5873
|
-
|
|
5874
|
-
@if (showTimePicker()) {
|
|
5875
|
-
<div [class]="timeSectionClasses()">
|
|
5876
|
-
<div class="flex items-center gap-3">
|
|
5877
|
-
<div class="flex flex-col gap-1">
|
|
5878
|
-
<span [class]="timeLabelClasses()">Start time</span>
|
|
5879
|
-
<com-time-picker
|
|
5880
|
-
variant="embedded"
|
|
5881
|
-
[size]="size()"
|
|
5882
|
-
[value]="startTimeValue()"
|
|
5883
|
-
[use12HourFormat]="use12HourFormat()"
|
|
5884
|
-
[showSeconds]="showSeconds()"
|
|
5885
|
-
[minuteStep]="minuteStep()"
|
|
5886
|
-
[disabled]="disabled()"
|
|
5887
|
-
ariaLabel="Start time"
|
|
5888
|
-
(timeChange)="onStartTimeChange($event)"
|
|
5889
|
-
/>
|
|
5890
|
-
</div>
|
|
5891
|
-
<span class="text-muted-foreground mt-5">
|
|
5892
|
-
<com-icon name="arrow-right" [size]="iconSize()" />
|
|
5893
|
-
</span>
|
|
5894
|
-
<div class="flex flex-col gap-1">
|
|
5895
|
-
<span [class]="timeLabelClasses()">End time</span>
|
|
5896
|
-
<com-time-picker
|
|
5897
|
-
variant="embedded"
|
|
5898
|
-
[size]="size()"
|
|
5899
|
-
[value]="endTimeValue()"
|
|
5900
|
-
[use12HourFormat]="use12HourFormat()"
|
|
5901
|
-
[showSeconds]="showSeconds()"
|
|
5902
|
-
[minuteStep]="minuteStep()"
|
|
5903
|
-
[disabled]="disabled()"
|
|
5904
|
-
ariaLabel="End time"
|
|
5905
|
-
(timeChange)="onEndTimeChange($event)"
|
|
5906
|
-
/>
|
|
5907
|
-
</div>
|
|
5908
|
-
</div>
|
|
5909
|
-
</div>
|
|
5910
|
-
}
|
|
5911
|
-
|
|
5912
|
-
@if (showTodayButton() || showFooterClearButton() || showTimePicker()) {
|
|
5913
|
-
<div [class]="footerClasses()">
|
|
5914
|
-
@if (showTodayButton()) {
|
|
5915
|
-
<button
|
|
5916
|
-
type="button"
|
|
5917
|
-
[class]="todayButtonClasses()"
|
|
5918
|
-
(click)="selectToday()"
|
|
5919
|
-
>
|
|
5920
|
-
Today
|
|
5921
|
-
</button>
|
|
5922
|
-
}
|
|
5923
|
-
@if (showFooterClearButton()) {
|
|
5924
|
-
<button
|
|
5925
|
-
type="button"
|
|
5926
|
-
[class]="clearButtonClasses()"
|
|
5927
|
-
(click)="clear($event)"
|
|
5928
|
-
>
|
|
5929
|
-
Clear
|
|
5930
|
-
</button>
|
|
5931
|
-
}
|
|
5932
|
-
@if (showTimePicker()) {
|
|
5933
|
-
<button
|
|
5934
|
-
type="button"
|
|
5935
|
-
[class]="todayButtonClasses()"
|
|
5936
|
-
(click)="close()"
|
|
5937
|
-
>
|
|
5938
|
-
Done
|
|
5939
|
-
</button>
|
|
5940
|
-
}
|
|
5941
|
-
</div>
|
|
5942
|
-
}
|
|
5943
|
-
</div>
|
|
5944
|
-
</ng-template>
|
|
5945
|
-
|
|
5946
|
-
<!-- Live announcer region -->
|
|
5947
|
-
<div class="sr-only" aria-live="polite" aria-atomic="true">
|
|
5948
|
-
{{ liveAnnouncement() }}
|
|
5949
|
-
</div>
|
|
5950
|
-
`, isInline: true, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: ComCalendar, selector: "com-calendar", inputs: ["activeDate", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "bordered", "startView", "firstDayOfWeek", "monthColumns", "cellTemplate"], outputs: ["selectedChange", "viewChanged", "activeDateChange"] }, { kind: "component", type: ComIcon, selector: "com-icon", inputs: ["name", "img", "color", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { kind: "component", type: ComTimePicker, selector: "com-time-picker", inputs: ["value", "disabled", "required", "showSeconds", "use12HourFormat", "minuteStep", "secondStep", "minTime", "maxTime", "variant", "size", "state", "ariaLabel", "class", "placeholder"], outputs: ["timeChange"], exportAs: ["comTimePicker"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5951
|
-
}
|
|
5952
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ComDateRangePicker, decorators: [{
|
|
5953
|
-
type: Component,
|
|
5954
|
-
args: [{ selector: 'com-date-range-picker', exportAs: 'comDateRangePicker', template: `
|
|
5955
|
-
<!-- Trigger container -->
|
|
5956
|
-
<div
|
|
5957
|
-
#triggerElement
|
|
5958
|
-
[class]="triggerClasses()"
|
|
5959
|
-
[attr.aria-expanded]="isOpen()"
|
|
5960
|
-
[attr.aria-haspopup]="'dialog'"
|
|
5961
|
-
[attr.aria-owns]="panelId()"
|
|
5962
|
-
[attr.aria-disabled]="disabled() || null"
|
|
5963
|
-
(click)="onTriggerClick()"
|
|
5964
|
-
(keydown)="onTriggerKeydown($event)"
|
|
5965
|
-
>
|
|
5966
|
-
<!-- Start date input -->
|
|
5967
|
-
<input
|
|
5968
|
-
#startInputElement
|
|
5969
|
-
type="text"
|
|
5970
|
-
[class]="inputClasses()"
|
|
5971
|
-
[value]="startDisplayValue()"
|
|
5972
|
-
[placeholder]="startPlaceholder()"
|
|
5973
|
-
[disabled]="disabled()"
|
|
5974
|
-
[readonly]="!allowManualInput()"
|
|
5975
|
-
[attr.id]="startInputId()"
|
|
5976
|
-
[attr.aria-label]="startAriaLabel() || startPlaceholder()"
|
|
5977
|
-
[attr.aria-invalid]="state() === 'error' || null"
|
|
5978
|
-
[attr.aria-required]="required() || null"
|
|
5979
|
-
(focus)="onStartInputFocus()"
|
|
5980
|
-
(input)="onStartInputChange($event)"
|
|
5981
|
-
(blur)="onStartInputBlur()"
|
|
5982
|
-
(keydown)="onInputKeydown($event, 'start')"
|
|
5983
|
-
/>
|
|
5984
|
-
|
|
5985
|
-
<!-- Range separator -->
|
|
5986
|
-
<span [class]="separatorClasses()">
|
|
5987
|
-
<com-icon name="arrow-right" [size]="iconSize()" />
|
|
5988
|
-
</span>
|
|
5989
|
-
|
|
5990
|
-
<!-- End date input -->
|
|
5991
|
-
<input
|
|
5992
|
-
#endInputElement
|
|
5993
|
-
type="text"
|
|
5994
|
-
[class]="inputClasses()"
|
|
5995
|
-
[value]="endDisplayValue()"
|
|
5996
|
-
[placeholder]="endPlaceholder()"
|
|
5997
|
-
[disabled]="disabled()"
|
|
5998
|
-
[readonly]="!allowManualInput()"
|
|
5999
|
-
[attr.id]="endInputId()"
|
|
6000
|
-
[attr.aria-label]="endAriaLabel() || endPlaceholder()"
|
|
6001
|
-
[attr.aria-invalid]="state() === 'error' || null"
|
|
6002
|
-
(focus)="onEndInputFocus()"
|
|
6003
|
-
(input)="onEndInputChange($event)"
|
|
6004
|
-
(blur)="onEndInputBlur()"
|
|
6005
|
-
(keydown)="onInputKeydown($event, 'end')"
|
|
6006
|
-
/>
|
|
6007
|
-
|
|
6008
|
-
<!-- Clear button -->
|
|
6009
|
-
@if (showClearButton() && hasValue() && !disabled()) {
|
|
6010
|
-
<button
|
|
6011
|
-
type="button"
|
|
6012
|
-
[class]="clearClasses()"
|
|
6013
|
-
[attr.aria-label]="'Clear date range'"
|
|
6014
|
-
(click)="clear($event)"
|
|
6015
|
-
>
|
|
6016
|
-
<com-icon name="x" [size]="iconSize()" />
|
|
6017
|
-
</button>
|
|
6018
|
-
}
|
|
6019
|
-
|
|
6020
|
-
<!-- Calendar icon -->
|
|
6021
|
-
<button
|
|
6022
|
-
type="button"
|
|
6023
|
-
[class]="iconClasses()"
|
|
6024
|
-
[attr.aria-label]="isOpen() ? 'Close calendar' : 'Open calendar'"
|
|
6025
|
-
[disabled]="disabled()"
|
|
6026
|
-
tabindex="-1"
|
|
6027
|
-
>
|
|
6028
|
-
<com-icon name="calendar" [size]="iconSize()" />
|
|
6029
|
-
</button>
|
|
6030
|
-
</div>
|
|
6031
|
-
|
|
6032
|
-
<!-- Panel template (rendered in overlay) -->
|
|
6033
|
-
<ng-template #panelTemplate>
|
|
6034
|
-
<div
|
|
6035
|
-
[class]="panelClasses()"
|
|
6036
|
-
[attr.id]="panelId()"
|
|
6037
|
-
role="dialog"
|
|
6038
|
-
aria-modal="true"
|
|
6039
|
-
[attr.aria-label]="'Choose date range'"
|
|
6040
|
-
(keydown)="onPanelKeydown($event)"
|
|
6041
|
-
cdkTrapFocus
|
|
6042
|
-
[cdkTrapFocusAutoCapture]="true"
|
|
6043
|
-
>
|
|
6044
|
-
<com-calendar
|
|
6045
|
-
[activeDate]="calendarActiveDate()"
|
|
6046
|
-
[selected]="calendarSelection()"
|
|
6047
|
-
[minDate]="min()"
|
|
6048
|
-
[maxDate]="max()"
|
|
6049
|
-
[dateFilter]="dateFilter()"
|
|
6050
|
-
[startView]="startView()"
|
|
6051
|
-
[firstDayOfWeek]="firstDayOfWeek()"
|
|
6052
|
-
[monthColumns]="2"
|
|
6053
|
-
[bordered]="false"
|
|
6054
|
-
(selectedChange)="onCalendarSelectionChange($event)"
|
|
6055
|
-
(activeDateChange)="onActiveDateChange($event)"
|
|
6056
|
-
/>
|
|
6057
|
-
|
|
6058
|
-
@if (showTimePicker()) {
|
|
6059
|
-
<div [class]="timeSectionClasses()">
|
|
6060
|
-
<div class="flex items-center gap-3">
|
|
6061
|
-
<div class="flex flex-col gap-1">
|
|
6062
|
-
<span [class]="timeLabelClasses()">Start time</span>
|
|
6063
|
-
<com-time-picker
|
|
6064
|
-
variant="embedded"
|
|
6065
|
-
[size]="size()"
|
|
6066
|
-
[value]="startTimeValue()"
|
|
6067
|
-
[use12HourFormat]="use12HourFormat()"
|
|
6068
|
-
[showSeconds]="showSeconds()"
|
|
6069
|
-
[minuteStep]="minuteStep()"
|
|
6070
|
-
[disabled]="disabled()"
|
|
6071
|
-
ariaLabel="Start time"
|
|
6072
|
-
(timeChange)="onStartTimeChange($event)"
|
|
6073
|
-
/>
|
|
6074
|
-
</div>
|
|
6075
|
-
<span class="text-muted-foreground mt-5">
|
|
6076
|
-
<com-icon name="arrow-right" [size]="iconSize()" />
|
|
6077
|
-
</span>
|
|
6078
|
-
<div class="flex flex-col gap-1">
|
|
6079
|
-
<span [class]="timeLabelClasses()">End time</span>
|
|
6080
|
-
<com-time-picker
|
|
6081
|
-
variant="embedded"
|
|
6082
|
-
[size]="size()"
|
|
6083
|
-
[value]="endTimeValue()"
|
|
6084
|
-
[use12HourFormat]="use12HourFormat()"
|
|
6085
|
-
[showSeconds]="showSeconds()"
|
|
6086
|
-
[minuteStep]="minuteStep()"
|
|
6087
|
-
[disabled]="disabled()"
|
|
6088
|
-
ariaLabel="End time"
|
|
6089
|
-
(timeChange)="onEndTimeChange($event)"
|
|
6090
|
-
/>
|
|
6091
|
-
</div>
|
|
6092
|
-
</div>
|
|
6093
|
-
</div>
|
|
6094
|
-
}
|
|
6095
|
-
|
|
6096
|
-
@if (showTodayButton() || showFooterClearButton() || showTimePicker()) {
|
|
6097
|
-
<div [class]="footerClasses()">
|
|
6098
|
-
@if (showTodayButton()) {
|
|
6099
|
-
<button
|
|
6100
|
-
type="button"
|
|
6101
|
-
[class]="todayButtonClasses()"
|
|
6102
|
-
(click)="selectToday()"
|
|
6103
|
-
>
|
|
6104
|
-
Today
|
|
6105
|
-
</button>
|
|
6106
|
-
}
|
|
6107
|
-
@if (showFooterClearButton()) {
|
|
6108
|
-
<button
|
|
6109
|
-
type="button"
|
|
6110
|
-
[class]="clearButtonClasses()"
|
|
6111
|
-
(click)="clear($event)"
|
|
6112
|
-
>
|
|
6113
|
-
Clear
|
|
6114
|
-
</button>
|
|
6115
|
-
}
|
|
6116
|
-
@if (showTimePicker()) {
|
|
6117
|
-
<button
|
|
6118
|
-
type="button"
|
|
6119
|
-
[class]="todayButtonClasses()"
|
|
6120
|
-
(click)="close()"
|
|
6121
|
-
>
|
|
6122
|
-
Done
|
|
6123
|
-
</button>
|
|
6124
|
-
}
|
|
6125
|
-
</div>
|
|
6126
|
-
}
|
|
6127
|
-
</div>
|
|
6128
|
-
</ng-template>
|
|
6129
|
-
|
|
6130
|
-
<!-- Live announcer region -->
|
|
6131
|
-
<div class="sr-only" aria-live="polite" aria-atomic="true">
|
|
6132
|
-
{{ liveAnnouncement() }}
|
|
6133
|
-
</div>
|
|
6134
|
-
`, imports: [
|
|
6135
|
-
OverlayModule,
|
|
6136
|
-
A11yModule,
|
|
6137
|
-
ComCalendar,
|
|
6138
|
-
ComIcon,
|
|
6139
|
-
ComTimePicker,
|
|
6140
|
-
], providers: [
|
|
6141
|
-
RangeSelectionStrategy,
|
|
6142
|
-
{ provide: CALENDAR_SELECTION_STRATEGY, useExisting: RangeSelectionStrategy },
|
|
6143
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
6144
|
-
class: 'com-date-range-picker-host inline-block',
|
|
6145
|
-
'[class.com-date-range-picker-disabled]': 'disabled()',
|
|
6146
|
-
'[class.com-date-range-picker-open]': 'isOpen()',
|
|
6147
|
-
}, styles: [".sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
|
|
6148
|
-
}], ctorParameters: () => [], propDecorators: { triggerRef: [{ type: i0.ViewChild, args: ['triggerElement', { isSignal: true }] }], startInputRef: [{ type: i0.ViewChild, args: ['startInputElement', { isSignal: true }] }], endInputRef: [{ type: i0.ViewChild, args: ['endInputElement', { isSignal: true }] }], panelTemplateRef: [{ type: i0.ViewChild, args: ['panelTemplate', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], startView: [{ type: i0.Input, args: [{ isSignal: true, alias: "startView", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], startPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "startPlaceholder", required: false }] }], endPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "endPlaceholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], showClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], showTodayButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTodayButton", required: false }] }], showFooterClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooterClearButton", required: false }] }], keepOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepOpen", required: false }] }], allowManualInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowManualInput", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], panelWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelWidth", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], startAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAriaLabel", required: false }] }], endAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "endAriaLabel", required: false }] }], showTimePicker: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTimePicker", required: false }] }], use12HourFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "use12HourFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], rangeChange: [{ type: i0.Output, args: ["rangeChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
6149
|
-
|
|
6150
|
-
/**
|
|
6151
|
-
* Datepicker components public API.
|
|
6152
|
-
*/
|
|
6153
|
-
|
|
6154
|
-
/**
|
|
6155
|
-
* TimePicker component public API.
|
|
6156
|
-
*/
|
|
6157
|
-
|
|
6158
3073
|
/**
|
|
6159
3074
|
* ngx-com/components/calendar
|
|
6160
3075
|
* Calendar component public API
|
|
@@ -6164,5 +3079,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
6164
3079
|
* Generated bundle index. Do not edit.
|
|
6165
3080
|
*/
|
|
6166
3081
|
|
|
6167
|
-
export { CALENDAR_SELECTION_STRATEGY, CalendarSelectionStrategy, CalendarViewBase, ComCalendar, ComCalendarCell, ComCalendarHeader, ComCalendarMonthView, ComCalendarMultiYearView, ComCalendarYearView,
|
|
3082
|
+
export { CALENDAR_SELECTION_STRATEGY, CalendarSelectionStrategy, CalendarViewBase, ComCalendar, ComCalendarCell, ComCalendarHeader, ComCalendarMonthView, ComCalendarMultiYearView, ComCalendarYearView, DATE_ADAPTER, DAYS_PER_WEEK, DateAdapter, MONTHS_PER_ROW, MultiSelectionStrategy, NativeDateAdapter, RangeSelectionStrategy, SingleSelectionStrategy, WEEKS_PER_MONTH, WeekSelectionStrategy, YEARS_PER_PAGE, YEARS_PER_ROW, calendarCellVariants, calendarCellWrapperVariants, calendarHeaderButtonVariants, calendarHeaderVariants, calendarVariants, createCalendarCell, createDateRange, createGrid, getMultiYearStartingYear, getWeekdayHeaders, isDateDisabled, isMonthDisabled, isYearDisabled, navigateGrid, provideMultiSelectionStrategy, provideNativeDateAdapter, provideRangeSelectionStrategy, provideSingleSelectionStrategy, provideWeekSelectionStrategy };
|
|
6168
3083
|
//# sourceMappingURL=ngx-com-components-calendar.mjs.map
|