@energycap/components 0.42.0 → 0.42.2-ECAP-26676-readonly-attribute-suppresses-help-popovers-on-checkboxes.20250122-1358

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 (41) hide show
  1. package/esm2022/lib/components.module.mjs +10 -5
  2. package/esm2022/lib/controls/calendar/calendar-item.component.mjs +46 -14
  3. package/esm2022/lib/controls/calendar/calendar.component.mjs +169 -121
  4. package/esm2022/lib/controls/calendar/calendar.types.mjs +2 -4
  5. package/esm2022/lib/controls/checkbox/checkbox.component.mjs +2 -2
  6. package/esm2022/lib/controls/date-input/date-input-selection-strategies/date-input-selection-strategy-base.mjs +57 -0
  7. package/esm2022/lib/controls/date-input/date-input-selection-strategies/day-selection-strategy.mjs +62 -0
  8. package/esm2022/lib/controls/date-input/date-input-selection-strategies/last-28-days-selection-strategy.mjs +100 -0
  9. package/esm2022/lib/controls/date-input/date-input-selection-strategies/last-7-days-selection-strategy.mjs +101 -0
  10. package/esm2022/lib/controls/date-input/date-input-selection-strategies/month-selection-strategy.mjs +76 -0
  11. package/esm2022/lib/controls/date-input/date-input-selection-strategies/quarter-selection-strategy.mjs +79 -0
  12. package/esm2022/lib/controls/date-input/date-input-selection-strategies/range-selection-strategy.mjs +210 -0
  13. package/esm2022/lib/controls/date-input/date-input-selection-strategies/year-selection-strategy.mjs +81 -0
  14. package/esm2022/lib/controls/date-input/date-input.component.mjs +322 -113
  15. package/esm2022/lib/controls/date-input/date-input.types.mjs +44 -0
  16. package/esm2022/lib/controls/file-upload/file-upload.component.mjs +1 -1
  17. package/esm2022/lib/controls/form-control/form-control.component.mjs +6 -12
  18. package/esm2022/lib/core/date-time-helper.mjs +10 -2
  19. package/esm2022/lib/shared/directives/keyboard-nav-container/keyboard-nav-container.directive.mjs +100 -0
  20. package/esm2022/public-api.mjs +63 -61
  21. package/fesm2022/energycap-components.mjs +1668 -509
  22. package/fesm2022/energycap-components.mjs.map +1 -1
  23. package/lib/components.module.d.ts +9 -8
  24. package/lib/controls/calendar/calendar-item.component.d.ts +11 -6
  25. package/lib/controls/calendar/calendar.component.d.ts +21 -23
  26. package/lib/controls/calendar/calendar.types.d.ts +11 -7
  27. package/lib/controls/date-input/date-input-selection-strategies/date-input-selection-strategy-base.d.ts +42 -0
  28. package/lib/controls/date-input/date-input-selection-strategies/day-selection-strategy.d.ts +21 -0
  29. package/lib/controls/date-input/date-input-selection-strategies/last-28-days-selection-strategy.d.ts +21 -0
  30. package/lib/controls/date-input/date-input-selection-strategies/last-7-days-selection-strategy.d.ts +21 -0
  31. package/lib/controls/date-input/date-input-selection-strategies/month-selection-strategy.d.ts +18 -0
  32. package/lib/controls/date-input/date-input-selection-strategies/quarter-selection-strategy.d.ts +18 -0
  33. package/lib/controls/date-input/date-input-selection-strategies/range-selection-strategy.d.ts +21 -0
  34. package/lib/controls/date-input/date-input-selection-strategies/year-selection-strategy.d.ts +20 -0
  35. package/lib/controls/date-input/date-input.component.d.ts +63 -28
  36. package/lib/controls/date-input/date-input.types.d.ts +62 -0
  37. package/lib/controls/form-control/form-control.component.d.ts +4 -6
  38. package/lib/shared/directives/keyboard-nav-container/keyboard-nav-container.directive.d.ts +23 -0
  39. package/package.json +1 -1
  40. package/public-api.d.ts +62 -60
  41. package/src/assets/locales/en_US.json +9 -1
@@ -1,15 +1,15 @@
1
- import * as i3$1 from '@angular/cdk/a11y';
1
+ import * as i1$3 from '@angular/cdk/a11y';
2
2
  import { A11yModule } from '@angular/cdk/a11y';
3
3
  import * as i1$1 from '@angular/cdk/overlay';
4
4
  import { OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
5
- import * as i1$3 from '@angular/cdk/scrolling';
5
+ import * as i1$4 from '@angular/cdk/scrolling';
6
6
  import { ScrollingModule } from '@angular/cdk/scrolling';
7
7
  import * as i1 from '@angular/common';
8
8
  import { DOCUMENT, CommonModule } from '@angular/common';
9
9
  import * as i0 from '@angular/core';
10
- import { Injectable, EventEmitter, Component, HostBinding, Input, Output, ViewChild, Directive, Host, ChangeDetectionStrategy, Pipe, HostListener, Inject, ViewEncapsulation, ContentChild, ElementRef, TemplateRef, ContentChildren, ViewContainerRef, NgModule, Injector } from '@angular/core';
10
+ import { Injectable, EventEmitter, Component, HostBinding, Input, Output, ViewChild, Directive, Host, Pipe, ChangeDetectionStrategy, HostListener, Inject, ViewEncapsulation, ContentChild, ElementRef, TemplateRef, ContentChildren, ViewContainerRef, NgModule, Injector } from '@angular/core';
11
11
  import * as i4 from '@angular/forms';
12
- import { Validators, UntypedFormControl, FormControlDirective, FormControl, UntypedFormGroup, UntypedFormArray, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
12
+ import { Validators, UntypedFormControl, FormControlDirective, FormControl, FormGroup, UntypedFormGroup, UntypedFormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
13
13
  import * as i1$2 from '@angular/router';
14
14
  import { NavigationEnd, convertToParamMap, NavigationStart, Router, RouterModule, ActivatedRoute } from '@angular/router';
15
15
  import * as i3 from '@ngx-translate/core';
@@ -455,65 +455,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
455
455
  args: ['ecCopyTableButton']
456
456
  }] } });
457
457
 
458
- function isCalendarSelectionSingleDate(selection) {
459
- return selection instanceof Date;
460
- }
461
-
462
- class CalendarItemComponent {
463
- constructor() {
464
- this.view = 'day';
465
- this.today = false;
466
- this.selected = false;
467
- this.outsideActiveMonth = false;
468
- }
469
- ngOnChanges() {
470
- if (this.view !== 'day') {
471
- this.today = false;
472
- this.outsideActiveMonth = false;
473
- }
474
- else {
475
- this.today = moment(this.item?.date).isSame(moment(), 'day');
476
- this.outsideActiveMonth = !moment(this.item?.date).isSame(this.activeDate, 'month');
477
- }
478
- this.selected = this.isSelected(this.item?.date, this.selection, this.view);
479
- }
480
- isSelected(date, selection, view) {
481
- if (!date || !selection) {
482
- return false;
483
- }
484
- if (isCalendarSelectionSingleDate(this.selection)) {
485
- return moment(this.item?.date).isSame(this.selection, view);
486
- }
487
- else {
488
- // TODO ECAP-26841: determine if the item is within the range selection
489
- return false;
490
- }
491
- }
492
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CalendarItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
493
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CalendarItemComponent, selector: "button[ec-calendar-item]", inputs: { item: "item", activeDate: "activeDate", selection: "selection", view: "view" }, host: { properties: { "class.is-today": "this.today", "class.is-selected": "this.selected", "class.is-outside-active-month": "this.outsideActiveMonth" } }, usesOnChanges: true, ngImport: i0, template: '{{item?.label}}', isInline: true, styles: [":host{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer;background-color:transparent;line-height:1.125rem}:host .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}:host .ec-icon{flex:none}:host .ec-icon+.label{flex:none;margin-left:.25rem}:host.has-badge{padding-right:.0625rem}:host:focus{outline:none;position:relative;z-index:1}:host:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}:host:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);opacity:1;--ec-color-icon: var(--ec-color-hint-dark)}:host:hover:not(:disabled){background-color:var(--ec-background-color-hover)}:host:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}:host:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}:host.is-selected,:host.is-selected:disabled{background-color:var(--ec-background-color-selected);font-weight:700}:host.is-today{text-decoration:underline}:host.is-outside-active-month{color:var(--ec-color-hint-dark)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
494
- }
495
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CalendarItemComponent, decorators: [{
496
- type: Component,
497
- args: [{ selector: 'button[ec-calendar-item]', template: '{{item?.label}}', changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer;background-color:transparent;line-height:1.125rem}:host .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}:host .ec-icon{flex:none}:host .ec-icon+.label{flex:none;margin-left:.25rem}:host.has-badge{padding-right:.0625rem}:host:focus{outline:none;position:relative;z-index:1}:host:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}:host:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);opacity:1;--ec-color-icon: var(--ec-color-hint-dark)}:host:hover:not(:disabled){background-color:var(--ec-background-color-hover)}:host:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}:host:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}:host.is-selected,:host.is-selected:disabled{background-color:var(--ec-background-color-selected);font-weight:700}:host.is-today{text-decoration:underline}:host.is-outside-active-month{color:var(--ec-color-hint-dark)}\n"] }]
498
- }], ctorParameters: () => [], propDecorators: { item: [{
499
- type: Input
500
- }], activeDate: [{
501
- type: Input
502
- }], selection: [{
503
- type: Input
504
- }], view: [{
505
- type: Input
506
- }], today: [{
507
- type: HostBinding,
508
- args: ['class.is-today']
509
- }], selected: [{
510
- type: HostBinding,
511
- args: ['class.is-selected']
512
- }], outsideActiveMonth: [{
513
- type: HostBinding,
514
- args: ['class.is-outside-active-month']
515
- }] } });
516
-
517
458
  /**
518
459
  * Helper class that provides common date constants and helpful date functions
519
460
  */
@@ -626,6 +567,8 @@ class DateTimeHelper {
626
567
  * This is not an exhaustive list of formats, but it should cover most common formats.
627
568
  */
628
569
  static { this.momentMedAndLongDateFormats = [
570
+ 'DD MMM',
571
+ 'MMM DD',
629
572
  'DD MMM YY',
630
573
  'DD MMM YYYY',
631
574
  'DD MMMM YYYY',
@@ -633,7 +576,13 @@ class DateTimeHelper {
633
576
  'MMM D, YYYY',
634
577
  'MMM DD, YYYY',
635
578
  'MMMM D, YYYY',
636
- 'MMMM DD, YYYY'
579
+ 'MMMM DD, YYYY',
580
+ 'MMM YY',
581
+ 'MMM YYYY',
582
+ 'MMMM YYYY',
583
+ 'MMM, YY',
584
+ 'MMM, YYYY',
585
+ 'MMMM, YYYY',
637
586
  ]; }
638
587
  /**
639
588
  * Format to display the time portion of a datetime
@@ -733,257 +682,1169 @@ class DateTimeHelper {
733
682
  }
734
683
  }
735
684
 
685
+ /**
686
+ * Contains the logic for selecting, formatting, and parsing date dates for a specific selection mode.
687
+ */
688
+ class DateInputSelectionStrategyBase {
689
+ /** Parses the string into a date using the provided parse formats. */
690
+ parseString(value, parseFormats, opts) {
691
+ if (!value) {
692
+ return null;
693
+ }
694
+ const date = moment(value, parseFormats);
695
+ if (date.isValid()) {
696
+ // If we're in a temporary state (when the user is typing in a textbox), we need to set the year to the current year if it's before the min year
697
+ // This prevents the calendars from showing unhelpful dates that are in the distant past before the user finishes typing in the date.
698
+ // We don't do this modification when the real selection happens on textbox blur.
699
+ if (opts?.shiftToCurrentYearIfBelow && date.isBefore(opts.shiftToCurrentYearIfBelow)) {
700
+ date.set('year', moment().year());
701
+ }
702
+ return date.toDate();
703
+ }
704
+ return null;
705
+ }
706
+ /** Returns a new selection for the provided date. */
707
+ getSelectionForQuickSelectDate(date, existingSelection) {
708
+ return this.getSelectionFromDate(date, existingSelection);
709
+ }
710
+ /** Returns the view for the primary calendar for the selection and selection mode */
711
+ getPrimaryCalendarView(selection, minDate, maxDate, currentView) {
712
+ let date;
713
+ // If we have a range, use the end date, defaulting to the start date or today
714
+ if (DateInput.isSelectionRange(selection)) {
715
+ date = selection.end || selection.start || new Date();
716
+ // If we have a single date, use it, defaulting to today
717
+ }
718
+ else {
719
+ date = selection || new Date();
720
+ }
721
+ // Ensure the date is within the min and max dates
722
+ date = date < minDate ? minDate : date;
723
+ date = date > maxDate ? maxDate : date;
724
+ // If the current calendar view mode is valid for the selection mode, use it, otherwise use the selection view mode
725
+ // This prevents the calendar from changing view modes as the user types/blurs the textboxes as long as the view mode is valid
726
+ const viewMode = this.validViewModes.includes(currentView.mode) ? currentView.mode : this.selectionViewMode;
727
+ return { mode: viewMode, date };
728
+ }
729
+ ;
730
+ /**
731
+ * Returns the view for the secondary calendar for the selection and selection mode.
732
+ * This is is only used by the range selection strategy. All others just return the current date.
733
+ */
734
+ getSecondaryCalendarView(selection, minDate, maxDate, currentView) {
735
+ return { mode: this.selectionViewMode, date: new Date() };
736
+ }
737
+ ;
738
+ }
739
+
740
+ /**
741
+ * Selection strategy for the 'day' selection mode.
742
+ */
743
+ class DaySelectionStrategy extends DateInputSelectionStrategyBase {
744
+ constructor(dateDisplayPipe) {
745
+ super();
746
+ this.dateDisplayPipe = dateDisplayPipe;
747
+ this.selectionViewMode = 'day';
748
+ this.validViewModes = ['day', 'month', 'year'];
749
+ this.showSecondaryTextbox = false;
750
+ this.showSecondaryCalendar = false;
751
+ }
752
+ formatSelection(selection) {
753
+ // If the selection is a single date, format it into the first textbox.
754
+ if (DateInput.isSelectionSingleDate(selection)) {
755
+ return { textbox: this.dateDisplayPipe.transform(selection, true), textbox2: null };
756
+ // Otherwise, clear both textboxes. This shouldn't happen based on current date input flows,
757
+ // and even if it did there's not really a good way to handle it.
758
+ }
759
+ else {
760
+ return { textbox: null, textbox2: null };
761
+ }
762
+ }
763
+ parseTextboxValues(value, parseFormats, opts) {
764
+ return this.parseString(value.textbox, parseFormats, opts);
765
+ }
766
+ getSelectionFromDate(date) {
767
+ // Nice and simple
768
+ return date;
769
+ }
770
+ getNewSelectionFromExisting(previousSelection) {
771
+ // If the previous selection was a range, return the end date and default to the start date if there isn't one.
772
+ if (DateInput.isSelectionRange(previousSelection)) {
773
+ return previousSelection.end || previousSelection.start;
774
+ // If the previous selection was a single date, return it.
775
+ }
776
+ else if (DateInput.isSelectionSingleDate(previousSelection)) {
777
+ return previousSelection;
778
+ }
779
+ return null;
780
+ }
781
+ getNextSelection(selection) {
782
+ // Add a single day to the selection
783
+ if (DateInput.isSelectionSingleDate(selection)) {
784
+ return moment(selection).add(1, 'day').toDate();
785
+ }
786
+ // This shouldn't happen based on current date input flows, but if it does just return the selection as-is.
787
+ return selection;
788
+ }
789
+ getPreviousSelection(selection) {
790
+ // Subtract a single day from the selection
791
+ if (DateInput.isSelectionSingleDate(selection)) {
792
+ return moment(selection).subtract(1, 'day').toDate();
793
+ }
794
+ // This shouldn't happen based on current date input flows, but if it does just return the selection as-is.
795
+ return selection;
796
+ }
797
+ }
798
+
799
+ /**
800
+ * Selection strategy for the 'last 28 days' selection mode.
801
+ */
802
+ class Last28DaysSelectionStrategy extends DateInputSelectionStrategyBase {
803
+ constructor(rangeStrategy) {
804
+ super();
805
+ this.rangeStrategy = rangeStrategy;
806
+ this.selectionViewMode = 'day';
807
+ this.validViewModes = ['day', 'month', 'year'];
808
+ this.showSecondaryTextbox = true;
809
+ this.showSecondaryCalendar = false;
810
+ }
811
+ formatSelection(value) {
812
+ // Delegate to the range strategy for formatting since the logic is the same
813
+ return this.rangeStrategy.formatSelection(value);
814
+ }
815
+ parseTextboxValues(value, parseFormats, opts) {
816
+ let start = this.parseString(value.textbox, parseFormats, opts);
817
+ let end = this.parseString(value.textbox2, parseFormats, opts);
818
+ if (start && end) {
819
+ // Even if both dates are provided, it's possible that they don't match a 28-day range
820
+ // Update the start and end dates to match a 28-day range, keying off the end date if parseFromEnd is true
821
+ // parseFromEnd is true when a date is being entered from the end date textbox
822
+ if (opts?.parseFromEnd) {
823
+ start = moment(end).subtract(27, 'days').toDate();
824
+ }
825
+ else {
826
+ end = moment(start).add(27, 'days').toDate();
827
+ }
828
+ }
829
+ // If the start date is not provided, we'll use the end date to calculate the start date
830
+ if (!start && end && !opts?.preventAutoComplete) {
831
+ start = moment(end).subtract(27, 'days').toDate();
832
+ }
833
+ // If the end date is not provided, we'll use the start date to calculate the end date
834
+ if (!end && start && !opts?.preventAutoComplete) {
835
+ end = moment(start).add(27, 'days').toDate();
836
+ }
837
+ if (!start && !end) {
838
+ return null;
839
+ }
840
+ else {
841
+ return { start, end };
842
+ }
843
+ }
844
+ getSelectionFromDate(date) {
845
+ return {
846
+ start: moment(date).subtract(27, 'days').toDate(),
847
+ end: date
848
+ };
849
+ }
850
+ getNewSelectionFromExisting(previousSelection) {
851
+ if (DateInput.isSelectionRange(previousSelection)) {
852
+ // If the range only has a start date, make the 28-day range start on that date
853
+ if (!previousSelection.end && previousSelection.start) {
854
+ return {
855
+ start: previousSelection.start,
856
+ end: moment(previousSelection.start).add(27, 'days').toDate()
857
+ };
858
+ // If the range only has an end date, make the 28-day range end on that date
859
+ }
860
+ else if (previousSelection.end) {
861
+ return this.getSelectionFromDate(previousSelection.end);
862
+ }
863
+ // If the previous selection was a single date, make the range the 28 days ending on that date
864
+ }
865
+ else if (DateInput.isSelectionSingleDate(previousSelection)) {
866
+ return this.getSelectionFromDate(previousSelection);
867
+ }
868
+ return null;
869
+ }
870
+ getNextSelection(selection) {
871
+ // Move the selection to the next 28 days
872
+ if (DateInput.isSelectionRange(selection) && selection.end) {
873
+ return {
874
+ start: moment(selection.end).add(1, 'day').toDate(),
875
+ end: moment(selection.end).add(28, 'days').toDate()
876
+ };
877
+ }
878
+ // This shouldn't happen since the next stepper is disabled if the selection only has one date.
879
+ // Just return the selection as-is in this case.
880
+ return selection;
881
+ }
882
+ getPreviousSelection(selection) {
883
+ // Move the selection to the previous 28 days
884
+ if (DateInput.isSelectionRange(selection) && selection.start) {
885
+ return {
886
+ start: moment(selection.start).subtract(28, 'days').toDate(),
887
+ end: moment(selection.start).subtract(1, 'day').toDate()
888
+ };
889
+ }
890
+ // This shouldn't happen since the previous stepper is disabled if the selection only has one date.
891
+ // Just return the selection as-is in this case.
892
+ return selection;
893
+ }
894
+ }
895
+
896
+ /**
897
+ * Selection strategy for the 'last 7 days' selection mode.
898
+ */
899
+ class Last7DaysSelectionStrategy extends DateInputSelectionStrategyBase {
900
+ constructor(rangeStrategy) {
901
+ super();
902
+ this.rangeStrategy = rangeStrategy;
903
+ this.selectionViewMode = 'day';
904
+ this.validViewModes = ['day', 'month', 'year'];
905
+ this.showSecondaryTextbox = true;
906
+ this.showSecondaryCalendar = false;
907
+ }
908
+ formatSelection(value) {
909
+ // Delegate to the range strategy for formatting since the logic is the same
910
+ return this.rangeStrategy.formatSelection(value);
911
+ }
912
+ parseTextboxValues(value, parseFormats, opts) {
913
+ let start = this.parseString(value.textbox, parseFormats, opts);
914
+ let end = this.parseString(value.textbox2, parseFormats, opts);
915
+ if (start && end) {
916
+ // Even if both dates are provided, it's possible that they don't match a 7-day range
917
+ // Update the start and end dates to match a 7-day range, keying off the end date if parseFromEnd is true
918
+ // parseFromEnd is true when a date is being entered from the end date textbox
919
+ if (opts?.parseFromEnd) {
920
+ start = moment(end).subtract(6, 'days').toDate();
921
+ }
922
+ else {
923
+ end = moment(start).add(6, 'days').toDate();
924
+ }
925
+ }
926
+ // If the start date is not provided, we'll use the end date to calculate the start date
927
+ if (!start && end && !opts?.preventAutoComplete) {
928
+ start = moment(end).subtract(6, 'days').toDate();
929
+ }
930
+ // If the end date is not provided, we'll use the start date to calculate the end date
931
+ if (!end && start && !opts?.preventAutoComplete) {
932
+ end = moment(start).add(6, 'days').toDate();
933
+ }
934
+ if (!start && !end) {
935
+ return null;
936
+ }
937
+ else {
938
+ return { start, end };
939
+ }
940
+ }
941
+ getSelectionFromDate(date) {
942
+ // Base the selection on the given date, moving back 6 days
943
+ return {
944
+ start: moment(date).subtract(6, 'days').toDate(),
945
+ end: date
946
+ };
947
+ }
948
+ getNewSelectionFromExisting(previousSelection) {
949
+ if (DateInput.isSelectionRange(previousSelection)) {
950
+ // If we don't have an end date, create the new selection based on the start date forwards
951
+ if (!previousSelection.end && previousSelection.start) {
952
+ return {
953
+ start: previousSelection.start,
954
+ end: moment(previousSelection.start).add(6, 'days').toDate()
955
+ };
956
+ // Otherwise, create the new selection based on the end date backwards
957
+ }
958
+ else if (previousSelection.end) {
959
+ return this.getSelectionFromDate(previousSelection.end);
960
+ }
961
+ // If we only have a single date, create the new selection based on that date backwards
962
+ }
963
+ else if (DateInput.isSelectionSingleDate(previousSelection)) {
964
+ return this.getSelectionFromDate(previousSelection);
965
+ }
966
+ return null;
967
+ }
968
+ getNextSelection(selection) {
969
+ // Shift the range forward by 7 days
970
+ if (DateInput.isSelectionRange(selection) && selection.end) {
971
+ return {
972
+ start: moment(selection.end).add(1, 'day').toDate(),
973
+ end: moment(selection.end).add(7, 'days').toDate()
974
+ };
975
+ }
976
+ // This shouldn't happen since the next stepper is disabled if the selection only has one date.
977
+ // Just return the selection as-is in this case.
978
+ return selection;
979
+ }
980
+ getPreviousSelection(selection) {
981
+ // Shift the range back 7 days
982
+ if (DateInput.isSelectionRange(selection) && selection.start) {
983
+ return {
984
+ start: moment(selection.start).subtract(7, 'days').toDate(),
985
+ end: moment(selection.start).subtract(1, 'day').toDate()
986
+ };
987
+ }
988
+ // This shouldn't happen since the previous stepper is disabled if the selection only has one date.
989
+ // Just return the selection as-is in this case.
990
+ return selection;
991
+ }
992
+ }
993
+
994
+ /**
995
+ * Selection strategy for the 'month' selection mode.
996
+ */
997
+ class MonthSelectionStrategy extends DateInputSelectionStrategyBase {
998
+ constructor() {
999
+ super(...arguments);
1000
+ this.selectionViewMode = 'month';
1001
+ this.validViewModes = ['month', 'year'];
1002
+ this.showSecondaryTextbox = false;
1003
+ this.showSecondaryCalendar = false;
1004
+ }
1005
+ formatSelection(selection) {
1006
+ if (!selection) {
1007
+ return { textbox: null, textbox2: null };
1008
+ }
1009
+ // We only need one date in the range to format since it only spans one month
1010
+ // A single date selection shouldn't happen in this mode but it's simple enough to handle
1011
+ const date = DateInput.isSelectionRange(selection) ? selection.start : selection;
1012
+ return {
1013
+ textbox: moment(date).format('MMM, YYYY'),
1014
+ textbox2: null
1015
+ };
1016
+ }
1017
+ parseTextboxValues(value, parseFormats, opts) {
1018
+ // Only one textbox is used in this mode
1019
+ const date = this.parseString(value.textbox, parseFormats, opts);
1020
+ if (!date) {
1021
+ return null;
1022
+ }
1023
+ return this.getSelectionFromDate(date);
1024
+ }
1025
+ getSelectionFromDate(date) {
1026
+ return {
1027
+ start: moment(date).startOf('month').toDate(),
1028
+ end: moment(date).endOf('month').toDate()
1029
+ };
1030
+ }
1031
+ getNewSelectionFromExisting(previousSelection) {
1032
+ if (DateInput.isSelectionRange(previousSelection)) {
1033
+ // We'll use the existing selection's end date and fall back to the start date if it's not available
1034
+ const date = previousSelection.end || previousSelection.start;
1035
+ if (date) {
1036
+ return this.getSelectionFromDate(date);
1037
+ }
1038
+ }
1039
+ else if (DateInput.isSelectionSingleDate(previousSelection)) {
1040
+ // If the previous selection was a single date, make the range that month
1041
+ return this.getSelectionFromDate(previousSelection);
1042
+ }
1043
+ return null;
1044
+ }
1045
+ getNextSelection(selection) {
1046
+ // Move the selection to the next month
1047
+ if (DateInput.isSelectionRange(selection) && selection.start) {
1048
+ const date = moment(selection.start).add(1, 'month');
1049
+ return this.getSelectionFromDate(date.toDate());
1050
+ }
1051
+ // This shouldn't happen since the next stepper is disabled if the selection only has one date.
1052
+ // If it does, just return the selection as-is.
1053
+ return selection;
1054
+ }
1055
+ getPreviousSelection(selection) {
1056
+ // Move the selection to the previous month
1057
+ if (DateInput.isSelectionRange(selection) && selection.start) {
1058
+ const date = moment(selection.start).subtract(1, 'month');
1059
+ return this.getSelectionFromDate(date.toDate());
1060
+ }
1061
+ // This shouldn't happen since the previous stepper is disabled if the selection only has one date.
1062
+ // If it does, just return the selection as-is.
1063
+ return selection;
1064
+ }
1065
+ }
1066
+
1067
+ /**
1068
+ * Selection strategy for the 'month' selection mode.
1069
+ */
1070
+ class QuarterSelectionStrategy extends DateInputSelectionStrategyBase {
1071
+ constructor() {
1072
+ super(...arguments);
1073
+ this.selectionViewMode = 'quarter';
1074
+ this.validViewModes = ['quarter', 'year'];
1075
+ this.showSecondaryTextbox = false;
1076
+ this.showSecondaryCalendar = false;
1077
+ }
1078
+ formatSelection(selection) {
1079
+ // Format the the quarter range as "MMM–MMM, YYYY"
1080
+ // We only have one textbox in this mode
1081
+ if (DateInput.isSelectionRange(selection)) {
1082
+ const start = moment(selection.start).format('MMM');
1083
+ const end = moment(selection.end).format('MMM');
1084
+ const year = moment(selection.end).format('YYYY');
1085
+ return {
1086
+ textbox: `${start}–${end}, ${year}`,
1087
+ textbox2: null
1088
+ };
1089
+ }
1090
+ // This shouldn't happen since the selection should always be a range in quarter mode
1091
+ return { textbox: null, textbox2: null };
1092
+ }
1093
+ parseTextboxValues(value, parseFormats, opts) {
1094
+ // Only one textbox is used in this mode
1095
+ const date = this.parseString(value.textbox, parseFormats, opts);
1096
+ if (!date) {
1097
+ return null;
1098
+ }
1099
+ return this.getSelectionFromDate(date);
1100
+ }
1101
+ getSelectionFromDate(date) {
1102
+ return {
1103
+ start: moment(date).startOf('quarter').toDate(),
1104
+ end: moment(date).endOf('quarter').toDate()
1105
+ };
1106
+ }
1107
+ getNewSelectionFromExisting(previousSelection) {
1108
+ if (DateInput.isSelectionRange(previousSelection)) {
1109
+ // Base the quarter range off of the existing selection's end date, falling back to the start date
1110
+ const date = previousSelection.end || previousSelection.start;
1111
+ if (date) {
1112
+ return this.getSelectionFromDate(date);
1113
+ }
1114
+ }
1115
+ else if (DateInput.isSelectionSingleDate(previousSelection)) {
1116
+ // If the previous selection was a single date, make the range that quarter
1117
+ return this.getSelectionFromDate(previousSelection);
1118
+ }
1119
+ return null;
1120
+ }
1121
+ getNextSelection(selection) {
1122
+ // Move the selection to the next quarter
1123
+ if (DateInput.isSelectionRange(selection) && selection.start) {
1124
+ const date = moment(selection.start).add(1, 'quarter');
1125
+ return this.getSelectionFromDate(date.toDate());
1126
+ }
1127
+ // This shouldn't happen since the next stepper is disabled if the selection only has one date.
1128
+ // If it does, just return the selection as-is.
1129
+ return selection;
1130
+ }
1131
+ getPreviousSelection(selection) {
1132
+ // Move the selection to the previous quarter
1133
+ if (DateInput.isSelectionRange(selection) && selection.start) {
1134
+ const date = moment(selection.start).subtract(1, 'quarter');
1135
+ return this.getSelectionFromDate(date.toDate());
1136
+ }
1137
+ // This shouldn't happen since the previous stepper is disabled if the selection only has one date.
1138
+ // If it does, just return the selection as-is.
1139
+ return selection;
1140
+ }
1141
+ }
1142
+
1143
+ /**
1144
+ * Selection strategy for the 'range' selection mode.
1145
+ */
1146
+ class RangeSelectionStrategy extends DateInputSelectionStrategyBase {
1147
+ constructor() {
1148
+ super(...arguments);
1149
+ this.selectionViewMode = 'day';
1150
+ this.validViewModes = ['day', 'month', 'year'];
1151
+ this.showSecondaryTextbox = true;
1152
+ this.showSecondaryCalendar = true;
1153
+ }
1154
+ formatSelection(selection) {
1155
+ if (!selection) {
1156
+ return { textbox: null, textbox2: null };
1157
+ }
1158
+ // We use the 'll' moment medium format here to make sure the formatted date is formatted according to the user's locale
1159
+ if (DateInput.isSelectionSingleDate(selection)) {
1160
+ return { textbox: moment(selection).format('ll'), textbox2: null };
1161
+ }
1162
+ else {
1163
+ const start = selection.start ? moment(selection.start).format('ll') : null;
1164
+ const end = selection.end ? moment(selection.end).format('ll') : null;
1165
+ return { textbox: start, textbox2: end };
1166
+ }
1167
+ }
1168
+ parseTextboxValues(value, parseFormats, opts) {
1169
+ let start = this.parseString(value.textbox, parseFormats, opts);
1170
+ let end = this.parseString(value.textbox2, parseFormats, opts);
1171
+ // If the start date is after the end date, we need to clear out the invalid date. This is different from the last 7/28 days strategies
1172
+ // because we don't have a fixed range to automatically adjust the dates to. If the user is changing the begin date or end date and ends
1173
+ // up crossing the other date, we should clear out the date that's not being changed so that the user can enter a valid range using the
1174
+ // begin/end date they just entered.
1175
+ if (start && end && moment(start).isAfter(end)) {
1176
+ if (opts?.parseFromEnd) {
1177
+ start = null;
1178
+ }
1179
+ else {
1180
+ end = null;
1181
+ }
1182
+ }
1183
+ if (!start && !end) {
1184
+ return null;
1185
+ }
1186
+ else {
1187
+ return { start, end };
1188
+ }
1189
+ }
1190
+ getSelectionFromDate(date, existingSelection) {
1191
+ if (DateInput.isSelectionRange(existingSelection)) {
1192
+ const { start, end } = existingSelection;
1193
+ if (start && !end) {
1194
+ // If the selected date is before the existing start date, set it as the new start date and use the existing start date as the end date
1195
+ return moment(date).isBefore(start) ? { start: date, end: start } : { start, end: date };
1196
+ }
1197
+ if (end && !start) {
1198
+ // If the selected date is after the existing end date, set it as the new end date and use the existing end date as the start date
1199
+ return moment(date).isBefore(end) ? { start: date, end } : { start: end, end: date };
1200
+ }
1201
+ }
1202
+ else if (DateInput.isSelectionSingleDate(existingSelection)) {
1203
+ // If the selected date is before the existing date, set it as the new start date and use the existing date as the end date
1204
+ return moment(date).isBefore(existingSelection) ? { start: date, end: existingSelection } : { start: existingSelection, end: date };
1205
+ }
1206
+ // If no selection exists or we already have a complete selection, start a new one with the selected date as the start date.
1207
+ return { start: date, end: null };
1208
+ }
1209
+ getNewSelectionFromExisting(previousSelection) {
1210
+ if (DateInput.isSelectionRange(previousSelection)) {
1211
+ // If we have a range, just return it as is. We don't have a fixed range to adjust the dates to.
1212
+ // Even if it's incomplete, the user will still be able to select the remaining date.
1213
+ return previousSelection;
1214
+ }
1215
+ else if (DateInput.isSelectionSingleDate(previousSelection)) {
1216
+ // If we have a single date selection, use it as the start date for the new one.
1217
+ return { start: previousSelection, end: null };
1218
+ }
1219
+ return null;
1220
+ }
1221
+ getSelectionForQuickSelectDate(date, existingSelection) {
1222
+ // If we have a valid range, we'll shift the range to the date provided, using it as the end date
1223
+ // The new selection will have the same length as the previous.
1224
+ if (DateInput.isSelectionRange(existingSelection) && existingSelection.start && existingSelection.end) {
1225
+ const length = moment(existingSelection.end).diff(existingSelection.start, 'days');
1226
+ return {
1227
+ start: moment(date).subtract(length, 'days').toDate(),
1228
+ end: date
1229
+ };
1230
+ }
1231
+ // If we only have a single date, we'll use the date provided as the end date.
1232
+ // The user will be able to select the start date.
1233
+ return { start: null, end: date };
1234
+ }
1235
+ getNextSelection(selection) {
1236
+ // We can only determine the next selection if we have a valid range
1237
+ if (DateInput.isSelectionRange(selection) && selection.start && selection.end) {
1238
+ // Shift the range forward by the number of days between the start and end dates
1239
+ const length = moment(selection.end).diff(selection.start, 'days');
1240
+ return {
1241
+ start: moment(selection.end).add(1, 'days').toDate(),
1242
+ end: moment(selection.end).add(1 + length, 'days').toDate()
1243
+ };
1244
+ }
1245
+ // This shouldn't happen since the next stepper is disabled if the selection only has one date.
1246
+ // If it does, just return the selection as-is.
1247
+ return selection;
1248
+ }
1249
+ getPreviousSelection(selection) {
1250
+ // We can only determine the previous selection if we have a valid range
1251
+ if (DateInput.isSelectionRange(selection) && selection.start && selection.end) {
1252
+ // Shift the range back by the number of days between the start and end dates
1253
+ const length = moment(selection.end).diff(selection.start, 'days');
1254
+ return {
1255
+ start: moment(selection.start).subtract(1 + length, 'days').toDate(),
1256
+ end: moment(selection.start).subtract(1, 'days').toDate()
1257
+ };
1258
+ }
1259
+ // This shouldn't happen since the previous stepper is disabled if the selection only has one date.
1260
+ // If it does, just return the selection as-is.
1261
+ return selection;
1262
+ }
1263
+ getPrimaryCalendarView(selection, minDate, maxDate, currentView) {
1264
+ let viewDate;
1265
+ if (DateInput.isSelectionRange(selection)) {
1266
+ let start = selection.start ? moment(selection.start) : null;
1267
+ let end = selection.end ? moment(selection.end) : null;
1268
+ // Since we're in range mode, the primary calendar is mostly concerned with the start date
1269
+ if (start) {
1270
+ // If we have a start date in the selection and it's before the min date, shift the view to the min date.
1271
+ if (start.isBefore(minDate, 'month')) {
1272
+ viewDate = minDate;
1273
+ // If the start is after the max date, shift the view to the max date.
1274
+ }
1275
+ else if (start.isSameOrAfter(maxDate, 'month')) {
1276
+ // the secondary calendar will show the max date month.
1277
+ // The primary calendar will show the month before the max date.
1278
+ viewDate = moment(maxDate).subtract(1, 'month').toDate();
1279
+ }
1280
+ else {
1281
+ viewDate = start.toDate();
1282
+ }
1283
+ }
1284
+ else if (end && end.isSameOrBefore(minDate, 'month')) {
1285
+ // If we don't have a start date, and the end date is the same month or before the min date, shift the view to the min date.
1286
+ viewDate = minDate;
1287
+ }
1288
+ else if (end && end.isSameOrBefore(new Date(), 'month')) {
1289
+ // If we don't have a start date, and the end date is the same month or before the current month, shift the view to the month before the end
1290
+ viewDate = moment(end).subtract(1, 'month').toDate();
1291
+ }
1292
+ else {
1293
+ // Otherwise, show the current month.
1294
+ viewDate = new Date();
1295
+ }
1296
+ }
1297
+ else {
1298
+ viewDate = selection || new Date();
1299
+ }
1300
+ // If the current calendar view mode is valid for the selection mode, use it, otherwise use the selection view mode
1301
+ // This prevents the calendar from changing view modes as the user types/blurs the textboxes as long as the view mode is valid
1302
+ const viewMode = this.validViewModes.includes(currentView.mode) ? currentView.mode : this.selectionViewMode;
1303
+ return { mode: viewMode, date: viewDate };
1304
+ }
1305
+ getSecondaryCalendarView(selection, minDate, maxDate, currentView) {
1306
+ let viewDate;
1307
+ if (DateInput.isSelectionRange(selection)) {
1308
+ let start = selection.start ? moment(selection.start) : null;
1309
+ let end = selection.end ? moment(selection.end) : null;
1310
+ // The secondary calendar is primarily concerned with the end date in the selection.
1311
+ if (end) {
1312
+ if (end.isAfter(maxDate, 'month')) {
1313
+ // If the end date is after the max date, shift the view to the max date.
1314
+ viewDate = maxDate;
1315
+ }
1316
+ else if (end.isSameOrBefore(minDate, 'month')) {
1317
+ // If the end date is the same month or before the min date, shift the view to show
1318
+ // the month after the min date. The primary calendar will show the min date month.
1319
+ viewDate = moment(minDate).add(1, 'month').toDate();
1320
+ }
1321
+ else {
1322
+ // Otherwise, show the end date month.
1323
+ viewDate = end.toDate();
1324
+ }
1325
+ }
1326
+ else if (start && start.isSameOrAfter(maxDate, 'month')) {
1327
+ // If we don't have an end date, and the start date is after the max date, show the max date month
1328
+ viewDate = maxDate;
1329
+ }
1330
+ else if (start && start.isSameOrAfter(new Date(), 'month')) {
1331
+ // If we don't have an end date, and the start date is on or after the current month,
1332
+ // show the month after the start date.
1333
+ viewDate = moment(start).add(1, 'month').toDate();
1334
+ }
1335
+ else {
1336
+ // Otherwise, show the current month.
1337
+ viewDate = new Date();
1338
+ }
1339
+ }
1340
+ else {
1341
+ viewDate = selection || new Date();
1342
+ }
1343
+ // If the current calendar view mode is valid for the selection mode, use it, otherwise use the selection view mode
1344
+ // This prevents the calendar from changing view modes as the user types/blurs the textboxes as long as the view mode is valid
1345
+ const viewMode = this.validViewModes.includes(currentView.mode) ? currentView.mode : this.selectionViewMode;
1346
+ return { mode: viewMode, date: viewDate };
1347
+ }
1348
+ }
1349
+
1350
+ /**
1351
+ * Selection strategy for the 'year' selection mode.
1352
+ */
1353
+ class YearSelectionStrategy extends DateInputSelectionStrategyBase {
1354
+ constructor() {
1355
+ super(...arguments);
1356
+ this.selectionViewMode = 'year';
1357
+ this.validViewModes = ['year'];
1358
+ this.showSecondaryTextbox = false;
1359
+ this.showSecondaryCalendar = false;
1360
+ }
1361
+ formatSelection(selection) {
1362
+ if (!selection) {
1363
+ return { textbox: null, textbox2: null };
1364
+ }
1365
+ // Only one date is needed for formatting since the ranges span a single year.
1366
+ // There shouldn't be any case where there's only a single date but it's covered anyway.
1367
+ const date = DateInput.isSelectionRange(selection) ? selection.start : selection;
1368
+ return { textbox: moment(date).format('YYYY'), textbox2: null };
1369
+ }
1370
+ parseString(value, parseFormats, opts) {
1371
+ // Including 'YY' and 'YYYY' as valid formats for year input. These aren't included in the default parse
1372
+ // formats because they cause issues with the default date parsing.
1373
+ return super.parseString(value, ['YY', 'YYYY', ...parseFormats], opts);
1374
+ }
1375
+ parseTextboxValues(value, parseFormats, opts) {
1376
+ // Only a single textbox is used in year mode
1377
+ const date = this.parseString(value.textbox, parseFormats, opts);
1378
+ if (!date) {
1379
+ return null;
1380
+ }
1381
+ return this.getSelectionFromDate(date);
1382
+ }
1383
+ getSelectionFromDate(date) {
1384
+ return {
1385
+ start: moment(date).startOf('year').toDate(),
1386
+ end: moment(date).endOf('year').toDate()
1387
+ };
1388
+ }
1389
+ getNewSelectionFromExisting(previousSelection) {
1390
+ if (DateInput.isSelectionRange(previousSelection)) {
1391
+ // Base the year range off of the existing selection's end date, falling back to the start date
1392
+ const date = previousSelection.end || previousSelection.start;
1393
+ if (date) {
1394
+ return this.getSelectionFromDate(date);
1395
+ }
1396
+ }
1397
+ else if (DateInput.isSelectionSingleDate(previousSelection)) {
1398
+ // If the previous selection was a single date, make the range that year
1399
+ return this.getSelectionFromDate(previousSelection);
1400
+ }
1401
+ return null;
1402
+ }
1403
+ getSelectionForQuickSelectDate(date) {
1404
+ return this.getSelectionFromDate(date);
1405
+ }
1406
+ getNextSelection(selection) {
1407
+ // Move the selection to the next year
1408
+ if (DateInput.isSelectionRange(selection) && selection.start) {
1409
+ const date = moment(selection.start).add(1, 'year');
1410
+ return this.getSelectionFromDate(date.toDate());
1411
+ }
1412
+ // This shouldn't happen since the next stepper is disabled if the selection only has one date.
1413
+ // If it does, just return the selection as-is.
1414
+ return selection;
1415
+ }
1416
+ getPreviousSelection(selection) {
1417
+ // Move the selection to the previous year
1418
+ if (DateInput.isSelectionRange(selection) && selection.start) {
1419
+ const date = moment(selection.start).subtract(1, 'year');
1420
+ return this.getSelectionFromDate(date.toDate());
1421
+ }
1422
+ // This shouldn't happen since the previous stepper is disabled if the selection only has one date.
1423
+ // If it does, just return the selection as-is.
1424
+ return selection;
1425
+ }
1426
+ }
1427
+
1428
+ class UserPreferenceService {
1429
+ getPreferences() {
1430
+ return of({ preference: { dateFormat: 'MM/DD/YYYY', timeFormat: 'h:mm:ss a' } });
1431
+ }
1432
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: UserPreferenceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1433
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: UserPreferenceService, providedIn: 'root' }); }
1434
+ }
1435
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: UserPreferenceService, decorators: [{
1436
+ type: Injectable,
1437
+ args: [{
1438
+ providedIn: 'root'
1439
+ }]
1440
+ }] });
1441
+
1442
+ /**
1443
+ * Format a date to the user's preference for display
1444
+ */
1445
+ class DateDisplayPipe {
1446
+ constructor(userPreferenceService) {
1447
+ this.userPreferenceService = userPreferenceService;
1448
+ this.lastFormatString = 'MM/DD/YYYY';
1449
+ }
1450
+ /**
1451
+ * Format a date for display, accounting for user's display preferences.
1452
+ *
1453
+ * If {@see date} is null or undefined, or the end of time, returns empty string
1454
+ */
1455
+ transform(date, showEndOfTime, showTime, showSeconds) {
1456
+ let display = '';
1457
+ let formatString = '';
1458
+ if (date && moment(date).isValid() && (showEndOfTime || !DateTimeHelper.isEndOfTime(date))) {
1459
+ // use user-preferred formats
1460
+ this.userPreferenceService.getPreferences().subscribe(result => {
1461
+ //if preferences exist then format date to users preference
1462
+ //otherwise use the last user preference
1463
+ if (result.preference) {
1464
+ formatString = result.preference.dateFormat;
1465
+ if (showTime) {
1466
+ let timeFormat = result.preference.timeFormat;
1467
+ if (!showSeconds) {
1468
+ timeFormat = timeFormat.replace(':ss', '');
1469
+ }
1470
+ formatString += ` ${timeFormat}`;
1471
+ }
1472
+ this.lastFormatString = formatString;
1473
+ }
1474
+ });
1475
+ display = moment(date).format(this.lastFormatString);
1476
+ }
1477
+ return display;
1478
+ }
1479
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DateDisplayPipe, deps: [{ token: UserPreferenceService }], target: i0.ɵɵFactoryTarget.Pipe }); }
1480
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: DateDisplayPipe, name: "dateDisplay" }); }
1481
+ }
1482
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DateDisplayPipe, decorators: [{
1483
+ type: Pipe,
1484
+ args: [{ name: 'dateDisplay' }]
1485
+ }], ctorParameters: () => [{ type: UserPreferenceService }] });
1486
+
1487
+ var DateInput;
1488
+ (function (DateInput) {
1489
+ function isSelectionSingleDate(selection) {
1490
+ return selection instanceof Date;
1491
+ }
1492
+ DateInput.isSelectionSingleDate = isSelectionSingleDate;
1493
+ function isSelectionRange(selection) {
1494
+ return !!selection && !isSelectionSingleDate(selection);
1495
+ }
1496
+ DateInput.isSelectionRange = isSelectionRange;
1497
+ class SelectionStrategies {
1498
+ constructor(dateDisplayPipe) {
1499
+ this.dateDisplayPipe = dateDisplayPipe;
1500
+ this._range = new RangeSelectionStrategy();
1501
+ this._day = new DaySelectionStrategy(this.dateDisplayPipe);
1502
+ this._last7Days = new Last7DaysSelectionStrategy(this._range);
1503
+ this._last28Days = new Last28DaysSelectionStrategy(this._range);
1504
+ this._month = new MonthSelectionStrategy();
1505
+ this._quarter = new QuarterSelectionStrategy();
1506
+ this._year = new YearSelectionStrategy();
1507
+ }
1508
+ get range() { return this._range; }
1509
+ get day() { return this._day; }
1510
+ get last7Days() { return this._last7Days; }
1511
+ get last28Days() { return this._last28Days; }
1512
+ get month() { return this._month; }
1513
+ get quarter() { return this._quarter; }
1514
+ get year() { return this._year; }
1515
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectionStrategies, deps: [{ token: DateDisplayPipe }], target: i0.ɵɵFactoryTarget.Injectable }); }
1516
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectionStrategies }); }
1517
+ }
1518
+ DateInput.SelectionStrategies = SelectionStrategies;
1519
+ })(DateInput || (DateInput = {}));
1520
+
1521
+ class CalendarItemComponent {
1522
+ get disabled() {
1523
+ return this.hidden || undefined;
1524
+ }
1525
+ constructor() {
1526
+ this.view = { mode: 'day', date: new Date() };
1527
+ this.minDate = DateTimeHelper.minDatePickerDate;
1528
+ this.maxDate = DateTimeHelper.maxDatePickerDate;
1529
+ this.today = false;
1530
+ this.selected = false;
1531
+ this.outsideActiveMonth = false;
1532
+ this.hidden = false;
1533
+ }
1534
+ ngOnChanges() {
1535
+ if (this.view.mode !== 'day') {
1536
+ this.today = false;
1537
+ this.outsideActiveMonth = false;
1538
+ }
1539
+ else {
1540
+ this.today = moment(this.item?.date).isSame(moment(), 'day');
1541
+ this.outsideActiveMonth = !moment(this.item?.date).isSame(this.view.date, 'month');
1542
+ }
1543
+ if (this.item?.date) {
1544
+ this.hidden = this.isHidden(this.item.date, this.minDate, this.maxDate, this.view.mode);
1545
+ }
1546
+ else {
1547
+ this.hidden = true;
1548
+ }
1549
+ this.selected = this.isSelected(this.item?.date, this.selection, this.view.mode);
1550
+ }
1551
+ isSelected(date, selection, view) {
1552
+ if (!date || !selection) {
1553
+ return false;
1554
+ }
1555
+ if (DateInput.isSelectionSingleDate(selection)) {
1556
+ return moment(date).isSame(selection, view);
1557
+ }
1558
+ else {
1559
+ if (selection.start && !selection.end) {
1560
+ return moment(date).isSame(selection.start, view);
1561
+ }
1562
+ else if (!selection.start && selection.end) {
1563
+ return moment(date).isSame(selection.end, view);
1564
+ }
1565
+ else if (selection.start && selection.end) {
1566
+ return moment(date).isBetween(selection.start, selection.end, view, '[]');
1567
+ }
1568
+ }
1569
+ return false;
1570
+ }
1571
+ isHidden(date, minDate, maxDate, view) {
1572
+ return moment(date).isBefore(minDate, view) || moment(date).isAfter(maxDate, view);
1573
+ }
1574
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CalendarItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1575
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CalendarItemComponent, selector: "button[ec-calendar-item]", inputs: { item: "item", selection: "selection", view: "view", minDate: "minDate", maxDate: "maxDate" }, host: { properties: { "class.is-today": "this.today", "class.is-selected": "this.selected", "class.is-outside-active-month": "this.outsideActiveMonth", "class.is-hidden": "this.hidden", "attr.disabled": "this.disabled" } }, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer;background-color:transparent;line-height:1.125rem}:host .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}:host .ec-icon{flex:none}:host .ec-icon+.label{flex:none;margin-left:.25rem}:host.has-badge{padding-right:.0625rem}:host:focus{outline:none;position:relative;z-index:1}:host:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}:host:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);--ec-color-icon: var(--ec-color-hint-dark)}:host:hover:not(:disabled){background-color:var(--ec-background-color-hover)}:host:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}:host:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}:host.is-selected{background-color:var(--ec-background-color-selected);font-weight:700}:host.is-selected,:host.is-selected:disabled{background-color:var(--ec-background-color-selected);font-weight:700}:host.is-today{text-decoration:underline}:host.is-outside-active-month{color:var(--ec-color-hint-dark)}:host.is-hidden{opacity:0!important}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1576
+ }
1577
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CalendarItemComponent, decorators: [{
1578
+ type: Component,
1579
+ args: [{ selector: 'button[ec-calendar-item]', template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer;background-color:transparent;line-height:1.125rem}:host .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}:host .ec-icon{flex:none}:host .ec-icon+.label{flex:none;margin-left:.25rem}:host.has-badge{padding-right:.0625rem}:host:focus{outline:none;position:relative;z-index:1}:host:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}:host:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);--ec-color-icon: var(--ec-color-hint-dark)}:host:hover:not(:disabled){background-color:var(--ec-background-color-hover)}:host:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}:host:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}:host.is-selected{background-color:var(--ec-background-color-selected);font-weight:700}:host.is-selected,:host.is-selected:disabled{background-color:var(--ec-background-color-selected);font-weight:700}:host.is-today{text-decoration:underline}:host.is-outside-active-month{color:var(--ec-color-hint-dark)}:host.is-hidden{opacity:0!important}\n"] }]
1580
+ }], ctorParameters: () => [], propDecorators: { item: [{
1581
+ type: Input
1582
+ }], selection: [{
1583
+ type: Input
1584
+ }], view: [{
1585
+ type: Input
1586
+ }], minDate: [{
1587
+ type: Input
1588
+ }], maxDate: [{
1589
+ type: Input
1590
+ }], today: [{
1591
+ type: HostBinding,
1592
+ args: ['class.is-today']
1593
+ }], selected: [{
1594
+ type: HostBinding,
1595
+ args: ['class.is-selected']
1596
+ }], outsideActiveMonth: [{
1597
+ type: HostBinding,
1598
+ args: ['class.is-outside-active-month']
1599
+ }], hidden: [{
1600
+ type: HostBinding,
1601
+ args: ['class.is-hidden']
1602
+ }], disabled: [{
1603
+ type: HostBinding,
1604
+ args: ['attr.disabled']
1605
+ }] } });
1606
+
736
1607
  class CalendarComponent {
737
1608
  constructor() {
738
1609
  this.id = 'calendar';
739
1610
  this.selection = null;
740
- this.selectionChange = new EventEmitter();
1611
+ this.selectionMode = 'day';
741
1612
  this.minDate = DateTimeHelper.minDatePickerDate;
742
1613
  this.maxDate = DateTimeHelper.maxDatePickerDate;
743
- this.focusOutStart = new EventEmitter();
744
- this.focusOutEnd = new EventEmitter();
745
- /** Array of calendar items to display in the calendar grid. */
1614
+ this.dateSelected = new EventEmitter();
1615
+ /** Determines the current view of the calendar. */
1616
+ this.view = { mode: 'day', date: new Date() };
1617
+ this.viewChange = new EventEmitter();
1618
+ /** Array of calendar item rows to display in the calendar. */
746
1619
  this.calendarItems = [];
747
- /** Determines the current view mode of the calendar. */
748
- this.view = 'day';
749
- /** TrackBy function for the calendar items. This avoids re-drawing calendar items if a date is shared between view updates */
750
- this.calendarItemTrackByDate = (index, item) => item.date.toISOString();
1620
+ /** Weekday labels to show at the top of the calendar in day view. */
1621
+ this.weekDays = moment.weekdaysShort().map(d => d.slice(0, 1));
751
1622
  this.disablePreviousButton = false;
752
1623
  this.disableNextButton = false;
753
- // By default, the active date is today.
754
- // This is replaced with the date of the selection if one is provided on init.
755
- this.activeDate = new Date();
756
- // Using moment here to get the weekday labels so they are localized.
757
- this.weekDays = moment.weekdaysShort().map(d => d.slice(0, 1));
1624
+ // Trackby functions for ngFor loops. These reduce the number of DOM elements that need to be updated when the calendar is re-drawn.
1625
+ // Without these there are some change-detection issues on the first-time rendering of the calendar.
1626
+ this.trackByDateRow = (index, row) => `${row[0].date.toISOString()}-${row[row.length - 1].date.toISOString()}`;
1627
+ this.trackByDate = (index, item) => item.date.toISOString();
758
1628
  }
759
1629
  ngOnChanges(changes) {
760
- if (changes.selection && this.selection) {
761
- // Only need to update the view if the selection is out of view.
762
- if (isCalendarSelectionSingleDate(this.selection) &&
763
- !this.isDateInView(this.selection) &&
764
- moment(this.selection).isBetween(this.minDate, this.maxDate, 'day', '[]')) {
765
- this.drawCalendar('day', this.selection);
766
- }
767
- else {
768
- // TODO ECAP-26841: determine the active date for a range selection and draw the calendar
769
- }
1630
+ if (changes.view) {
1631
+ this.drawCalendar(this.view);
1632
+ }
1633
+ if (changes.minDate || changes.maxDate) {
1634
+ this.updateNextPreviousStates();
770
1635
  }
771
1636
  }
772
1637
  ngOnInit() {
773
1638
  if (!this.calendarItems.length) {
774
- this.drawCalendar('day');
775
- }
776
- }
777
- onItemSelected(item) {
778
- if (this.view === 'day') {
779
- this.selection = item.date;
780
- this.selectionChange.emit(this.selection);
781
- }
782
- if (this.view === 'month') {
783
- this.drawCalendar('day', item.date);
784
- }
785
- if (this.view === 'year') {
786
- this.drawCalendar('month', item.date);
1639
+ this.drawCalendar(this.view);
787
1640
  }
788
1641
  }
789
1642
  onNextClick() {
790
1643
  // If we're in day view, we're incrementing by month
791
- // In both month and year views we're incrementing by year
792
- // In year view, we're moving by 16 years at a time
793
- const unit = this.view === 'day' ? 'month' : 'year';
1644
+ // In month, quarter, and year views we're incrementing by year\
1645
+ const unit = this.view.mode === 'day' ? 'month' : 'year';
794
1646
  // In year view, we're moving by 16 years at a time. Otherwise we're just moving by 1 month/year.
795
- const count = this.view === 'year' ? 16 : 1;
796
- const goToDate = moment(this.activeDate).add(count, unit).toDate();
797
- this.drawCalendar(this.view, goToDate);
1647
+ const count = this.view.mode === 'year' ? 16 : 1;
1648
+ const goToDate = moment(this.view.date).add(count, unit).toDate();
1649
+ this.drawCalendar({ mode: this.view.mode, date: goToDate });
798
1650
  }
799
1651
  onPreviousClick() {
800
1652
  // If we're in day view, we're incrementing by month
801
- // In both month and year views we're incrementing years
802
- const unit = this.view === 'day' ? 'month' : 'year';
1653
+ // In month, quarter, and year views we're incrementing by year
1654
+ const unit = this.view.mode === 'day' ? 'month' : 'year';
803
1655
  // In year view, we're moving by 16 years at a time. Otherwise we're just moving by 1 month/year.
804
- const count = this.view === 'year' ? 16 : 1;
805
- const goToDate = moment(this.activeDate).subtract(count, unit).toDate();
806
- this.drawCalendar(this.view, goToDate);
1656
+ const count = this.view.mode === 'year' ? 16 : 1;
1657
+ const goToDate = moment(this.view.date).subtract(count, unit).toDate();
1658
+ this.drawCalendar({ mode: this.view.mode, date: goToDate });
807
1659
  }
808
1660
  /** Switches the calendar to month view. */
809
1661
  onMonthClick() {
810
- this.drawCalendar('month');
1662
+ this.drawCalendar({ mode: 'month', date: this.view.date });
811
1663
  }
812
1664
  /** Switches the calendar to year view. */
813
1665
  onYearClick() {
814
- this.drawCalendar('year');
815
- }
816
- onFirstItemKeydown(event) {
817
- // If the user is tabbing backwards from the first item, emit the focusOutStart event.
818
- if (event.key === 'Tab' && event.shiftKey) {
819
- this.focusOutStart.emit(event);
820
- }
1666
+ this.drawCalendar({ mode: 'year', date: this.view.date });
821
1667
  }
822
- onLastItemKeydown(event) {
823
- // If the user is tabbing forwards from the last item, emit the focusOutEnd event.
824
- if (event.key === 'Tab' && !event.shiftKey) {
825
- this.focusOutEnd.emit(event);
1668
+ onItemSelected(item) {
1669
+ switch (this.view.mode) {
1670
+ case 'day':
1671
+ this.onDaySelected(item);
1672
+ break;
1673
+ case 'month':
1674
+ this.onMonthSelected(item);
1675
+ break;
1676
+ case 'quarter':
1677
+ this.onQuarterSelected(item);
1678
+ break;
1679
+ case 'year':
1680
+ this.onYearSelected(item);
1681
+ break;
826
1682
  }
827
1683
  }
828
- drawCalendar(view, goTo) {
829
- // If a goTo date is provided, update the active date so we know what to increment on next/previous clicks.
830
- if (goTo) {
831
- this.activeDate = goTo;
1684
+ onYearSelected(item) {
1685
+ // If in year selection mode, emit the calendar item so the date picker can update the selection.
1686
+ if (this.selectionMode === 'year') {
1687
+ this.dateSelected.emit(item.date);
1688
+ // If we're in quarter selection mode, draw the quarter view.
832
1689
  }
833
- this.month = moment(this.activeDate).format('MMM');
834
- this.year = moment(this.activeDate).format('YYYY');
835
- this.view = view;
836
- this.calendarItems = this.getCalendarItems(view, this.activeDate);
837
- const startYear = this.calendarItems[0].date < this.minDate ? this.minDate : this.calendarItems[0].date;
838
- const endYear = this.calendarItems[this.calendarItems.length - 1].date > this.maxDate ? this.maxDate : this.calendarItems[this.calendarItems.length - 1].date;
839
- this.yearRange = `${moment(startYear).format('YYYY')}&ndash;${moment(endYear).format('YYYY')}`;
840
- // If the active date is less than the min date or the min date is in view, disable the previous button.
841
- if (this.activeDate < this.minDate || this.isDateInView(this.minDate)) {
842
- this.disablePreviousButton = true;
1690
+ else if (this.selectionMode === 'quarter') {
1691
+ this.drawCalendar({ mode: 'quarter', date: item.date });
1692
+ // All other selection modes should zoom in to the month view when a year is selected.
843
1693
  }
844
1694
  else {
845
- this.disablePreviousButton = false;
1695
+ this.drawCalendar({ mode: 'month', date: item.date });
846
1696
  }
847
- // If the active date is greater than the max date or the max date is in view, disable the next button.
848
- if (this.activeDate > this.maxDate || this.isDateInView(this.maxDate)) {
849
- this.disableNextButton = true;
1697
+ }
1698
+ onQuarterSelected(item) {
1699
+ // Quarter view is only accessible when in quarter selection mode,
1700
+ // so there's no other views to draw from here. Just emit the selected item.
1701
+ this.dateSelected.emit(item.date);
1702
+ }
1703
+ onMonthSelected(item) {
1704
+ // When in month selection mode, emit the selected month item and don't change the view.
1705
+ if (this.selectionMode === 'month') {
1706
+ this.dateSelected.emit(item.date);
1707
+ // Month view is only accessible from day, last7days, last28days, month, and range selection modes.
1708
+ // If we're not in month selection mode, we need to zoom in to the day view.
850
1709
  }
851
1710
  else {
852
- this.disableNextButton = false;
1711
+ this.drawCalendar({ mode: 'day', date: item.date });
1712
+ }
1713
+ }
1714
+ onDaySelected(item) {
1715
+ // No further views other than day mode. Just emit the selected item.
1716
+ this.dateSelected.emit(item.date);
1717
+ }
1718
+ drawCalendar(view) {
1719
+ // If the view has changed, emit the new view.
1720
+ if (view.date !== this.view.date || view.mode !== this.view.mode) {
1721
+ this.view = view;
1722
+ this.viewChange.emit(view);
853
1723
  }
1724
+ this.month = moment(this.view.date).format('MMM');
1725
+ this.year = moment(this.view.date).format('YYYY');
1726
+ this.calendarItems = this.getCalendarItems(this.view);
1727
+ const startYear = this.calendarItems[0][0].date < this.minDate ? this.minDate : this.calendarItems[0][0].date;
1728
+ const lastItem = this.getLastItem();
1729
+ const endYear = lastItem.date > this.maxDate ? this.maxDate : lastItem.date;
1730
+ this.yearRange = `${moment(startYear).format('YYYY')}&ndash;${moment(endYear).format('YYYY')}`;
1731
+ this.updateNextPreviousStates();
854
1732
  }
855
- getCalendarItems(view, activeDate) {
856
- switch (view) {
857
- case 'day': return this.getDayViewItems(activeDate);
858
- case 'month': return this.getMonthViewItems(activeDate);
859
- case 'year': return this.getYearViewItems(activeDate);
1733
+ getCalendarItems(view) {
1734
+ switch (view.mode) {
1735
+ case 'day': return this.getDayViewItems(view.date);
1736
+ case 'month': return this.getMonthViewItems(view.date);
1737
+ case 'quarter': return this.getQuarterViewItems(view.date);
1738
+ case 'year': return this.getYearViewItems(view.date);
860
1739
  }
861
1740
  }
862
1741
  getDayViewItems(activeDate) {
863
1742
  // 6 rows of 7 days = 42 days
864
- return range(0, 42).map(i => {
865
- // Use the start of the week of the first day of the month.
866
- // This pads out the first week with any days from the previous month.
867
- const date = moment(activeDate).startOf('month').startOf('week').add(i, 'day');
868
- return {
869
- date: date.toDate(),
870
- label: date.format('D')
871
- };
1743
+ return range(0, 6).map(r => {
1744
+ return range(0, 7).map(d => {
1745
+ // Use the start of the week of the first day of the month.
1746
+ // This pads out the first week with any days from the previous month.
1747
+ const date = moment(activeDate).startOf('month').startOf('week').add(r * 7 + d, 'day');
1748
+ return {
1749
+ date: date.toDate(),
1750
+ label: date.format('D')
1751
+ };
1752
+ });
872
1753
  });
873
1754
  }
874
1755
  getMonthViewItems(activeDate) {
875
- return range(0, 12).map(i => {
876
- const date = moment(activeDate).startOf('year').add(i, 'month');
877
- return {
878
- date: date.toDate(),
879
- label: date.format('MMM')
880
- };
1756
+ // 4 rows of 3 months = 12 months
1757
+ return range(0, 4).map(r => {
1758
+ return range(0, 3).map(m => {
1759
+ const date = moment(activeDate).startOf('year').add(r * 3 + m, 'month');
1760
+ return {
1761
+ date: date.toDate(),
1762
+ label: date.format('MMM')
1763
+ };
1764
+ });
1765
+ });
1766
+ }
1767
+ getQuarterViewItems(activeDate) {
1768
+ // 2 rows of 2 quarters = 4 quarters
1769
+ return range(0, 2).map(r => {
1770
+ return range(0, 2).map(q => {
1771
+ const date = moment(activeDate).startOf('year').add(r * 2 + q, 'quarter');
1772
+ const endDate = moment(date).endOf('quarter');
1773
+ return {
1774
+ date: date.toDate(),
1775
+ label: `${date.format('MMM')}&ndash;${endDate.format('MMM')}`
1776
+ };
1777
+ });
881
1778
  });
882
1779
  }
883
1780
  getYearViewItems(activeDate) {
884
- // 4x4 grid of years = 16 years
885
- return range(0, 16).map(i => {
886
- // Put the current active year at the beginning of the 3rd row.
887
- const date = moment(activeDate).startOf('year').subtract(8, 'year').add(i, 'year');
888
- return {
889
- date: date.toDate(),
890
- label: date.format('YYYY')
891
- };
1781
+ // 4 rows of 4 years = 16 years
1782
+ return range(0, 4).map(r => {
1783
+ return range(0, 4).map(y => {
1784
+ // Subtracting 8 years to put the current active year at the beginning of the 3rd row.
1785
+ const date = moment(activeDate).startOf('year').subtract(8, 'years').add(r * 4 + y, 'year');
1786
+ return {
1787
+ date: date.toDate(),
1788
+ label: date.format('YYYY')
1789
+ };
1790
+ });
892
1791
  });
893
1792
  }
894
- /** Returns true if the date is within the current calendar view */
895
- isDateInView(date) {
896
- if (!this.calendarItems.length) {
897
- return false;
1793
+ updateNextPreviousStates() {
1794
+ // We change the granularity of the min and max date checks based on the current view mode.
1795
+ // We don't want to disable the next/previous buttons if the min or max date is within the
1796
+ // next or previous view
1797
+ const unit = this.view.mode === 'day' ? 'month' : 'year';
1798
+ // When in year view, we need to subtract 9 years to determine if we're past the min date.
1799
+ // The year view is 16 years long, and the current date is the 9th year in the view.
1800
+ const subCount = this.view.mode === 'year' ? 9 : 1;
1801
+ if (moment(this.view.date).subtract(subCount, unit).isBefore(this.minDate, unit)) {
1802
+ this.disablePreviousButton = true;
1803
+ }
1804
+ else {
1805
+ this.disablePreviousButton = false;
1806
+ }
1807
+ // When in year view, we need to add 8 years to determine if we're past the max date.
1808
+ // The year view is 16 years long, and the current date is the 9th year in the view.
1809
+ const addCount = this.view.mode === 'year' ? 8 : 1;
1810
+ if (moment(this.view.date).add(addCount, unit).isAfter(this.maxDate, unit)) {
1811
+ this.disableNextButton = true;
898
1812
  }
899
- const viewStart = this.calendarItems[0].date;
900
- const viewEnd = this.calendarItems[this.calendarItems.length - 1].date;
901
- return date >= viewStart && date <= viewEnd;
1813
+ else {
1814
+ this.disableNextButton = false;
1815
+ }
1816
+ }
1817
+ getLastItem() {
1818
+ const lastRow = this.calendarItems[this.calendarItems.length - 1];
1819
+ return lastRow[lastRow.length - 1];
902
1820
  }
903
1821
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
904
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CalendarComponent, selector: "ec-calendar", inputs: { id: "id", selection: "selection", minDate: "minDate", maxDate: "maxDate" }, outputs: { selectionChange: "selectionChange", focusOutStart: "focusOutStart", focusOutEnd: "focusOutEnd" }, host: { properties: { "attr.id": "this.id" } }, usesOnChanges: true, ngImport: i0, template: "<header class=\"d-flex align-items-center mb-2\">\r\n <button id=\"{{id}}_prev_button\"\r\n class=\"mr-auto\"\r\n (click)=\"onPreviousClick()\"\r\n (keydown)=\"!disablePreviousButton ? onFirstItemKeydown($event) : undefined\"\r\n [disabled]=\"disablePreviousButton\">\r\n <i class=\"ec-icon icon-angle-down rotate-90\"></i>\r\n </button>\r\n\r\n <button *ngIf=\"view === 'day'\"\r\n id=\"{{id}}_month_button\"\r\n class=\"text-body-1 font-weight-bold\"\r\n (click)=\"onMonthClick()\"\r\n (keydown)=\"disablePreviousButton ? onFirstItemKeydown($event) : undefined\">\r\n {{month}}\r\n </button>\r\n\r\n <button *ngIf=\"view !== 'year'\"\r\n id=\"{{id}}_year_button\"\r\n class=\"text-body-1 font-weight-bold\"\r\n (click)=\"onYearClick()\"\r\n (keydown)=\"disablePreviousButton && view !== 'day' ? onFirstItemKeydown($event) : undefined\">\r\n {{year}}\r\n </button>\r\n\r\n <div id=\"{{id}}_year_range\"\r\n *ngIf=\"view === 'year'\"\r\n class=\"text-body-1 font-weight-bold\"\r\n [innerHTML]=\"yearRange\">\r\n </div>\r\n\r\n <button id=\"{{id}}_next_button\"\r\n class=\"ml-auto\"\r\n (click)=\"onNextClick()\"\r\n [disabled]=\"disableNextButton\"\r\n (keydown)=\"disablePreviousButton && view === 'year' ? onFirstItemKeydown($event) : undefined\">\r\n <i class=\"ec-icon icon-angle-down rotate-270\"></i>\r\n </button>\r\n</header>\r\n\r\n<ul class=\"px-1 {{view}}-view\">\r\n <ng-container *ngIf=\"view === 'day'\">\r\n <li *ngFor=\"let day of weekDays\"\r\n class=\"d-flex align-items-center justify-content-center text-heading-3\">\r\n {{day}}\r\n </li>\r\n </ng-container>\r\n\r\n <li *ngFor=\"let item of calendarItems; last as isLast; trackBy: calendarItemTrackByDate;\">\r\n <button id=\"{{id}}_item_{{item.date | date:'MM_dd_yyyy'}}\"\r\n ec-calendar-item\r\n [item]=\"item\"\r\n [activeDate]=\"activeDate\"\r\n [selection]=\"selection\"\r\n [view]=\"view\"\r\n (click)=\"onItemSelected(item)\"\r\n (keydown)=\"isLast ? onLastItemKeydown($event) : undefined\"\r\n [hidden]=\"item.date < minDate || item.date > maxDate\">\r\n </button>\r\n </li>\r\n</ul>", styles: [":host{display:inline-block}button{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer;background-color:transparent}button .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}button .ec-icon{flex:none}button .ec-icon+.label{flex:none;margin-left:.25rem}button.has-badge{padding-right:.0625rem}button:focus{outline:none;position:relative;z-index:1}button:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}button:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);opacity:1;--ec-color-icon: var(--ec-color-hint-dark)}button:hover:not(:disabled){background-color:var(--ec-background-color-hover)}button:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}button:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}ul{list-style:none;padding:0;margin:0;display:grid;align-items:stretch;justify-items:stretch}button[ec-calendar-item]{height:100%;width:100%}ul.day-view{grid-template-columns:repeat(7,2rem);grid-auto-rows:1.75rem;row-gap:.25rem}ul.month-view{grid-template-columns:repeat(3,4.67rem);grid-auto-rows:3.25rem;row-gap:.25rem}ul.year-view{grid-template-columns:repeat(4,3.5rem);grid-auto-rows:3.25rem;row-gap:.25rem}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CalendarItemComponent, selector: "button[ec-calendar-item]", inputs: ["item", "activeDate", "selection", "view"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1822
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CalendarComponent, selector: "ec-calendar", inputs: { id: "id", selection: "selection", selectionMode: "selectionMode", minDate: "minDate", maxDate: "maxDate", view: "view" }, outputs: { dateSelected: "dateSelected", viewChange: "viewChange" }, host: { properties: { "attr.id": "this.id" } }, usesOnChanges: true, ngImport: i0, template: "<header class=\"d-flex align-items-center mt-1 mb-2 px-1\">\r\n <button id=\"{{id}}_prev_button\"\r\n class=\"mr-auto\"\r\n (click)=\"onPreviousClick()\"\r\n [disabled]=\"disablePreviousButton\">\r\n <i class=\"ec-icon icon-angle-down rotate-90\"></i>\r\n </button>\r\n\r\n <button *ngIf=\"view.mode === 'day'\"\r\n id=\"{{id}}_month_button\"\r\n class=\"text-body-1 font-weight-bold\"\r\n (click)=\"onMonthClick()\">\r\n {{month}}\r\n </button>\r\n\r\n <button *ngIf=\"view.mode !== 'year'\"\r\n id=\"{{id}}_year_button\"\r\n class=\"text-body-1 font-weight-bold\"\r\n (click)=\"onYearClick()\">\r\n {{year}}\r\n </button>\r\n\r\n <div id=\"{{id}}_year_range\"\r\n *ngIf=\"view.mode === 'year'\"\r\n class=\"text-body-1 font-weight-bold\"\r\n [innerHTML]=\"yearRange\">\r\n </div>\r\n\r\n <button id=\"{{id}}_next_button\"\r\n class=\"ml-auto\"\r\n (click)=\"onNextClick()\"\r\n [disabled]=\"disableNextButton\">\r\n <i class=\"ec-icon icon-angle-down rotate-270\"></i>\r\n </button>\r\n</header>\r\n\r\n<div *ngIf=\"view.mode === 'day'\"\r\n class=\"mb-1 px-2 d-flex\">\r\n <h3 *ngFor=\"let day of weekDays\"\r\n class=\"text-heading-3 d-flex justify-content-center align-items-center\"\r\n style=\"width: 2rem; height: 1.75rem;\">{{day}}</h3>\r\n</div>\r\n\r\n<div *ngFor=\"let row of calendarItems; last as isLast; trackBy: trackByDateRow\"\r\n class=\"px-2 d-flex {{view.mode}}-view\"\r\n [class.mb-1]=\"!isLast\"\r\n [class.mb-2]=\"isLast\">\r\n <button *ngFor=\"let item of row; trackBy: trackByDate\"\r\n id=\"{{id}}_item_{{item.date | date:'MM_dd_yyyy'}}\"\r\n ec-calendar-item\r\n [item]=\"item\"\r\n [selection]=\"selection\"\r\n [view]=\"view\"\r\n (click)=\"onItemSelected(item)\"\r\n [innerHTML]=\"item.label\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\">\r\n </button>\r\n</div>\r\n", styles: [":host{display:inline-block}button{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer;background-color:transparent}button .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}button .ec-icon{flex:none}button .ec-icon+.label{flex:none;margin-left:.25rem}button.has-badge{padding-right:.0625rem}button:focus{outline:none;position:relative;z-index:1}button:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}button:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);--ec-color-icon: var(--ec-color-hint-dark)}button:hover:not(:disabled){background-color:var(--ec-background-color-hover)}button:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}button:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}button.is-selected{background-color:var(--ec-background-color-selected);font-weight:700}.day-view button{width:2rem;height:1.75rem}.month-view button{width:4.67rem;height:3.25rem}.quarter-view button{width:7rem;height:6.75rem}.year-view button{width:3.5rem;height:3.25rem}.is-selected:has(+.is-selected:not(:disabled)){border-top-right-radius:0;border-bottom-right-radius:0}.is-selected:not(:disabled)+.is-selected{border-top-left-radius:0;border-bottom-left-radius:0}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CalendarItemComponent, selector: "button[ec-calendar-item]", inputs: ["item", "selection", "view", "minDate", "maxDate"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
905
1823
  }
906
1824
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CalendarComponent, decorators: [{
907
1825
  type: Component,
908
- args: [{ selector: 'ec-calendar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<header class=\"d-flex align-items-center mb-2\">\r\n <button id=\"{{id}}_prev_button\"\r\n class=\"mr-auto\"\r\n (click)=\"onPreviousClick()\"\r\n (keydown)=\"!disablePreviousButton ? onFirstItemKeydown($event) : undefined\"\r\n [disabled]=\"disablePreviousButton\">\r\n <i class=\"ec-icon icon-angle-down rotate-90\"></i>\r\n </button>\r\n\r\n <button *ngIf=\"view === 'day'\"\r\n id=\"{{id}}_month_button\"\r\n class=\"text-body-1 font-weight-bold\"\r\n (click)=\"onMonthClick()\"\r\n (keydown)=\"disablePreviousButton ? onFirstItemKeydown($event) : undefined\">\r\n {{month}}\r\n </button>\r\n\r\n <button *ngIf=\"view !== 'year'\"\r\n id=\"{{id}}_year_button\"\r\n class=\"text-body-1 font-weight-bold\"\r\n (click)=\"onYearClick()\"\r\n (keydown)=\"disablePreviousButton && view !== 'day' ? onFirstItemKeydown($event) : undefined\">\r\n {{year}}\r\n </button>\r\n\r\n <div id=\"{{id}}_year_range\"\r\n *ngIf=\"view === 'year'\"\r\n class=\"text-body-1 font-weight-bold\"\r\n [innerHTML]=\"yearRange\">\r\n </div>\r\n\r\n <button id=\"{{id}}_next_button\"\r\n class=\"ml-auto\"\r\n (click)=\"onNextClick()\"\r\n [disabled]=\"disableNextButton\"\r\n (keydown)=\"disablePreviousButton && view === 'year' ? onFirstItemKeydown($event) : undefined\">\r\n <i class=\"ec-icon icon-angle-down rotate-270\"></i>\r\n </button>\r\n</header>\r\n\r\n<ul class=\"px-1 {{view}}-view\">\r\n <ng-container *ngIf=\"view === 'day'\">\r\n <li *ngFor=\"let day of weekDays\"\r\n class=\"d-flex align-items-center justify-content-center text-heading-3\">\r\n {{day}}\r\n </li>\r\n </ng-container>\r\n\r\n <li *ngFor=\"let item of calendarItems; last as isLast; trackBy: calendarItemTrackByDate;\">\r\n <button id=\"{{id}}_item_{{item.date | date:'MM_dd_yyyy'}}\"\r\n ec-calendar-item\r\n [item]=\"item\"\r\n [activeDate]=\"activeDate\"\r\n [selection]=\"selection\"\r\n [view]=\"view\"\r\n (click)=\"onItemSelected(item)\"\r\n (keydown)=\"isLast ? onLastItemKeydown($event) : undefined\"\r\n [hidden]=\"item.date < minDate || item.date > maxDate\">\r\n </button>\r\n </li>\r\n</ul>", styles: [":host{display:inline-block}button{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer;background-color:transparent}button .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}button .ec-icon{flex:none}button .ec-icon+.label{flex:none;margin-left:.25rem}button.has-badge{padding-right:.0625rem}button:focus{outline:none;position:relative;z-index:1}button:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}button:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);opacity:1;--ec-color-icon: var(--ec-color-hint-dark)}button:hover:not(:disabled){background-color:var(--ec-background-color-hover)}button:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}button:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}ul{list-style:none;padding:0;margin:0;display:grid;align-items:stretch;justify-items:stretch}button[ec-calendar-item]{height:100%;width:100%}ul.day-view{grid-template-columns:repeat(7,2rem);grid-auto-rows:1.75rem;row-gap:.25rem}ul.month-view{grid-template-columns:repeat(3,4.67rem);grid-auto-rows:3.25rem;row-gap:.25rem}ul.year-view{grid-template-columns:repeat(4,3.5rem);grid-auto-rows:3.25rem;row-gap:.25rem}\n"] }]
909
- }], ctorParameters: () => [], propDecorators: { id: [{
1826
+ args: [{ selector: 'ec-calendar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<header class=\"d-flex align-items-center mt-1 mb-2 px-1\">\r\n <button id=\"{{id}}_prev_button\"\r\n class=\"mr-auto\"\r\n (click)=\"onPreviousClick()\"\r\n [disabled]=\"disablePreviousButton\">\r\n <i class=\"ec-icon icon-angle-down rotate-90\"></i>\r\n </button>\r\n\r\n <button *ngIf=\"view.mode === 'day'\"\r\n id=\"{{id}}_month_button\"\r\n class=\"text-body-1 font-weight-bold\"\r\n (click)=\"onMonthClick()\">\r\n {{month}}\r\n </button>\r\n\r\n <button *ngIf=\"view.mode !== 'year'\"\r\n id=\"{{id}}_year_button\"\r\n class=\"text-body-1 font-weight-bold\"\r\n (click)=\"onYearClick()\">\r\n {{year}}\r\n </button>\r\n\r\n <div id=\"{{id}}_year_range\"\r\n *ngIf=\"view.mode === 'year'\"\r\n class=\"text-body-1 font-weight-bold\"\r\n [innerHTML]=\"yearRange\">\r\n </div>\r\n\r\n <button id=\"{{id}}_next_button\"\r\n class=\"ml-auto\"\r\n (click)=\"onNextClick()\"\r\n [disabled]=\"disableNextButton\">\r\n <i class=\"ec-icon icon-angle-down rotate-270\"></i>\r\n </button>\r\n</header>\r\n\r\n<div *ngIf=\"view.mode === 'day'\"\r\n class=\"mb-1 px-2 d-flex\">\r\n <h3 *ngFor=\"let day of weekDays\"\r\n class=\"text-heading-3 d-flex justify-content-center align-items-center\"\r\n style=\"width: 2rem; height: 1.75rem;\">{{day}}</h3>\r\n</div>\r\n\r\n<div *ngFor=\"let row of calendarItems; last as isLast; trackBy: trackByDateRow\"\r\n class=\"px-2 d-flex {{view.mode}}-view\"\r\n [class.mb-1]=\"!isLast\"\r\n [class.mb-2]=\"isLast\">\r\n <button *ngFor=\"let item of row; trackBy: trackByDate\"\r\n id=\"{{id}}_item_{{item.date | date:'MM_dd_yyyy'}}\"\r\n ec-calendar-item\r\n [item]=\"item\"\r\n [selection]=\"selection\"\r\n [view]=\"view\"\r\n (click)=\"onItemSelected(item)\"\r\n [innerHTML]=\"item.label\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\">\r\n </button>\r\n</div>\r\n", styles: [":host{display:inline-block}button{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer;background-color:transparent}button .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}button .ec-icon{flex:none}button .ec-icon+.label{flex:none;margin-left:.25rem}button.has-badge{padding-right:.0625rem}button:focus{outline:none;position:relative;z-index:1}button:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}button:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);--ec-color-icon: var(--ec-color-hint-dark)}button:hover:not(:disabled){background-color:var(--ec-background-color-hover)}button:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}button:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}button.is-selected{background-color:var(--ec-background-color-selected);font-weight:700}.day-view button{width:2rem;height:1.75rem}.month-view button{width:4.67rem;height:3.25rem}.quarter-view button{width:7rem;height:6.75rem}.year-view button{width:3.5rem;height:3.25rem}.is-selected:has(+.is-selected:not(:disabled)){border-top-right-radius:0;border-bottom-right-radius:0}.is-selected:not(:disabled)+.is-selected{border-top-left-radius:0;border-bottom-left-radius:0}\n"] }]
1827
+ }], propDecorators: { id: [{
910
1828
  type: HostBinding,
911
1829
  args: ['attr.id']
912
1830
  }, {
913
1831
  type: Input
914
1832
  }], selection: [{
915
1833
  type: Input
916
- }], selectionChange: [{
917
- type: Output
1834
+ }], selectionMode: [{
1835
+ type: Input
918
1836
  }], minDate: [{
919
1837
  type: Input
920
1838
  }], maxDate: [{
921
1839
  type: Input
922
- }], focusOutStart: [{
1840
+ }], dateSelected: [{
923
1841
  type: Output
924
- }], focusOutEnd: [{
1842
+ }], view: [{
1843
+ type: Input
1844
+ }], viewChange: [{
925
1845
  type: Output
926
1846
  }] } });
927
1847
 
928
- class UserPreferenceService {
929
- getPreferences() {
930
- return of({ preference: { dateFormat: 'MM/DD/YYYY', timeFormat: 'h:mm:ss a' } });
931
- }
932
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: UserPreferenceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
933
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: UserPreferenceService, providedIn: 'root' }); }
934
- }
935
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: UserPreferenceService, decorators: [{
936
- type: Injectable,
937
- args: [{
938
- providedIn: 'root'
939
- }]
940
- }] });
941
-
942
- /**
943
- * Format a date to the user's preference for display
944
- */
945
- class DateDisplayPipe {
946
- constructor(userPreferenceService) {
947
- this.userPreferenceService = userPreferenceService;
948
- this.lastFormatString = 'MM/DD/YYYY';
949
- }
950
- /**
951
- * Format a date for display, accounting for user's display preferences.
952
- *
953
- * If {@see date} is null or undefined, or the end of time, returns empty string
954
- */
955
- transform(date, showEndOfTime, showTime, showSeconds) {
956
- let display = '';
957
- let formatString = '';
958
- if (date && moment(date).isValid() && (showEndOfTime || !DateTimeHelper.isEndOfTime(date))) {
959
- // use user-preferred formats
960
- this.userPreferenceService.getPreferences().subscribe(result => {
961
- //if preferences exist then format date to users preference
962
- //otherwise use the last user preference
963
- if (result.preference) {
964
- formatString = result.preference.dateFormat;
965
- if (showTime) {
966
- let timeFormat = result.preference.timeFormat;
967
- if (!showSeconds) {
968
- timeFormat = timeFormat.replace(':ss', '');
969
- }
970
- formatString += ` ${timeFormat}`;
971
- }
972
- this.lastFormatString = formatString;
973
- }
974
- });
975
- display = moment(date).format(this.lastFormatString);
976
- }
977
- return display;
978
- }
979
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DateDisplayPipe, deps: [{ token: UserPreferenceService }], target: i0.ɵɵFactoryTarget.Pipe }); }
980
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: DateDisplayPipe, name: "dateDisplay" }); }
981
- }
982
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DateDisplayPipe, decorators: [{
983
- type: Pipe,
984
- args: [{ name: 'dateDisplay' }]
985
- }], ctorParameters: () => [{ type: UserPreferenceService }] });
986
-
987
1848
  /**
988
1849
  * "Weak Type" describing interpolation parameters for NumericBox
989
1850
  */
@@ -1788,11 +2649,11 @@ class CheckboxComponent extends FormControlBase {
1788
2649
  }
1789
2650
  }
1790
2651
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CheckboxComponent, deps: [{ token: ValidationMessageService }, { token: FormGroupHelper }], target: i0.ɵɵFactoryTarget.Component }); }
1791
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CheckboxComponent, selector: "ec-checkbox", inputs: { name: "name", dependentCheckboxesGroup: "dependentCheckboxesGroup", ignoreDisabledDependents: "ignoreDisabledDependents" }, viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["checkboxInput"], descendants: true, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"control\">\r\n <label class=\"checkbox\"\r\n [ngClass]=\"{'is-disabled': formModel.disabled, 'no-label': !label, 'is-readonly': readonly}\">\r\n <input id=\"{{id}}_input\"\r\n #checkboxInput\r\n class='input'\r\n [class.indeterminate]=\"indeterminate\"\r\n [attr.id]=\"inputId\"\r\n [attr.name]=\"name\"\r\n type=\"checkbox\"\r\n tabindex=\"{{tabindex}}\"\r\n [formControl]=\"formModel\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n <i class=\"ec-icon icon-check\"></i>\r\n\r\n <span id=\"{{id}}_label\"\r\n *ngIf=\"label\"\r\n class=\"label\">\r\n <span [innerHtml]=\"label | translate\"></span>\r\n <ec-help-popover id=\"{{id}}_helpPopover\"\r\n *ngIf=\"helpPopover\"\r\n class=\"d-inline-block my-n2 mx-n1\"\r\n text=\"{{helpPopover | translate}}\"\r\n contentPosition=\"{{helpPopoverPosition}}\">\r\n </ec-help-popover>\r\n </span>\r\n </label>\r\n</div>", styles: [":host{color:var(--ec-form-control-color);font-size:var(--ec-form-control-font-size);display:block;margin-bottom:1rem;width:100%}:host :host-context(.form-condensed){margin-bottom:.5rem}:host .control{width:100%;display:flex;flex-direction:column}:host .control.control-label-bottom{flex-direction:column-reverse}:host .control.control-label-left{flex-direction:row}:host .control.control-label-left label{margin-right:.25rem}:host .control.control-label-right{flex-direction:row-reverse}:host .control.control-label-right label{margin-left:.25rem}:host .control.control-label-left,:host .control.control-label-right{align-items:center}:host .control.control-label-left label,:host .control.control-label-right label{flex:1 1;margin-top:0;margin-bottom:0}:host .control.control-label-left .control-input,:host .control.control-label-right .control-input{flex:2 2}:host .control.is-readonly input,:host .control.is-readonly select,:host .control.is-readonly textarea{border-color:var(--ec-form-control-border-color-readonly);background-color:var(--ec-form-control-background-color-readonly);background-clip:border-box;background-image:none;color:var(--ec-form-control-color-readonly);opacity:1;-webkit-user-select:none;user-select:none;pointer-events:none;overflow:hidden;white-space:nowrap}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid{background-color:var(--ec-form-control-background-color-invalid);border-color:var(--ec-form-control-border-color-invalid);background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid:focus,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid:focus{border-color:var(--ec-form-control-background-color-invalid)}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid~.icon-invalid,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid~.icon-required,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid~.icon-required{display:none}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button{background-color:var(--ec-form-control-background-color-invalid)}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button:not(:focus){border-color:var(--ec-form-control-border-color-invalid)}:host .textbox-group{display:flex;position:relative}:host textarea:focus,:host input:focus,:host select:focus{outline:none}:host(.w-auto){width:auto}.checkbox{cursor:pointer;display:inline-flex;margin-bottom:0;position:relative}.checkbox.is-disabled{cursor:default}.input{margin-top:.5rem;opacity:0;position:absolute;z-index:-1}.input:not(:checked)+.ec-icon{color:var(--ec-form-control-border-color)}.input:not(:checked)+.ec-icon:before{display:none}.input.indeterminate+.ec-icon,.input:indeterminate+.ec-icon{color:var(--ec-color-interactive)}.input.indeterminate+.ec-icon:before,.input:indeterminate+.ec-icon:before{content:\"\";background-color:currentColor;display:block;width:10px;height:3px}.input:focus+.ec-icon{color:var(--ec-color-interactive);box-shadow:var(--ec-form-control-box-shadow-focus);border-color:var(--ec-form-control-border-color-focus)}.input:disabled+.ec-icon{color:var(--ec-form-control-color-disabled);background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}.input:disabled~.label{color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}.ec-icon{background-color:var(--ec-form-control-background-color);background-clip:padding-box;border:1px solid currentColor;color:var(--ec-color-interactive);margin-top:.5rem;flex:none;pointer-events:none;display:inline-flex;align-items:center;justify-content:center;height:1em;width:1em;border-radius:.125rem}.ec-icon:before{font-size:.6875em}.label{line-height:1.25rem;padding:.375rem 0;margin-left:.5rem;min-height:2rem;height:auto}.checkbox.is-readonly{pointer-events:none}.checkbox.is-readonly .input{opacity:0}.checkbox.is-readonly .ec-icon{background-color:var(--ec-form-control-background-color-readonly);border-color:var(--ec-form-control-border-color-readonly)}.checkbox.is-readonly .label,.checkbox.is-readonly .ec-icon{opacity:1;color:var(--ec-form-control-color)}.no-label .input,.no-label .icon-check{margin-top:0}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: HelpPopoverComponent, selector: "ec-help-popover", inputs: ["id", "text", "contentPosition", "maxWidth"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] }); }
2652
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CheckboxComponent, selector: "ec-checkbox", inputs: { name: "name", dependentCheckboxesGroup: "dependentCheckboxesGroup", ignoreDisabledDependents: "ignoreDisabledDependents" }, viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["checkboxInput"], descendants: true, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"control\">\r\n <label class=\"checkbox\"\r\n [ngClass]=\"{'is-disabled': formModel.disabled, 'no-label': !label, 'is-readonly': readonly}\">\r\n <input id=\"{{id}}_input\"\r\n #checkboxInput\r\n class='input'\r\n [class.indeterminate]=\"indeterminate\"\r\n [attr.id]=\"inputId\"\r\n [attr.name]=\"name\"\r\n type=\"checkbox\"\r\n tabindex=\"{{tabindex}}\"\r\n [formControl]=\"formModel\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n <i class=\"ec-icon icon-check\"></i>\r\n\r\n <span id=\"{{id}}_label\"\r\n *ngIf=\"label\"\r\n class=\"label\">\r\n <span [innerHtml]=\"label | translate\"></span>\r\n <ec-help-popover id=\"{{id}}_helpPopover\"\r\n *ngIf=\"helpPopover\"\r\n class=\"d-inline-block my-n2 mx-n1\"\r\n text=\"{{helpPopover | translate}}\"\r\n contentPosition=\"{{helpPopoverPosition}}\">\r\n </ec-help-popover>\r\n </span>\r\n </label>\r\n</div>", styles: [":host{color:var(--ec-form-control-color);font-size:var(--ec-form-control-font-size);display:block;margin-bottom:1rem;width:100%}:host :host-context(.form-condensed){margin-bottom:.5rem}:host .control{width:100%;display:flex;flex-direction:column}:host .control.control-label-bottom{flex-direction:column-reverse}:host .control.control-label-left{flex-direction:row}:host .control.control-label-left label{margin-right:.25rem}:host .control.control-label-right{flex-direction:row-reverse}:host .control.control-label-right label{margin-left:.25rem}:host .control.control-label-left,:host .control.control-label-right{align-items:center}:host .control.control-label-left label,:host .control.control-label-right label{flex:1 1;margin-top:0;margin-bottom:0}:host .control.control-label-left .control-input,:host .control.control-label-right .control-input{flex:2 2}:host .control.is-readonly input,:host .control.is-readonly select,:host .control.is-readonly textarea{border-color:var(--ec-form-control-border-color-readonly);background-color:var(--ec-form-control-background-color-readonly);background-clip:border-box;background-image:none;color:var(--ec-form-control-color-readonly);opacity:1;-webkit-user-select:none;user-select:none;pointer-events:none;overflow:hidden;white-space:nowrap}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid{background-color:var(--ec-form-control-background-color-invalid);border-color:var(--ec-form-control-border-color-invalid);background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid:focus,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid:focus{border-color:var(--ec-form-control-background-color-invalid)}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid~.icon-invalid,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid~.icon-required,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid~.icon-required{display:none}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button{background-color:var(--ec-form-control-background-color-invalid)}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button:not(:focus){border-color:var(--ec-form-control-border-color-invalid)}:host .textbox-group{display:flex;position:relative}:host textarea:focus,:host input:focus,:host select:focus{outline:none}:host(.w-auto){width:auto}.checkbox{cursor:pointer;display:inline-flex;margin-bottom:0;position:relative}.checkbox.is-disabled{cursor:default}.input{margin-top:.5rem;opacity:0;position:absolute;z-index:-1}.input:not(:checked)+.ec-icon{color:var(--ec-form-control-border-color)}.input:not(:checked)+.ec-icon:before{display:none}.input.indeterminate+.ec-icon,.input:indeterminate+.ec-icon{color:var(--ec-color-interactive)}.input.indeterminate+.ec-icon:before,.input:indeterminate+.ec-icon:before{content:\"\";background-color:currentColor;display:block;width:10px;height:3px}.input:focus+.ec-icon{color:var(--ec-color-interactive);box-shadow:var(--ec-form-control-box-shadow-focus);border-color:var(--ec-form-control-border-color-focus)}.input:disabled+.ec-icon{color:var(--ec-form-control-color-disabled);background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}.input:disabled~.label{color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}.ec-icon{background-color:var(--ec-form-control-background-color);background-clip:padding-box;border:1px solid currentColor;color:var(--ec-color-interactive);margin-top:.5rem;flex:none;pointer-events:none;display:inline-flex;align-items:center;justify-content:center;height:1em;width:1em;border-radius:.125rem}.ec-icon:before{font-size:.6875em}.label{line-height:1.25rem;padding:.375rem 0;margin-left:.5rem;min-height:2rem;height:auto}.checkbox.is-readonly{pointer-events:none}.checkbox.is-readonly .input{opacity:0}.checkbox.is-readonly .ec-icon{background-color:var(--ec-form-control-background-color-readonly);border-color:var(--ec-form-control-border-color-readonly)}.checkbox.is-readonly .label,.checkbox.is-readonly .ec-icon{opacity:1;color:var(--ec-form-control-color)}.checkbox.is-readonly ec-help-popover{pointer-events:auto}.no-label .input,.no-label .icon-check{margin-top:0}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: HelpPopoverComponent, selector: "ec-help-popover", inputs: ["id", "text", "contentPosition", "maxWidth"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] }); }
1792
2653
  }
1793
2654
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CheckboxComponent, decorators: [{
1794
2655
  type: Component,
1795
- args: [{ selector: 'ec-checkbox', template: "<div class=\"control\">\r\n <label class=\"checkbox\"\r\n [ngClass]=\"{'is-disabled': formModel.disabled, 'no-label': !label, 'is-readonly': readonly}\">\r\n <input id=\"{{id}}_input\"\r\n #checkboxInput\r\n class='input'\r\n [class.indeterminate]=\"indeterminate\"\r\n [attr.id]=\"inputId\"\r\n [attr.name]=\"name\"\r\n type=\"checkbox\"\r\n tabindex=\"{{tabindex}}\"\r\n [formControl]=\"formModel\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n <i class=\"ec-icon icon-check\"></i>\r\n\r\n <span id=\"{{id}}_label\"\r\n *ngIf=\"label\"\r\n class=\"label\">\r\n <span [innerHtml]=\"label | translate\"></span>\r\n <ec-help-popover id=\"{{id}}_helpPopover\"\r\n *ngIf=\"helpPopover\"\r\n class=\"d-inline-block my-n2 mx-n1\"\r\n text=\"{{helpPopover | translate}}\"\r\n contentPosition=\"{{helpPopoverPosition}}\">\r\n </ec-help-popover>\r\n </span>\r\n </label>\r\n</div>", styles: [":host{color:var(--ec-form-control-color);font-size:var(--ec-form-control-font-size);display:block;margin-bottom:1rem;width:100%}:host :host-context(.form-condensed){margin-bottom:.5rem}:host .control{width:100%;display:flex;flex-direction:column}:host .control.control-label-bottom{flex-direction:column-reverse}:host .control.control-label-left{flex-direction:row}:host .control.control-label-left label{margin-right:.25rem}:host .control.control-label-right{flex-direction:row-reverse}:host .control.control-label-right label{margin-left:.25rem}:host .control.control-label-left,:host .control.control-label-right{align-items:center}:host .control.control-label-left label,:host .control.control-label-right label{flex:1 1;margin-top:0;margin-bottom:0}:host .control.control-label-left .control-input,:host .control.control-label-right .control-input{flex:2 2}:host .control.is-readonly input,:host .control.is-readonly select,:host .control.is-readonly textarea{border-color:var(--ec-form-control-border-color-readonly);background-color:var(--ec-form-control-background-color-readonly);background-clip:border-box;background-image:none;color:var(--ec-form-control-color-readonly);opacity:1;-webkit-user-select:none;user-select:none;pointer-events:none;overflow:hidden;white-space:nowrap}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid{background-color:var(--ec-form-control-background-color-invalid);border-color:var(--ec-form-control-border-color-invalid);background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid:focus,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid:focus{border-color:var(--ec-form-control-background-color-invalid)}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid~.icon-invalid,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid~.icon-required,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid~.icon-required{display:none}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button{background-color:var(--ec-form-control-background-color-invalid)}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button:not(:focus){border-color:var(--ec-form-control-border-color-invalid)}:host .textbox-group{display:flex;position:relative}:host textarea:focus,:host input:focus,:host select:focus{outline:none}:host(.w-auto){width:auto}.checkbox{cursor:pointer;display:inline-flex;margin-bottom:0;position:relative}.checkbox.is-disabled{cursor:default}.input{margin-top:.5rem;opacity:0;position:absolute;z-index:-1}.input:not(:checked)+.ec-icon{color:var(--ec-form-control-border-color)}.input:not(:checked)+.ec-icon:before{display:none}.input.indeterminate+.ec-icon,.input:indeterminate+.ec-icon{color:var(--ec-color-interactive)}.input.indeterminate+.ec-icon:before,.input:indeterminate+.ec-icon:before{content:\"\";background-color:currentColor;display:block;width:10px;height:3px}.input:focus+.ec-icon{color:var(--ec-color-interactive);box-shadow:var(--ec-form-control-box-shadow-focus);border-color:var(--ec-form-control-border-color-focus)}.input:disabled+.ec-icon{color:var(--ec-form-control-color-disabled);background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}.input:disabled~.label{color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}.ec-icon{background-color:var(--ec-form-control-background-color);background-clip:padding-box;border:1px solid currentColor;color:var(--ec-color-interactive);margin-top:.5rem;flex:none;pointer-events:none;display:inline-flex;align-items:center;justify-content:center;height:1em;width:1em;border-radius:.125rem}.ec-icon:before{font-size:.6875em}.label{line-height:1.25rem;padding:.375rem 0;margin-left:.5rem;min-height:2rem;height:auto}.checkbox.is-readonly{pointer-events:none}.checkbox.is-readonly .input{opacity:0}.checkbox.is-readonly .ec-icon{background-color:var(--ec-form-control-background-color-readonly);border-color:var(--ec-form-control-border-color-readonly)}.checkbox.is-readonly .label,.checkbox.is-readonly .ec-icon{opacity:1;color:var(--ec-form-control-color)}.no-label .input,.no-label .icon-check{margin-top:0}\n"] }]
2656
+ args: [{ selector: 'ec-checkbox', template: "<div class=\"control\">\r\n <label class=\"checkbox\"\r\n [ngClass]=\"{'is-disabled': formModel.disabled, 'no-label': !label, 'is-readonly': readonly}\">\r\n <input id=\"{{id}}_input\"\r\n #checkboxInput\r\n class='input'\r\n [class.indeterminate]=\"indeterminate\"\r\n [attr.id]=\"inputId\"\r\n [attr.name]=\"name\"\r\n type=\"checkbox\"\r\n tabindex=\"{{tabindex}}\"\r\n [formControl]=\"formModel\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n <i class=\"ec-icon icon-check\"></i>\r\n\r\n <span id=\"{{id}}_label\"\r\n *ngIf=\"label\"\r\n class=\"label\">\r\n <span [innerHtml]=\"label | translate\"></span>\r\n <ec-help-popover id=\"{{id}}_helpPopover\"\r\n *ngIf=\"helpPopover\"\r\n class=\"d-inline-block my-n2 mx-n1\"\r\n text=\"{{helpPopover | translate}}\"\r\n contentPosition=\"{{helpPopoverPosition}}\">\r\n </ec-help-popover>\r\n </span>\r\n </label>\r\n</div>", styles: [":host{color:var(--ec-form-control-color);font-size:var(--ec-form-control-font-size);display:block;margin-bottom:1rem;width:100%}:host :host-context(.form-condensed){margin-bottom:.5rem}:host .control{width:100%;display:flex;flex-direction:column}:host .control.control-label-bottom{flex-direction:column-reverse}:host .control.control-label-left{flex-direction:row}:host .control.control-label-left label{margin-right:.25rem}:host .control.control-label-right{flex-direction:row-reverse}:host .control.control-label-right label{margin-left:.25rem}:host .control.control-label-left,:host .control.control-label-right{align-items:center}:host .control.control-label-left label,:host .control.control-label-right label{flex:1 1;margin-top:0;margin-bottom:0}:host .control.control-label-left .control-input,:host .control.control-label-right .control-input{flex:2 2}:host .control.is-readonly input,:host .control.is-readonly select,:host .control.is-readonly textarea{border-color:var(--ec-form-control-border-color-readonly);background-color:var(--ec-form-control-background-color-readonly);background-clip:border-box;background-image:none;color:var(--ec-form-control-color-readonly);opacity:1;-webkit-user-select:none;user-select:none;pointer-events:none;overflow:hidden;white-space:nowrap}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid{background-color:var(--ec-form-control-background-color-invalid);border-color:var(--ec-form-control-border-color-invalid);background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid:focus,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid:focus{border-color:var(--ec-form-control-background-color-invalid)}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid~.icon-invalid,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-invalid~.icon-required,:host .control.invalid .textbox-group-input ::ng-deep .control input.ng-valid~.icon-required{display:none}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button{background-color:var(--ec-form-control-background-color-invalid)}:host .control.invalid:not(.open) .textbox-group-btn-right ::ng-deep button:not(:focus){border-color:var(--ec-form-control-border-color-invalid)}:host .textbox-group{display:flex;position:relative}:host textarea:focus,:host input:focus,:host select:focus{outline:none}:host(.w-auto){width:auto}.checkbox{cursor:pointer;display:inline-flex;margin-bottom:0;position:relative}.checkbox.is-disabled{cursor:default}.input{margin-top:.5rem;opacity:0;position:absolute;z-index:-1}.input:not(:checked)+.ec-icon{color:var(--ec-form-control-border-color)}.input:not(:checked)+.ec-icon:before{display:none}.input.indeterminate+.ec-icon,.input:indeterminate+.ec-icon{color:var(--ec-color-interactive)}.input.indeterminate+.ec-icon:before,.input:indeterminate+.ec-icon:before{content:\"\";background-color:currentColor;display:block;width:10px;height:3px}.input:focus+.ec-icon{color:var(--ec-color-interactive);box-shadow:var(--ec-form-control-box-shadow-focus);border-color:var(--ec-form-control-border-color-focus)}.input:disabled+.ec-icon{color:var(--ec-form-control-color-disabled);background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}.input:disabled~.label{color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}.ec-icon{background-color:var(--ec-form-control-background-color);background-clip:padding-box;border:1px solid currentColor;color:var(--ec-color-interactive);margin-top:.5rem;flex:none;pointer-events:none;display:inline-flex;align-items:center;justify-content:center;height:1em;width:1em;border-radius:.125rem}.ec-icon:before{font-size:.6875em}.label{line-height:1.25rem;padding:.375rem 0;margin-left:.5rem;min-height:2rem;height:auto}.checkbox.is-readonly{pointer-events:none}.checkbox.is-readonly .input{opacity:0}.checkbox.is-readonly .ec-icon{background-color:var(--ec-form-control-background-color-readonly);border-color:var(--ec-form-control-border-color-readonly)}.checkbox.is-readonly .label,.checkbox.is-readonly .ec-icon{opacity:1;color:var(--ec-form-control-color)}.checkbox.is-readonly ec-help-popover{pointer-events:auto}.no-label .input,.no-label .icon-check{margin-top:0}\n"] }]
1796
2657
  }], ctorParameters: () => [{ type: ValidationMessageService }, { type: FormGroupHelper }], propDecorators: { name: [{
1797
2658
  type: Input
1798
2659
  }], dependentCheckboxesGroup: [{
@@ -3906,6 +4767,9 @@ class FormControlComponent {
3906
4767
  ;
3907
4768
  get disabled() { return this._formModel?.disabled == true; }
3908
4769
  ;
4770
+ get _formModel() {
4771
+ return this.formModelInput || this.formControlDirective;
4772
+ }
3909
4773
  constructor(el) {
3910
4774
  this.el = el;
3911
4775
  this.id = '';
@@ -3915,15 +4779,8 @@ class FormControlComponent {
3915
4779
  this.required = false;
3916
4780
  this.readonly = false;
3917
4781
  this.actionClicked = new EventEmitter();
3918
- this.actionKeydown = new EventEmitter();
3919
- }
3920
- ngOnChanges(changes) {
3921
- if (changes.formModelInput) {
3922
- this._formModel = this.formModelInput || this.formControlDirective;
3923
- }
3924
4782
  }
3925
4783
  ngAfterViewInit() {
3926
- this._formModel = this.formModelInput || this.formControlDirective;
3927
4784
  if (!this._formModel) {
3928
4785
  console.error('Missing [formModel] input or [formControl] directive on ec-form-control content.');
3929
4786
  }
@@ -3945,11 +4802,11 @@ class FormControlComponent {
3945
4802
  this._formModel?.reset();
3946
4803
  }
3947
4804
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FormControlComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
3948
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: FormControlComponent, selector: "ec-form-control", inputs: { id: "id", icon: "icon", actionIcon: "actionIcon", showClear: "showClear", formModelInput: ["formModel", "formModelInput"], autofocus: "autofocus", pending: "pending", required: "required", readonly: "readonly" }, outputs: { actionClicked: "actionClicked", actionKeydown: "actionKeydown" }, host: { listeners: { "click": "onClick()" }, properties: { "class.is-pending": "this.pending", "class.is-required": "this.required", "class.is-readonly": "this.readonly", "class.is-empty": "this.empty", "class.is-invalid": "this.invalid", "class.is-disabled": "this.disabled" } }, queries: [{ propertyName: "formControlDirective", first: true, predicate: FormControlDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-content></ng-content>\r\n<i id=\"{{id + '_icon'}}\" class=\"ec-form-control-icon ec-icon {{icon}}\"></i>\r\n<i id=\"{{id + '_loading'}}\" class=\"ec-form-control-icon ec-icon icon-loading\"></i>\r\n<i id=\"{{id + '_required'}}\" class=\"ec-form-control-icon ec-icon icon-required\"></i>\r\n<i id=\"{{id + '_invalid'}}\" class=\"ec-form-control-icon ec-icon icon-invalid\"></i>\r\n<button *ngIf=\"showClear\"\r\n id=\"{{id + '_clear'}}\"\r\n [attr.disabled]=\"disabled || undefined\"\r\n class=\"ec-form-control-clear\"\r\n (click)=\"clear()\">\r\n <i class=\"ec-icon icon-cancel\"></i>\r\n</button>\r\n<button *ngIf=\"actionIcon\"\r\n id=\"{{id + '_action'}}\"\r\n [attr.disabled]=\"disabled || undefined\"\r\n class=\"ec-form-control-action\"\r\n (click)=\"actionClicked.emit($event)\"\r\n (keydown)=\"actionKeydown.emit($event)\">\r\n <i class=\"ec-icon {{actionIcon}}\"></i>\r\n</button>\r\n<div class=\"ec-focus-ring\"></div>", styles: ["ec-form-control{background-color:var(--ec-form-control-background-color);background-clip:padding-box;border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);padding:0 .5rem;position:relative;color:var(--ec-form-control-color);display:flex;font-size:var(--ec-form-control-font-size);min-height:2rem;width:100%}ec-form-control>input,ec-form-control>select,ec-form-control>textarea,ec-form-control>div[contenteditable=true]{color:inherit;flex:1 1;min-width:0;border:0;background-color:transparent;order:2}ec-form-control>input::selection,ec-form-control>select::selection,ec-form-control>textarea::selection,ec-form-control>div[contenteditable=true]::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}ec-form-control>input::-webkit-input-placeholder,ec-form-control>select::-webkit-input-placeholder,ec-form-control>textarea::-webkit-input-placeholder,ec-form-control>div[contenteditable=true]::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}ec-form-control>input::-moz-placeholder,ec-form-control>select::-moz-placeholder,ec-form-control>textarea::-moz-placeholder,ec-form-control>div[contenteditable=true]::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}ec-form-control>input:-ms-input-placeholder,ec-form-control>select:-ms-input-placeholder,ec-form-control>textarea:-ms-input-placeholder,ec-form-control>div[contenteditable=true]:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}ec-form-control>input:-moz-placeholder,ec-form-control>select:-moz-placeholder,ec-form-control>textarea:-moz-placeholder,ec-form-control>div[contenteditable=true]:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}ec-form-control>input:focus,ec-form-control>select:focus,ec-form-control>textarea:focus,ec-form-control>div[contenteditable=true]:focus{outline:none}ec-form-control>input:focus~.ec-focus-ring,ec-form-control>select:focus~.ec-focus-ring,ec-form-control>textarea:focus~.ec-focus-ring,ec-form-control>div[contenteditable=true]:focus~.ec-focus-ring{display:block}ec-form-control>input,ec-form-control>textarea,ec-form-control>select,ec-form-control>div[contenteditable=true],ec-form-control .ec-form-control-prefix,ec-form-control .ec-form-control-suffix{padding:calc((1.875rem - var(--ec-font-size-body) * 1.25) / 2) 0;line-height:1.25;font-size:inherit}ec-form-control>textarea{resize:none;padding:.3125rem 0}ec-form-control .ec-form-control-icon{margin-top:.4375rem;margin-right:.25rem;order:1}ec-form-control .ec-form-control-icon:not([class*=icon-]){display:none}ec-form-control .icon-required,ec-form-control .icon-invalid{color:var(--ec-form-control-border-color-invalid)}ec-form-control .ec-form-control-clear,ec-form-control .ec-form-control-action{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border-radius:var(--ec-border-radius);display:flex;cursor:pointer;flex:none;height:1.875rem;width:2rem;order:3;background-color:transparent;border:0;border-radius:0;display:inline-flex;align-items:center;justify-content:center;outline:none}ec-form-control .ec-form-control-clear .label,ec-form-control .ec-form-control-action .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}ec-form-control .ec-form-control-clear .ec-icon,ec-form-control .ec-form-control-action .ec-icon{flex:none}ec-form-control .ec-form-control-clear .ec-icon+.label,ec-form-control .ec-form-control-action .ec-icon+.label{flex:none;margin-left:.25rem}ec-form-control .ec-form-control-clear.has-badge,ec-form-control .ec-form-control-action.has-badge{padding-right:.0625rem}ec-form-control .ec-form-control-clear:focus,ec-form-control .ec-form-control-action:focus{outline:none;position:relative;z-index:1}ec-form-control .ec-form-control-clear:disabled,ec-form-control .ec-form-control-action:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}ec-form-control .ec-form-control-clear:disabled,ec-form-control .ec-form-control-action:disabled{border:0;background-color:transparent;border-color:transparent}ec-form-control .ec-form-control-clear:last-of-type,ec-form-control .ec-form-control-action:last-of-type{margin-right:-.5rem}ec-form-control .ec-form-control-clear:hover:not(:disabled),ec-form-control .ec-form-control-action:hover:not(:disabled){cursor:pointer;background-color:var(--ec-background-color-hover)}ec-form-control .ec-form-control-clear:active:not(:disabled),ec-form-control .ec-form-control-action:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}ec-form-control .ec-form-control-clear:focus:not(:disabled),ec-form-control .ec-form-control-action:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}ec-form-control button:last-of-type{border-top-right-radius:calc(var(--ec-form-control-border-radius) - .0625rem);border-bottom-right-radius:calc(var(--ec-form-control-border-radius) - .0625rem)}ec-form-control .ec-form-control-clear{width:1.5rem}ec-form-control .ec-form-control-prefix,ec-form-control .ec-form-control-suffix{color:var(--ec-color-secondary-dark);flex:none;cursor:default}ec-form-control .ec-form-control-prefix{margin-right:.125rem;order:2}ec-form-control .ec-form-control-suffix{margin-left:.125rem;order:3}ec-form-control .ec-focus-ring{position:absolute;inset:-1px;border:.125rem solid var(--ec-color-interactive);pointer-events:none;display:none;border-radius:var(--ec-form-control-border-radius);z-index:1}ec-form-control.is-pending .icon-invalid,ec-form-control.is-pending .icon-required{display:none}ec-form-control.is-invalid{border-color:var(--ec-form-control-border-color-invalid);background-color:var(--ec-form-control-background-color-invalid)}ec-form-control.is-invalid .icon-required{display:none}ec-form-control.is-empty .ec-form-control-clear{display:none}ec-form-control.is-required.is-empty .ec-form-control-icon:first-of-type{display:none}ec-form-control:not(.is-pending) .icon-loading{display:none}ec-form-control:not(.is-required) .icon-required,ec-form-control:not(.is-empty) .icon-required{display:none}ec-form-control:not(.is-invalid) .icon-invalid{display:none}ec-form-control.is-readonly,ec-form-control.is-disabled{background-color:var(--ec-form-control-background-color-disabled)}ec-form-control.is-readonly .icon-loading,ec-form-control.is-readonly .icon-invalid,ec-form-control.is-readonly .icon-required,ec-form-control.is-readonly .ec-form-control-clear,ec-form-control.is-disabled .icon-loading,ec-form-control.is-disabled .icon-invalid,ec-form-control.is-disabled .icon-required,ec-form-control.is-disabled .ec-form-control-clear{display:none}ec-form-control.is-readonly{border-color:var(--ec-form-control-border-color-readonly);color:var(--ec-form-control-color-readonly)}ec-form-control.is-readonly .ec-form-control-action{display:none}ec-form-control.is-disabled:not(.is-readonly){color:var(--ec-form-control-color-disabled);opacity:.6}ec-form-control.is-disabled:not(.is-readonly) .ec-form-control-prefix,ec-form-control.is-disabled:not(.is-readonly) .ec-form-control-suffix{color:inherit}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], encapsulation: i0.ViewEncapsulation.None }); }
4805
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: FormControlComponent, selector: "ec-form-control", inputs: { id: "id", icon: "icon", actionIcon: "actionIcon", showClear: "showClear", formModelInput: ["formModel", "formModelInput"], autofocus: "autofocus", pending: "pending", required: "required", readonly: "readonly" }, outputs: { actionClicked: "actionClicked" }, host: { listeners: { "click": "onClick()" }, properties: { "class.is-pending": "this.pending", "class.is-required": "this.required", "class.is-readonly": "this.readonly", "class.is-empty": "this.empty", "class.is-invalid": "this.invalid", "class.is-disabled": "this.disabled" } }, queries: [{ propertyName: "formControlDirective", first: true, predicate: FormControlDirective, descendants: true }], ngImport: i0, template: "<ng-content></ng-content>\r\n<i id=\"{{id + '_icon'}}\" class=\"ec-form-control-icon ec-icon {{icon}}\"></i>\r\n<i id=\"{{id + '_loading'}}\" class=\"ec-form-control-icon ec-icon icon-loading\"></i>\r\n<i id=\"{{id + '_required'}}\" class=\"ec-form-control-icon ec-icon icon-required\"></i>\r\n<i id=\"{{id + '_invalid'}}\" class=\"ec-form-control-icon ec-icon icon-invalid\"></i>\r\n<button *ngIf=\"showClear\"\r\n id=\"{{id + '_clear'}}\"\r\n [attr.disabled]=\"disabled || undefined\"\r\n class=\"ec-form-control-clear\"\r\n (click)=\"clear()\">\r\n <i class=\"ec-icon icon-cancel\"></i>\r\n</button>\r\n<button *ngIf=\"actionIcon\"\r\n id=\"{{id + '_action'}}\"\r\n [attr.disabled]=\"disabled || undefined\"\r\n class=\"ec-form-control-action\"\r\n (click)=\"actionClicked.emit($event)\">\r\n <i class=\"ec-icon {{actionIcon}}\"></i>\r\n</button>\r\n<div class=\"ec-focus-ring\"></div>\r\n", styles: ["ec-form-control{background-color:var(--ec-form-control-background-color);background-clip:padding-box;border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);padding:0 .5rem;position:relative;color:var(--ec-form-control-color);display:flex;font-size:var(--ec-form-control-font-size);min-height:2rem;width:100%}ec-form-control>input,ec-form-control>select,ec-form-control>textarea,ec-form-control>div[contenteditable=true]{color:inherit;flex:1 1;min-width:0;border:0;background-color:transparent;order:2}ec-form-control>input::selection,ec-form-control>select::selection,ec-form-control>textarea::selection,ec-form-control>div[contenteditable=true]::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}ec-form-control>input::-webkit-input-placeholder,ec-form-control>select::-webkit-input-placeholder,ec-form-control>textarea::-webkit-input-placeholder,ec-form-control>div[contenteditable=true]::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}ec-form-control>input::-moz-placeholder,ec-form-control>select::-moz-placeholder,ec-form-control>textarea::-moz-placeholder,ec-form-control>div[contenteditable=true]::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}ec-form-control>input:-ms-input-placeholder,ec-form-control>select:-ms-input-placeholder,ec-form-control>textarea:-ms-input-placeholder,ec-form-control>div[contenteditable=true]:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}ec-form-control>input:-moz-placeholder,ec-form-control>select:-moz-placeholder,ec-form-control>textarea:-moz-placeholder,ec-form-control>div[contenteditable=true]:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}ec-form-control>input:focus,ec-form-control>select:focus,ec-form-control>textarea:focus,ec-form-control>div[contenteditable=true]:focus{outline:none}ec-form-control>input:focus~.ec-focus-ring,ec-form-control>select:focus~.ec-focus-ring,ec-form-control>textarea:focus~.ec-focus-ring,ec-form-control>div[contenteditable=true]:focus~.ec-focus-ring{display:block}ec-form-control>input,ec-form-control>textarea,ec-form-control>select,ec-form-control>div[contenteditable=true],ec-form-control .ec-form-control-prefix,ec-form-control .ec-form-control-suffix{padding:calc((1.875rem - var(--ec-font-size-body) * 1.25) / 2) 0;line-height:1.25;font-size:inherit}ec-form-control>textarea{resize:none;padding:.3125rem 0}ec-form-control .ec-form-control-icon{margin-top:.4375rem;margin-right:.25rem;order:1}ec-form-control .ec-form-control-icon:not([class*=icon-]){display:none}ec-form-control .icon-required,ec-form-control .icon-invalid{color:var(--ec-form-control-border-color-invalid)}ec-form-control .ec-form-control-clear,ec-form-control .ec-form-control-action{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border-radius:var(--ec-border-radius);display:flex;cursor:pointer;flex:none;height:1.875rem;width:2rem;order:3;background-color:transparent;border:0;border-radius:0;display:inline-flex;align-items:center;justify-content:center;outline:none}ec-form-control .ec-form-control-clear .label,ec-form-control .ec-form-control-action .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}ec-form-control .ec-form-control-clear .ec-icon,ec-form-control .ec-form-control-action .ec-icon{flex:none}ec-form-control .ec-form-control-clear .ec-icon+.label,ec-form-control .ec-form-control-action .ec-icon+.label{flex:none;margin-left:.25rem}ec-form-control .ec-form-control-clear.has-badge,ec-form-control .ec-form-control-action.has-badge{padding-right:.0625rem}ec-form-control .ec-form-control-clear:focus,ec-form-control .ec-form-control-action:focus{outline:none;position:relative;z-index:1}ec-form-control .ec-form-control-clear:disabled,ec-form-control .ec-form-control-action:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}ec-form-control .ec-form-control-clear:disabled,ec-form-control .ec-form-control-action:disabled{border:0;background-color:transparent;border-color:transparent}ec-form-control .ec-form-control-clear:last-of-type,ec-form-control .ec-form-control-action:last-of-type{margin-right:-.5rem}ec-form-control .ec-form-control-clear:hover:not(:disabled),ec-form-control .ec-form-control-action:hover:not(:disabled){cursor:pointer;background-color:var(--ec-background-color-hover)}ec-form-control .ec-form-control-clear:active:not(:disabled),ec-form-control .ec-form-control-action:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}ec-form-control .ec-form-control-clear:focus:not(:disabled),ec-form-control .ec-form-control-action:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}ec-form-control button:last-of-type{border-top-right-radius:calc(var(--ec-form-control-border-radius) - .0625rem);border-bottom-right-radius:calc(var(--ec-form-control-border-radius) - .0625rem)}ec-form-control .ec-form-control-clear{width:1.5rem}ec-form-control .ec-form-control-prefix,ec-form-control .ec-form-control-suffix{color:var(--ec-color-secondary-dark);flex:none;cursor:default}ec-form-control .ec-form-control-prefix{margin-right:.125rem;order:2}ec-form-control .ec-form-control-suffix{margin-left:.125rem;order:3}ec-form-control .ec-focus-ring{position:absolute;inset:-1px;border:.125rem solid var(--ec-color-interactive);pointer-events:none;display:none;border-radius:var(--ec-form-control-border-radius);z-index:1}ec-form-control.is-pending .icon-invalid,ec-form-control.is-pending .icon-required{display:none}ec-form-control.is-invalid{border-color:var(--ec-form-control-border-color-invalid);background-color:var(--ec-form-control-background-color-invalid)}ec-form-control.is-invalid .icon-required{display:none}ec-form-control.is-empty .ec-form-control-clear{display:none}ec-form-control.is-required.is-empty .ec-form-control-icon:first-of-type{display:none}ec-form-control:not(.is-pending) .icon-loading{display:none}ec-form-control:not(.is-required) .icon-required,ec-form-control:not(.is-empty) .icon-required{display:none}ec-form-control:not(.is-invalid) .icon-invalid{display:none}ec-form-control.is-readonly,ec-form-control.is-disabled{background-color:var(--ec-form-control-background-color-disabled)}ec-form-control.is-readonly .icon-loading,ec-form-control.is-readonly .icon-invalid,ec-form-control.is-readonly .icon-required,ec-form-control.is-readonly .ec-form-control-clear,ec-form-control.is-disabled .icon-loading,ec-form-control.is-disabled .icon-invalid,ec-form-control.is-disabled .icon-required,ec-form-control.is-disabled .ec-form-control-clear{display:none}ec-form-control.is-readonly{border-color:var(--ec-form-control-border-color-readonly);color:var(--ec-form-control-color-readonly)}ec-form-control.is-readonly .ec-form-control-action{display:none}ec-form-control.is-disabled:not(.is-readonly){color:var(--ec-form-control-color-disabled);opacity:.6}ec-form-control.is-disabled:not(.is-readonly) .ec-form-control-prefix,ec-form-control.is-disabled:not(.is-readonly) .ec-form-control-suffix{color:inherit}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], encapsulation: i0.ViewEncapsulation.None }); }
3949
4806
  }
3950
4807
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FormControlComponent, decorators: [{
3951
4808
  type: Component,
3952
- args: [{ selector: 'ec-form-control', encapsulation: ViewEncapsulation.None, template: "<ng-content></ng-content>\r\n<i id=\"{{id + '_icon'}}\" class=\"ec-form-control-icon ec-icon {{icon}}\"></i>\r\n<i id=\"{{id + '_loading'}}\" class=\"ec-form-control-icon ec-icon icon-loading\"></i>\r\n<i id=\"{{id + '_required'}}\" class=\"ec-form-control-icon ec-icon icon-required\"></i>\r\n<i id=\"{{id + '_invalid'}}\" class=\"ec-form-control-icon ec-icon icon-invalid\"></i>\r\n<button *ngIf=\"showClear\"\r\n id=\"{{id + '_clear'}}\"\r\n [attr.disabled]=\"disabled || undefined\"\r\n class=\"ec-form-control-clear\"\r\n (click)=\"clear()\">\r\n <i class=\"ec-icon icon-cancel\"></i>\r\n</button>\r\n<button *ngIf=\"actionIcon\"\r\n id=\"{{id + '_action'}}\"\r\n [attr.disabled]=\"disabled || undefined\"\r\n class=\"ec-form-control-action\"\r\n (click)=\"actionClicked.emit($event)\"\r\n (keydown)=\"actionKeydown.emit($event)\">\r\n <i class=\"ec-icon {{actionIcon}}\"></i>\r\n</button>\r\n<div class=\"ec-focus-ring\"></div>", styles: ["ec-form-control{background-color:var(--ec-form-control-background-color);background-clip:padding-box;border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);padding:0 .5rem;position:relative;color:var(--ec-form-control-color);display:flex;font-size:var(--ec-form-control-font-size);min-height:2rem;width:100%}ec-form-control>input,ec-form-control>select,ec-form-control>textarea,ec-form-control>div[contenteditable=true]{color:inherit;flex:1 1;min-width:0;border:0;background-color:transparent;order:2}ec-form-control>input::selection,ec-form-control>select::selection,ec-form-control>textarea::selection,ec-form-control>div[contenteditable=true]::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}ec-form-control>input::-webkit-input-placeholder,ec-form-control>select::-webkit-input-placeholder,ec-form-control>textarea::-webkit-input-placeholder,ec-form-control>div[contenteditable=true]::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}ec-form-control>input::-moz-placeholder,ec-form-control>select::-moz-placeholder,ec-form-control>textarea::-moz-placeholder,ec-form-control>div[contenteditable=true]::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}ec-form-control>input:-ms-input-placeholder,ec-form-control>select:-ms-input-placeholder,ec-form-control>textarea:-ms-input-placeholder,ec-form-control>div[contenteditable=true]:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}ec-form-control>input:-moz-placeholder,ec-form-control>select:-moz-placeholder,ec-form-control>textarea:-moz-placeholder,ec-form-control>div[contenteditable=true]:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}ec-form-control>input:focus,ec-form-control>select:focus,ec-form-control>textarea:focus,ec-form-control>div[contenteditable=true]:focus{outline:none}ec-form-control>input:focus~.ec-focus-ring,ec-form-control>select:focus~.ec-focus-ring,ec-form-control>textarea:focus~.ec-focus-ring,ec-form-control>div[contenteditable=true]:focus~.ec-focus-ring{display:block}ec-form-control>input,ec-form-control>textarea,ec-form-control>select,ec-form-control>div[contenteditable=true],ec-form-control .ec-form-control-prefix,ec-form-control .ec-form-control-suffix{padding:calc((1.875rem - var(--ec-font-size-body) * 1.25) / 2) 0;line-height:1.25;font-size:inherit}ec-form-control>textarea{resize:none;padding:.3125rem 0}ec-form-control .ec-form-control-icon{margin-top:.4375rem;margin-right:.25rem;order:1}ec-form-control .ec-form-control-icon:not([class*=icon-]){display:none}ec-form-control .icon-required,ec-form-control .icon-invalid{color:var(--ec-form-control-border-color-invalid)}ec-form-control .ec-form-control-clear,ec-form-control .ec-form-control-action{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border-radius:var(--ec-border-radius);display:flex;cursor:pointer;flex:none;height:1.875rem;width:2rem;order:3;background-color:transparent;border:0;border-radius:0;display:inline-flex;align-items:center;justify-content:center;outline:none}ec-form-control .ec-form-control-clear .label,ec-form-control .ec-form-control-action .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}ec-form-control .ec-form-control-clear .ec-icon,ec-form-control .ec-form-control-action .ec-icon{flex:none}ec-form-control .ec-form-control-clear .ec-icon+.label,ec-form-control .ec-form-control-action .ec-icon+.label{flex:none;margin-left:.25rem}ec-form-control .ec-form-control-clear.has-badge,ec-form-control .ec-form-control-action.has-badge{padding-right:.0625rem}ec-form-control .ec-form-control-clear:focus,ec-form-control .ec-form-control-action:focus{outline:none;position:relative;z-index:1}ec-form-control .ec-form-control-clear:disabled,ec-form-control .ec-form-control-action:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}ec-form-control .ec-form-control-clear:disabled,ec-form-control .ec-form-control-action:disabled{border:0;background-color:transparent;border-color:transparent}ec-form-control .ec-form-control-clear:last-of-type,ec-form-control .ec-form-control-action:last-of-type{margin-right:-.5rem}ec-form-control .ec-form-control-clear:hover:not(:disabled),ec-form-control .ec-form-control-action:hover:not(:disabled){cursor:pointer;background-color:var(--ec-background-color-hover)}ec-form-control .ec-form-control-clear:active:not(:disabled),ec-form-control .ec-form-control-action:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}ec-form-control .ec-form-control-clear:focus:not(:disabled),ec-form-control .ec-form-control-action:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}ec-form-control button:last-of-type{border-top-right-radius:calc(var(--ec-form-control-border-radius) - .0625rem);border-bottom-right-radius:calc(var(--ec-form-control-border-radius) - .0625rem)}ec-form-control .ec-form-control-clear{width:1.5rem}ec-form-control .ec-form-control-prefix,ec-form-control .ec-form-control-suffix{color:var(--ec-color-secondary-dark);flex:none;cursor:default}ec-form-control .ec-form-control-prefix{margin-right:.125rem;order:2}ec-form-control .ec-form-control-suffix{margin-left:.125rem;order:3}ec-form-control .ec-focus-ring{position:absolute;inset:-1px;border:.125rem solid var(--ec-color-interactive);pointer-events:none;display:none;border-radius:var(--ec-form-control-border-radius);z-index:1}ec-form-control.is-pending .icon-invalid,ec-form-control.is-pending .icon-required{display:none}ec-form-control.is-invalid{border-color:var(--ec-form-control-border-color-invalid);background-color:var(--ec-form-control-background-color-invalid)}ec-form-control.is-invalid .icon-required{display:none}ec-form-control.is-empty .ec-form-control-clear{display:none}ec-form-control.is-required.is-empty .ec-form-control-icon:first-of-type{display:none}ec-form-control:not(.is-pending) .icon-loading{display:none}ec-form-control:not(.is-required) .icon-required,ec-form-control:not(.is-empty) .icon-required{display:none}ec-form-control:not(.is-invalid) .icon-invalid{display:none}ec-form-control.is-readonly,ec-form-control.is-disabled{background-color:var(--ec-form-control-background-color-disabled)}ec-form-control.is-readonly .icon-loading,ec-form-control.is-readonly .icon-invalid,ec-form-control.is-readonly .icon-required,ec-form-control.is-readonly .ec-form-control-clear,ec-form-control.is-disabled .icon-loading,ec-form-control.is-disabled .icon-invalid,ec-form-control.is-disabled .icon-required,ec-form-control.is-disabled .ec-form-control-clear{display:none}ec-form-control.is-readonly{border-color:var(--ec-form-control-border-color-readonly);color:var(--ec-form-control-color-readonly)}ec-form-control.is-readonly .ec-form-control-action{display:none}ec-form-control.is-disabled:not(.is-readonly){color:var(--ec-form-control-color-disabled);opacity:.6}ec-form-control.is-disabled:not(.is-readonly) .ec-form-control-prefix,ec-form-control.is-disabled:not(.is-readonly) .ec-form-control-suffix{color:inherit}\n"] }]
4809
+ args: [{ selector: 'ec-form-control', encapsulation: ViewEncapsulation.None, template: "<ng-content></ng-content>\r\n<i id=\"{{id + '_icon'}}\" class=\"ec-form-control-icon ec-icon {{icon}}\"></i>\r\n<i id=\"{{id + '_loading'}}\" class=\"ec-form-control-icon ec-icon icon-loading\"></i>\r\n<i id=\"{{id + '_required'}}\" class=\"ec-form-control-icon ec-icon icon-required\"></i>\r\n<i id=\"{{id + '_invalid'}}\" class=\"ec-form-control-icon ec-icon icon-invalid\"></i>\r\n<button *ngIf=\"showClear\"\r\n id=\"{{id + '_clear'}}\"\r\n [attr.disabled]=\"disabled || undefined\"\r\n class=\"ec-form-control-clear\"\r\n (click)=\"clear()\">\r\n <i class=\"ec-icon icon-cancel\"></i>\r\n</button>\r\n<button *ngIf=\"actionIcon\"\r\n id=\"{{id + '_action'}}\"\r\n [attr.disabled]=\"disabled || undefined\"\r\n class=\"ec-form-control-action\"\r\n (click)=\"actionClicked.emit($event)\">\r\n <i class=\"ec-icon {{actionIcon}}\"></i>\r\n</button>\r\n<div class=\"ec-focus-ring\"></div>\r\n", styles: ["ec-form-control{background-color:var(--ec-form-control-background-color);background-clip:padding-box;border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);padding:0 .5rem;position:relative;color:var(--ec-form-control-color);display:flex;font-size:var(--ec-form-control-font-size);min-height:2rem;width:100%}ec-form-control>input,ec-form-control>select,ec-form-control>textarea,ec-form-control>div[contenteditable=true]{color:inherit;flex:1 1;min-width:0;border:0;background-color:transparent;order:2}ec-form-control>input::selection,ec-form-control>select::selection,ec-form-control>textarea::selection,ec-form-control>div[contenteditable=true]::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}ec-form-control>input::-webkit-input-placeholder,ec-form-control>select::-webkit-input-placeholder,ec-form-control>textarea::-webkit-input-placeholder,ec-form-control>div[contenteditable=true]::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}ec-form-control>input::-moz-placeholder,ec-form-control>select::-moz-placeholder,ec-form-control>textarea::-moz-placeholder,ec-form-control>div[contenteditable=true]::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}ec-form-control>input:-ms-input-placeholder,ec-form-control>select:-ms-input-placeholder,ec-form-control>textarea:-ms-input-placeholder,ec-form-control>div[contenteditable=true]:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}ec-form-control>input:-moz-placeholder,ec-form-control>select:-moz-placeholder,ec-form-control>textarea:-moz-placeholder,ec-form-control>div[contenteditable=true]:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}ec-form-control>input:focus,ec-form-control>select:focus,ec-form-control>textarea:focus,ec-form-control>div[contenteditable=true]:focus{outline:none}ec-form-control>input:focus~.ec-focus-ring,ec-form-control>select:focus~.ec-focus-ring,ec-form-control>textarea:focus~.ec-focus-ring,ec-form-control>div[contenteditable=true]:focus~.ec-focus-ring{display:block}ec-form-control>input,ec-form-control>textarea,ec-form-control>select,ec-form-control>div[contenteditable=true],ec-form-control .ec-form-control-prefix,ec-form-control .ec-form-control-suffix{padding:calc((1.875rem - var(--ec-font-size-body) * 1.25) / 2) 0;line-height:1.25;font-size:inherit}ec-form-control>textarea{resize:none;padding:.3125rem 0}ec-form-control .ec-form-control-icon{margin-top:.4375rem;margin-right:.25rem;order:1}ec-form-control .ec-form-control-icon:not([class*=icon-]){display:none}ec-form-control .icon-required,ec-form-control .icon-invalid{color:var(--ec-form-control-border-color-invalid)}ec-form-control .ec-form-control-clear,ec-form-control .ec-form-control-action{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border-radius:var(--ec-border-radius);display:flex;cursor:pointer;flex:none;height:1.875rem;width:2rem;order:3;background-color:transparent;border:0;border-radius:0;display:inline-flex;align-items:center;justify-content:center;outline:none}ec-form-control .ec-form-control-clear .label,ec-form-control .ec-form-control-action .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}ec-form-control .ec-form-control-clear .ec-icon,ec-form-control .ec-form-control-action .ec-icon{flex:none}ec-form-control .ec-form-control-clear .ec-icon+.label,ec-form-control .ec-form-control-action .ec-icon+.label{flex:none;margin-left:.25rem}ec-form-control .ec-form-control-clear.has-badge,ec-form-control .ec-form-control-action.has-badge{padding-right:.0625rem}ec-form-control .ec-form-control-clear:focus,ec-form-control .ec-form-control-action:focus{outline:none;position:relative;z-index:1}ec-form-control .ec-form-control-clear:disabled,ec-form-control .ec-form-control-action:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}ec-form-control .ec-form-control-clear:disabled,ec-form-control .ec-form-control-action:disabled{border:0;background-color:transparent;border-color:transparent}ec-form-control .ec-form-control-clear:last-of-type,ec-form-control .ec-form-control-action:last-of-type{margin-right:-.5rem}ec-form-control .ec-form-control-clear:hover:not(:disabled),ec-form-control .ec-form-control-action:hover:not(:disabled){cursor:pointer;background-color:var(--ec-background-color-hover)}ec-form-control .ec-form-control-clear:active:not(:disabled),ec-form-control .ec-form-control-action:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}ec-form-control .ec-form-control-clear:focus:not(:disabled),ec-form-control .ec-form-control-action:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}ec-form-control button:last-of-type{border-top-right-radius:calc(var(--ec-form-control-border-radius) - .0625rem);border-bottom-right-radius:calc(var(--ec-form-control-border-radius) - .0625rem)}ec-form-control .ec-form-control-clear{width:1.5rem}ec-form-control .ec-form-control-prefix,ec-form-control .ec-form-control-suffix{color:var(--ec-color-secondary-dark);flex:none;cursor:default}ec-form-control .ec-form-control-prefix{margin-right:.125rem;order:2}ec-form-control .ec-form-control-suffix{margin-left:.125rem;order:3}ec-form-control .ec-focus-ring{position:absolute;inset:-1px;border:.125rem solid var(--ec-color-interactive);pointer-events:none;display:none;border-radius:var(--ec-form-control-border-radius);z-index:1}ec-form-control.is-pending .icon-invalid,ec-form-control.is-pending .icon-required{display:none}ec-form-control.is-invalid{border-color:var(--ec-form-control-border-color-invalid);background-color:var(--ec-form-control-background-color-invalid)}ec-form-control.is-invalid .icon-required{display:none}ec-form-control.is-empty .ec-form-control-clear{display:none}ec-form-control.is-required.is-empty .ec-form-control-icon:first-of-type{display:none}ec-form-control:not(.is-pending) .icon-loading{display:none}ec-form-control:not(.is-required) .icon-required,ec-form-control:not(.is-empty) .icon-required{display:none}ec-form-control:not(.is-invalid) .icon-invalid{display:none}ec-form-control.is-readonly,ec-form-control.is-disabled{background-color:var(--ec-form-control-background-color-disabled)}ec-form-control.is-readonly .icon-loading,ec-form-control.is-readonly .icon-invalid,ec-form-control.is-readonly .icon-required,ec-form-control.is-readonly .ec-form-control-clear,ec-form-control.is-disabled .icon-loading,ec-form-control.is-disabled .icon-invalid,ec-form-control.is-disabled .icon-required,ec-form-control.is-disabled .ec-form-control-clear{display:none}ec-form-control.is-readonly{border-color:var(--ec-form-control-border-color-readonly);color:var(--ec-form-control-color-readonly)}ec-form-control.is-readonly .ec-form-control-action{display:none}ec-form-control.is-disabled:not(.is-readonly){color:var(--ec-form-control-color-disabled);opacity:.6}ec-form-control.is-disabled:not(.is-readonly) .ec-form-control-prefix,ec-form-control.is-disabled:not(.is-readonly) .ec-form-control-suffix{color:inherit}\n"] }]
3953
4810
  }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { formControlDirective: [{
3954
4811
  type: ContentChild,
3955
4812
  args: [FormControlDirective]
@@ -3992,29 +4849,139 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3992
4849
  args: ['class.is-disabled']
3993
4850
  }], actionClicked: [{
3994
4851
  type: Output
3995
- }], actionKeydown: [{
3996
- type: Output
3997
4852
  }], onClick: [{
3998
4853
  type: HostListener,
3999
4854
  args: ['click']
4000
4855
  }] } });
4001
4856
 
4857
+ class LinkButtonComponent {
4858
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LinkButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4859
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: LinkButtonComponent, selector: "button[ecLinkButton]", ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, styles: [":host{display:inline;border:none;padding:0;background-color:transparent;font-size:inherit;text-align:start;color:var(--ec-color-link);cursor:pointer}:host:hover{text-decoration:underline}:host:focus{outline:none;text-decoration:underline}:host(:disabled){cursor:default;color:var(--ec-color-hint-dark)}:host(:disabled):hover{text-decoration:none}\n"] }); }
4860
+ }
4861
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LinkButtonComponent, decorators: [{
4862
+ type: Component,
4863
+ args: [{ selector: 'button[ecLinkButton]', template: `<ng-content></ng-content>`, styles: [":host{display:inline;border:none;padding:0;background-color:transparent;font-size:inherit;text-align:start;color:var(--ec-color-link);cursor:pointer}:host:hover{text-decoration:underline}:host:focus{outline:none;text-decoration:underline}:host(:disabled){cursor:default;color:var(--ec-color-hint-dark)}:host(:disabled):hover{text-decoration:none}\n"] }]
4864
+ }] });
4865
+
4866
+ /**
4867
+ * A basic helper directive to determine when focus leaves the host element.
4868
+ *
4869
+ * NOTE: This directive utilizes hidden anchor elements. These will disrupt tab order for elements
4870
+ * within a form. It is recommended to only use this directive when you need to redirect focus when
4871
+ * focus leaves a container. Also make sure this directive is disabled when the focus out events
4872
+ * are not needed to avoid keyboard nav problems.
4873
+ */
4874
+ class KeyboardNavContainerDirective {
4875
+ constructor(hostEl, _document, interactivityChecker) {
4876
+ this.hostEl = hostEl;
4877
+ this._document = _document;
4878
+ this.interactivityChecker = interactivityChecker;
4879
+ this.enabled = true;
4880
+ this.focusOutStart = new EventEmitter();
4881
+ this.focusOutEnd = new EventEmitter();
4882
+ this.destroyed = new Subject();
4883
+ // Create the start and end anchors.
4884
+ this.startAnchor = this._document.createElement('div');
4885
+ this.endAnchor = this._document.createElement('div');
4886
+ // Hide the anchors from screen readers.
4887
+ this.startAnchor.setAttribute('aria-hidden', 'true');
4888
+ this.endAnchor.setAttribute('aria-hidden', 'true');
4889
+ }
4890
+ ngOnChanges() {
4891
+ this.toggleAnchors(this.enabled);
4892
+ }
4893
+ ngAfterViewInit() {
4894
+ // Insert the anchors into the DOM before and after the host element.
4895
+ this.hostEl.nativeElement.parentNode?.insertBefore(this.startAnchor, this.hostEl.nativeElement);
4896
+ this.hostEl.nativeElement.parentNode?.insertBefore(this.endAnchor, this.hostEl.nativeElement.nextSibling);
4897
+ // Listen for focus events on the anchors.
4898
+ fromEvent(this.startAnchor, 'focus').pipe(takeUntil(this.destroyed)).subscribe(() => this.focusOutStart.emit());
4899
+ fromEvent(this.endAnchor, 'focus').pipe(takeUntil(this.destroyed)).subscribe(() => this.focusOutEnd.emit());
4900
+ this.toggleAnchors(this.enabled);
4901
+ }
4902
+ ngOnDestroy() {
4903
+ this.destroyed.next();
4904
+ this.destroyed.complete();
4905
+ // Cleanup the anchors
4906
+ this.startAnchor.remove();
4907
+ this.endAnchor.remove();
4908
+ }
4909
+ focus() {
4910
+ const firstFocusableElement = this.getFirstFocusableElement(this.hostEl.nativeElement);
4911
+ firstFocusableElement?.focus();
4912
+ }
4913
+ getFirstFocusableElement(element) {
4914
+ // These are only possibly focusable. Some may be disabled or not visible.
4915
+ const elements = element.querySelectorAll('input, textarea, select, button, a, [tabindex], [contenteditable]');
4916
+ // Use the Angular CDK interactivity checker to determine if an element is actually focusable and tabbable.
4917
+ // This checks for disabledness among other things.
4918
+ const first = Array.from(elements).find(el => {
4919
+ return this.interactivityChecker.isFocusable(el) && this.interactivityChecker.isTabbable(el);
4920
+ });
4921
+ return first || null;
4922
+ }
4923
+ toggleAnchors(enabled) {
4924
+ // Make the anchors focusable if the container is enabled and we have subscribers for the events.
4925
+ // Otherwise, remove the tabindexes so they cannot receive focus and disrupt the tab order.
4926
+ if (enabled && this.focusOutStart.observers.length > 0) {
4927
+ this.startAnchor.setAttribute('tabindex', '0');
4928
+ }
4929
+ else {
4930
+ this.startAnchor.removeAttribute('tabindex');
4931
+ }
4932
+ if (enabled && this.focusOutEnd.observers.length > 0) {
4933
+ this.endAnchor.setAttribute('tabindex', '0');
4934
+ }
4935
+ else {
4936
+ this.endAnchor.removeAttribute('tabindex');
4937
+ }
4938
+ }
4939
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: KeyboardNavContainerDirective, deps: [{ token: i0.ElementRef }, { token: DOCUMENT }, { token: i1$3.InteractivityChecker }], target: i0.ɵɵFactoryTarget.Directive }); }
4940
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: KeyboardNavContainerDirective, selector: "[ecKeyboardNavContainer]", inputs: { enabled: ["ecKeyboardNavContainer", "enabled"] }, outputs: { focusOutStart: "focusOutStart", focusOutEnd: "focusOutEnd" }, exportAs: ["ecKeyboardNavContainer"], usesOnChanges: true, ngImport: i0 }); }
4941
+ }
4942
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: KeyboardNavContainerDirective, decorators: [{
4943
+ type: Directive,
4944
+ args: [{
4945
+ selector: '[ecKeyboardNavContainer]',
4946
+ exportAs: 'ecKeyboardNavContainer'
4947
+ }]
4948
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: Document, decorators: [{
4949
+ type: Inject,
4950
+ args: [DOCUMENT]
4951
+ }] }, { type: i1$3.InteractivityChecker }], propDecorators: { enabled: [{
4952
+ type: Input,
4953
+ args: ['ecKeyboardNavContainer']
4954
+ }], focusOutStart: [{
4955
+ type: Output
4956
+ }], focusOutEnd: [{
4957
+ type: Output
4958
+ }] } });
4959
+
4002
4960
  class DateInputComponent extends FormControlBase {
4003
- constructor(validationMessageService, formGroupHelper, userPreferenceService, dateDisplayPipe, el, overlayService) {
4961
+ constructor(validationMessageService, formGroupHelper, userPreferenceService, el, overlayService, selectionStrategies) {
4004
4962
  super(validationMessageService, formGroupHelper);
4005
4963
  this.validationMessageService = validationMessageService;
4006
4964
  this.formGroupHelper = formGroupHelper;
4007
4965
  this.userPreferenceService = userPreferenceService;
4008
- this.dateDisplayPipe = dateDisplayPipe;
4009
4966
  this.el = el;
4010
4967
  this.overlayService = overlayService;
4968
+ this.selectionStrategies = selectionStrategies;
4011
4969
  this.id = '';
4012
4970
  /** The form control provided by the hosting form. */
4013
4971
  this.formModel = new FormControl(null);
4014
4972
  this.minDate = DateTimeHelper.minDatePickerDate;
4015
4973
  this.maxDate = DateTimeHelper.maxDatePickerDate;
4016
- /** The internal textbox's form control. */
4017
- this.textboxControl = new FormControl(null);
4974
+ /** The initial selection mode for the calendar. Defaults to day if not provided */
4975
+ this.selectionMode = 'day';
4976
+ /** The available selection modes for the calendar. Defaults to only the initial selection mode if not provided. */
4977
+ this.selectionModeOptions = ['day'];
4978
+ /** Enables the next/previous selection buttons. */
4979
+ this.enableSteppers = false;
4980
+ /** The form group for the internal textboxes. Textbox2 is only used for ranges. */
4981
+ this.textboxGroup = new FormGroup({
4982
+ textbox: new FormControl(null),
4983
+ textbox2: new FormControl(null)
4984
+ });
4018
4985
  /**
4019
4986
  * The current calendar selection.
4020
4987
  * Updated when the user clicks on a calendar item or when the date entered into the textbox is parsed.
@@ -4026,40 +4993,51 @@ class DateInputComponent extends FormControlBase {
4026
4993
  this.placeholder = 'MM/DD/YYYY';
4027
4994
  /** Overlay scroll strategy for the calendar overlay. Closes the calendar on scroll. */
4028
4995
  this.overlayScrollStrategy = this.overlayService.scrollStrategies.close();
4996
+ this.primaryCalendarView = { mode: 'day', date: new Date() };
4997
+ this.secondaryCalendarView = { mode: 'day', date: new Date() };
4998
+ this.primaryCalendarMaxDate = DateTimeHelper.maxDatePickerDate;
4999
+ this.secondaryCalendarMinDate = DateTimeHelper.minDatePickerDate;
5000
+ this.disableSteppers = false;
4029
5001
  /**
4030
5002
  * Date parsing formats for user-entered dates. Defaults to month-first formats, but is updated in onInit
4031
5003
  * to use the user's preferred date format.
4032
5004
  */
4033
- this.parseFormats = DateTimeHelper.getParseFormats();
4034
- /**
4035
- * Validator that checks if the date is within the min and max date range.
4036
- * If the date is outside of the range, the validator returns an error that
4037
- * triggers the validation message service to show the error in the label.
4038
- */
4039
- this.dateValidator = (control) => {
4040
- if (control.value) {
4041
- if (control.value < this.minDate) {
4042
- return { minDate: { minValue: this.minDate } };
4043
- }
4044
- else if (control.value > this.maxDate) {
4045
- return { maxDate: { maxValue: this.maxDate } };
4046
- }
4047
- }
4048
- return null;
4049
- };
5005
+ this.parseFormats = DateTimeHelper.getMomentParseFormats();
5006
+ }
5007
+ ngOnChanges(changes) {
5008
+ if (changes.selectionMode && !changes.selectionMode.isFirstChange()) {
5009
+ this.onSelectionModeChange(this.selectionMode);
5010
+ }
5011
+ }
5012
+ ngOnInit() {
5013
+ // Setup
5014
+ super.ngOnInit();
5015
+ this.setDateFormats();
5016
+ this.setSelectionMode(this.selectionMode);
5017
+ // Subscriptions
5018
+ this.onFormModelStatusChanges();
5019
+ this.onFormModelValueChanges();
5020
+ this.onTextboxValueChanges();
5021
+ // Sync the initial disabled status and value of the textbox
5022
+ this.syncTextboxControlDisabledStatus(this.formModel.status);
5023
+ const initialDisplayValue = this.selectionStrategy.formatSelection(this.formModel.value);
5024
+ this.textboxGroup.patchValue(initialDisplayValue, { emitEvent: false });
5025
+ // Update the calendar selection and view based on the initial form model value
5026
+ this.calendarSelection = this.formModel.value;
5027
+ this.updateCalendars(this.calendarSelection);
5028
+ this.updateSteppers(this.calendarSelection);
5029
+ console.log(this.calendarSelection);
4050
5030
  }
4051
5031
  /** Focuses the input whenever the calendar is shift-tabbed out of. */
4052
- onCalendarFocusOutStart(event) {
4053
- event.preventDefault();
5032
+ onCalendarFocusOutStart() {
4054
5033
  this.focusInput();
4055
5034
  }
4056
5035
  /** Closes the calendar and focuses the input whenever the calendar is tabbed out of. */
4057
- onCalendarFocusOutEnd(event) {
4058
- event.preventDefault();
5036
+ onCalendarFocusOutEnd() {
4059
5037
  this.isCalendarOpen = false;
4060
5038
  this.focusInput();
4061
5039
  }
4062
- /** Close the calendar if the user clicks outside of the calendar and date input. */
5040
+ /** Closes the calendar if the user clicks outside of the calendar and date input. */
4063
5041
  onOverlayOutsideClick(event) {
4064
5042
  // Do not close the calendar if the click was within the date input or action button
4065
5043
  const rect = this.el.nativeElement.getBoundingClientRect();
@@ -4070,74 +5048,107 @@ class DateInputComponent extends FormControlBase {
4070
5048
  // It's possible that the user hit enter on the action button instead of clicking with the mouse.
4071
5049
  // In this case the "click" event will be outside of the component because the clientx and y are 0,
4072
5050
  // but we don't want to close in this case because button clicks trigger calendar open/close separately.
4073
- const isActionClick = event.target.id === `${this.id}_action`;
5051
+ const targetId = event.target.id;
5052
+ const isActionClick = targetId === `${this.id}_action` || targetId === `${this.id}_control2_action`;
4074
5053
  if (!isActionClick && clickedOutsideControl) {
4075
5054
  this.isCalendarOpen = false;
4076
5055
  }
4077
5056
  }
4078
5057
  /** If the user tabs out of the form control's action button and the calendar is open, focus the first item in the calendar overlay */
4079
- onActionKeydown(event) {
4080
- if (event.key === 'Tab' && !event.shiftKey && this.isCalendarOpen) {
4081
- // Prevent the default tab action so the focus doesn't move to the next element in the tab order after we manually focus the calendar button.
4082
- event.preventDefault();
4083
- // Focus the first button in the calendar overlay
4084
- const firstButton = this.overlay?.overlayRef.hostElement.querySelector('button:not(:disabled)');
4085
- firstButton?.focus();
5058
+ onControlsFocusOutEnd() {
5059
+ if (this.isCalendarOpen) {
5060
+ this.calendar?.focus();
4086
5061
  }
4087
5062
  }
4088
- onTextboxKeydown(event) {
4089
- if (event.key === 'Tab' && event.shiftKey) {
4090
- // If the user is tabbing backwards from the textbox, close the calendar.
4091
- this.isCalendarOpen = false;
4092
- }
4093
- }
4094
- /** Whenever the user selects a date from the calendar, update the formModel with the selection */
4095
- onSelectionChange(selection) {
4096
- this.calendarSelection = selection;
4097
- if (isCalendarSelectionSingleDate(selection)) {
4098
- this.formModel.setValue(selection);
5063
+ onTextboxBlur() {
5064
+ // We want to prevent the fixed date range modes from re-autocompleting the first textbox when it is explicitly cleared.
5065
+ const previousValue = DateInput.isSelectionRange(this.formModel.value) ? this.formModel.value.start : this.formModel.value;
5066
+ const currentValue = this.textboxGroup.value.textbox;
5067
+ const cleared = !!previousValue && !currentValue;
5068
+ const options = { preventAutoComplete: cleared };
5069
+ // Parse the textbox values into a selection and update the form model
5070
+ const parsedSelection = this.selectionStrategy.parseTextboxValues(this.textboxGroup.value, this.parseFormats, options);
5071
+ this.updateFormModel(parsedSelection);
5072
+ }
5073
+ onTextbox2Blur() {
5074
+ // We want to prevent the fixed date range modes from re-autocompleting the second textbox when it is explicitly cleared.
5075
+ const previousValue = DateInput.isSelectionRange(this.formModel.value) ? this.formModel.value.end : null;
5076
+ const currentValue = this.textboxGroup.value.textbox2;
5077
+ const cleared = !!previousValue && !currentValue;
5078
+ const options = { parseFromEnd: true, preventAutoComplete: cleared };
5079
+ // Parse the textbox values into a selection and update the form model,
5080
+ // For the second box we're keying the parse from the end date in the selection.
5081
+ const parsedSelection = this.selectionStrategy.parseTextboxValues(this.textboxGroup.value, this.parseFormats, options);
5082
+ this.updateFormModel(parsedSelection);
5083
+ }
5084
+ onSelectionModeChange(mode) {
5085
+ this.setSelectionMode(mode);
5086
+ const newSelection = this.selectionStrategy.getNewSelectionFromExisting(this.calendarSelection);
5087
+ this.updateFormModel(newSelection);
5088
+ // On selection mode change, we want to force the calendars to show the right view mode for the new selection.
5089
+ // This prevents the user from seeing a view mode that doesn't make sense for the new selection,
5090
+ // Like when swiching from year mode to last 7 days mode.
5091
+ this.primaryCalendarView = { mode: this.selectionStrategy.selectionViewMode, date: this.primaryCalendarView.date };
5092
+ this.secondaryCalendarView = { mode: this.selectionStrategy.selectionViewMode, date: this.secondaryCalendarView.date };
5093
+ this.updateCalendarMinMaxDates();
5094
+ }
5095
+ onCalendarDateSelected(date) {
5096
+ const newSelection = this.selectionStrategy.getSelectionFromDate(date, this.calendarSelection);
5097
+ const displayValue = this.selectionStrategy.formatSelection(newSelection);
5098
+ // Don't emit events when patching values here. We don't want to trigger the calendar updates since the calendar is already
5099
+ // showing the selected date. We also don't want to trigger the textbox parsing logic since the date was selected from the calendar.
5100
+ this.textboxGroup.patchValue(displayValue, { emitEvent: false });
5101
+ this.formModel.patchValue(newSelection, { emitEvent: false });
5102
+ this.calendarSelection = newSelection;
5103
+ this.updateSteppers(newSelection);
5104
+ // Close the calendar if the selection mode is not a range mode where either the start or the end date can be changed.
5105
+ if (!this.selectionStrategy.showSecondaryTextbox) {
4099
5106
  this.isCalendarOpen = false;
4100
5107
  this.focusInput();
4101
5108
  }
4102
5109
  }
4103
- onTextboxBlur() {
4104
- // Parse the textbox value into a date and update the form model
4105
- const value = this.textboxControl.value;
4106
- if (value) {
4107
- const parsedDate = moment(value, this.parseFormats);
4108
- if (parsedDate.isValid()) {
4109
- this.formModel.setValue(parsedDate.toDate());
4110
- }
4111
- else {
4112
- this.formModel.setValue(null);
4113
- }
5110
+ onPrimaryCalendarViewChange(view) {
5111
+ this.primaryCalendarView = view;
5112
+ this.updateCalendarMinMaxDates();
5113
+ }
5114
+ onSecondaryCalendarViewChange(view) {
5115
+ this.secondaryCalendarView = view;
5116
+ this.updateCalendarMinMaxDates();
5117
+ }
5118
+ /** Shifts the calendar views to display today. Does not update the calendar selection. */
5119
+ goToToday() {
5120
+ // If both calendars are visible, show today in the secondary calendar and the month before in the primary calendar.
5121
+ if (this.selectionStrategy.showSecondaryCalendar) {
5122
+ this.primaryCalendarView = { mode: 'day', date: moment().subtract(1, 'month').toDate() };
5123
+ this.secondaryCalendarView = { mode: 'day', date: new Date() };
5124
+ // If we're in a single date mode, show today in the primary calendar.
4114
5125
  }
4115
5126
  else {
4116
- this.formModel.setValue(null);
4117
- }
4118
- // Update the form model's touched and dirty status based on the textbox's status.
4119
- // Since the user interacts with a control that is internal to this component, the
4120
- // form model's status won't be updated automatically.
4121
- if (this.textboxControl.touched && !this.formModel.touched) {
4122
- this.formModel.markAsTouched();
5127
+ this.primaryCalendarView = { mode: 'day', date: new Date() };
4123
5128
  }
4124
- if (this.textboxControl.dirty && !this.formModel.dirty) {
4125
- this.formModel.markAsDirty();
5129
+ this.updateCalendarMinMaxDates();
5130
+ }
5131
+ goToQuickSelectDate() {
5132
+ if (this.quickSelectDate) {
5133
+ const newSelection = this.selectionStrategy.getSelectionForQuickSelectDate(this.quickSelectDate, this.calendarSelection);
5134
+ this.updateFormModel(newSelection);
4126
5135
  }
4127
5136
  }
4128
- ngOnInit() {
4129
- // Setup
4130
- super.ngOnInit();
4131
- this.setDateFormats();
4132
- this.formModel.addValidators(this.dateValidator);
4133
- // Subscriptions
4134
- this.onFormModelStatusChanges();
4135
- this.onFormModelValueChanges();
4136
- this.onTextboxValueChanges();
4137
- // Sync the initial disabled status and value of the textbox
4138
- this.syncTextboxControlDisabledStatus(this.formModel.status);
4139
- this.textboxControl.setValue(this.dateDisplayPipe.transform(this.formModel.value, true), { emitEvent: false });
4140
- this.calendarSelection = this.formModel.value;
5137
+ nextSelection() {
5138
+ const newSelection = this.selectionStrategy.getNextSelection(this.calendarSelection);
5139
+ this.updateFormModel(newSelection);
5140
+ }
5141
+ previousSelection() {
5142
+ const newSelection = this.selectionStrategy.getPreviousSelection(this.calendarSelection);
5143
+ this.updateFormModel(newSelection);
5144
+ }
5145
+ updateFormModel(value) {
5146
+ this.formModel.patchValue(value);
5147
+ // Validate the textboxes and sync the form errors
5148
+ // We do this after patching the form model because the form model patch will trigger
5149
+ // the date formatting logic and overwrite any errors on the controls from before.
5150
+ this.validateTextboxes();
5151
+ this.syncFormErrors();
4141
5152
  }
4142
5153
  onFormModelStatusChanges() {
4143
5154
  // Keep the textboxControl disabled status in sync with the formModel
@@ -4155,12 +5166,13 @@ class DateInputComponent extends FormControlBase {
4155
5166
  }
4156
5167
  onFormModelValueChanges() {
4157
5168
  // Update the calendar selection textbox value with a formatted date when the form model changes.
4158
- // This is usually triggered by programmatic changes to the form model by a parent component.
4159
- this.formModel.valueChanges.pipe(distinctUntilChanged((a, b) => moment(a).isSame(b, 'day')), takeUntil(this.componentDestroyed)).subscribe(value => {
4160
- const displayValue = this.dateDisplayPipe.transform(value, true);
5169
+ // This is triggered by the user selecting a date from the calendar or when the textbox is blurred.
5170
+ this.formModel.valueChanges.pipe(takeUntil(this.componentDestroyed)).subscribe(value => {
5171
+ const displayValue = this.selectionStrategy.formatSelection(value);
4161
5172
  // Don't emit an event when setting the textbox value to avoid circular updates between the textbox and form model.
4162
- this.textboxControl.setValue(displayValue, { emitEvent: false });
4163
- this.calendarSelection = value;
5173
+ this.textboxGroup.patchValue(displayValue, { emitEvent: false });
5174
+ this.updateCalendars(value);
5175
+ this.updateSteppers(value);
4164
5176
  });
4165
5177
  }
4166
5178
  onTextboxValueChanges() {
@@ -4168,34 +5180,67 @@ class DateInputComponent extends FormControlBase {
4168
5180
  // We don't patch the formModel here because we don't want to trigger the
4169
5181
  // date formatting logic and overwrite the user's input.
4170
5182
  // We'll do that when the user blurs out of the textbox. See onTextboxBlur()
4171
- this.textboxControl.valueChanges.pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.componentDestroyed)).subscribe(value => {
4172
- if (value) {
4173
- const parsedDate = moment(value, this.parseFormats);
4174
- if (parsedDate.isValid()) {
4175
- // If the parsed date is before the minDate, set the year to the current year.
4176
- // This prevents the calendar from showing unhelpful dates in the distant past as the user types
4177
- if (parsedDate.year() < this.minDate.getFullYear()) {
4178
- parsedDate.set('year', moment().year());
4179
- }
4180
- this.calendarSelection = parsedDate.toDate();
4181
- }
5183
+ this.textboxGroup.controls.textbox.valueChanges.pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.componentDestroyed)).subscribe(() => {
5184
+ const options = { shiftToCurrentYearIfBelow: this.minDate };
5185
+ const newSelection = this.selectionStrategy.parseTextboxValues(this.textboxGroup.value, this.parseFormats, options);
5186
+ // Calendar selection will be null if the dates are invalid. Don't update the calendars in this case.
5187
+ if (newSelection) {
5188
+ this.calendarSelection = newSelection;
5189
+ this.updatePrimaryCalendar(this.calendarSelection, this.selectionStrategy.showSecondaryCalendar);
5190
+ this.updateCalendarMinMaxDates();
4182
5191
  }
4183
- else {
4184
- this.calendarSelection = null;
5192
+ });
5193
+ // The second textbox is only used in last7Days, last28Days, and range modes.
5194
+ this.textboxGroup.controls.textbox2.valueChanges.pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.componentDestroyed)).subscribe(() => {
5195
+ const options = { shiftToCurrentYearIfBelow: this.minDate, parseFromEnd: true };
5196
+ const newSelection = this.selectionStrategy.parseTextboxValues(this.textboxGroup.value, this.parseFormats, options);
5197
+ // Calendar selection will be null if the dates are invalid. Don't update the calendars in this case.
5198
+ if (newSelection) {
5199
+ this.calendarSelection = newSelection;
5200
+ // The secondary calendar is only shown in range mode. Update the primary calendar if we're not in range mode.
5201
+ if (this.selectionStrategy.showSecondaryCalendar) {
5202
+ this.updateSecondaryCalendar(this.calendarSelection, true);
5203
+ }
5204
+ else {
5205
+ this.updatePrimaryCalendar(this.calendarSelection);
5206
+ }
5207
+ this.updateCalendarMinMaxDates();
4185
5208
  }
4186
5209
  });
4187
5210
  }
4188
5211
  syncTextboxControlDisabledStatus(status) {
4189
5212
  // The textbox should only be disabled if the form model is disabled.
4190
5213
  // All other statuses are considered enabled.
4191
- if (status === 'DISABLED' && this.textboxControl.enabled) {
4192
- this.textboxControl.disable();
5214
+ if (status === 'DISABLED' && this.textboxGroup.enabled) {
5215
+ this.textboxGroup.disable();
4193
5216
  }
4194
- else if (status !== 'DISABLED' && this.textboxControl.disabled) {
4195
- this.textboxControl.enable();
5217
+ else if (status !== 'DISABLED' && this.textboxGroup.disabled) {
5218
+ this.textboxGroup.enable();
4196
5219
  }
4197
5220
  }
4198
5221
  ;
5222
+ syncFormErrors() {
5223
+ // Start with the existing form model errors
5224
+ let errors = this.formModel.errors;
5225
+ // Add the errors from the textboxes if they exist
5226
+ if (this.textboxGroup.controls.textbox.errors) {
5227
+ errors = { ...errors, ...this.textboxGroup.controls.textbox.errors };
5228
+ }
5229
+ if (this.textboxGroup.controls.textbox2.errors) {
5230
+ errors = { ...errors, ...this.textboxGroup.controls.textbox2.errors };
5231
+ }
5232
+ // Update the form model's errors with the combined errors
5233
+ this.formModel.setErrors(errors);
5234
+ // Update the form model's touched and dirty status based on the textbox's status.
5235
+ // Since the user interacts with a control that is internal to this component, the
5236
+ // form model's status won't be updated automatically.
5237
+ if (this.textboxGroup.touched && !this.formModel.touched) {
5238
+ this.formModel.markAsTouched();
5239
+ }
5240
+ if (this.textboxGroup.dirty && !this.formModel.dirty) {
5241
+ this.formModel.markAsDirty();
5242
+ }
5243
+ }
4199
5244
  /**
4200
5245
  * Updates the date parsing formats and placeholder based on the user's display preference.
4201
5246
  * NOTE: This is async because we're retrieving the user's preferences. We're not awaiting the result
@@ -4211,15 +5256,120 @@ class DateInputComponent extends FormControlBase {
4211
5256
  }
4212
5257
  /** Focuses the date input. */
4213
5258
  focusInput() {
4214
- this.el.nativeElement.querySelector('input')?.focus();
5259
+ this.controls?.focus();
5260
+ }
5261
+ setSelectionMode(mode) {
5262
+ this.selectionMode = mode;
5263
+ this.selectionStrategy = this.selectionStrategies[mode];
5264
+ }
5265
+ /**
5266
+ * Sets the max date for the primary calendar and the min date for the secondary calendar based
5267
+ * on the current views in each. This prevents the user from moving the calendars out of order.
5268
+ */
5269
+ updateCalendarMinMaxDates() {
5270
+ // Only update the min/max dates when the view mode is 'day'.
5271
+ // When a calendar is in a month or year view mode, the view dates at the beginning of the year.
5272
+ // This would cause the dates in the other calendar to be unselectable if we were to
5273
+ // update the min/max dates in these cases.
5274
+ if (this.primaryCalendarView?.mode === 'day') {
5275
+ this.secondaryCalendarMinDate = moment(this.primaryCalendarView?.date).add(1, 'month').startOf('month').toDate();
5276
+ }
5277
+ if (this.secondaryCalendarView?.mode === 'day') {
5278
+ this.primaryCalendarMaxDate = moment(this.secondaryCalendarView?.date).subtract(1, 'month').endOf('month').toDate();
5279
+ }
5280
+ }
5281
+ updateCalendars(selection) {
5282
+ this.calendarSelection = selection;
5283
+ this.updatePrimaryCalendar(selection);
5284
+ // Only shift the primary calendar if we're showing the secondary calendar
5285
+ this.updateSecondaryCalendar(selection, this.selectionStrategy.showSecondaryCalendar);
5286
+ this.updateCalendarMinMaxDates();
5287
+ }
5288
+ updatePrimaryCalendar(selection, shiftSecondary = false) {
5289
+ this.primaryCalendarView = this.selectionStrategy.getPrimaryCalendarView(selection, this.minDate, this.maxDate, this.primaryCalendarView);
5290
+ // When entering a date into the first textbox, we really only want to update the primary calendar.
5291
+ // However, it's possible that the new date is after the secondary calendar's date. In this case,
5292
+ // We want to shift the secondary calendar so the calendars stay in order.
5293
+ if (shiftSecondary && this.secondaryCalendarView) {
5294
+ if (moment(this.primaryCalendarView.date).isSameOrAfter(this.secondaryCalendarView.date, 'month')) {
5295
+ let newSecondaryDate = moment(this.primaryCalendarView.date).add(1, 'month').toDate();
5296
+ this.secondaryCalendarView = { mode: this.selectionStrategy.selectionViewMode, date: newSecondaryDate };
5297
+ }
5298
+ }
5299
+ }
5300
+ updateSecondaryCalendar(selection, shiftPrimary = false) {
5301
+ this.secondaryCalendarView = this.selectionStrategy.getSecondaryCalendarView(selection, this.minDate, this.maxDate, this.secondaryCalendarView);
5302
+ // When entering a date into the second textbox, we really only want to update the secondary calendar.
5303
+ // However, it's possible that the new date is before the primary calendar's date. In this case,
5304
+ // We want to shift the primary calendar so the calendars stay in order.
5305
+ if (shiftPrimary && this.primaryCalendarView) {
5306
+ if (moment(this.primaryCalendarView.date).isSameOrAfter(this.secondaryCalendarView.date, 'month')) {
5307
+ let newPrimaryDate = moment(this.secondaryCalendarView.date).subtract(1, 'month').toDate();
5308
+ this.primaryCalendarView = { mode: this.selectionStrategy.selectionViewMode, date: newPrimaryDate };
5309
+ }
5310
+ }
5311
+ }
5312
+ updateSteppers(value) {
5313
+ // Disable the steppers if we either don't have a selection or only have one date in the selection.
5314
+ if (!value ||
5315
+ (DateInput.isSelectionSingleDate(value) && this.selectionMode !== 'day') ||
5316
+ (DateInput.isSelectionRange(value) && (!value.start || !value.end))) {
5317
+ this.disableSteppers = true;
5318
+ }
5319
+ else {
5320
+ this.disableSteppers = false;
5321
+ }
5322
+ }
5323
+ validateTextboxes() {
5324
+ const control = this.textboxGroup.controls.textbox;
5325
+ const control2 = this.textboxGroup.controls.textbox2;
5326
+ // The first textbox should only have the required error if it's empty and the date input is required,
5327
+ // or if the date input is not required and the second control is visible and has a value (meaning a partial range)
5328
+ if (!control.value &&
5329
+ (this.required || (control2.value && this.selectionStrategy.showSecondaryTextbox))) {
5330
+ control.setErrors({ required: true });
5331
+ }
5332
+ // The same idea applies to the second textbox, but only if it's visible
5333
+ if (this.selectionStrategy.showSecondaryTextbox &&
5334
+ !control2.value &&
5335
+ (this.required || control.value)) {
5336
+ control2.setErrors({ required: true });
5337
+ }
5338
+ if (control.value) {
5339
+ const errors = this.validateDateString(control.value);
5340
+ if (errors) {
5341
+ control.setErrors(errors);
5342
+ }
5343
+ }
5344
+ if (control2.value && this.selectionStrategy.showSecondaryTextbox) {
5345
+ const errors = this.validateDateString(control2.value);
5346
+ if (errors) {
5347
+ control2.setErrors(errors);
5348
+ }
5349
+ }
5350
+ }
5351
+ validateDateString(date) {
5352
+ const value = this.selectionStrategy.parseString(date, this.parseFormats);
5353
+ if (value) {
5354
+ // We're using the view mode as the granularity. We don't want to invalidate
5355
+ // the date in the case where you have a month/quarter/year selected and the min
5356
+ // or max date is somewhere within that month/quarter/year.
5357
+ if (moment(value).isBefore(this.minDate, this.selectionStrategy.selectionViewMode)) {
5358
+ return { minDate: { minValue: this.minDate } };
5359
+ }
5360
+ else if (moment(value).isAfter(this.maxDate, this.selectionStrategy.selectionViewMode)) {
5361
+ return { maxDate: { maxValue: this.maxDate } };
5362
+ }
5363
+ }
5364
+ return null;
4215
5365
  }
4216
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DateInputComponent, deps: [{ token: ValidationMessageService }, { token: FormGroupHelper }, { token: UserPreferenceService }, { token: DateDisplayPipe }, { token: i0.ElementRef }, { token: i1$1.Overlay }], target: i0.ɵɵFactoryTarget.Component }); }
4217
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: DateInputComponent, selector: "ec-date-input", inputs: { id: "id", formModel: "formModel", minDate: "minDate", maxDate: "maxDate" }, host: { properties: { "attr.id": "this.id" } }, viewQueries: [{ propertyName: "overlay", first: true, predicate: ["overlay"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<label *ngIf=\"label\">\r\n <span>{{label | translate}}</span>\r\n <span *ngIf=\"validationErrors.length > 0 && formModel.touched && formModel.invalid\">&nbsp;{{validationErrors}}</span>\r\n <ec-help-popover id=\"{{id}}_helpPopover\"\r\n *ngIf=\"helpPopover\"\r\n class=\"d-inline-block my-n3 mx-n1\"\r\n text=\"{{helpPopover | translate}}\"\r\n contentPosition=\"{{helpPopoverPosition}}\">\r\n </ec-help-popover>\r\n</label>\r\n\r\n<ec-form-control id=\"{{id}}\"\r\n [required]=\"required\"\r\n [autofocus]=\"autofocus\"\r\n [pending]=\"pending\"\r\n [readonly]=\"readonly\"\r\n [formModel]=\"formModel\"\r\n (actionClicked)=\"isCalendarOpen = !isCalendarOpen\"\r\n (actionKeydown)=\"onActionKeydown($event)\"\r\n [showClear]=\"false\"\r\n actionIcon=\"icon-date\"\r\n cdkOverlayOrigin\r\n #overlayOrigin=\"cdkOverlayOrigin\">\r\n <input id=\"{{id}}_input\"\r\n type=\"text\"\r\n placeholder=\"{{placeholder}}\"\r\n [formControl]=\"textboxControl\"\r\n (blur)=\"onTextboxBlur()\"\r\n (keydown)=\"onTextboxKeydown($event)\">\r\n</ec-form-control>\r\n\r\n<ng-template cdkConnectedOverlay\r\n #overlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isCalendarOpen\"\r\n [cdkConnectedOverlayScrollStrategy]=\"overlayScrollStrategy\"\r\n cdkConnectedOverlayPanelClass=\"my-1\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick($event)\"\r\n (detach)=\"isCalendarOpen = false\">\r\n <ec-calendar [id]=\"id + '_calendar'\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"\r\n [selection]=\"calendarSelection\"\r\n (selectionChange)=\"onSelectionChange($event)\"\r\n class=\"card px-1 pt-1 pb-2\"\r\n (focusOutStart)=\"onCalendarFocusOutStart($event)\"\r\n (focusOutEnd)=\"onCalendarFocusOutEnd($event)\">\r\n </ec-calendar>\r\n</ng-template>\r\n", styles: [":host{display:block}label{color:var(--ec-form-control-label-color, var(--ec-color-secondary-dark));display:block;font-size:var(--ec-font-size-label);line-height:1;margin:calc(var(--ec-font-size-label) / 2) 0}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: FormControlComponent, selector: "ec-form-control", inputs: ["id", "icon", "actionIcon", "showClear", "formModel", "autofocus", "pending", "required", "readonly"], outputs: ["actionClicked", "actionKeydown"] }, { kind: "component", type: HelpPopoverComponent, selector: "ec-help-popover", inputs: ["id", "text", "contentPosition", "maxWidth"] }, { kind: "component", type: CalendarComponent, selector: "ec-calendar", inputs: ["id", "selection", "minDate", "maxDate"], outputs: ["selectionChange", "focusOutStart", "focusOutEnd"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] }); }
5366
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DateInputComponent, deps: [{ token: ValidationMessageService }, { token: FormGroupHelper }, { token: UserPreferenceService }, { token: i0.ElementRef }, { token: i1$1.Overlay }, { token: DateInput.SelectionStrategies }], target: i0.ɵɵFactoryTarget.Component }); }
5367
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: DateInputComponent, selector: "ec-date-input", inputs: { id: "id", formModel: "formModel", minDate: "minDate", maxDate: "maxDate", selectionMode: "selectionMode", selectionModeOptions: "selectionModeOptions", quickSelectDate: "quickSelectDate", enableSteppers: "enableSteppers" }, host: { properties: { "attr.id": "this.id" } }, providers: [DateInput.SelectionStrategies], viewQueries: [{ propertyName: "calendar", first: true, predicate: ["calendar"], descendants: true }, { propertyName: "controls", first: true, predicate: ["controls"], descendants: true }, { propertyName: "overlay", first: true, predicate: ["overlay"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<label *ngIf=\"label\">\r\n <span>{{label | translate}}</span>\r\n <span *ngIf=\"validationErrors.length > 0 && formModel.touched && formModel.invalid\">&nbsp;{{validationErrors}}</span>\r\n <ec-help-popover id=\"{{id}}_helpPopover\"\r\n *ngIf=\"helpPopover\"\r\n class=\"d-inline-block my-n3 mx-n1\"\r\n text=\"{{helpPopover | translate}}\"\r\n contentPosition=\"{{helpPopoverPosition}}\">\r\n </ec-help-popover>\r\n</label>\r\n\r\n<div class=\"d-flex align-items-center\"\r\n [ecKeyboardNavContainer]=\"isCalendarOpen\"\r\n #controls=\"ecKeyboardNavContainer\"\r\n (focusOutEnd)=\"onControlsFocusOutEnd()\">\r\n <ec-form-control id=\"{{id}}\"\r\n [required]=\"required\"\r\n [autofocus]=\"autofocus\"\r\n [pending]=\"pending\"\r\n [readonly]=\"readonly\"\r\n (actionClicked)=\"isCalendarOpen = !isCalendarOpen\"\r\n [showClear]=\"false\"\r\n actionIcon=\"icon-date\"\r\n cdkOverlayOrigin\r\n #overlayOrigin=\"cdkOverlayOrigin\"\r\n class=\"flex-grow\"\r\n style=\"height: 2rem;\">\r\n <input id=\"{{id}}_input\"\r\n type=\"text\"\r\n placeholder=\"{{placeholder}}\"\r\n [formControl]=\"textboxGroup.get('textbox')\"\r\n (blur)=\"onTextboxBlur()\">\r\n </ec-form-control>\r\n\r\n <ng-container *ngIf=\"selectionStrategy.showSecondaryTextbox\">\r\n <span class=\"flex-shrink mx-1\">&ndash;</span>\r\n <ec-form-control id=\"{{id}}_control2\"\r\n [required]=\"required\"\r\n [autofocus]=\"autofocus\"\r\n [pending]=\"pending\"\r\n [readonly]=\"readonly\"\r\n (actionClicked)=\"isCalendarOpen = !isCalendarOpen\"\r\n [showClear]=\"false\"\r\n actionIcon=\"icon-date\"\r\n class=\"flex-grow\"\r\n style=\"height: 2rem;\">\r\n <input id=\"{{id}}_input2\"\r\n type=\"text\"\r\n placeholder=\"{{placeholder}}\"\r\n [formControl]=\"textboxGroup.get('textbox2')\"\r\n (blur)=\"onTextbox2Blur()\">\r\n </ec-form-control>\r\n </ng-container>\r\n\r\n <div *ngIf=\"enableSteppers\"\r\n class=\"control-group ml-2\">\r\n <ec-button id=\"{{id}}_previousSelection\"\r\n type=\"secondary\"\r\n icon=\"icon-angle-down rotate-90\"\r\n (clicked)=\"previousSelection()\"\r\n [disabled]=\"isCalendarOpen || disableSteppers || formModel?.disabled\">\r\n </ec-button>\r\n <ec-button id=\"{{id}}_nextSelection\"\r\n type=\"secondary\"\r\n icon=\"icon-angle-down rotate-270\"\r\n (clicked)=\"nextSelection()\"\r\n [disabled]=\"isCalendarOpen || disableSteppers || formModel?.disabled\">\r\n </ec-button>\r\n </div>\r\n\r\n <ec-button *ngIf=\"quickSelectDate\"\r\n id=\"{{id}}_quickSelect\"\r\n icon=\"icon-day\"\r\n type=\"secondary\"\r\n title=\"{{'DateInput_LatestDataAvailableTitle' | translate}}\"\r\n (clicked)=\"goToQuickSelectDate()\"\r\n class=\"ml-2\">\r\n </ec-button>\r\n</div>\r\n\r\n<ng-template cdkConnectedOverlay\r\n #overlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isCalendarOpen\"\r\n [cdkConnectedOverlayScrollStrategy]=\"overlayScrollStrategy\"\r\n cdkConnectedOverlayPanelClass=\"my-1\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick($event)\"\r\n (detach)=\"isCalendarOpen = false\">\r\n <article id=\"{{id}}_datePicker\"\r\n class=\"card d-flex\"\r\n [ecKeyboardNavContainer]=\"isCalendarOpen\"\r\n #calendar=\"ecKeyboardNavContainer\"\r\n (focusOutStart)=\"onCalendarFocusOutStart()\"\r\n (focusOutEnd)=\"onCalendarFocusOutEnd()\">\r\n <ul *ngIf=\"selectionModeOptions.length > 1\"\r\n class=\"selection-mode-menu border-right p-1\">\r\n <li *ngFor=\"let option of selectionModeOptions\">\r\n <button id=\"{{id}}_selectionMode_{{option}}\"\r\n class=\"text-body-1\"\r\n [class.is-selected]=\"option === selectionMode\"\r\n (click)=\"onSelectionModeChange(option)\">\r\n {{'DateInputSelectionMode_' + option | translate}}\r\n </button>\r\n </li>\r\n </ul>\r\n\r\n <div>\r\n <div class=\"d-flex\">\r\n <ec-calendar id=\"{{id}}_calendar\"\r\n [view]=\"primaryCalendarView\"\r\n (viewChange)=\"onPrimaryCalendarViewChange($event)\"\r\n [selectionMode]=\"selectionMode\"\r\n [selection]=\"calendarSelection\"\r\n (dateSelected)=\"onCalendarDateSelected($event)\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"selectionStrategy.showSecondaryCalendar ? primaryCalendarMaxDate : maxDate\">\r\n </ec-calendar>\r\n\r\n <ec-calendar *ngIf=\"selectionStrategy.showSecondaryCalendar\"\r\n id=\"{{id}}_secondaryCalendar\"\r\n [view]=\"secondaryCalendarView\"\r\n (viewChange)=\"onSecondaryCalendarViewChange($event)\"\r\n [selectionMode]=\"selectionMode\"\r\n [selection]=\"calendarSelection\"\r\n (dateSelected)=\"onCalendarDateSelected($event)\"\r\n [minDate]=\"secondaryCalendarMinDate\"\r\n [maxDate]=\"maxDate\">\r\n </ec-calendar>\r\n </div>\r\n\r\n <footer *ngIf=\"selectionStrategy.selectionViewMode === 'day'\"\r\n class=\"px-2 my-2 d-flex\">\r\n <button id=\"{{id}}_today_button\"\r\n ecLinkButton\r\n class=\"ml-auto d-inline-block\"\r\n (click)=\"goToToday()\"\r\n style=\"height: 1.75rem;\">\r\n {{'Today' | translate}}\r\n </button>\r\n </footer>\r\n </div>\r\n </article>\r\n</ng-template>\r\n", styles: [":host{display:block}label{color:var(--ec-form-control-label-color, var(--ec-color-secondary-dark));display:block;font-size:var(--ec-font-size-label);line-height:1;margin:calc(var(--ec-font-size-label) / 2) 0}.date-picker{display:grid;grid-template-areas:\"menu calendar calendar\" \"menu footer footer\"}.date-picker footer{grid-area:footer}ul.selection-mode-menu{grid-area:menu;list-style:none;padding:0;margin:0;min-width:7rem}ul.selection-mode-menu li{margin-bottom:.25rem}ul.selection-mode-menu li button{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer;background-color:transparent;width:100%;height:1.75rem}ul.selection-mode-menu li button .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}ul.selection-mode-menu li button .ec-icon{flex:none}ul.selection-mode-menu li button .ec-icon+.label{flex:none;margin-left:.25rem}ul.selection-mode-menu li button.has-badge{padding-right:.0625rem}ul.selection-mode-menu li button:focus{outline:none;position:relative;z-index:1}ul.selection-mode-menu li button:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}ul.selection-mode-menu li button:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);--ec-color-icon: var(--ec-color-hint-dark)}ul.selection-mode-menu li button:hover:not(:disabled){background-color:var(--ec-background-color-hover)}ul.selection-mode-menu li button:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}ul.selection-mode-menu li button:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}ul.selection-mode-menu li button.is-selected{background-color:var(--ec-background-color-selected);font-weight:700}ec-button{--ec-button-border-color-secondary: var(--ec-border-color-control)}.control-group ec-button:has(+ec-button) ::ng-deep button{border-right:0}.control-group ec-button+ec-button ::ng-deep button{border-left:0}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: ButtonComponent, selector: "ec-button", inputs: ["id", "disabled", "icon", "label", "badge", "tabindex", "type", "pending", "pendingIcon", "customTemplate", "isSubmit", "autofocus"], outputs: ["clicked"] }, { kind: "component", type: FormControlComponent, selector: "ec-form-control", inputs: ["id", "icon", "actionIcon", "showClear", "formModel", "autofocus", "pending", "required", "readonly"], outputs: ["actionClicked"] }, { kind: "component", type: HelpPopoverComponent, selector: "ec-help-popover", inputs: ["id", "text", "contentPosition", "maxWidth"] }, { kind: "component", type: LinkButtonComponent, selector: "button[ecLinkButton]" }, { kind: "component", type: CalendarComponent, selector: "ec-calendar", inputs: ["id", "selection", "selectionMode", "minDate", "maxDate", "view"], outputs: ["dateSelected", "viewChange"] }, { kind: "directive", type: KeyboardNavContainerDirective, selector: "[ecKeyboardNavContainer]", inputs: ["ecKeyboardNavContainer"], outputs: ["focusOutStart", "focusOutEnd"], exportAs: ["ecKeyboardNavContainer"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] }); }
4218
5368
  }
4219
5369
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DateInputComponent, decorators: [{
4220
5370
  type: Component,
4221
- args: [{ selector: 'ec-date-input', template: "<label *ngIf=\"label\">\r\n <span>{{label | translate}}</span>\r\n <span *ngIf=\"validationErrors.length > 0 && formModel.touched && formModel.invalid\">&nbsp;{{validationErrors}}</span>\r\n <ec-help-popover id=\"{{id}}_helpPopover\"\r\n *ngIf=\"helpPopover\"\r\n class=\"d-inline-block my-n3 mx-n1\"\r\n text=\"{{helpPopover | translate}}\"\r\n contentPosition=\"{{helpPopoverPosition}}\">\r\n </ec-help-popover>\r\n</label>\r\n\r\n<ec-form-control id=\"{{id}}\"\r\n [required]=\"required\"\r\n [autofocus]=\"autofocus\"\r\n [pending]=\"pending\"\r\n [readonly]=\"readonly\"\r\n [formModel]=\"formModel\"\r\n (actionClicked)=\"isCalendarOpen = !isCalendarOpen\"\r\n (actionKeydown)=\"onActionKeydown($event)\"\r\n [showClear]=\"false\"\r\n actionIcon=\"icon-date\"\r\n cdkOverlayOrigin\r\n #overlayOrigin=\"cdkOverlayOrigin\">\r\n <input id=\"{{id}}_input\"\r\n type=\"text\"\r\n placeholder=\"{{placeholder}}\"\r\n [formControl]=\"textboxControl\"\r\n (blur)=\"onTextboxBlur()\"\r\n (keydown)=\"onTextboxKeydown($event)\">\r\n</ec-form-control>\r\n\r\n<ng-template cdkConnectedOverlay\r\n #overlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isCalendarOpen\"\r\n [cdkConnectedOverlayScrollStrategy]=\"overlayScrollStrategy\"\r\n cdkConnectedOverlayPanelClass=\"my-1\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick($event)\"\r\n (detach)=\"isCalendarOpen = false\">\r\n <ec-calendar [id]=\"id + '_calendar'\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"\r\n [selection]=\"calendarSelection\"\r\n (selectionChange)=\"onSelectionChange($event)\"\r\n class=\"card px-1 pt-1 pb-2\"\r\n (focusOutStart)=\"onCalendarFocusOutStart($event)\"\r\n (focusOutEnd)=\"onCalendarFocusOutEnd($event)\">\r\n </ec-calendar>\r\n</ng-template>\r\n", styles: [":host{display:block}label{color:var(--ec-form-control-label-color, var(--ec-color-secondary-dark));display:block;font-size:var(--ec-font-size-label);line-height:1;margin:calc(var(--ec-font-size-label) / 2) 0}\n"] }]
4222
- }], ctorParameters: () => [{ type: ValidationMessageService }, { type: FormGroupHelper }, { type: UserPreferenceService }, { type: DateDisplayPipe }, { type: i0.ElementRef }, { type: i1$1.Overlay }], propDecorators: { id: [{
5371
+ args: [{ selector: 'ec-date-input', providers: [DateInput.SelectionStrategies], template: "<label *ngIf=\"label\">\r\n <span>{{label | translate}}</span>\r\n <span *ngIf=\"validationErrors.length > 0 && formModel.touched && formModel.invalid\">&nbsp;{{validationErrors}}</span>\r\n <ec-help-popover id=\"{{id}}_helpPopover\"\r\n *ngIf=\"helpPopover\"\r\n class=\"d-inline-block my-n3 mx-n1\"\r\n text=\"{{helpPopover | translate}}\"\r\n contentPosition=\"{{helpPopoverPosition}}\">\r\n </ec-help-popover>\r\n</label>\r\n\r\n<div class=\"d-flex align-items-center\"\r\n [ecKeyboardNavContainer]=\"isCalendarOpen\"\r\n #controls=\"ecKeyboardNavContainer\"\r\n (focusOutEnd)=\"onControlsFocusOutEnd()\">\r\n <ec-form-control id=\"{{id}}\"\r\n [required]=\"required\"\r\n [autofocus]=\"autofocus\"\r\n [pending]=\"pending\"\r\n [readonly]=\"readonly\"\r\n (actionClicked)=\"isCalendarOpen = !isCalendarOpen\"\r\n [showClear]=\"false\"\r\n actionIcon=\"icon-date\"\r\n cdkOverlayOrigin\r\n #overlayOrigin=\"cdkOverlayOrigin\"\r\n class=\"flex-grow\"\r\n style=\"height: 2rem;\">\r\n <input id=\"{{id}}_input\"\r\n type=\"text\"\r\n placeholder=\"{{placeholder}}\"\r\n [formControl]=\"textboxGroup.get('textbox')\"\r\n (blur)=\"onTextboxBlur()\">\r\n </ec-form-control>\r\n\r\n <ng-container *ngIf=\"selectionStrategy.showSecondaryTextbox\">\r\n <span class=\"flex-shrink mx-1\">&ndash;</span>\r\n <ec-form-control id=\"{{id}}_control2\"\r\n [required]=\"required\"\r\n [autofocus]=\"autofocus\"\r\n [pending]=\"pending\"\r\n [readonly]=\"readonly\"\r\n (actionClicked)=\"isCalendarOpen = !isCalendarOpen\"\r\n [showClear]=\"false\"\r\n actionIcon=\"icon-date\"\r\n class=\"flex-grow\"\r\n style=\"height: 2rem;\">\r\n <input id=\"{{id}}_input2\"\r\n type=\"text\"\r\n placeholder=\"{{placeholder}}\"\r\n [formControl]=\"textboxGroup.get('textbox2')\"\r\n (blur)=\"onTextbox2Blur()\">\r\n </ec-form-control>\r\n </ng-container>\r\n\r\n <div *ngIf=\"enableSteppers\"\r\n class=\"control-group ml-2\">\r\n <ec-button id=\"{{id}}_previousSelection\"\r\n type=\"secondary\"\r\n icon=\"icon-angle-down rotate-90\"\r\n (clicked)=\"previousSelection()\"\r\n [disabled]=\"isCalendarOpen || disableSteppers || formModel?.disabled\">\r\n </ec-button>\r\n <ec-button id=\"{{id}}_nextSelection\"\r\n type=\"secondary\"\r\n icon=\"icon-angle-down rotate-270\"\r\n (clicked)=\"nextSelection()\"\r\n [disabled]=\"isCalendarOpen || disableSteppers || formModel?.disabled\">\r\n </ec-button>\r\n </div>\r\n\r\n <ec-button *ngIf=\"quickSelectDate\"\r\n id=\"{{id}}_quickSelect\"\r\n icon=\"icon-day\"\r\n type=\"secondary\"\r\n title=\"{{'DateInput_LatestDataAvailableTitle' | translate}}\"\r\n (clicked)=\"goToQuickSelectDate()\"\r\n class=\"ml-2\">\r\n </ec-button>\r\n</div>\r\n\r\n<ng-template cdkConnectedOverlay\r\n #overlay=\"cdkConnectedOverlay\"\r\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\r\n [cdkConnectedOverlayOpen]=\"isCalendarOpen\"\r\n [cdkConnectedOverlayScrollStrategy]=\"overlayScrollStrategy\"\r\n cdkConnectedOverlayPanelClass=\"my-1\"\r\n (overlayOutsideClick)=\"onOverlayOutsideClick($event)\"\r\n (detach)=\"isCalendarOpen = false\">\r\n <article id=\"{{id}}_datePicker\"\r\n class=\"card d-flex\"\r\n [ecKeyboardNavContainer]=\"isCalendarOpen\"\r\n #calendar=\"ecKeyboardNavContainer\"\r\n (focusOutStart)=\"onCalendarFocusOutStart()\"\r\n (focusOutEnd)=\"onCalendarFocusOutEnd()\">\r\n <ul *ngIf=\"selectionModeOptions.length > 1\"\r\n class=\"selection-mode-menu border-right p-1\">\r\n <li *ngFor=\"let option of selectionModeOptions\">\r\n <button id=\"{{id}}_selectionMode_{{option}}\"\r\n class=\"text-body-1\"\r\n [class.is-selected]=\"option === selectionMode\"\r\n (click)=\"onSelectionModeChange(option)\">\r\n {{'DateInputSelectionMode_' + option | translate}}\r\n </button>\r\n </li>\r\n </ul>\r\n\r\n <div>\r\n <div class=\"d-flex\">\r\n <ec-calendar id=\"{{id}}_calendar\"\r\n [view]=\"primaryCalendarView\"\r\n (viewChange)=\"onPrimaryCalendarViewChange($event)\"\r\n [selectionMode]=\"selectionMode\"\r\n [selection]=\"calendarSelection\"\r\n (dateSelected)=\"onCalendarDateSelected($event)\"\r\n [minDate]=\"minDate\"\r\n [maxDate]=\"selectionStrategy.showSecondaryCalendar ? primaryCalendarMaxDate : maxDate\">\r\n </ec-calendar>\r\n\r\n <ec-calendar *ngIf=\"selectionStrategy.showSecondaryCalendar\"\r\n id=\"{{id}}_secondaryCalendar\"\r\n [view]=\"secondaryCalendarView\"\r\n (viewChange)=\"onSecondaryCalendarViewChange($event)\"\r\n [selectionMode]=\"selectionMode\"\r\n [selection]=\"calendarSelection\"\r\n (dateSelected)=\"onCalendarDateSelected($event)\"\r\n [minDate]=\"secondaryCalendarMinDate\"\r\n [maxDate]=\"maxDate\">\r\n </ec-calendar>\r\n </div>\r\n\r\n <footer *ngIf=\"selectionStrategy.selectionViewMode === 'day'\"\r\n class=\"px-2 my-2 d-flex\">\r\n <button id=\"{{id}}_today_button\"\r\n ecLinkButton\r\n class=\"ml-auto d-inline-block\"\r\n (click)=\"goToToday()\"\r\n style=\"height: 1.75rem;\">\r\n {{'Today' | translate}}\r\n </button>\r\n </footer>\r\n </div>\r\n </article>\r\n</ng-template>\r\n", styles: [":host{display:block}label{color:var(--ec-form-control-label-color, var(--ec-color-secondary-dark));display:block;font-size:var(--ec-font-size-label);line-height:1;margin:calc(var(--ec-font-size-label) / 2) 0}.date-picker{display:grid;grid-template-areas:\"menu calendar calendar\" \"menu footer footer\"}.date-picker footer{grid-area:footer}ul.selection-mode-menu{grid-area:menu;list-style:none;padding:0;margin:0;min-width:7rem}ul.selection-mode-menu li{margin-bottom:.25rem}ul.selection-mode-menu li button{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer;background-color:transparent;width:100%;height:1.75rem}ul.selection-mode-menu li button .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}ul.selection-mode-menu li button .ec-icon{flex:none}ul.selection-mode-menu li button .ec-icon+.label{flex:none;margin-left:.25rem}ul.selection-mode-menu li button.has-badge{padding-right:.0625rem}ul.selection-mode-menu li button:focus{outline:none;position:relative;z-index:1}ul.selection-mode-menu li button:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}ul.selection-mode-menu li button:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);--ec-color-icon: var(--ec-color-hint-dark)}ul.selection-mode-menu li button:hover:not(:disabled){background-color:var(--ec-background-color-hover)}ul.selection-mode-menu li button:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}ul.selection-mode-menu li button:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}ul.selection-mode-menu li button.is-selected{background-color:var(--ec-background-color-selected);font-weight:700}ec-button{--ec-button-border-color-secondary: var(--ec-border-color-control)}.control-group ec-button:has(+ec-button) ::ng-deep button{border-right:0}.control-group ec-button+ec-button ::ng-deep button{border-left:0}\n"] }]
5372
+ }], ctorParameters: () => [{ type: ValidationMessageService }, { type: FormGroupHelper }, { type: UserPreferenceService }, { type: i0.ElementRef }, { type: i1$1.Overlay }, { type: DateInput.SelectionStrategies }], propDecorators: { id: [{
4223
5373
  type: HostBinding,
4224
5374
  args: ['attr.id']
4225
5375
  }, {
@@ -4230,6 +5380,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
4230
5380
  type: Input
4231
5381
  }], maxDate: [{
4232
5382
  type: Input
5383
+ }], selectionMode: [{
5384
+ type: Input
5385
+ }], selectionModeOptions: [{
5386
+ type: Input
5387
+ }], quickSelectDate: [{
5388
+ type: Input
5389
+ }], enableSteppers: [{
5390
+ type: Input
5391
+ }], calendar: [{
5392
+ type: ViewChild,
5393
+ args: ['calendar']
5394
+ }], controls: [{
5395
+ type: ViewChild,
5396
+ args: ['controls']
4233
5397
  }], overlay: [{
4234
5398
  type: ViewChild,
4235
5399
  args: ['overlay']
@@ -4931,7 +6095,7 @@ class FileUploadComponent extends FormControlBase {
4931
6095
  }
4932
6096
  }
4933
6097
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadComponent, deps: [{ token: ValidationMessageService }, { token: FormGroupHelper }], target: i0.ɵɵFactoryTarget.Component }); }
4934
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: FileUploadComponent, selector: "ec-file-upload", inputs: { formModel: "formModel", placeholder: "placeholder", fileType: "fileType", fileOutput: "fileOutput", customExtensions: "customExtensions", onFileSelected: "onFileSelected", onMultipleFilesSelected: "onMultipleFilesSelected", displayType: "displayType", buttonLabel: "buttonLabel", buttonType: "buttonType", multiSelect: "multiSelect", validateBeforeUpload: "validateBeforeUpload" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<ec-form-group [label]=\"label\"\r\n [formGroup]=\"formModel\"\r\n [helpPopover]=\"helpPopover\"\r\n [helpPopoverPosition]=\"helpPopoverPosition\"\r\n class=\"mb-0\">\r\n <div class=\"d-flex control-group\">\r\n <div class=\"d-flex flex-grow position-relative\">\r\n <input #fileInput\r\n id=\"{{inputId}}_input\"\r\n type=\"file\"\r\n tabindex=\"-1\"\r\n [attr.accept]=\"fileTypeAccept\"\r\n (change)=\"fileChange($event.target.files)\"\r\n [class.has-value]=\"displayType === 'file' ? formModel?.get('name').value : undefined\"\r\n [attr.multiple]=\"multiSelect ? 'multiple' : undefined\">\r\n <ec-form-control *ngIf=\"displayType === 'file'\"\r\n id=\"{{inputId}}_formControl\"\r\n class=\"text-truncate\"\r\n [required]=\"required\"\r\n [pending]=\"pending || formModel?.pending\">\r\n <input id=\"{{inputId}}_name\"\r\n [formControl]=\"formModel?.get('name')\"\r\n type=\"text\"\r\n [placeholder]=\"placeholder\"\r\n [tabindex]=\"-1\">\r\n </ec-form-control>\r\n </div>\r\n <ec-button *ngIf=\"displayType === 'file'\"\r\n #browseBtn\r\n id=\"{{inputId}}_browseBtn\"\r\n (clicked)=\"fileInput.click()\"\r\n type=\"secondary\"\r\n [tabindex]=\"tabindex\"\r\n [disabled]=\"formModel?.get('name').disabled\"\r\n label=\"Browse\"\r\n [autofocus]=\"autofocus\">\r\n </ec-button>\r\n </div>\r\n <ec-button *ngIf=\"displayType === 'button'\"\r\n id=\"{{inputId}}_btn\"\r\n [pending]=\"pending\"\r\n [type]=\"buttonType\"\r\n [label]=\"buttonLabel ?? 'Browse_TC' | translate\"\r\n (clicked)=\"fileInput.click()\"\r\n style=\"width: 100%;\">\r\n </ec-button>\r\n</ec-form-group>", styles: [":host{display:block;margin-bottom:1rem}ec-form-control{margin-bottom:0}ec-form-control ::ng-deep>.ec-focus-ring{display:none!important}input[type=file]{opacity:0;display:block;position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;cursor:pointer}input[type=file].has-value{width:calc(100% - 1.5rem)}ec-button{--ec-button-border-color-secondary: var(--ec-form-control-border-color);--ec-button-color-icon-secondary: var(--ec-color-icon)}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ButtonComponent, selector: "ec-button", inputs: ["id", "disabled", "icon", "label", "badge", "tabindex", "type", "pending", "pendingIcon", "customTemplate", "isSubmit", "autofocus"], outputs: ["clicked"] }, { kind: "component", type: FormControlComponent, selector: "ec-form-control", inputs: ["id", "icon", "actionIcon", "showClear", "formModel", "autofocus", "pending", "required", "readonly"], outputs: ["actionClicked", "actionKeydown"] }, { kind: "component", type: FormGroupComponent, selector: "ec-form-group", inputs: ["id", "label", "formGroup", "labelPosition", "overrideValidationError", "hideValidationMessage", "helpPopover", "helpPopoverPosition"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] }); }
6098
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: FileUploadComponent, selector: "ec-file-upload", inputs: { formModel: "formModel", placeholder: "placeholder", fileType: "fileType", fileOutput: "fileOutput", customExtensions: "customExtensions", onFileSelected: "onFileSelected", onMultipleFilesSelected: "onMultipleFilesSelected", displayType: "displayType", buttonLabel: "buttonLabel", buttonType: "buttonType", multiSelect: "multiSelect", validateBeforeUpload: "validateBeforeUpload" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<ec-form-group [label]=\"label\"\r\n [formGroup]=\"formModel\"\r\n [helpPopover]=\"helpPopover\"\r\n [helpPopoverPosition]=\"helpPopoverPosition\"\r\n class=\"mb-0\">\r\n <div class=\"d-flex control-group\">\r\n <div class=\"d-flex flex-grow position-relative\">\r\n <input #fileInput\r\n id=\"{{inputId}}_input\"\r\n type=\"file\"\r\n tabindex=\"-1\"\r\n [attr.accept]=\"fileTypeAccept\"\r\n (change)=\"fileChange($event.target.files)\"\r\n [class.has-value]=\"displayType === 'file' ? formModel?.get('name').value : undefined\"\r\n [attr.multiple]=\"multiSelect ? 'multiple' : undefined\">\r\n <ec-form-control *ngIf=\"displayType === 'file'\"\r\n id=\"{{inputId}}_formControl\"\r\n class=\"text-truncate\"\r\n [required]=\"required\"\r\n [pending]=\"pending || formModel?.pending\">\r\n <input id=\"{{inputId}}_name\"\r\n [formControl]=\"formModel?.get('name')\"\r\n type=\"text\"\r\n [placeholder]=\"placeholder\"\r\n [tabindex]=\"-1\">\r\n </ec-form-control>\r\n </div>\r\n <ec-button *ngIf=\"displayType === 'file'\"\r\n #browseBtn\r\n id=\"{{inputId}}_browseBtn\"\r\n (clicked)=\"fileInput.click()\"\r\n type=\"secondary\"\r\n [tabindex]=\"tabindex\"\r\n [disabled]=\"formModel?.get('name').disabled\"\r\n label=\"Browse\"\r\n [autofocus]=\"autofocus\">\r\n </ec-button>\r\n </div>\r\n <ec-button *ngIf=\"displayType === 'button'\"\r\n id=\"{{inputId}}_btn\"\r\n [pending]=\"pending\"\r\n [type]=\"buttonType\"\r\n [label]=\"buttonLabel ?? 'Browse_TC' | translate\"\r\n (clicked)=\"fileInput.click()\"\r\n style=\"width: 100%;\">\r\n </ec-button>\r\n</ec-form-group>", styles: [":host{display:block;margin-bottom:1rem}ec-form-control{margin-bottom:0}ec-form-control ::ng-deep>.ec-focus-ring{display:none!important}input[type=file]{opacity:0;display:block;position:absolute;top:0;left:0;width:100%;height:100%;z-index:1;cursor:pointer}input[type=file].has-value{width:calc(100% - 1.5rem)}ec-button{--ec-button-border-color-secondary: var(--ec-form-control-border-color);--ec-button-color-icon-secondary: var(--ec-color-icon)}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ButtonComponent, selector: "ec-button", inputs: ["id", "disabled", "icon", "label", "badge", "tabindex", "type", "pending", "pendingIcon", "customTemplate", "isSubmit", "autofocus"], outputs: ["clicked"] }, { kind: "component", type: FormControlComponent, selector: "ec-form-control", inputs: ["id", "icon", "actionIcon", "showClear", "formModel", "autofocus", "pending", "required", "readonly"], outputs: ["actionClicked"] }, { kind: "component", type: FormGroupComponent, selector: "ec-form-group", inputs: ["id", "label", "formGroup", "labelPosition", "overrideValidationError", "hideValidationMessage", "helpPopover", "helpPopoverPosition"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] }); }
4935
6099
  }
4936
6100
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadComponent, decorators: [{
4937
6101
  type: Component,
@@ -5401,7 +6565,7 @@ class TableDetailRowComponent {
5401
6565
  <td [class.has-max-height]="maxHeight" class="table-detail-content {{contentClass}}" [attr.colspan]="contentColSpan">
5402
6566
  <div [style.max-height]="maxHeight" cdkScrollable><ng-content></ng-content></div>
5403
6567
  </td>
5404
- `, isInline: true, styles: [":host{background-color:var(--ec-background-color-detail)}td:first-child{width:1.5rem;padding:.25rem 0!important;vertical-align:top}.table-detail-content{background-color:transparent;border-top:1px solid var(--ec-border-color);padding:1rem 2rem 1rem 0!important}.table-detail-content.has-max-height{padding:0!important}.table-detail-content.has-max-height>div{overflow-y:auto;padding:1rem 2rem 1rem 0}\n"], dependencies: [{ kind: "directive", type: i1$3.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }] }); }
6568
+ `, isInline: true, styles: [":host{background-color:var(--ec-background-color-detail)}td:first-child{width:1.5rem;padding:.25rem 0!important;vertical-align:top}.table-detail-content{background-color:transparent;border-top:1px solid var(--ec-border-color);padding:1rem 2rem 1rem 0!important}.table-detail-content.has-max-height{padding:0!important}.table-detail-content.has-max-height>div{overflow-y:auto;padding:1rem 2rem 1rem 0}\n"], dependencies: [{ kind: "directive", type: i1$4.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }] }); }
5405
6569
  }
5406
6570
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableDetailRowComponent, decorators: [{
5407
6571
  type: Component,
@@ -6090,7 +7254,7 @@ class TableComponent {
6090
7254
  });
6091
7255
  }
6092
7256
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
6093
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: TableComponent, selector: "ec-table", inputs: { id: "id", scrollable: "scrollable", resizable: "resizable", condensed: "condensed", sortable: "sortable", selectionContext: "selectionContext", selectionToolbarTemplate: "selectionToolbarTemplate", selectable: "selectable", isForm: "isForm", sort: "sort", searchableTableResizableColumns: ["resizableColumns", "searchableTableResizableColumns"] }, outputs: { sortChange: "sortChange" }, host: { properties: { "attr.id": "this.id", "class.is-scrollable": "this.scrollable", "class.is-resizable": "this.resizable", "class.is-condensed": "this.condensed", "class.is-sortable": "this.sortable", "class.is-selectable": "this.selectable", "class.is-form-table": "this.isForm", "class.is-master-detail": "this.hasMasterDetailRows" } }, queries: [{ propertyName: "masterRows", predicate: TableMasterRowComponent, descendants: true }, { propertyName: "_resizableColumns", predicate: ResizableColumnComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"selectable-table-toolbar\"\r\n *ngIf=\"hasSelection && selectionToolbarTemplate\">\r\n <ng-container *ngTemplateOutlet=\"selectionToolbarTemplate\"></ng-container>\r\n</div>\r\n<div id=\"{{id}}-scroll-container\" \r\n class=\"table-scroll-container\"\r\n cdkScrollable>\r\n <table class=\"main-table\"\r\n id=\"{{id}}\"\r\n [ecResizableTable]=\"resizable\"\r\n [containerEl]=\"el\"\r\n [sortableTable]=\"sortable\"\r\n [resizableColumns]=\"resizableColumns\">\r\n <ng-content></ng-content>\r\n </table>\r\n</div>", styles: ["ec-table{display:flex;position:relative;min-height:0}ec-table .table-scroll-container{flex:1 1;min-height:0;overflow-y:auto}ec-table .main-table{border-collapse:separate;border-spacing:0;width:100%;font-size:var(--ec-font-size-label)}ec-table .main-table th{height:2rem;line-height:1rem;padding:.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-bottom:1px solid var(--ec-border-color-dark);color:var(--ec-color-secondary-dark);font-weight:400;vertical-align:middle}ec-table .main-table th:first-child{padding-left:1rem}ec-table .main-table th:last-child{padding-right:1rem}ec-table .main-table td{height:2rem;line-height:1rem;padding:.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-top:1px solid var(--ec-border-color);vertical-align:top}ec-table .main-table td:first-child{padding-left:1rem}ec-table .main-table td:last-child{padding-right:1rem}ec-table .main-table tbody>tr:first-child td{border-top:0}ec-table .main-table tbody>tr.is-error td{background-color:var(--ec-background-color-danger)}ec-table .main-table tbody>tr.is-success td{background-color:var(--ec-background-color-success)}ec-table .main-table tfoot td{font-weight:700}ec-table .main-table tbody>tr.is-selected>td,ec-table .main-table tbody>tr.is-selected{background-color:var(--ec-background-color-selected)}ec-table .main-table tr.is-heading td{color:var(--ec-color-secondary-dark);font-size:var(--ec-font-size-label);font-weight:var(--ec-font-weight-bold);line-height:1.333333333;text-transform:uppercase;padding-bottom:0;vertical-align:bottom;border-top:0}ec-table .main-table tr.is-heading+tr td{border-top:0}ec-table .main-table th.actions-col,ec-table .main-table td.actions-col{padding:0}ec-table .main-table th.actions-1,ec-table .main-table td.actions-1{width:2.0625rem}ec-table .main-table th.actions-2,ec-table .main-table td.actions-2{width:4.0625rem}ec-table .main-table th.actions-3,ec-table .main-table td.actions-3{width:6.0625rem}ec-table .main-table th.actions-4,ec-table .main-table td.actions-4{width:8.0625rem}ec-table .main-table th.actions-5,ec-table .main-table td.actions-5{width:10.0625rem}ec-table.is-condensed th,ec-table.is-condensed td{padding-top:.25rem;padding-bottom:.25rem;height:1.5rem}ec-table.is-condensed:not(.has-borders)>table td{border-bottom-width:0;border-top-width:0}ec-table .selectable-table-toolbar{align-items:center;background-color:var(--ec-background-color);border-bottom:1px solid var(--ec-border-color-dark);display:flex;padding:0 .5rem;position:absolute;left:calc(var(--selection-toolbar-left, 0rem) + 1.625rem);top:0;height:3rem;right:0;z-index:calc(var(--ec-z-index-sticky-header) + 3)}ec-table.is-scrollable>.table-scroll-container>table{position:relative}ec-table.is-scrollable>.table-scroll-container>table>thead th{background-color:var(--ec-background-color);position:sticky!important;top:0;z-index:var(--ec-z-index-sticky-header)}ec-table.is-scrollable>.table-scroll-container>table>tfoot td{background-color:var(--ec-background-color);position:sticky!important;bottom:0;z-index:var(--ec-z-index-sticky-header)}ec-table.is-scrollable.bg-body>.table-scroll-container>table>thead th{background-color:var(--ec-background-color-body)}ec-table.is-scrollable.bg-body>.table-scroll-container>table>tfoot td{background-color:var(--ec-background-color-body)}ec-table.is-sortable th[data-sortfield]{-webkit-user-select:none;user-select:none}ec-table.is-sortable th[data-sortfield].is-resizable .content-wrapper{display:flex;cursor:pointer}ec-table.is-sortable th[data-sortfield].is-resizable .content{flex:0 1 auto}ec-table.is-sortable th[data-sortfield].is-resizable .content-wrapper:after{flex:none;width:.875rem;height:.875rem;margin:0 .25rem;font-size:.75rem;display:none;align-items:center;justify-content:center}ec-table.is-sortable th[data-sortfield].is-resizable.is-sorted-desc .content-wrapper:after,ec-table.is-sortable th[data-sortfield].is-resizable.is-sorted-asc .content-wrapper:after{font:var(--fa-font-solid);content:\"\\f062\";display:inline-flex}ec-table.is-sortable th[data-sortfield].is-resizable.is-sorted-desc .content-wrapper:after{transform:scaleY(-1)}ec-table.is-sortable th[data-sortfield].is-resizable.text-right .content-wrapper{flex-direction:row-reverse}ec-table.is-sortable th[data-sortfield]:not(.is-resizable){cursor:pointer}ec-table.is-sortable th[data-sortfield]:not(.is-resizable):after{width:.875rem;height:.875rem;margin:0 .25rem;font-size:.75rem;display:none;align-items:center;justify-content:center}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).is-sorted-desc:after,ec-table.is-sortable th[data-sortfield]:not(.is-resizable).is-sorted-asc:after{font:var(--fa-font-solid);content:\"\\f062\";display:inline-flex}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).is-sorted-desc:after{transform:scaleY(-1)}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).text-right:after{content:\"\";display:none!important}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).text-right:before{width:.875rem;height:.875rem;margin:0 .25rem;font-size:.75rem;display:none;align-items:center;justify-content:center}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).text-right.is-sorted-desc:before,ec-table.is-sortable th[data-sortfield]:not(.is-resizable).text-right.is-sorted-asc:before{font:var(--fa-font-solid);content:\"\\f062\";display:inline-block}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).text-right.is-sorted-desc:before{transform:scaleY(-1)}ec-table.is-resizable .main-table{table-layout:fixed;width:100%}ec-table.is-resizable th.is-resizable{position:relative;overflow:visible;z-index:var(--ec-z-index-sticky-header)}ec-table.is-resizable th.is-resizable.is-active{-webkit-user-select:none;user-select:none}ec-table.is-resizable th.is-resizable.is-active .handle:after{background-color:var(--ec-color-interactive)}ec-table.is-resizable th.is-resizable .handle{position:absolute;width:13px;height:100%;top:0;padding:0 5px;z-index:var(--ec-z-index-splitter);right:0;padding:.5rem 0 .5rem 10px}ec-table.is-resizable th.is-resizable .handle:after{content:\"\";display:block;transition:background-color .3s ease;height:100%;position:relative}ec-table.is-resizable th.is-resizable .handle:hover{cursor:col-resize}ec-table.is-resizable th.is-resizable .handle:hover:after{background-color:var(--ec-color-interactive)}ec-table.is-resizable th.is-resizable .handle:before{content:\"\";display:block;width:1px;background-color:var(--ec-border-color);position:absolute;top:.5rem;bottom:.5rem;right:0}ec-table.is-resizable th.is-resizable .content{overflow:hidden;text-overflow:clip;white-space:nowrap}ec-table.is-resizable th.is-resizable:last-child .handle:before{display:none}ec-table.is-resizable td,ec-table.is-resizable th{overflow:hidden;text-overflow:clip;white-space:nowrap}ec-table.is-selectable .main-table thead th{height:3rem}ec-table.is-selectable .main-table tbody>tr:hover>td{background-color:var(--ec-background-color-hover);border-color:transparent;cursor:pointer}ec-table.is-selectable .main-table tbody>tr:hover.is-selected{background-color:var(--ec-background-color-selected)}ec-table.is-selectable .main-table tbody>tr:hover+tr>td{border-color:var(--ec-background-color-hover)}ec-table.is-selectable th.is-resizable .handle{padding-top:1rem;padding-bottom:1rem}ec-table.is-selectable th.is-resizable .handle:before{top:1rem;bottom:1rem}ec-table.is-master-detail>table{table-layout:fixed}ec-table.is-form-table td{padding-bottom:.25rem;padding-top:.25rem;height:2.5rem;line-height:2rem;border-top:0;font-size:var(--ec-font-size-body)}ec-table.is-form-table tr:first-child td{padding-top:.5rem;height:2.75rem}ec-table.is-form-table tr:last-child td{padding-bottom:.5rem;height:2.75rem}ec-table.is-fixed .main-table{table-layout:fixed}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$3.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: ResizableTableDirective, selector: "[ecResizableTable]", inputs: ["ecResizableTable", "containerEl", "sortableTable", "resizableColumns"] }], encapsulation: i0.ViewEncapsulation.None }); }
7257
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: TableComponent, selector: "ec-table", inputs: { id: "id", scrollable: "scrollable", resizable: "resizable", condensed: "condensed", sortable: "sortable", selectionContext: "selectionContext", selectionToolbarTemplate: "selectionToolbarTemplate", selectable: "selectable", isForm: "isForm", sort: "sort", searchableTableResizableColumns: ["resizableColumns", "searchableTableResizableColumns"] }, outputs: { sortChange: "sortChange" }, host: { properties: { "attr.id": "this.id", "class.is-scrollable": "this.scrollable", "class.is-resizable": "this.resizable", "class.is-condensed": "this.condensed", "class.is-sortable": "this.sortable", "class.is-selectable": "this.selectable", "class.is-form-table": "this.isForm", "class.is-master-detail": "this.hasMasterDetailRows" } }, queries: [{ propertyName: "masterRows", predicate: TableMasterRowComponent, descendants: true }, { propertyName: "_resizableColumns", predicate: ResizableColumnComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"selectable-table-toolbar\"\r\n *ngIf=\"hasSelection && selectionToolbarTemplate\">\r\n <ng-container *ngTemplateOutlet=\"selectionToolbarTemplate\"></ng-container>\r\n</div>\r\n<div id=\"{{id}}-scroll-container\" \r\n class=\"table-scroll-container\"\r\n cdkScrollable>\r\n <table class=\"main-table\"\r\n id=\"{{id}}\"\r\n [ecResizableTable]=\"resizable\"\r\n [containerEl]=\"el\"\r\n [sortableTable]=\"sortable\"\r\n [resizableColumns]=\"resizableColumns\">\r\n <ng-content></ng-content>\r\n </table>\r\n</div>", styles: ["ec-table{display:flex;position:relative;min-height:0}ec-table .table-scroll-container{flex:1 1;min-height:0;overflow-y:auto}ec-table .main-table{border-collapse:separate;border-spacing:0;width:100%;font-size:var(--ec-font-size-label)}ec-table .main-table th{height:2rem;line-height:1rem;padding:.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-bottom:1px solid var(--ec-border-color-dark);color:var(--ec-color-secondary-dark);font-weight:400;vertical-align:middle}ec-table .main-table th:first-child{padding-left:1rem}ec-table .main-table th:last-child{padding-right:1rem}ec-table .main-table td{height:2rem;line-height:1rem;padding:.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-top:1px solid var(--ec-border-color);vertical-align:top}ec-table .main-table td:first-child{padding-left:1rem}ec-table .main-table td:last-child{padding-right:1rem}ec-table .main-table tbody>tr:first-child td{border-top:0}ec-table .main-table tbody>tr.is-error td{background-color:var(--ec-background-color-danger)}ec-table .main-table tbody>tr.is-success td{background-color:var(--ec-background-color-success)}ec-table .main-table tfoot td{font-weight:700}ec-table .main-table tbody>tr.is-selected>td,ec-table .main-table tbody>tr.is-selected{background-color:var(--ec-background-color-selected)}ec-table .main-table tr.is-heading td{color:var(--ec-color-secondary-dark);font-size:var(--ec-font-size-label);font-weight:var(--ec-font-weight-bold);line-height:1.333333333;text-transform:uppercase;padding-bottom:0;vertical-align:bottom;border-top:0}ec-table .main-table tr.is-heading+tr td{border-top:0}ec-table .main-table th.actions-col,ec-table .main-table td.actions-col{padding:0}ec-table .main-table th.actions-1,ec-table .main-table td.actions-1{width:2.0625rem}ec-table .main-table th.actions-2,ec-table .main-table td.actions-2{width:4.0625rem}ec-table .main-table th.actions-3,ec-table .main-table td.actions-3{width:6.0625rem}ec-table .main-table th.actions-4,ec-table .main-table td.actions-4{width:8.0625rem}ec-table .main-table th.actions-5,ec-table .main-table td.actions-5{width:10.0625rem}ec-table.is-condensed th,ec-table.is-condensed td{padding-top:.25rem;padding-bottom:.25rem;height:1.5rem}ec-table.is-condensed:not(.has-borders)>table td{border-bottom-width:0;border-top-width:0}ec-table .selectable-table-toolbar{align-items:center;background-color:var(--ec-background-color);border-bottom:1px solid var(--ec-border-color-dark);display:flex;padding:0 .5rem;position:absolute;left:calc(var(--selection-toolbar-left, 0rem) + 1.625rem);top:0;height:3rem;right:0;z-index:calc(var(--ec-z-index-sticky-header) + 3)}ec-table.is-scrollable>.table-scroll-container>table{position:relative}ec-table.is-scrollable>.table-scroll-container>table>thead th{background-color:var(--ec-background-color);position:sticky!important;top:0;z-index:var(--ec-z-index-sticky-header)}ec-table.is-scrollable>.table-scroll-container>table>tfoot td{background-color:var(--ec-background-color);position:sticky!important;bottom:0;z-index:var(--ec-z-index-sticky-header)}ec-table.is-scrollable.bg-body>.table-scroll-container>table>thead th{background-color:var(--ec-background-color-body)}ec-table.is-scrollable.bg-body>.table-scroll-container>table>tfoot td{background-color:var(--ec-background-color-body)}ec-table.is-sortable th[data-sortfield]{-webkit-user-select:none;user-select:none}ec-table.is-sortable th[data-sortfield].is-resizable .content-wrapper{display:flex;cursor:pointer}ec-table.is-sortable th[data-sortfield].is-resizable .content{flex:0 1 auto}ec-table.is-sortable th[data-sortfield].is-resizable .content-wrapper:after{flex:none;width:.875rem;height:.875rem;margin:0 .25rem;font-size:.75rem;display:none;align-items:center;justify-content:center}ec-table.is-sortable th[data-sortfield].is-resizable.is-sorted-desc .content-wrapper:after,ec-table.is-sortable th[data-sortfield].is-resizable.is-sorted-asc .content-wrapper:after{font:var(--fa-font-solid);content:\"\\f062\";display:inline-flex}ec-table.is-sortable th[data-sortfield].is-resizable.is-sorted-desc .content-wrapper:after{transform:scaleY(-1)}ec-table.is-sortable th[data-sortfield].is-resizable.text-right .content-wrapper{flex-direction:row-reverse}ec-table.is-sortable th[data-sortfield]:not(.is-resizable){cursor:pointer}ec-table.is-sortable th[data-sortfield]:not(.is-resizable):after{width:.875rem;height:.875rem;margin:0 .25rem;font-size:.75rem;display:none;align-items:center;justify-content:center}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).is-sorted-desc:after,ec-table.is-sortable th[data-sortfield]:not(.is-resizable).is-sorted-asc:after{font:var(--fa-font-solid);content:\"\\f062\";display:inline-flex}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).is-sorted-desc:after{transform:scaleY(-1)}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).text-right:after{content:\"\";display:none!important}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).text-right:before{width:.875rem;height:.875rem;margin:0 .25rem;font-size:.75rem;display:none;align-items:center;justify-content:center}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).text-right.is-sorted-desc:before,ec-table.is-sortable th[data-sortfield]:not(.is-resizable).text-right.is-sorted-asc:before{font:var(--fa-font-solid);content:\"\\f062\";display:inline-block}ec-table.is-sortable th[data-sortfield]:not(.is-resizable).text-right.is-sorted-desc:before{transform:scaleY(-1)}ec-table.is-resizable .main-table{table-layout:fixed;width:100%}ec-table.is-resizable th.is-resizable{position:relative;overflow:visible;z-index:var(--ec-z-index-sticky-header)}ec-table.is-resizable th.is-resizable.is-active{-webkit-user-select:none;user-select:none}ec-table.is-resizable th.is-resizable.is-active .handle:after{background-color:var(--ec-color-interactive)}ec-table.is-resizable th.is-resizable .handle{position:absolute;width:13px;height:100%;top:0;padding:0 5px;z-index:var(--ec-z-index-splitter);right:0;padding:.5rem 0 .5rem 10px}ec-table.is-resizable th.is-resizable .handle:after{content:\"\";display:block;transition:background-color .3s ease;height:100%;position:relative}ec-table.is-resizable th.is-resizable .handle:hover{cursor:col-resize}ec-table.is-resizable th.is-resizable .handle:hover:after{background-color:var(--ec-color-interactive)}ec-table.is-resizable th.is-resizable .handle:before{content:\"\";display:block;width:1px;background-color:var(--ec-border-color);position:absolute;top:.5rem;bottom:.5rem;right:0}ec-table.is-resizable th.is-resizable .content{overflow:hidden;text-overflow:clip;white-space:nowrap}ec-table.is-resizable th.is-resizable:last-child .handle:before{display:none}ec-table.is-resizable td,ec-table.is-resizable th{overflow:hidden;text-overflow:clip;white-space:nowrap}ec-table.is-selectable .main-table thead th{height:3rem}ec-table.is-selectable .main-table tbody>tr:hover>td{background-color:var(--ec-background-color-hover);border-color:transparent;cursor:pointer}ec-table.is-selectable .main-table tbody>tr:hover.is-selected{background-color:var(--ec-background-color-selected)}ec-table.is-selectable .main-table tbody>tr:hover+tr>td{border-color:var(--ec-background-color-hover)}ec-table.is-selectable th.is-resizable .handle{padding-top:1rem;padding-bottom:1rem}ec-table.is-selectable th.is-resizable .handle:before{top:1rem;bottom:1rem}ec-table.is-master-detail>table{table-layout:fixed}ec-table.is-form-table td{padding-bottom:.25rem;padding-top:.25rem;height:2.5rem;line-height:2rem;border-top:0;font-size:var(--ec-font-size-body)}ec-table.is-form-table tr:first-child td{padding-top:.5rem;height:2.75rem}ec-table.is-form-table tr:last-child td{padding-bottom:.5rem;height:2.75rem}ec-table.is-fixed .main-table{table-layout:fixed}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$4.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: ResizableTableDirective, selector: "[ecResizableTable]", inputs: ["ecResizableTable", "containerEl", "sortableTable", "resizableColumns"] }], encapsulation: i0.ViewEncapsulation.None }); }
6094
7258
  }
6095
7259
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableComponent, decorators: [{
6096
7260
  type: Component,
@@ -6806,19 +7970,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
6806
7970
  }], overlayClasses: [{
6807
7971
  type: Input
6808
7972
  }], fillParentHeight: [{
6809
- type: Input
6810
- }], disablePaginationControls: [{
6811
- type: Input
6812
- }] } });
6813
-
6814
- class LinkButtonComponent {
6815
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LinkButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6816
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: LinkButtonComponent, selector: "button[ecLinkButton]", ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, styles: [":host{display:inline;border:none;padding:0;background-color:transparent;font-size:inherit;text-align:start;color:var(--ec-color-link);cursor:pointer}:host:hover{text-decoration:underline}:host:focus{outline:none;text-decoration:underline}:host(:disabled){cursor:default;color:var(--ec-color-hint-dark)}:host(:disabled):hover{text-decoration:none}\n"] }); }
6817
- }
6818
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LinkButtonComponent, decorators: [{
6819
- type: Component,
6820
- args: [{ selector: 'button[ecLinkButton]', template: `<ng-content></ng-content>`, styles: [":host{display:inline;border:none;padding:0;background-color:transparent;font-size:inherit;text-align:start;color:var(--ec-color-link);cursor:pointer}:host:hover{text-decoration:underline}:host:focus{outline:none;text-decoration:underline}:host(:disabled){cursor:default;color:var(--ec-color-hint-dark)}:host(:disabled):hover{text-decoration:none}\n"] }]
6821
- }] });
7973
+ type: Input
7974
+ }], disablePaginationControls: [{
7975
+ type: Input
7976
+ }] } });
6822
7977
 
6823
7978
  ;
6824
7979
  class ItemPickerSelectableContext extends TableSelectableRowContext {
@@ -8352,7 +9507,7 @@ class DialogComponent {
8352
9507
  return this.componentRef?.instance.dialogId || '';
8353
9508
  }
8354
9509
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DialogComponent, deps: [{ token: i0.ComponentFactoryResolver }, { token: WindowService }, { token: DialogService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); }
8355
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: DialogComponent, selector: "ec-dialog", inputs: { size: "size", content: "content", context: "context", options: "options", dialogOpenStartEventId: "dialogOpenStartEventId" }, outputs: { opened: "opened", closed: "closed" }, host: { listeners: { "click": "onOverlayClick($event)" }, properties: { "class": "dialogSizeClass", "style.--ec-dialog-width.px": "width", "class.is-open": "this.isOpen", "class.fade-in": "this.fadeIn", "class.fade-out": "this.fadeOut", "class.is-panel": "this.displayAsPanel", "class.is-top-aligned": "this.alignToTop", "style.--ec-dialog-margin-align-to-top": "this.alignToTopMargin", "class.is-transparent": "this.transparentMask", "class.no-mask": "this.noMask" } }, viewQueries: [{ propertyName: "contentContainer", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: '<article [style.min-width]="minWidth" cdkTrapFocus cdkTrapFocusAutoCapture><ng-template #content></ng-template></article>', isInline: true, styles: ["@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideIn{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes panelMaskFadeIn{0%{background-color:transparent}to{background-color:var(--ec-dialog-background-color)}}:host{--ec-dialog-background-color: var(--ec-background-color-dialog);align-items:center;background-color:var(--ec-dialog-background-color);justify-content:center;position:fixed;z-index:var(--ec-z-index-dialog);inset:0;display:none}:host.is-open{display:flex}:host.fade-in{animation-name:fadeIn;animation-duration:125ms;animation-fill-mode:forwards;animation-timing-function:ease-in-out}:host.fade-out{animation-name:fadeIn;animation-duration:.1s;animation-direction:reverse;animation-fill-mode:forwards;animation-timing-function:ease-in-out}:host.is-panel article{position:absolute;top:0;bottom:0;right:0;max-height:none;border-right:0;border-top:0;border-bottom:0;border-radius:0;box-shadow:0 0 .5rem var(--ec-color-shadow)}:host.is-panel.fade-in{animation-name:panelMaskFadeIn;animation-duration:.25s;animation-fill-mode:forwards}:host.is-panel.fade-in article{animation-name:slideIn;animation-duration:.25s;animation-fill-mode:forwards;animation-timing-function:ease-out}:host.is-panel.fade-out{animation-name:panelMaskFadeIn;animation-direction:reverse;animation-fill-mode:forwards}:host.is-panel.fade-out article{animation-name:slideIn;animation-duration:225ms;animation-direction:reverse;animation-fill-mode:forwards;animation-timing-function:ease-in}:host.is-panel.no-mask{left:auto;width:var(--ec-dialog-width)}:host.is-top-aligned{align-items:flex-start}:host.is-top-aligned article{min-height:auto;margin-top:var(--ec-dialog-margin-align-to-top, 20vh);max-height:calc(100vh - var(--ec-dialog-margin-align-to-top, 20vh) - 5vh)}:host.is-transparent{--ec-dialog-background-color: transparent}article{background-color:var(--ec-background-color-body);background-clip:padding-box;box-shadow:0 0 .625rem #1a1a2333;border-radius:var(--ec-border-radius-dialog);overflow:hidden;display:flex;flex:none;min-height:9rem;max-height:90vh;max-width:90vw;width:var(--ec-dialog-width)}:host.dialog-xsmall{--ec-dialog-width: 20rem}:host.dialog-small{--ec-dialog-width: 30rem}:host.dialog-medium{--ec-dialog-width: 40rem}:host.dialog-large{--ec-dialog-width: 50rem}:host.dialog-xlarge{--ec-dialog-width: 60rem}:host.dialog-full{--ec-dialog-width: 90vw}\n"], dependencies: [{ kind: "directive", type: i3$1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }] }); }
9510
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: DialogComponent, selector: "ec-dialog", inputs: { size: "size", content: "content", context: "context", options: "options", dialogOpenStartEventId: "dialogOpenStartEventId" }, outputs: { opened: "opened", closed: "closed" }, host: { listeners: { "click": "onOverlayClick($event)" }, properties: { "class": "dialogSizeClass", "style.--ec-dialog-width.px": "width", "class.is-open": "this.isOpen", "class.fade-in": "this.fadeIn", "class.fade-out": "this.fadeOut", "class.is-panel": "this.displayAsPanel", "class.is-top-aligned": "this.alignToTop", "style.--ec-dialog-margin-align-to-top": "this.alignToTopMargin", "class.is-transparent": "this.transparentMask", "class.no-mask": "this.noMask" } }, viewQueries: [{ propertyName: "contentContainer", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: '<article [style.min-width]="minWidth" cdkTrapFocus cdkTrapFocusAutoCapture><ng-template #content></ng-template></article>', isInline: true, styles: ["@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes slideIn{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes panelMaskFadeIn{0%{background-color:transparent}to{background-color:var(--ec-dialog-background-color)}}:host{--ec-dialog-background-color: var(--ec-background-color-dialog);align-items:center;background-color:var(--ec-dialog-background-color);justify-content:center;position:fixed;z-index:var(--ec-z-index-dialog);inset:0;display:none}:host.is-open{display:flex}:host.fade-in{animation-name:fadeIn;animation-duration:125ms;animation-fill-mode:forwards;animation-timing-function:ease-in-out}:host.fade-out{animation-name:fadeIn;animation-duration:.1s;animation-direction:reverse;animation-fill-mode:forwards;animation-timing-function:ease-in-out}:host.is-panel article{position:absolute;top:0;bottom:0;right:0;max-height:none;border-right:0;border-top:0;border-bottom:0;border-radius:0;box-shadow:0 0 .5rem var(--ec-color-shadow)}:host.is-panel.fade-in{animation-name:panelMaskFadeIn;animation-duration:.25s;animation-fill-mode:forwards}:host.is-panel.fade-in article{animation-name:slideIn;animation-duration:.25s;animation-fill-mode:forwards;animation-timing-function:ease-out}:host.is-panel.fade-out{animation-name:panelMaskFadeIn;animation-direction:reverse;animation-fill-mode:forwards}:host.is-panel.fade-out article{animation-name:slideIn;animation-duration:225ms;animation-direction:reverse;animation-fill-mode:forwards;animation-timing-function:ease-in}:host.is-panel.no-mask{left:auto;width:var(--ec-dialog-width)}:host.is-top-aligned{align-items:flex-start}:host.is-top-aligned article{min-height:auto;margin-top:var(--ec-dialog-margin-align-to-top, 20vh);max-height:calc(100vh - var(--ec-dialog-margin-align-to-top, 20vh) - 5vh)}:host.is-transparent{--ec-dialog-background-color: transparent}article{background-color:var(--ec-background-color-body);background-clip:padding-box;box-shadow:0 0 .625rem #1a1a2333;border-radius:var(--ec-border-radius-dialog);overflow:hidden;display:flex;flex:none;min-height:9rem;max-height:90vh;max-width:90vw;width:var(--ec-dialog-width)}:host.dialog-xsmall{--ec-dialog-width: 20rem}:host.dialog-small{--ec-dialog-width: 30rem}:host.dialog-medium{--ec-dialog-width: 40rem}:host.dialog-large{--ec-dialog-width: 50rem}:host.dialog-xlarge{--ec-dialog-width: 60rem}:host.dialog-full{--ec-dialog-width: 90vw}\n"], dependencies: [{ kind: "directive", type: i1$3.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }] }); }
8356
9511
  }
8357
9512
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DialogComponent, decorators: [{
8358
9513
  type: Component,
@@ -10274,7 +11429,7 @@ class PageViewComponent {
10274
11429
  this.dialogService.closeLatestDialog(new DialogResult(false));
10275
11430
  }
10276
11431
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PageViewComponent, deps: [{ token: DialogService }], target: i0.ɵɵFactoryTarget.Component }); }
10277
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: PageViewComponent, selector: "ec-page-view", inputs: { isDialog: "isDialog", readonly: "readonly", status: "status", showHeader: "showHeader", errors: "errors", breadcrumbs: "breadcrumbs", title: "title", titleIcon: "titleIcon", subTitle: "subTitle", subTitleUrl: "subTitleUrl", moreActionsLabel: "moreActionsLabel", moreActions: "moreActions", secondaryActionLabel: "secondaryActionLabel", hideSecondaryAction: "hideSecondaryAction", hideCloseOnPending: "hideCloseOnPending", primaryActionLabel: "primaryActionLabel", hidePrimaryAction: "hidePrimaryAction", customTitleTemplate: "customTitleTemplate", customActionsTemplate: "customActionsTemplate", customHeaderTemplate: "customHeaderTemplate", footerTemplate: "footerTemplate", customErrorBannerTemplate: "customErrorBannerTemplate", stickyFooter: "stickyFooter", fitContent: "fitContent", disablePrimaryAction: "disablePrimaryAction", bgContent: "bgContent" }, outputs: { onPrimaryAction: "onPrimaryAction", onSecondaryAction: "onSecondaryAction" }, host: { properties: { "class.bg-content": "this.bgContent" }, classAttribute: "flex-grow" }, ngImport: i0, template: "<div ecOverlay\r\n [status]=\"status?.status\"\r\n [message]=\"status?.message\"\r\n [displayAsMask]=\"true\"\r\n class=\"flex-grow d-flex\"\r\n [ngClass]=\"{'bg-body': !bgContent, 'bg-content': bgContent}\">\r\n <div id=\"PageViewScrollContainer\"\r\n class=\"d-flex flex-column flex-grow scroll-y\"\r\n [class.is-dialog]=\"isDialog\"\r\n [class.fit-content]=\"fitContent\"\r\n [class.sticky-footer]=\"stickyFooter && !!footerTemplate\"\r\n [class.overlay-visible]=\"status?.status !== 'hasData'\"\r\n [class.footer-visible]=\"!!footerTemplate\"\r\n cdkScrollable>\r\n <section>\r\n <ng-content></ng-content>\r\n </section>\r\n\r\n <footer *ngIf=\"footerTemplate\">\r\n <ng-container *ngTemplateOutlet=\"footerTemplate\"></ng-container>\r\n </footer>\r\n\r\n <header *ngIf=\"showHeader\">\r\n <ol id=\"breadcrumbs\"\r\n *ngIf=\"breadcrumbs?.length && !isDialog\">\r\n <li *ngFor=\"let crumb of breadcrumbs; last as isLast\">\r\n <a *ngIf=\"crumb.url; else label\"\r\n [routerLink]=\"crumb.url\">\r\n <ng-container *ngTemplateOutlet=\"label\"></ng-container>\r\n </a>\r\n <ng-template #label>{{crumb.label}}</ng-template>\r\n </li>\r\n </ol>\r\n\r\n <div class=\"titlebar\">\r\n <app-page-title *ngIf=\"!customTitleTemplate; else customTitle\"\r\n [title]=\"title\"\r\n [subTitle]=\"subTitle\"\r\n [subTitleUrl]=\"subTitleUrl\"\r\n [titleIcon]=\"titleIcon\"\r\n class=\"title text-truncate\">\r\n </app-page-title>\r\n\r\n <ng-template #customTitle>\r\n <div class=\"title\">\r\n <ng-container *ngTemplateOutlet=\"customTitleTemplate\"></ng-container>\r\n </div>\r\n </ng-template>\r\n\r\n <div class=\"actions\">\r\n <ec-button id=\"primaryAction\"\r\n class=\"ml-2\"\r\n *ngIf=\"!hidePrimaryAction && onPrimaryAction.observers?.length && !readonly\"\r\n [disabled]=\"status?.status === 'pending' || disablePrimaryAction\"\r\n type=\"primary\"\r\n [label]=\"primaryActionLabel\"\r\n (clicked)=\"primaryAction($event)\">\r\n </ec-button>\r\n <ec-button id=\"secondaryAction\"\r\n class=\"ml-2\"\r\n *ngIf=\"!hideSecondaryAction && onSecondaryAction.observers?.length\"\r\n type=\"secondary\"\r\n [label]=\"readonly ? 'Close' : secondaryActionLabel\"\r\n (clicked)=\"secondaryAction($event)\">\r\n </ec-button>\r\n <ec-dropdown id=\"moreActions\"\r\n *ngIf=\"moreActions?.length && !readonly\"\r\n [disabled]=\"status?.status === 'pending'\"\r\n class=\"ml-2\"\r\n buttonType=\"text\"\r\n [label]=\"moreActionsLabel\"\r\n [items]=\"moreActions\">\r\n </ec-dropdown>\r\n <ng-container *ngTemplateOutlet=\"customActionsTemplate\"></ng-container>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"customHeaderTemplate\"\r\n class=\"page-header\">\r\n <ng-container *ngTemplateOutlet=\"customHeaderTemplate\"></ng-container>\r\n </div>\r\n\r\n <ec-banner *ngIf=\"!customErrorBannerTemplate && errors; else customErrorBannerOutlet\"\r\n id=\"pageViewErrors\"\r\n [class.border-bottom-0]=\"!isDialog\">\r\n <div [innerHtml]=\"errors\"></div>\r\n </ec-banner>\r\n\r\n <ng-template #customErrorBannerOutlet>\r\n <ec-banner *ngIf=\"errors\"\r\n id=\"pageViewErrors\"\r\n [class.border-bottom-0]=\"!isDialog\">\r\n <ng-container *ngTemplateOutlet=\"customErrorBannerTemplate\"></ng-container>\r\n </ec-banner>\r\n </ng-template>\r\n </header>\r\n </div>\r\n\r\n <ec-button *ngIf=\"isDialog && ( (status?.status === 'pending' && !hideCloseOnPending) || status?.status === 'error')\"\r\n id=\"pageViewDialogClose\"\r\n type=\"icon\"\r\n icon=\"icon-cancel\"\r\n (clicked)=\"closeDialog()\">\r\n </ec-button>\r\n</div>", styles: [":host{flex:1 1;min-height:0;display:flex}header{background-color:var(--ec-background-color-body);position:sticky;top:0;order:1;padding:1rem 1.5rem .5rem;flex:none;z-index:var(--ec-z-index-sticky-page-header)}ol{font-size:var(--ec-font-size-label);line-height:1rem;grid-column:1/3;grid-row:1/2;list-style:none;padding:0;margin:0 0 .25rem}ol li{display:inline}ol li:not(:last-child):after{content:\" / \";display:inline;color:var(--ec-color-secondary-dark)}div[ecOverlay]{position:relative}.titlebar{display:grid;grid-template-columns:auto max-content;grid-template-rows:max-content max-content;gap:0 1rem}.title{grid-column:1/2;grid-row:2/3;align-self:center}.actions{grid-column:2/3;grid-row:2/3;display:flex;flex-direction:row-reverse}ec-banner{margin-top:1rem}section{padding:var(--ec-page-view-padding-section, .5rem 1.5rem 2rem);order:2;flex:1 0 auto;min-height:0}:not(.is-dialog)>section{z-index:0}footer{background-color:var(--ec-background-color-body);order:3;padding:0 1.5rem;height:4.5rem;flex:none;display:flex;align-items:center}.is-dialog header{padding:0}.is-dialog .titlebar{background-color:var(--ec-background-color);padding:1rem}.is-dialog ec-banner{margin:0}.is-dialog section{padding:var(--ec-page-view-padding-section, 1rem 1rem 1.5rem)}.sticky-footer section{padding-bottom:4.5rem}.sticky-footer footer{position:sticky;bottom:0;z-index:var(--ec-z-index-sticky-page-header)}.fit-content>section{flex:1 1;display:flex}.footer-visible section{padding-bottom:0}.overlay-visible header{z-index:var(--ec-z-index-overlay)1}.overlay-visible ec-banner{display:none}:host(.bg-content) header{background-color:var(--ec-background-color)}:host(.bg-content) section{background-color:var(--ec-background-color)}:host(.bg-content) footer{background-color:var(--ec-background-color)}#pageViewDialogClose{position:absolute;top:1rem;right:1rem;z-index:calc(var(--ec-z-index-overlay) + 1)}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1$3.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "component", type: ButtonComponent, selector: "ec-button", inputs: ["id", "disabled", "icon", "label", "badge", "tabindex", "type", "pending", "pendingIcon", "customTemplate", "isSubmit", "autofocus"], outputs: ["clicked"] }, { kind: "component", type: ViewOverlayComponent, selector: "[ecOverlay]", inputs: ["status", "message", "action", "noDataTemplate", "displayAsMask", "overlayClassList"] }, { kind: "component", type: BannerComponent, selector: "ec-banner", inputs: ["hidden", "id", "type", "bannerStyle", "title", "text", "list", "showCloseBtn", "autoHideOnClose", "customIcon", "rememberClosed"], outputs: ["closed"] }, { kind: "component", type: DropdownComponent, selector: "ec-dropdown", inputs: ["id", "autofocus", "status", "disabled", "label", "icon", "buttonType", "buttonAlignment", "buttonTitle", "tabindex", "showArrow", "items", "menuTemplateType", "menuTitle", "menuHeight", "menuWidth", "menuMinWidth", "menuPosition", "menuFooter", "popupFixed", "buttonCustomTemplate", "pending"], outputs: ["itemSelected", "popupOpened"] }, { kind: "component", type: PageTitleComponent, selector: "app-page-title", inputs: ["title", "titleIcon", "subTitle", "subTitleUrl"] }] }); }
11432
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: PageViewComponent, selector: "ec-page-view", inputs: { isDialog: "isDialog", readonly: "readonly", status: "status", showHeader: "showHeader", errors: "errors", breadcrumbs: "breadcrumbs", title: "title", titleIcon: "titleIcon", subTitle: "subTitle", subTitleUrl: "subTitleUrl", moreActionsLabel: "moreActionsLabel", moreActions: "moreActions", secondaryActionLabel: "secondaryActionLabel", hideSecondaryAction: "hideSecondaryAction", hideCloseOnPending: "hideCloseOnPending", primaryActionLabel: "primaryActionLabel", hidePrimaryAction: "hidePrimaryAction", customTitleTemplate: "customTitleTemplate", customActionsTemplate: "customActionsTemplate", customHeaderTemplate: "customHeaderTemplate", footerTemplate: "footerTemplate", customErrorBannerTemplate: "customErrorBannerTemplate", stickyFooter: "stickyFooter", fitContent: "fitContent", disablePrimaryAction: "disablePrimaryAction", bgContent: "bgContent" }, outputs: { onPrimaryAction: "onPrimaryAction", onSecondaryAction: "onSecondaryAction" }, host: { properties: { "class.bg-content": "this.bgContent" }, classAttribute: "flex-grow" }, ngImport: i0, template: "<div ecOverlay\r\n [status]=\"status?.status\"\r\n [message]=\"status?.message\"\r\n [displayAsMask]=\"true\"\r\n class=\"flex-grow d-flex\"\r\n [ngClass]=\"{'bg-body': !bgContent, 'bg-content': bgContent}\">\r\n <div id=\"PageViewScrollContainer\"\r\n class=\"d-flex flex-column flex-grow scroll-y\"\r\n [class.is-dialog]=\"isDialog\"\r\n [class.fit-content]=\"fitContent\"\r\n [class.sticky-footer]=\"stickyFooter && !!footerTemplate\"\r\n [class.overlay-visible]=\"status?.status !== 'hasData'\"\r\n [class.footer-visible]=\"!!footerTemplate\"\r\n cdkScrollable>\r\n <section>\r\n <ng-content></ng-content>\r\n </section>\r\n\r\n <footer *ngIf=\"footerTemplate\">\r\n <ng-container *ngTemplateOutlet=\"footerTemplate\"></ng-container>\r\n </footer>\r\n\r\n <header *ngIf=\"showHeader\">\r\n <ol id=\"breadcrumbs\"\r\n *ngIf=\"breadcrumbs?.length && !isDialog\">\r\n <li *ngFor=\"let crumb of breadcrumbs; last as isLast\">\r\n <a *ngIf=\"crumb.url; else label\"\r\n [routerLink]=\"crumb.url\">\r\n <ng-container *ngTemplateOutlet=\"label\"></ng-container>\r\n </a>\r\n <ng-template #label>{{crumb.label}}</ng-template>\r\n </li>\r\n </ol>\r\n\r\n <div class=\"titlebar\">\r\n <app-page-title *ngIf=\"!customTitleTemplate; else customTitle\"\r\n [title]=\"title\"\r\n [subTitle]=\"subTitle\"\r\n [subTitleUrl]=\"subTitleUrl\"\r\n [titleIcon]=\"titleIcon\"\r\n class=\"title text-truncate\">\r\n </app-page-title>\r\n\r\n <ng-template #customTitle>\r\n <div class=\"title\">\r\n <ng-container *ngTemplateOutlet=\"customTitleTemplate\"></ng-container>\r\n </div>\r\n </ng-template>\r\n\r\n <div class=\"actions\">\r\n <ec-button id=\"primaryAction\"\r\n class=\"ml-2\"\r\n *ngIf=\"!hidePrimaryAction && onPrimaryAction.observers?.length && !readonly\"\r\n [disabled]=\"status?.status === 'pending' || disablePrimaryAction\"\r\n type=\"primary\"\r\n [label]=\"primaryActionLabel\"\r\n (clicked)=\"primaryAction($event)\">\r\n </ec-button>\r\n <ec-button id=\"secondaryAction\"\r\n class=\"ml-2\"\r\n *ngIf=\"!hideSecondaryAction && onSecondaryAction.observers?.length\"\r\n type=\"secondary\"\r\n [label]=\"readonly ? 'Close' : secondaryActionLabel\"\r\n (clicked)=\"secondaryAction($event)\">\r\n </ec-button>\r\n <ec-dropdown id=\"moreActions\"\r\n *ngIf=\"moreActions?.length && !readonly\"\r\n [disabled]=\"status?.status === 'pending'\"\r\n class=\"ml-2\"\r\n buttonType=\"text\"\r\n [label]=\"moreActionsLabel\"\r\n [items]=\"moreActions\">\r\n </ec-dropdown>\r\n <ng-container *ngTemplateOutlet=\"customActionsTemplate\"></ng-container>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"customHeaderTemplate\"\r\n class=\"page-header\">\r\n <ng-container *ngTemplateOutlet=\"customHeaderTemplate\"></ng-container>\r\n </div>\r\n\r\n <ec-banner *ngIf=\"!customErrorBannerTemplate && errors; else customErrorBannerOutlet\"\r\n id=\"pageViewErrors\"\r\n [class.border-bottom-0]=\"!isDialog\">\r\n <div [innerHtml]=\"errors\"></div>\r\n </ec-banner>\r\n\r\n <ng-template #customErrorBannerOutlet>\r\n <ec-banner *ngIf=\"errors\"\r\n id=\"pageViewErrors\"\r\n [class.border-bottom-0]=\"!isDialog\">\r\n <ng-container *ngTemplateOutlet=\"customErrorBannerTemplate\"></ng-container>\r\n </ec-banner>\r\n </ng-template>\r\n </header>\r\n </div>\r\n\r\n <ec-button *ngIf=\"isDialog && ( (status?.status === 'pending' && !hideCloseOnPending) || status?.status === 'error')\"\r\n id=\"pageViewDialogClose\"\r\n type=\"icon\"\r\n icon=\"icon-cancel\"\r\n (clicked)=\"closeDialog()\">\r\n </ec-button>\r\n</div>", styles: [":host{flex:1 1;min-height:0;display:flex}header{background-color:var(--ec-background-color-body);position:sticky;top:0;order:1;padding:1rem 1.5rem .5rem;flex:none;z-index:var(--ec-z-index-sticky-page-header)}ol{font-size:var(--ec-font-size-label);line-height:1rem;grid-column:1/3;grid-row:1/2;list-style:none;padding:0;margin:0 0 .25rem}ol li{display:inline}ol li:not(:last-child):after{content:\" / \";display:inline;color:var(--ec-color-secondary-dark)}div[ecOverlay]{position:relative}.titlebar{display:grid;grid-template-columns:auto max-content;grid-template-rows:max-content max-content;gap:0 1rem}.title{grid-column:1/2;grid-row:2/3;align-self:center}.actions{grid-column:2/3;grid-row:2/3;display:flex;flex-direction:row-reverse}ec-banner{margin-top:1rem}section{padding:var(--ec-page-view-padding-section, .5rem 1.5rem 2rem);order:2;flex:1 0 auto;min-height:0}:not(.is-dialog)>section{z-index:0}footer{background-color:var(--ec-background-color-body);order:3;padding:0 1.5rem;height:4.5rem;flex:none;display:flex;align-items:center}.is-dialog header{padding:0}.is-dialog .titlebar{background-color:var(--ec-background-color);padding:1rem}.is-dialog ec-banner{margin:0}.is-dialog section{padding:var(--ec-page-view-padding-section, 1rem 1rem 1.5rem)}.sticky-footer section{padding-bottom:4.5rem}.sticky-footer footer{position:sticky;bottom:0;z-index:var(--ec-z-index-sticky-page-header)}.fit-content>section{flex:1 1;display:flex}.footer-visible section{padding-bottom:0}.overlay-visible header{z-index:var(--ec-z-index-overlay)1}.overlay-visible ec-banner{display:none}:host(.bg-content) header{background-color:var(--ec-background-color)}:host(.bg-content) section{background-color:var(--ec-background-color)}:host(.bg-content) footer{background-color:var(--ec-background-color)}#pageViewDialogClose{position:absolute;top:1rem;right:1rem;z-index:calc(var(--ec-z-index-overlay) + 1)}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1$4.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "component", type: ButtonComponent, selector: "ec-button", inputs: ["id", "disabled", "icon", "label", "badge", "tabindex", "type", "pending", "pendingIcon", "customTemplate", "isSubmit", "autofocus"], outputs: ["clicked"] }, { kind: "component", type: ViewOverlayComponent, selector: "[ecOverlay]", inputs: ["status", "message", "action", "noDataTemplate", "displayAsMask", "overlayClassList"] }, { kind: "component", type: BannerComponent, selector: "ec-banner", inputs: ["hidden", "id", "type", "bannerStyle", "title", "text", "list", "showCloseBtn", "autoHideOnClose", "customIcon", "rememberClosed"], outputs: ["closed"] }, { kind: "component", type: DropdownComponent, selector: "ec-dropdown", inputs: ["id", "autofocus", "status", "disabled", "label", "icon", "buttonType", "buttonAlignment", "buttonTitle", "tabindex", "showArrow", "items", "menuTemplateType", "menuTitle", "menuHeight", "menuWidth", "menuMinWidth", "menuPosition", "menuFooter", "popupFixed", "buttonCustomTemplate", "pending"], outputs: ["itemSelected", "popupOpened"] }, { kind: "component", type: PageTitleComponent, selector: "app-page-title", inputs: ["title", "titleIcon", "subTitle", "subTitleUrl"] }] }); }
10278
11433
  }
10279
11434
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PageViewComponent, decorators: [{
10280
11435
  type: Component,
@@ -10794,7 +11949,8 @@ class ComponentsModule {
10794
11949
  TooltipDirective,
10795
11950
  CalendarComponent,
10796
11951
  CalendarItemComponent,
10797
- DateInputComponent], imports: [CommonModule,
11952
+ DateInputComponent,
11953
+ KeyboardNavContainerDirective], imports: [CommonModule,
10798
11954
  FormsModule,
10799
11955
  ReactiveFormsModule,
10800
11956
  RouterModule,
@@ -10864,7 +12020,8 @@ class ComponentsModule {
10864
12020
  CopyTableButtonDirective,
10865
12021
  TooltipDirective,
10866
12022
  CalendarComponent,
10867
- DateInputComponent] }); }
12023
+ DateInputComponent,
12024
+ KeyboardNavContainerDirective] }); }
10868
12025
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentsModule, providers: [
10869
12026
  FormGroupHelper,
10870
12027
  DialogService,
@@ -10957,7 +12114,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
10957
12114
  TooltipDirective,
10958
12115
  CalendarComponent,
10959
12116
  CalendarItemComponent,
10960
- DateInputComponent
12117
+ DateInputComponent,
12118
+ KeyboardNavContainerDirective
10961
12119
  ],
10962
12120
  imports: [
10963
12121
  CommonModule,
@@ -11043,7 +12201,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
11043
12201
  CopyTableButtonDirective,
11044
12202
  TooltipDirective,
11045
12203
  CalendarComponent,
11046
- DateInputComponent
12204
+ DateInputComponent,
12205
+ KeyboardNavContainerDirective
11047
12206
  ]
11048
12207
  }]
11049
12208
  }] });
@@ -11051,6 +12210,104 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
11051
12210
  class RadioButtonOption {
11052
12211
  }
11053
12212
 
12213
+ class CustomValidators {
12214
+ /**
12215
+ * Tests the control using Angular's required validator, except returns
12216
+ * an error map that triggers the plural 'are required' validation message
12217
+ * instead of 'is required'
12218
+ *
12219
+ * @returns An error map with the `requiredPlural` property
12220
+ * if the validation check fails, otherwise `null`.
12221
+ */
12222
+ static { this.requiredPlural = (control) => {
12223
+ return Validators.required(control) !== null ? { requiredPlural: true } : null;
12224
+ }; }
12225
+ /**
12226
+ * Returns a validation error if the control's value is not valid JSON.
12227
+ */
12228
+ static { this.json = (control) => {
12229
+ return (control.value && JsonHelper.tryParseJSON(control.value) === undefined) ? { json: true } : null;
12230
+ }; }
12231
+ /**
12232
+ * Returns a validation error if the control's value is not a valid domain.
12233
+ */
12234
+ static { this.domain = (control) => {
12235
+ return (control.value && domainPattern.test(control.value) === false) ? { domain: true } : null;
12236
+ }; }
12237
+ }
12238
+
12239
+ var HierarchyMocks;
12240
+ (function (HierarchyMocks) {
12241
+ HierarchyMocks.mockRoot = () => ({
12242
+ id: "1",
12243
+ level: 0,
12244
+ hasChildren: true,
12245
+ children: [],
12246
+ label: ''
12247
+ });
12248
+ HierarchyMocks.bldgWithChildren = () => {
12249
+ return {
12250
+ placeId: 3, parentId: 0, placeTypeId: 2, placeCode: 'HASCHILDREN_BLDG', placeInfo: 'A Cool Bldg Has Children',
12251
+ hasChildren: true, placeChildren: [], meterChildren: [], hasActiveChildren: true
12252
+ };
12253
+ };
12254
+ HierarchyMocks.bldgWithChildrenHierarchyItem = () => ({
12255
+ id: HierarchyMocks.bldgWithChildren().placeId.toString(), icon: 'icon-building', label: `${HierarchyMocks.bldgWithChildren().placeInfo} [${HierarchyMocks.bldgWithChildren().placeCode}]`,
12256
+ children: [], hasChildren: true, level: 1, selectable: true, topLevel: false
12257
+ });
12258
+ HierarchyMocks.orgWithChildren = () => {
12259
+ return {
12260
+ placeId: 1, parentId: 0, placeTypeId: 1, placeCode: 'HASCHILDREN_ORG', placeInfo: 'A Org Has Children',
12261
+ hasChildren: true, placeChildren: [], meterChildren: [], hasActiveChildren: true
12262
+ };
12263
+ };
12264
+ HierarchyMocks.orgWithChildrenHierarchyItem = () => ({
12265
+ id: HierarchyMocks.orgWithChildren().placeId.toString(), icon: 'icon-organization', label: `${HierarchyMocks.orgWithChildren().placeInfo} [${HierarchyMocks.orgWithChildren().placeCode}]`,
12266
+ children: [], hasChildren: true, level: 1, selectable: true, topLevel: true
12267
+ });
12268
+ HierarchyMocks.orgWithoutChildren = () => {
12269
+ return {
12270
+ placeId: 2, parentId: 0, placeTypeId: 1, placeCode: 'NOCHILDREN_ORG', placeInfo: 'No Children Org',
12271
+ hasChildren: false, placeChildren: [], meterChildren: [], hasActiveChildren: false
12272
+ };
12273
+ };
12274
+ HierarchyMocks.orgWithoutChildrenHierarchyItem = () => ({
12275
+ id: HierarchyMocks.orgWithoutChildren().placeId.toString(), icon: 'icon-organization', label: `${HierarchyMocks.orgWithoutChildren().placeInfo} [${HierarchyMocks.orgWithoutChildren().placeCode}]`,
12276
+ children: [], hasChildren: false, level: 1, selectable: true, topLevel: true
12277
+ });
12278
+ HierarchyMocks.bldgWithoutChildren = () => {
12279
+ return {
12280
+ placeId: 4, parentId: 0, placeTypeId: 2, placeCode: 'NOCHILDREN_BLDG', placeInfo: 'Zzz No Children Bldg',
12281
+ hasChildren: false, placeChildren: [], meterChildren: [], hasActiveChildren: false
12282
+ };
12283
+ };
12284
+ HierarchyMocks.bldgWithoutChildrenHierarchyItem = () => ({
12285
+ id: HierarchyMocks.bldgWithoutChildren().placeId.toString(), icon: 'icon-building', label: `${HierarchyMocks.bldgWithoutChildren().placeInfo} [${HierarchyMocks.bldgWithoutChildren().placeCode}]`,
12286
+ children: [], hasChildren: false, level: 1, selectable: true, topLevel: false
12287
+ });
12288
+ HierarchyMocks.sortedHierarchyPlaces = () => [
12289
+ HierarchyMocks.bldgWithChildrenHierarchyItem(), HierarchyMocks.orgWithChildrenHierarchyItem(), HierarchyMocks.orgWithoutChildrenHierarchyItem(), HierarchyMocks.bldgWithoutChildrenHierarchyItem()
12290
+ ];
12291
+ })(HierarchyMocks || (HierarchyMocks = {}));
12292
+
12293
+ /** Tag contains a label and type. Type is default by default */
12294
+ class Tag {
12295
+ constructor(label, type, classList, icon, isDismissable, tooltip, url, target) {
12296
+ this.target = '_self';
12297
+ this.label = label;
12298
+ this.type = type || 'info';
12299
+ this.icon = icon;
12300
+ this.isDismissable = isDismissable ?? false;
12301
+ this.tooltip = tooltip;
12302
+ this.url = url;
12303
+ this.target = target || '_self';
12304
+ if (classList) {
12305
+ this.classList = classList;
12306
+ }
12307
+ }
12308
+ }
12309
+ ;
12310
+
11054
12311
  /** Common unicode strings */
11055
12312
  class UnicodeStrings {
11056
12313
  /** Equivalent of &ndash; */
@@ -11108,50 +12365,6 @@ function safeToLower(item, prop) {
11108
12365
  }
11109
12366
  ;
11110
12367
 
11111
- /** Tag contains a label and type. Type is default by default */
11112
- class Tag {
11113
- constructor(label, type, classList, icon, isDismissable, tooltip, url, target) {
11114
- this.target = '_self';
11115
- this.label = label;
11116
- this.type = type || 'info';
11117
- this.icon = icon;
11118
- this.isDismissable = isDismissable ?? false;
11119
- this.tooltip = tooltip;
11120
- this.url = url;
11121
- this.target = target || '_self';
11122
- if (classList) {
11123
- this.classList = classList;
11124
- }
11125
- }
11126
- }
11127
- ;
11128
-
11129
- class CustomValidators {
11130
- /**
11131
- * Tests the control using Angular's required validator, except returns
11132
- * an error map that triggers the plural 'are required' validation message
11133
- * instead of 'is required'
11134
- *
11135
- * @returns An error map with the `requiredPlural` property
11136
- * if the validation check fails, otherwise `null`.
11137
- */
11138
- static { this.requiredPlural = (control) => {
11139
- return Validators.required(control) !== null ? { requiredPlural: true } : null;
11140
- }; }
11141
- /**
11142
- * Returns a validation error if the control's value is not valid JSON.
11143
- */
11144
- static { this.json = (control) => {
11145
- return (control.value && JsonHelper.tryParseJSON(control.value) === undefined) ? { json: true } : null;
11146
- }; }
11147
- /**
11148
- * Returns a validation error if the control's value is not a valid domain.
11149
- */
11150
- static { this.domain = (control) => {
11151
- return (control.value && domainPattern.test(control.value) === false) ? { domain: true } : null;
11152
- }; }
11153
- }
11154
-
11155
12368
  var PageStatus;
11156
12369
  (function (PageStatus) {
11157
12370
  PageStatus["Loading"] = "loading";
@@ -11548,6 +12761,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
11548
12761
  args: ['class']
11549
12762
  }] } });
11550
12763
 
12764
+ class CopyButtonBaseTestInjectorFactory {
12765
+ static getComponentInjector() {
12766
+ return Injector.create({
12767
+ providers: [
12768
+ {
12769
+ provide: ClipboardService,
12770
+ useFactory: () => SpyFactory.createSpy(ClipboardService),
12771
+ deps: []
12772
+ }
12773
+ ]
12774
+ });
12775
+ }
12776
+ }
12777
+
12778
+ class HierarchyBaseTestInjectorFactory {
12779
+ static getComponentInjector() {
12780
+ return Injector.create({
12781
+ providers: [
12782
+ {
12783
+ provide: TelemetryService,
12784
+ useFactory: () => SpyFactory.createSpy(TelemetryService),
12785
+ deps: []
12786
+ }
12787
+ ]
12788
+ });
12789
+ }
12790
+ }
12791
+
11551
12792
  const clickEvent = new MouseEvent('click');
11552
12793
  ;
11553
12794
  /**
@@ -11967,88 +13208,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
11967
13208
  type: Directive
11968
13209
  }], ctorParameters: () => [{ type: i0.Injector }] });
11969
13210
 
11970
- var HierarchyMocks;
11971
- (function (HierarchyMocks) {
11972
- HierarchyMocks.mockRoot = () => ({
11973
- id: "1",
11974
- level: 0,
11975
- hasChildren: true,
11976
- children: [],
11977
- label: ''
11978
- });
11979
- HierarchyMocks.bldgWithChildren = () => {
11980
- return {
11981
- placeId: 3, parentId: 0, placeTypeId: 2, placeCode: 'HASCHILDREN_BLDG', placeInfo: 'A Cool Bldg Has Children',
11982
- hasChildren: true, placeChildren: [], meterChildren: [], hasActiveChildren: true
11983
- };
11984
- };
11985
- HierarchyMocks.bldgWithChildrenHierarchyItem = () => ({
11986
- id: HierarchyMocks.bldgWithChildren().placeId.toString(), icon: 'icon-building', label: `${HierarchyMocks.bldgWithChildren().placeInfo} [${HierarchyMocks.bldgWithChildren().placeCode}]`,
11987
- children: [], hasChildren: true, level: 1, selectable: true, topLevel: false
11988
- });
11989
- HierarchyMocks.orgWithChildren = () => {
11990
- return {
11991
- placeId: 1, parentId: 0, placeTypeId: 1, placeCode: 'HASCHILDREN_ORG', placeInfo: 'A Org Has Children',
11992
- hasChildren: true, placeChildren: [], meterChildren: [], hasActiveChildren: true
11993
- };
11994
- };
11995
- HierarchyMocks.orgWithChildrenHierarchyItem = () => ({
11996
- id: HierarchyMocks.orgWithChildren().placeId.toString(), icon: 'icon-organization', label: `${HierarchyMocks.orgWithChildren().placeInfo} [${HierarchyMocks.orgWithChildren().placeCode}]`,
11997
- children: [], hasChildren: true, level: 1, selectable: true, topLevel: true
11998
- });
11999
- HierarchyMocks.orgWithoutChildren = () => {
12000
- return {
12001
- placeId: 2, parentId: 0, placeTypeId: 1, placeCode: 'NOCHILDREN_ORG', placeInfo: 'No Children Org',
12002
- hasChildren: false, placeChildren: [], meterChildren: [], hasActiveChildren: false
12003
- };
12004
- };
12005
- HierarchyMocks.orgWithoutChildrenHierarchyItem = () => ({
12006
- id: HierarchyMocks.orgWithoutChildren().placeId.toString(), icon: 'icon-organization', label: `${HierarchyMocks.orgWithoutChildren().placeInfo} [${HierarchyMocks.orgWithoutChildren().placeCode}]`,
12007
- children: [], hasChildren: false, level: 1, selectable: true, topLevel: true
12008
- });
12009
- HierarchyMocks.bldgWithoutChildren = () => {
12010
- return {
12011
- placeId: 4, parentId: 0, placeTypeId: 2, placeCode: 'NOCHILDREN_BLDG', placeInfo: 'Zzz No Children Bldg',
12012
- hasChildren: false, placeChildren: [], meterChildren: [], hasActiveChildren: false
12013
- };
12014
- };
12015
- HierarchyMocks.bldgWithoutChildrenHierarchyItem = () => ({
12016
- id: HierarchyMocks.bldgWithoutChildren().placeId.toString(), icon: 'icon-building', label: `${HierarchyMocks.bldgWithoutChildren().placeInfo} [${HierarchyMocks.bldgWithoutChildren().placeCode}]`,
12017
- children: [], hasChildren: false, level: 1, selectable: true, topLevel: false
12018
- });
12019
- HierarchyMocks.sortedHierarchyPlaces = () => [
12020
- HierarchyMocks.bldgWithChildrenHierarchyItem(), HierarchyMocks.orgWithChildrenHierarchyItem(), HierarchyMocks.orgWithoutChildrenHierarchyItem(), HierarchyMocks.bldgWithoutChildrenHierarchyItem()
12021
- ];
12022
- })(HierarchyMocks || (HierarchyMocks = {}));
12023
-
12024
- class HierarchyBaseTestInjectorFactory {
12025
- static getComponentInjector() {
12026
- return Injector.create({
12027
- providers: [
12028
- {
12029
- provide: TelemetryService,
12030
- useFactory: () => SpyFactory.createSpy(TelemetryService),
12031
- deps: []
12032
- }
12033
- ]
12034
- });
12035
- }
12036
- }
12037
-
12038
- class CopyButtonBaseTestInjectorFactory {
12039
- static getComponentInjector() {
12040
- return Injector.create({
12041
- providers: [
12042
- {
12043
- provide: ClipboardService,
12044
- useFactory: () => SpyFactory.createSpy(ClipboardService),
12045
- deps: []
12046
- }
12047
- ]
12048
- });
12049
- }
12050
- }
12051
-
12052
13211
  /*
12053
13212
  * Public API Surface of @energycap/components
12054
13213
  */
@@ -12057,5 +13216,5 @@ class CopyButtonBaseTestInjectorFactory {
12057
13216
  * Generated bundle index. Do not edit.
12058
13217
  */
12059
13218
 
12060
- export { AppBarComponent, AvatarComponent, BannerComponent, ButtonComponent, CacheService, CalendarComponent, CheckboxComponent, ClickAreaForDirective, CollapsibleToggleComponent, ComboboxComponent, ComponentsModule, ConfirmComponent, ConfirmDialogContext, CopyButtonBaseTestInjectorFactory, CopyButtonDirective, CopyTableButtonDirective, CustomValidators, DateDisplayPipe, DateInputComponent, DateTimeHelper, DialogCloseDuration, DialogCloseEvent, DialogCloseLatestEvent, DialogComponent, DialogEvent, DialogGroupComponent, DialogOpenDuration, DialogOpenEndEvent, DialogOpenStartEvent, DialogResult, DialogService, DropdownComponent, ErrorService, FileTypeExtensions, FileUploadComponent, FormControlBase, FormControlComponent, FormControlLabelComponent, FormGroupComponent, FormGroupHelper, HelpPopoverComponent, HierarchyBase, HierarchyBaseTestInjectorFactory, HierarchyItem, HierarchyMocks, HierarchyTreeComponent, HighlightTextPipe, IfViewportWidthDirective, ItemDisplayComponent, ItemPickerComponent, ItemPickerSelectableContext, JsonDisplayComponent, JsonHelper, LinkButtonComponent, MenuComponent, MockActivatedRoute, MockDateDisplayPipe, MockDialog, MockDialogContent, MockTranslateService, MockTranslationHelperService, NavGroup, NavItemActiveDirective, NumericboxComponent, Overlay, PageBaseComponent, PageBaseComponentTestHelper, PageBaseComponentTestInjectorFactory, PageInitResult, PageStatus, PageStatuses, PageTitleComponent, PageViewComponent, PanelCloseDuration, PanelOpenDuration, PopoverComponent, PopupContainerDirective, RadioButtonComponent, RadioButtonOption, RelativeDatePipe, ResizableBase, ResizableColumnComponent, ResizableComponent, RouterHelper, RowCountPipe, ScrollService, SearchableTableComponent, SelectComponent, SpinnerComponent, SplashComponent, SplashService, SpyFactory, TableComponent, TableLockedColumnComponent, TableMasterHeaderRowComponent, TableMasterRowComponent, TablePaginationComponent, TableSelectableRowComponent, TableSelectableRowContext, TabsComponent, Tag, TagsComponent, TelemetryService, TelemetryTrackerService, TextboxComponent, TimeDisplayPipe, ToastComponent, ToastEvent, ToastService, ToasterComponent, TooltipComponent, TooltipDirective, TooltipService, Tour, TourAnchor, TourComponent, TourEvent, TourService, TourStep, TreeComponent, UnicodeStrings, UserPreferenceService, ValidationMessageService, ViewOverlayComponent, WindowService, WizardBaseComponent, WizardButtonsComponent, WizardProgressComponent, canadianPostalCodeRegex, clickEvent, dateInputFormatRegex, domainPattern, findAllSpacesPattern, forEachFormControl, getApiError, getControlValue, getDecimalPattern, integerPattern, isApiError, isCalendarSelectionSingleDate, menuAnimationSpeed, mockRouterFactory, mockRouterHelperFactory, numericboxValidation, orderByIgnoreCase, otherZipCodeRegex, phoneNumberValidationPattern, sortByIgnoreCase, textboxValidation, unitedStatesZipCodeRegex, urlValidationPattern, validateFormGroupValuesAreUnique };
13219
+ export { AppBarComponent, AvatarComponent, BannerComponent, ButtonComponent, CacheService, CalendarComponent, CheckboxComponent, ClickAreaForDirective, CollapsibleToggleComponent, ComboboxComponent, ComponentsModule, ConfirmComponent, ConfirmDialogContext, CopyButtonBaseTestInjectorFactory, CopyButtonDirective, CopyTableButtonDirective, CustomValidators, DateDisplayPipe, DateInput, DateInputComponent, DateTimeHelper, DialogCloseDuration, DialogCloseEvent, DialogCloseLatestEvent, DialogComponent, DialogEvent, DialogGroupComponent, DialogOpenDuration, DialogOpenEndEvent, DialogOpenStartEvent, DialogResult, DialogService, DropdownComponent, ErrorService, FileTypeExtensions, FileUploadComponent, FormControlBase, FormControlComponent, FormControlLabelComponent, FormGroupComponent, FormGroupHelper, HelpPopoverComponent, HierarchyBase, HierarchyBaseTestInjectorFactory, HierarchyItem, HierarchyMocks, HierarchyTreeComponent, HighlightTextPipe, IfViewportWidthDirective, ItemDisplayComponent, ItemPickerComponent, ItemPickerSelectableContext, JsonDisplayComponent, JsonHelper, KeyboardNavContainerDirective, LinkButtonComponent, MenuComponent, MockActivatedRoute, MockDateDisplayPipe, MockDialog, MockDialogContent, MockTranslateService, MockTranslationHelperService, NavGroup, NavItemActiveDirective, NumericboxComponent, Overlay, PageBaseComponent, PageBaseComponentTestHelper, PageBaseComponentTestInjectorFactory, PageInitResult, PageStatus, PageStatuses, PageTitleComponent, PageViewComponent, PanelCloseDuration, PanelOpenDuration, PopoverComponent, PopupContainerDirective, RadioButtonComponent, RadioButtonOption, RelativeDatePipe, ResizableBase, ResizableColumnComponent, ResizableComponent, RouterHelper, RowCountPipe, ScrollService, SearchableTableComponent, SelectComponent, SpinnerComponent, SplashComponent, SplashService, SpyFactory, TableComponent, TableLockedColumnComponent, TableMasterHeaderRowComponent, TableMasterRowComponent, TablePaginationComponent, TableSelectableRowComponent, TableSelectableRowContext, TabsComponent, Tag, TagsComponent, TelemetryService, TelemetryTrackerService, TextboxComponent, TimeDisplayPipe, ToastComponent, ToastEvent, ToastService, ToasterComponent, TooltipComponent, TooltipDirective, TooltipService, Tour, TourAnchor, TourComponent, TourEvent, TourService, TourStep, TreeComponent, UnicodeStrings, UserPreferenceService, ValidationMessageService, ViewOverlayComponent, WindowService, WizardBaseComponent, WizardButtonsComponent, WizardProgressComponent, canadianPostalCodeRegex, clickEvent, dateInputFormatRegex, domainPattern, findAllSpacesPattern, forEachFormControl, getApiError, getControlValue, getDecimalPattern, integerPattern, isApiError, menuAnimationSpeed, mockRouterFactory, mockRouterHelperFactory, numericboxValidation, orderByIgnoreCase, otherZipCodeRegex, phoneNumberValidationPattern, sortByIgnoreCase, textboxValidation, unitedStatesZipCodeRegex, urlValidationPattern, validateFormGroupValuesAreUnique };
12061
13220
  //# sourceMappingURL=energycap-components.mjs.map