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