@energycap/components 0.39.17-ECAP-23124-menu-item-divider-improvements.20240523-1631 → 0.39.17-ECAP-25250-eclipse-formula-builder-proto.20240529-1651

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.
@@ -1488,224 +1488,197 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
1488
1488
  }] } });
1489
1489
 
1490
1490
  /**
1491
- * Service to help with interfacing with the window object
1492
- * and navigating around the application (going outside of the Angular 2+ router)
1491
+ * Primitive directive that popups a container using PopperJS
1492
+ *
1493
+ * @export
1493
1494
  */
1494
- class WindowService {
1495
- /**
1496
- * Tracks if there are any unsaved changes that the user could lose.
1497
- *
1498
- * It is set up as `get` only because it is set with `addNavigateAwayPrompt`.
1499
- *
1500
- * This also includes adding a prompt to the window itself (in addition to
1501
- * working with the `CanDeactivateUnsavedChanges` guard) to cover page reloads
1502
- * which do not trigger router events.
1503
- */
1504
- get hasUnsavedChanges() {
1505
- return this._hasUnsavedChanges;
1506
- }
1495
+ class PopupContainerDirective {
1507
1496
  /**
1508
- * Expose the innerWidth on the window global. Protects against errors when code
1509
- * is running on a non-browser platform.
1497
+ * Creates an instance of PopupContainerDirective.
1498
+ * @param templateRef Reference to the popup template
1499
+ * @param viewContainer Reference to the view container
1500
+ * @param document Reference to Document
1501
+ * @memberof PopupContainerDirective
1510
1502
  */
1511
- get innerWidth() {
1512
- return window ? window.innerWidth : undefined;
1513
- }
1514
- constructor(router, activatedRoute) {
1515
- this.router = router;
1516
- this.activatedRoute = activatedRoute;
1517
- this._hasUnsavedChanges = false;
1503
+ constructor(templateRef, viewContainer, document, renderer) {
1504
+ this.templateRef = templateRef;
1505
+ this.viewContainer = viewContainer;
1506
+ this.document = document;
1507
+ this.renderer = renderer;
1518
1508
  /**
1519
- * Function called when the window `beforeunload` event is fired.
1520
- *
1521
- * A reference to the function that was passed to `window.addEventListener`
1522
- * must be retained for `window.removeEventListener` to function properly.
1523
- *
1524
- * Some browsers require the event's `returnValue` to be set to show the confirmation
1525
- * dialog.
1526
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
1509
+ * Emit the {@link PopupStatus} when it changes
1527
1510
  */
1528
- this.beforeUnloadFunction = (event) => {
1529
- // Cancel the event as stated by the standard.
1530
- event.preventDefault();
1531
- // Chrome requires returnValue to be set.
1532
- event.returnValue = '';
1533
- };
1534
- if (window) {
1535
- this.resized = fromEvent(window, 'resize');
1536
- }
1511
+ this.popperStatusChange = new EventEmitter();
1537
1512
  }
1538
1513
  /**
1539
- * Navigates to the previous page the user had visited
1514
+ * Angular onInit lifecycle hook
1515
+ * @see https://angular.io/guide/lifecycle-hooks
1540
1516
  */
1541
- goBack() {
1542
- window.history.back();
1517
+ ngOnInit() {
1518
+ this.templateViewRef = this.viewContainer.createEmbeddedView(this.templateRef);
1543
1519
  }
1544
- /**An abstraction around the browsers window history length.
1545
- * Returns zero if unable to access or running outside a browser context
1520
+ /**
1521
+ * Angular onDestroy lifecycle hook. Close and delete references. Unsubscribe observables
1522
+ * @see https://angular.io/guide/lifecycle-hooks
1546
1523
  */
1547
- getHistoryLength() {
1548
- var _a;
1549
- return ((_a = window === null || window === void 0 ? void 0 : window.history) === null || _a === void 0 ? void 0 : _a.length) || 0;
1524
+ ngOnDestroy() {
1525
+ this.hide();
1550
1526
  }
1551
1527
  /**
1552
- * Navigate to any url you know the path to
1553
- * @param url The URL to navigate to
1528
+ * Displays the templateRef as a popup
1554
1529
  *
1555
- * @deprecated For legacy support only; use `router.navigateByUrl` instead
1530
+ * @memberof PopupContainerDirective
1556
1531
  */
1557
- navigateToUrl(url) {
1558
- return __awaiter(this, void 0, void 0, function* () {
1559
- try {
1560
- if (url.indexOf('/app/') === 0) {
1561
- yield this.router.navigateByUrl(url.substring(5));
1562
- }
1563
- else {
1564
- yield this.router.navigateByUrl(url);
1565
- }
1566
- }
1567
- catch (e) {
1568
- // If the router throws we will try to navigate to the fully qualified url as a last ditch effort.
1569
- // This can happen if we missed a link that needs to be converted to ng5 or our ng1Href directive
1570
- // didn't handle a link correctly
1571
- window.location.href = url;
1532
+ show() {
1533
+ if (PopupContainerDirective.GlobalPopupRef) {
1534
+ if (PopupContainerDirective.GlobalPopupRef != this) {
1535
+ PopupContainerDirective.GlobalPopupRef.hide();
1536
+ PopupContainerDirective.GlobalPopupRef = undefined;
1572
1537
  }
1573
- });
1538
+ }
1539
+ if (!this.globalCloseSubscription) {
1540
+ this.globalCloseSubscription = fromEvent(this.document.body, "click").subscribe((event) => {
1541
+ this.hide();
1542
+ });
1543
+ }
1544
+ if (!this.popperRef) {
1545
+ // Add the popper template as an embedded view since PopperJS
1546
+ // manipulates DOM elements.
1547
+ this.popupViewRef = this.viewContainer.createEmbeddedView(this.popup);
1548
+ // Since popper needs real DOM elements, grab the first non-comment
1549
+ // DOM element to use as our anchor.
1550
+ let anchorElement = this.popupViewRef.rootNodes.find(elem => { return elem.nodeName !== "#text"; });
1551
+ // Use the parents elements as our DOM elements to Popper
1552
+ this.popperRef = new Popper(this.templateViewRef.rootNodes[0], anchorElement, this.popperOptions);
1553
+ PopupContainerDirective.GlobalPopupRef = this;
1554
+ this.popperStatusChange.emit('visible');
1555
+ }
1574
1556
  }
1575
1557
  /**
1576
- * Adds a `beforeunload` function to the window to alert the user that there are about to leave
1577
- * the current page and ask if they'd like to leave or stay
1558
+ * Hides the templateRef
1559
+ *
1560
+ * @memberof PopupContainerDirective
1578
1561
  */
1579
- addNavigateAwayPrompt() {
1580
- this._hasUnsavedChanges = true;
1581
- window.addEventListener("beforeunload", this.beforeUnloadFunction);
1562
+ hide() {
1563
+ if (this.globalCloseSubscription) {
1564
+ this.globalCloseSubscription.unsubscribe();
1565
+ this.globalCloseSubscription = undefined;
1566
+ }
1567
+ if (this.popperRef && this.popupViewRef) {
1568
+ this.popupViewRef.destroy();
1569
+ this.popperRef.destroy();
1570
+ this.popperRef = undefined;
1571
+ this.popperStatusChange.emit('hidden');
1572
+ }
1582
1573
  }
1583
1574
  /**
1584
- * Removes the `beforeunload` function added to the window
1575
+ * Updates the popup container position
1585
1576
  */
1586
- removeNavigateAwayPrompt() {
1587
- this._hasUnsavedChanges = false;
1588
- window.removeEventListener("beforeunload", this.beforeUnloadFunction);
1577
+ update() {
1578
+ if (this.popperRef) {
1579
+ this.popperRef.update();
1580
+ }
1581
+ }
1582
+ fixPosition(minWidthNone, appendToBody = false) {
1583
+ if (this.popperRef && this.popperRef['reference'] && this.popperRef['popper']) {
1584
+ let popupEl = this.popperRef['popper'];
1585
+ // Reset width style previously assigned because the content may have
1586
+ // changed and the auto width would be different
1587
+ this.renderer.removeStyle(popupEl, 'width');
1588
+ this.renderer.setStyle(popupEl, 'position', 'fixed');
1589
+ if (appendToBody) {
1590
+ const bodyEl = this.document.querySelector('body');
1591
+ const popupParent = this.renderer.parentNode(popupEl);
1592
+ if (popupParent !== bodyEl) {
1593
+ this.renderer.appendChild(bodyEl, popupEl);
1594
+ }
1595
+ }
1596
+ let toggleEl = this.popperRef['reference'];
1597
+ let width = popupEl.offsetWidth;
1598
+ let boundaries = popupEl.getBoundingClientRect();
1599
+ let left = boundaries.left;
1600
+ let coords = toggleEl.getBoundingClientRect();
1601
+ // Set the top of our menu to the bottom of the toggle element
1602
+ let top = coords.bottom;
1603
+ if (this.popperOptions && this.popperOptions.placement) {
1604
+ if (this.popperOptions.placement === 'bottom-start' || this.popperOptions.placement === 'top-start') {
1605
+ left = coords.left;
1606
+ }
1607
+ else {
1608
+ left = coords.right - ((minWidthNone || width > coords.width) ? width : coords.width);
1609
+ }
1610
+ }
1611
+ // if it won't fit (with 10px space before hitting the window edge), flip it
1612
+ if (boundaries.height + top + 10 > window.innerHeight) {
1613
+ top = coords.top - boundaries.height;
1614
+ }
1615
+ this.renderer.setStyle(popupEl, 'transform', 'none');
1616
+ this.renderer.setStyle(popupEl, 'left', left + 'px');
1617
+ this.renderer.setStyle(popupEl, 'top', top + 'px');
1618
+ this.renderer.setStyle(popupEl, 'width', width + 'px');
1619
+ if (!minWidthNone) {
1620
+ this.renderer.setStyle(popupEl, 'min-width', coords.width + 'px');
1621
+ }
1622
+ }
1589
1623
  }
1624
+ }
1625
+ /**
1626
+ * Global reference to the currently displayed popup; only
1627
+ * one popup directive can be in `show` state at a given time.
1628
+ *
1629
+ * @memberof PopupContainerDirective
1630
+ */
1631
+ PopupContainerDirective.GlobalPopupRef = undefined;
1632
+ PopupContainerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: PopupContainerDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: DOCUMENT }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
1633
+ PopupContainerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: PopupContainerDirective, selector: "[ecPopup]", inputs: { popup: ["ecPopup", "popup"], popperOptions: ["options", "popperOptions"] }, ngImport: i0 });
1634
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: PopupContainerDirective, decorators: [{
1635
+ type: Directive,
1636
+ args: [{ selector: '[ecPopup]' }]
1637
+ }], ctorParameters: function () {
1638
+ return [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{
1639
+ type: Inject,
1640
+ args: [DOCUMENT]
1641
+ }] }, { type: i0.Renderer2 }];
1642
+ }, propDecorators: { popup: [{
1643
+ type: Input,
1644
+ args: ['ecPopup']
1645
+ }], popperOptions: [{
1646
+ type: Input,
1647
+ args: ['options']
1648
+ }] } });
1649
+
1650
+ class ScrollService {
1651
+ constructor() { }
1590
1652
  /**
1591
- * Send data to another window.
1592
- *
1593
- * __SECURITY RISK__ - Always use a specific target origin. Failing to provide a specific target origin can allow
1594
- * malicious sites to receive the message.
1653
+ * Given a container and the target element to scroll to, we will set the scroll top on
1654
+ * the container to bring the target into view.
1595
1655
  *
1596
- * @param targetWindow - Window to send the message to
1597
- * @param message - Data to send
1598
- * @param targetOrigin - What the URI of the target window must be for the message to be sent.
1599
- * If sending data to another EnergyCAP window, this should always be `window.location.origin` to ensure
1600
- * that only instances of EnergyCAP app receive the message.
1656
+ * @param scrollContainerSelector A valid CSS selector string for the scroll container.
1657
+ * @param targetElementSelector A valid CSS selector string for the target element.
1658
+ * @param topPadding The amount of space to leave above the target
1659
+ * to keep it from being pinned to the top of the scrollContainer. Defaults
1660
+ * to 32px, the default height of a menu item.
1601
1661
  */
1602
- postMessage(targetWindow, message, targetOrigin) {
1603
- targetWindow.postMessage(message, targetOrigin);
1662
+ scrollToItem(scrollContainerSelector, targetElementSelector, topPadding = 32) {
1663
+ let scrollContainer = document.querySelector(scrollContainerSelector);
1664
+ if (!scrollContainer) {
1665
+ return;
1666
+ }
1667
+ let targetElement = scrollContainer.querySelector(targetElementSelector);
1668
+ if (!targetElement) {
1669
+ return;
1670
+ }
1671
+ let targetRect = targetElement.getBoundingClientRect();
1672
+ let containerRect = scrollContainer.getBoundingClientRect();
1673
+ // Only scroll if the target is outside of the view bounds of the container
1674
+ if (targetRect.bottom > containerRect.bottom || targetRect.top < containerRect.top) {
1675
+ scrollContainer.scrollTop =
1676
+ (targetRect.top - containerRect.top) + scrollContainer.scrollTop - topPadding;
1677
+ }
1604
1678
  }
1605
1679
  /**
1606
- * Open a new window
1607
- * @param url - The URL of the resource to be loaded
1608
- */
1609
- openNew(url) {
1610
- window.open(url, '_blank');
1611
- }
1612
- /**
1613
- * A wrapper around the router for changing the query params for the current url
1614
- * without creating a new history entry or removing any existing query parameters.
1615
- * The provided params are updated if they already exist or added to the url if they don't
1616
- *
1617
- * @returns a promise that resolves to true if the navigation succeeds, false if something (like a guard) blocks it.
1618
- * In normal use, the navigation should succeed unless we use query params to block access to a route the user is already on
1619
- */
1620
- modifyHistoryQueryParamsSubset(queryParams) {
1621
- return __awaiter(this, void 0, void 0, function* () {
1622
- return this.router.navigate([], {
1623
- relativeTo: this.activatedRoute,
1624
- replaceUrl: true,
1625
- queryParams: queryParams,
1626
- queryParamsHandling: 'merge',
1627
- });
1628
- });
1629
- }
1630
- /**A wrapper around the default javascript confirm dialog to allow us to unit test dependent code.
1631
- * Of course eventually we'd like to have pretty confirmations for everything, but in some cases it wasn't worth the extra time
1632
- * so we're using this instead.
1633
- */
1634
- confirm(prompt) {
1635
- return Promise.resolve(confirm(prompt));
1636
- }
1637
- /**
1638
- * Close the current window or a window instance if one is provided
1639
- * @param windowInstance - Window to close (optional)
1640
- */
1641
- closeWindow(windowInstance) {
1642
- if (windowInstance) {
1643
- windowInstance.close();
1644
- }
1645
- else {
1646
- window.close();
1647
- }
1648
- }
1649
- getLocation() {
1650
- return window.location.pathname + window.location.hash;
1651
- }
1652
- /** Get the current value of the full url, including protocol, host and path */
1653
- getFullUrl() {
1654
- return window.location.href;
1655
- }
1656
- /** Get the current value of the base url, including protocol, domain and port (if explicitly specified) */
1657
- getBaseUrl() {
1658
- return window.location.origin;
1659
- }
1660
- /**
1661
- * Reloads the browser window.
1662
- * NOT RECOMMENDED. Seek other options for reloading content within Angular before resorting to this.
1663
- */
1664
- reloadWindow() {
1665
- window.location.reload();
1666
- }
1667
- }
1668
- WindowService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: WindowService, deps: [{ token: i1$2.Router }, { token: i1$2.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Injectable });
1669
- WindowService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: WindowService, providedIn: 'root' });
1670
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: WindowService, decorators: [{
1671
- type: Injectable,
1672
- args: [{
1673
- providedIn: 'root'
1674
- }]
1675
- }], ctorParameters: function () { return [{ type: i1$2.Router }, { type: i1$2.ActivatedRoute }]; } });
1676
-
1677
- class ScrollService {
1678
- constructor() { }
1679
- /**
1680
- * Given a container and the target element to scroll to, we will set the scroll top on
1681
- * the container to bring the target into view.
1682
- *
1683
- * @param scrollContainerSelector A valid CSS selector string for the scroll container.
1684
- * @param targetElementSelector A valid CSS selector string for the target element.
1685
- * @param topPadding The amount of space to leave above the target
1686
- * to keep it from being pinned to the top of the scrollContainer. Defaults
1687
- * to 32px, the default height of a menu item.
1688
- */
1689
- scrollToItem(scrollContainerSelector, targetElementSelector, topPadding = 32) {
1690
- let scrollContainer = document.querySelector(scrollContainerSelector);
1691
- if (!scrollContainer) {
1692
- return;
1693
- }
1694
- let targetElement = scrollContainer.querySelector(targetElementSelector);
1695
- if (!targetElement) {
1696
- return;
1697
- }
1698
- let targetRect = targetElement.getBoundingClientRect();
1699
- let containerRect = scrollContainer.getBoundingClientRect();
1700
- // Only scroll if the target is outside of the view bounds of the container
1701
- if (targetRect.bottom > containerRect.bottom || targetRect.top < containerRect.top) {
1702
- scrollContainer.scrollTop =
1703
- (targetRect.top - containerRect.top) + scrollContainer.scrollTop - topPadding;
1704
- }
1705
- }
1706
- /**
1707
- * Return the value of the scrollTop property for an HTMLElement that matches the selector
1708
- * @param scrollContainerSelector A valid CSS selector
1680
+ * Return the value of the scrollTop property for an HTMLElement that matches the selector
1681
+ * @param scrollContainerSelector A valid CSS selector
1709
1682
  */
1710
1683
  getCurrentScrollPosition(scrollContainerSelector) {
1711
1684
  let scrollContainer = document.querySelector(scrollContainerSelector);
@@ -1761,930 +1734,929 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
1761
1734
  }]
1762
1735
  }], ctorParameters: function () { return []; } });
1763
1736
 
1764
- class NavItemActiveDirective {
1765
- /**
1766
- * Determines whether the directive will try to make an exact match on the url or not
1767
- * If false, the directive will add the active class if the first part of the url matches
1768
- * the active route.
1769
- * see: https://angular.io/api/router/Router#isactive
1770
- */
1771
- set exact(value) {
1772
- if (value === undefined) {
1773
- this._exact = true;
1737
+ /** Advanced validation for textbox form controls */
1738
+ const textboxValidation = (validatorParams) => {
1739
+ return (control) => {
1740
+ let validators = [];
1741
+ // Innocent until proven guilty
1742
+ validatorParams.valid = true;
1743
+ if (validatorParams.required) {
1744
+ validators.push(Validators.required);
1745
+ }
1746
+ if (validatorParams.minLength !== undefined) {
1747
+ validators.push(Validators.minLength(validatorParams.minLength));
1748
+ }
1749
+ if (validatorParams.maxLength !== undefined) {
1750
+ validators.push(Validators.maxLength(validatorParams.maxLength));
1751
+ }
1752
+ if (validatorParams.pattern !== undefined) {
1753
+ validators.push(Validators.pattern(validatorParams.pattern));
1754
+ }
1755
+ validators.forEach(validator => {
1756
+ let validationResult = validator(control);
1757
+ if (validationResult) {
1758
+ validatorParams.valid = false;
1759
+ }
1760
+ });
1761
+ if (validatorParams.valid) {
1762
+ return null;
1774
1763
  }
1775
1764
  else {
1776
- this._exact = value;
1765
+ return {
1766
+ textbox: validatorParams
1767
+ };
1777
1768
  }
1778
- this.update();
1769
+ };
1770
+ };
1771
+ const phoneNumberValidationPattern = '^\\s*(?:\\+?(\\d{1,3}))?[-. (]*(\\d{3})[-. )]*(\\d{3})[-. ]*(\\d{4})(?: *x(\\d+))?\\s*$';
1772
+ const urlValidationPattern = '([A-Za-z])+(:\/\/)+[^\\s]*';
1773
+ class TextboxComponent extends FormControlBase {
1774
+ constructor(validationMessageService, formGroupHelper, translate) {
1775
+ super(validationMessageService, formGroupHelper);
1776
+ this.validationMessageService = validationMessageService;
1777
+ this.formGroupHelper = formGroupHelper;
1778
+ this.translate = translate;
1779
+ /**
1780
+ * Set the value of the input's autocomplete attribute
1781
+ */
1782
+ this.autocomplete = 'off';
1783
+ /**
1784
+ * The textbox type
1785
+ */
1786
+ this.type = "text";
1787
+ /**
1788
+ * The value of the rows attribute for a textarea. Only applies to multi-line type
1789
+ */
1790
+ this.rows = 3;
1791
+ /**
1792
+ * If set to true, we will select all text within the input if
1793
+ * autofocus is also set to true
1794
+ */
1795
+ this.selectOnAutofocus = false;
1796
+ /**
1797
+ * If set to true, we will upper case on focus out
1798
+ */
1799
+ this.upperCase = false;
1800
+ /**
1801
+ * Validation pattern for the input. This is determined on the input type specified
1802
+ */
1803
+ this.validationPattern = '';
1804
+ }
1805
+ ngOnChanges(changes) {
1806
+ super.ngOnChanges(changes);
1779
1807
  }
1780
1808
  /**
1781
- * The url of the NavItem to check for activeness. Convert the item url into a
1782
- * UrlTree relative to the ActivatedRoute so router#isActive works even with relative urls.
1783
- * See Angular's [routerLink](https://github.com/angular/angular/blob/8282e15c2becbe42a49befa07d6407247e8243d8/packages/router/src/directives/router_link.ts#L249)
1784
- * and [routerLinkActive](https://github.com/angular/angular/blob/8282e15c2becbe42a49befa07d6407247e8243d8/packages/router/src/directives/router_link_active.ts#L139)
1785
- * for a similiar implementation.
1809
+ * The angular onInit lifecycle hook
1786
1810
  */
1787
- set url(value) {
1788
- if (value !== null && value !== undefined) {
1789
- this._url = this.router.createUrlTree([value], { relativeTo: this.route, queryParams: this.queryParams });
1790
- this.update();
1811
+ ngOnInit() {
1812
+ super.ngOnInit();
1813
+ this.validationPattern = '';
1814
+ if (this.type === 'tel') {
1815
+ this.validationPattern = phoneNumberValidationPattern;
1816
+ }
1817
+ else if (this.type === 'url') {
1818
+ this.validationPattern = urlValidationPattern;
1819
+ }
1820
+ if (this.placeholder) {
1821
+ this.translate.get(this.placeholder)
1822
+ .subscribe((translated) => {
1823
+ this.placeholder = translated;
1824
+ });
1791
1825
  }
1792
1826
  }
1793
- constructor(router, el, renderer, route) {
1794
- this.router = router;
1795
- this.el = el;
1796
- this.renderer = renderer;
1797
- this.route = route;
1798
- this._exact = true;
1799
- /** Emits when the url becomes active */
1800
- this.routerLinkActivated = new EventEmitter();
1801
- /** Subject that emits when component is destroyed to unsubscribe from any subscriptions */
1802
- this.destroyed = new Subject();
1803
- }
1804
- /** Check if url is active on NavigationEnd events */
1805
- ngOnInit() {
1806
- this.router.events.pipe(takeUntil(this.destroyed), filter(e => e instanceof NavigationEnd)).subscribe(() => {
1807
- this.update();
1808
- });
1827
+ /**
1828
+ * The angular afterViewInit lifecycle hook
1829
+ */
1830
+ ngAfterViewInit() {
1831
+ if (this.autofocus) {
1832
+ this.setFocus(this.selectOnAutofocus);
1833
+ }
1809
1834
  }
1810
- ngOnDestroy() {
1811
- this.destroyed.next();
1812
- this.destroyed.unsubscribe();
1835
+ /**
1836
+ * Function to set focus on an input programmatically after the page
1837
+ * had been rendered. The highlight text flag will select the text
1838
+ * within the input if passed in and true
1839
+ */
1840
+ setFocus(highlightText) {
1841
+ this.inputElement.nativeElement.focus();
1842
+ if (highlightText) {
1843
+ this.inputElement.nativeElement.select();
1844
+ }
1813
1845
  }
1814
- /** If url is active apply the defined class to the element, otherwise remove it */
1815
- update() {
1816
- if (this._url && this.classValue) {
1817
- if (this.router.isActive(this._url, { matrixParams: 'ignored', queryParams: this._exact ? 'exact' : 'subset', paths: this._exact ? 'exact' : 'subset', fragment: 'ignored' })) {
1818
- this.renderer.addClass(this.el.nativeElement, this.classValue);
1819
- this.routerLinkActivated.emit(new Event('routerLinkActivated'));
1820
- }
1821
- else {
1822
- this.renderer.removeClass(this.el.nativeElement, this.classValue);
1823
- }
1846
+ /**
1847
+ * Focus out event handler
1848
+ * will upper case and trim value if upperCase is true (this is what we do on the apis)
1849
+ */
1850
+ focusOutEvent() {
1851
+ if (this.upperCase && this.formModel.value) {
1852
+ this.formModel.setValue(this.formModel.value.toUpperCase().trim());
1824
1853
  }
1825
1854
  }
1826
1855
  }
1827
- NavItemActiveDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NavItemActiveDirective, deps: [{ token: i1$2.Router }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1$2.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Directive });
1828
- NavItemActiveDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: NavItemActiveDirective, selector: "[ecNavItemActive]", inputs: { classValue: ["ecNavItemActive", "classValue"], exact: ["ecNavItemActiveExactMatch", "exact"], queryParams: ["ecNavItemActiveQueryParams", "queryParams"], url: ["ecNavItemActiveUrl", "url"] }, outputs: { routerLinkActivated: "routerLinkActivated" }, ngImport: i0 });
1829
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NavItemActiveDirective, decorators: [{
1830
- type: Directive,
1831
- args: [{
1832
- selector: '[ecNavItemActive]'
1833
- }]
1834
- }], ctorParameters: function () { return [{ type: i1$2.Router }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1$2.ActivatedRoute }]; }, propDecorators: { classValue: [{
1835
- type: Input,
1836
- args: ['ecNavItemActive']
1837
- }], exact: [{
1838
- type: Input,
1839
- args: ['ecNavItemActiveExactMatch']
1840
- }], queryParams: [{
1841
- type: Input,
1842
- args: ['ecNavItemActiveQueryParams']
1843
- }], url: [{
1844
- type: Input,
1845
- args: ['ecNavItemActiveUrl']
1846
- }], routerLinkActivated: [{
1847
- type: Output
1856
+ TextboxComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TextboxComponent, deps: [{ token: ValidationMessageService }, { token: FormGroupHelper }, { token: i2.TranslateService }], target: i0.ɵɵFactoryTarget.Component });
1857
+ TextboxComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: TextboxComponent, selector: "ec-textbox", inputs: { autocomplete: "autocomplete", type: "type", placeholder: "placeholder", maxlength: "maxlength", minlength: "minlength", rows: "rows", selectOnAutofocus: "selectOnAutofocus", upperCase: "upperCase" }, viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["textboxInput"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"control control-label-{{labelPosition}}\"\r\n [ngClass]=\"{'is-readonly': readonly}\">\r\n\r\n <label *ngIf=\"label\">\r\n <span>{{label | translate}}</span>\r\n <span *ngIf=\"validationErrors.length > 0 && formModel.touched && formModel.invalid\">&nbsp;{{validationErrors |\r\n translate}}</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=\"input-wrapper control-input\">\r\n <input *ngIf=\"type !== 'multi_line'\"\r\n #textboxInput\r\n email=\"{{type === 'email' ? true : false}}\"\r\n pattern=\"{{validationPattern}}\"\r\n type=\"{{type}}\"\r\n tabindex=\"{{tabindex}}\"\r\n title=\"{{tooltip}}\"\r\n [attr.id]=\"inputId\"\r\n [attr.autocomplete]=\"autocomplete\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [attr.required]=\"required ? required : null\"\r\n [formControl]=\"formModel\"\r\n [ngClass]=\"{'is-empty': !formModel?.value, 'is-pending': pending, 'is-uppercase': upperCase}\"\r\n (focusout)=\"focusOutEvent()\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n\r\n <textarea *ngIf=\"type === 'multi_line'\"\r\n [attr.rows]=\"rows\"\r\n #textboxInput\r\n tabindex=\"{{tabindex}}\"\r\n [attr.id]=\"inputId\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [attr.required]=\"required ? required : null\"\r\n [formControl]=\"formModel\"\r\n [ngClass]=\"{'is-empty': formModel?.value === '', 'is-pending': pending}\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n </textarea>\r\n\r\n <i class=\"ec-icon icon-required\"></i>\r\n <i class=\"ec-icon icon-invalid\"></i>\r\n <i class=\"ec-icon icon-loading\"></i>\r\n </div>\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 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}:host input{background-color:var(--ec-form-control-background-color);border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);background-image:none;background-clip:padding-box;width:100%;line-height:1.25rem;padding:.3125rem .5rem;height:2rem}:host input::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}:host input::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host input::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host input:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host input:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host input~.icon-required,:host input~.icon-invalid{color:var(--ec-form-control-border-color-invalid)}:host input:required.is-empty{background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host input:required.is-empty~.icon-required{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.ng-invalid.ng-touched{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 input.ng-invalid.ng-touched:focus{border-color:var(--ec-form-control-background-color-invalid)}:host input.ng-invalid.ng-touched~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.ng-invalid.ng-touched~.icon-required{display:none}:host input.is-pending.ng-valid,:host input.is-pending.ng-invalid,:host input.is-pending.ng-pending{background-image:\"\";background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem}:host input.is-pending.ng-valid~.icon-loading,:host input.is-pending.ng-invalid~.icon-loading,:host input.is-pending.ng-pending~.icon-loading{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.is-pending.ng-valid~.icon-required,:host input.is-pending.ng-valid~.icon-invalid,:host input.is-pending.ng-invalid~.icon-required,:host input.is-pending.ng-invalid~.icon-invalid,:host input.is-pending.ng-pending~.icon-required,:host input.is-pending.ng-pending~.icon-invalid{display:none}:host input:focus,:host input:focus.is-empty{border-color:var(--ec-form-control-border-color-focus);box-shadow:var(--ec-form-control-box-shadow-focus);position:relative;z-index:1}:host input:disabled{background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}:host input:disabled:required,:host input:disabled:required.is-empty{background-image:none;padding-left:.5rem;background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled)}:host input:disabled:required+.icon-required,:host input:disabled:required.is-empty+.icon-required{display:none}:host input.is-uppercase:not(.is-empty){text-transform:uppercase}:host textarea{background-color:var(--ec-form-control-background-color);border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);background-image:none;background-clip:padding-box;width:100%;line-height:1.25rem;padding:.3125rem .5rem;height:auto;resize:none;display:block}:host textarea::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}:host textarea::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host textarea::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host textarea:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host textarea:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host textarea~.icon-required,:host textarea~.icon-invalid{color:var(--ec-form-control-border-color-invalid)}:host textarea:required.is-empty{background-repeat:no-repeat;background-position:.5rem .5rem;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host textarea:required.is-empty~.icon-required{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.ng-invalid.ng-touched{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 .5rem;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host textarea.ng-invalid.ng-touched:focus{border-color:var(--ec-form-control-background-color-invalid)}:host textarea.ng-invalid.ng-touched~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.ng-invalid.ng-touched~.icon-required{display:none}:host textarea.is-pending.ng-valid,:host textarea.is-pending.ng-invalid,:host textarea.is-pending.ng-pending{background-image:\"\";background-repeat:no-repeat;background-position:.5rem .5rem;background-size:1rem,1rem;padding-left:1.75rem}:host textarea.is-pending.ng-valid~.icon-loading,:host textarea.is-pending.ng-invalid~.icon-loading,:host textarea.is-pending.ng-pending~.icon-loading{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.is-pending.ng-valid~.icon-required,:host textarea.is-pending.ng-valid~.icon-invalid,:host textarea.is-pending.ng-invalid~.icon-required,:host textarea.is-pending.ng-invalid~.icon-invalid,:host textarea.is-pending.ng-pending~.icon-required,:host textarea.is-pending.ng-pending~.icon-invalid{display:none}:host textarea:focus,:host textarea:focus.is-empty{border-color:var(--ec-form-control-border-color-focus);box-shadow:var(--ec-form-control-box-shadow-focus);position:relative;z-index:1}:host textarea:disabled{background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}:host textarea:disabled:required,:host textarea:disabled:required.is-empty{background-image:none;padding-left:.5rem;background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled)}:host textarea:disabled:required+.icon-required,:host textarea:disabled:required.is-empty+.icon-required{display:none}:host textarea.is-uppercase:not(.is-empty){text-transform:uppercase}.input-wrapper{position:relative}.input-wrapper>.ec-icon{display:none}:host(.textbox-group-input:not(:last-child)){flex:1 1 0%;width:1px}:host(.textbox-group-input:not(:last-child)) .control{margin-bottom:0}:host(.textbox-group-input:not(:last-child)) .control.is-readonly input{border-right-width:1px}:host(.textbox-group-input:not(:last-child)) input{border-top-right-radius:0;border-bottom-right-radius:0;border-right-width:0}:host(.textbox-group-input:not(:last-child)) input:focus{position:relative;z-index:1;border-right-width:1px}:host(.text-truncate) input{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host(.is-monospace) input,:host(.is-monospace) textarea,:host-context(.is-monospace) input,:host-context(.is-monospace) textarea{font-family:var(--ec-font-family-monospace)}\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.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.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i4.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i4.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i4.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i4.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { 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: i2.TranslatePipe, name: "translate" }] });
1858
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TextboxComponent, decorators: [{
1859
+ type: Component,
1860
+ args: [{ selector: 'ec-textbox', template: "<div class=\"control control-label-{{labelPosition}}\"\r\n [ngClass]=\"{'is-readonly': readonly}\">\r\n\r\n <label *ngIf=\"label\">\r\n <span>{{label | translate}}</span>\r\n <span *ngIf=\"validationErrors.length > 0 && formModel.touched && formModel.invalid\">&nbsp;{{validationErrors |\r\n translate}}</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=\"input-wrapper control-input\">\r\n <input *ngIf=\"type !== 'multi_line'\"\r\n #textboxInput\r\n email=\"{{type === 'email' ? true : false}}\"\r\n pattern=\"{{validationPattern}}\"\r\n type=\"{{type}}\"\r\n tabindex=\"{{tabindex}}\"\r\n title=\"{{tooltip}}\"\r\n [attr.id]=\"inputId\"\r\n [attr.autocomplete]=\"autocomplete\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [attr.required]=\"required ? required : null\"\r\n [formControl]=\"formModel\"\r\n [ngClass]=\"{'is-empty': !formModel?.value, 'is-pending': pending, 'is-uppercase': upperCase}\"\r\n (focusout)=\"focusOutEvent()\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n\r\n <textarea *ngIf=\"type === 'multi_line'\"\r\n [attr.rows]=\"rows\"\r\n #textboxInput\r\n tabindex=\"{{tabindex}}\"\r\n [attr.id]=\"inputId\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [attr.required]=\"required ? required : null\"\r\n [formControl]=\"formModel\"\r\n [ngClass]=\"{'is-empty': formModel?.value === '', 'is-pending': pending}\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n </textarea>\r\n\r\n <i class=\"ec-icon icon-required\"></i>\r\n <i class=\"ec-icon icon-invalid\"></i>\r\n <i class=\"ec-icon icon-loading\"></i>\r\n </div>\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 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}:host input{background-color:var(--ec-form-control-background-color);border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);background-image:none;background-clip:padding-box;width:100%;line-height:1.25rem;padding:.3125rem .5rem;height:2rem}:host input::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}:host input::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host input::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host input:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host input:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host input~.icon-required,:host input~.icon-invalid{color:var(--ec-form-control-border-color-invalid)}:host input:required.is-empty{background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host input:required.is-empty~.icon-required{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.ng-invalid.ng-touched{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 input.ng-invalid.ng-touched:focus{border-color:var(--ec-form-control-background-color-invalid)}:host input.ng-invalid.ng-touched~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.ng-invalid.ng-touched~.icon-required{display:none}:host input.is-pending.ng-valid,:host input.is-pending.ng-invalid,:host input.is-pending.ng-pending{background-image:\"\";background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem}:host input.is-pending.ng-valid~.icon-loading,:host input.is-pending.ng-invalid~.icon-loading,:host input.is-pending.ng-pending~.icon-loading{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.is-pending.ng-valid~.icon-required,:host input.is-pending.ng-valid~.icon-invalid,:host input.is-pending.ng-invalid~.icon-required,:host input.is-pending.ng-invalid~.icon-invalid,:host input.is-pending.ng-pending~.icon-required,:host input.is-pending.ng-pending~.icon-invalid{display:none}:host input:focus,:host input:focus.is-empty{border-color:var(--ec-form-control-border-color-focus);box-shadow:var(--ec-form-control-box-shadow-focus);position:relative;z-index:1}:host input:disabled{background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}:host input:disabled:required,:host input:disabled:required.is-empty{background-image:none;padding-left:.5rem;background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled)}:host input:disabled:required+.icon-required,:host input:disabled:required.is-empty+.icon-required{display:none}:host input.is-uppercase:not(.is-empty){text-transform:uppercase}:host textarea{background-color:var(--ec-form-control-background-color);border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);background-image:none;background-clip:padding-box;width:100%;line-height:1.25rem;padding:.3125rem .5rem;height:auto;resize:none;display:block}:host textarea::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}:host textarea::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host textarea::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host textarea:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host textarea:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host textarea~.icon-required,:host textarea~.icon-invalid{color:var(--ec-form-control-border-color-invalid)}:host textarea:required.is-empty{background-repeat:no-repeat;background-position:.5rem .5rem;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host textarea:required.is-empty~.icon-required{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.ng-invalid.ng-touched{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 .5rem;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host textarea.ng-invalid.ng-touched:focus{border-color:var(--ec-form-control-background-color-invalid)}:host textarea.ng-invalid.ng-touched~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.ng-invalid.ng-touched~.icon-required{display:none}:host textarea.is-pending.ng-valid,:host textarea.is-pending.ng-invalid,:host textarea.is-pending.ng-pending{background-image:\"\";background-repeat:no-repeat;background-position:.5rem .5rem;background-size:1rem,1rem;padding-left:1.75rem}:host textarea.is-pending.ng-valid~.icon-loading,:host textarea.is-pending.ng-invalid~.icon-loading,:host textarea.is-pending.ng-pending~.icon-loading{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.is-pending.ng-valid~.icon-required,:host textarea.is-pending.ng-valid~.icon-invalid,:host textarea.is-pending.ng-invalid~.icon-required,:host textarea.is-pending.ng-invalid~.icon-invalid,:host textarea.is-pending.ng-pending~.icon-required,:host textarea.is-pending.ng-pending~.icon-invalid{display:none}:host textarea:focus,:host textarea:focus.is-empty{border-color:var(--ec-form-control-border-color-focus);box-shadow:var(--ec-form-control-box-shadow-focus);position:relative;z-index:1}:host textarea:disabled{background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}:host textarea:disabled:required,:host textarea:disabled:required.is-empty{background-image:none;padding-left:.5rem;background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled)}:host textarea:disabled:required+.icon-required,:host textarea:disabled:required.is-empty+.icon-required{display:none}:host textarea.is-uppercase:not(.is-empty){text-transform:uppercase}.input-wrapper{position:relative}.input-wrapper>.ec-icon{display:none}:host(.textbox-group-input:not(:last-child)){flex:1 1 0%;width:1px}:host(.textbox-group-input:not(:last-child)) .control{margin-bottom:0}:host(.textbox-group-input:not(:last-child)) .control.is-readonly input{border-right-width:1px}:host(.textbox-group-input:not(:last-child)) input{border-top-right-radius:0;border-bottom-right-radius:0;border-right-width:0}:host(.textbox-group-input:not(:last-child)) input:focus{position:relative;z-index:1;border-right-width:1px}:host(.text-truncate) input{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host(.is-monospace) input,:host(.is-monospace) textarea,:host-context(.is-monospace) input,:host-context(.is-monospace) textarea{font-family:var(--ec-font-family-monospace)}\n"] }]
1861
+ }], ctorParameters: function () { return [{ type: ValidationMessageService }, { type: FormGroupHelper }, { type: i2.TranslateService }]; }, propDecorators: { autocomplete: [{
1862
+ type: Input
1863
+ }], type: [{
1864
+ type: Input
1865
+ }], placeholder: [{
1866
+ type: Input
1867
+ }], maxlength: [{
1868
+ type: Input
1869
+ }], minlength: [{
1870
+ type: Input
1871
+ }], rows: [{
1872
+ type: Input
1873
+ }], selectOnAutofocus: [{
1874
+ type: Input
1875
+ }], upperCase: [{
1876
+ type: Input
1877
+ }], inputElement: [{
1878
+ type: ViewChild,
1879
+ args: ['textboxInput']
1848
1880
  }] } });
1849
1881
 
1850
- ;
1851
- const menuAnimationSpeed = 350;
1882
+ /** Exposes the markup and styles that represent the spinner. No inputs or outputs defined because it is just a visual component*/
1883
+ class SpinnerComponent {
1884
+ }
1885
+ SpinnerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1886
+ SpinnerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: SpinnerComponent, selector: "ec-spinner", ngImport: i0, template: "<div class=\"spinner\">\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n</div>", styles: ["@keyframes sk-bouncedelay{0%,80%,to{opacity:0}40%{opacity:1}}.spinner{display:flex}.spinner-dot{width:.75rem;height:.75rem;background-color:var(--ec-color-interactive);animation:sk-bouncedelay 1.7s infinite ease-in-out both;margin-right:.25rem}.spinner-dot:nth-child(1){animation-delay:-.6s}.spinner-dot:nth-child(2){animation-delay:-.4s}.spinner-dot:nth-child(3){animation-delay:-.2s}:host(.spinner-small) .spinner-dot{width:.5rem;height:.5rem;background-color:var(--ec-color-interactive);animation:sk-bouncedelay 1.7s infinite ease-in-out both;margin-right:.1666666667rem}:host(.spinner-small) .spinner-dot:nth-child(1){animation-delay:-.6s}:host(.spinner-small) .spinner-dot:nth-child(2){animation-delay:-.4s}:host(.spinner-small) .spinner-dot:nth-child(3){animation-delay:-.2s}\n"] });
1887
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SpinnerComponent, decorators: [{
1888
+ type: Component,
1889
+ args: [{ selector: 'ec-spinner', template: "<div class=\"spinner\">\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n</div>", styles: ["@keyframes sk-bouncedelay{0%,80%,to{opacity:0}40%{opacity:1}}.spinner{display:flex}.spinner-dot{width:.75rem;height:.75rem;background-color:var(--ec-color-interactive);animation:sk-bouncedelay 1.7s infinite ease-in-out both;margin-right:.25rem}.spinner-dot:nth-child(1){animation-delay:-.6s}.spinner-dot:nth-child(2){animation-delay:-.4s}.spinner-dot:nth-child(3){animation-delay:-.2s}:host(.spinner-small) .spinner-dot{width:.5rem;height:.5rem;background-color:var(--ec-color-interactive);animation:sk-bouncedelay 1.7s infinite ease-in-out both;margin-right:.1666666667rem}:host(.spinner-small) .spinner-dot:nth-child(1){animation-delay:-.6s}:host(.spinner-small) .spinner-dot:nth-child(2){animation-delay:-.4s}:host(.spinner-small) .spinner-dot:nth-child(3){animation-delay:-.2s}\n"] }]
1890
+ }] });
1891
+
1892
+ class Overlay {
1893
+ constructor(status, message) {
1894
+ this.status = 'hasData';
1895
+ this.message = '';
1896
+ this.setStatus(status, message);
1897
+ }
1898
+ setStatus(status, message, action, noDataTemplate, overlayClassList) {
1899
+ this.status = status;
1900
+ this.message = message || '';
1901
+ this.action = action || undefined;
1902
+ this.noDataTemplate = noDataTemplate || undefined;
1903
+ this.overlayClassList = overlayClassList || '';
1904
+ }
1905
+ }
1852
1906
  /**
1853
- * Primitive Menu component that encapsulates known templates
1854
- *
1855
- * @export
1907
+ * Wraps content in order to show pending, error, and no data states with an optional message/noDataTemplate
1856
1908
  */
1857
- class MenuComponent {
1909
+ class ViewOverlayComponent {
1910
+ constructor() {
1911
+ this.status = 'hasData';
1912
+ }
1913
+ setStatus(status, message, action, noDataTemplate) {
1914
+ this.status = status;
1915
+ this.message = message || '';
1916
+ this.action = action || undefined;
1917
+ this.noDataTemplate = noDataTemplate || undefined;
1918
+ }
1919
+ actionClicked(event) {
1920
+ if (this.action && this.action.onClick) {
1921
+ this.action.onClick(event);
1922
+ }
1923
+ }
1924
+ }
1925
+ ViewOverlayComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ViewOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1926
+ ViewOverlayComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: ViewOverlayComponent, selector: "[ecOverlay]", inputs: { status: "status", message: "message", action: "action", noDataTemplate: "noDataTemplate", displayAsMask: "displayAsMask", overlayClassList: "overlayClassList" }, ngImport: i0, template: "<!-- Transcluded Content -->\r\n<ng-content *ngIf=\"displayAsMask || (!displayAsMask && status === 'hasData')\"></ng-content>\r\n<!--Used by GI tests to know the overlay status whether we use ngIf or mask version. No visual impact-->\r\n<span [hidden]=\"true\"\r\n\t class=\"overlay-status-{{status}}\"></span>\r\n<!-- Overlay goes last so it is rendered on top of preceding content due to source order -->\r\n<div *ngIf=\"status !== 'hasData'\"\r\n\t class=\"overlay flex-grow {{overlayClassList}}\"\r\n\t [ngClass]=\"{'not-mask': !displayAsMask,\r\n\t\t\t\t'overlay-error': status === 'error',\r\n\t\t\t\t'overlay-nodata': status === 'noData',\r\n\t\t\t\t'overlay-pending': status === 'pending'}\">\r\n\r\n\t<!--Pending Spinner-->\r\n\t<ec-spinner [hidden]=\"status !== 'pending'\"></ec-spinner>\r\n\r\n\t<ng-template [ngIf]=\"status === 'noData' && noDataTemplate\">\r\n\t\t<ng-container *ngTemplateOutlet=\"noDataTemplate\"></ng-container>\r\n\t</ng-template>\r\n\r\n\t<ng-container *ngIf=\"(status === 'noData' && !noDataTemplate) || status !== 'noData'\">\r\n\t\t<!--Status Message-->\r\n\t\t<div id=\"statusMessage\"\r\n\t\t\t class=\"message\"\r\n\t\t\t *ngIf=\"message\"\r\n\t\t\t [ngClass]=\"{'error': status === 'error', 'mt-1': status === 'pending'}\"\r\n\t\t\t [innerHtml]=\"message | translate\">\r\n\t\t</div>\r\n\r\n\t\t<!-- Action -->\r\n\t\t<ec-button type=\"common\"\r\n\t\t\t\t class=\"mt-3\"\r\n\t\t\t\t *ngIf=\"action?.onClick\"\r\n\t\t\t\t [icon]=\"action?.icon\"\r\n\t\t\t\t (clicked)=\"actionClicked($event)\"\r\n\t\t\t\t [label]=\"action?.label\"\r\n\t\t\t\t [hidden]=\"status === 'pending'\">\r\n\t\t</ec-button>\r\n\t</ng-container>\r\n\r\n</div>", styles: [":host{position:relative}:host(.bg-body)>.overlay{background-color:var(--ec-background-color-body)}:host(.bg-body).is-translucent>.overlay{background-color:var(--ec-background-color-overlay)}:host(.bg-content)>.overlay{background-color:var(--ec-background-color)}:host(.bg-content).is-translucent>.overlay{background-color:var(--ec-background-color-overlay)}.overlay{align-items:center;background-color:var(--ec-overlay-background-color, var(--ec-background-color));display:flex;flex-direction:column;justify-content:center;padding:3rem 4rem;z-index:var(--ec-z-index-overlay);position:absolute;inset:0}.overlay.not-mask{position:relative;min-height:100%}.message{color:var(--ec-color-secondary-dark);font-size:var(--ec-font-size-title)}.message.error{color:var(--ec-color-danger);font-size:var(--ec-font-size-title)}\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: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: SpinnerComponent, selector: "ec-spinner" }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] });
1927
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ViewOverlayComponent, decorators: [{
1928
+ type: Component,
1929
+ args: [{ selector: '[ecOverlay]', template: "<!-- Transcluded Content -->\r\n<ng-content *ngIf=\"displayAsMask || (!displayAsMask && status === 'hasData')\"></ng-content>\r\n<!--Used by GI tests to know the overlay status whether we use ngIf or mask version. No visual impact-->\r\n<span [hidden]=\"true\"\r\n\t class=\"overlay-status-{{status}}\"></span>\r\n<!-- Overlay goes last so it is rendered on top of preceding content due to source order -->\r\n<div *ngIf=\"status !== 'hasData'\"\r\n\t class=\"overlay flex-grow {{overlayClassList}}\"\r\n\t [ngClass]=\"{'not-mask': !displayAsMask,\r\n\t\t\t\t'overlay-error': status === 'error',\r\n\t\t\t\t'overlay-nodata': status === 'noData',\r\n\t\t\t\t'overlay-pending': status === 'pending'}\">\r\n\r\n\t<!--Pending Spinner-->\r\n\t<ec-spinner [hidden]=\"status !== 'pending'\"></ec-spinner>\r\n\r\n\t<ng-template [ngIf]=\"status === 'noData' && noDataTemplate\">\r\n\t\t<ng-container *ngTemplateOutlet=\"noDataTemplate\"></ng-container>\r\n\t</ng-template>\r\n\r\n\t<ng-container *ngIf=\"(status === 'noData' && !noDataTemplate) || status !== 'noData'\">\r\n\t\t<!--Status Message-->\r\n\t\t<div id=\"statusMessage\"\r\n\t\t\t class=\"message\"\r\n\t\t\t *ngIf=\"message\"\r\n\t\t\t [ngClass]=\"{'error': status === 'error', 'mt-1': status === 'pending'}\"\r\n\t\t\t [innerHtml]=\"message | translate\">\r\n\t\t</div>\r\n\r\n\t\t<!-- Action -->\r\n\t\t<ec-button type=\"common\"\r\n\t\t\t\t class=\"mt-3\"\r\n\t\t\t\t *ngIf=\"action?.onClick\"\r\n\t\t\t\t [icon]=\"action?.icon\"\r\n\t\t\t\t (clicked)=\"actionClicked($event)\"\r\n\t\t\t\t [label]=\"action?.label\"\r\n\t\t\t\t [hidden]=\"status === 'pending'\">\r\n\t\t</ec-button>\r\n\t</ng-container>\r\n\r\n</div>", styles: [":host{position:relative}:host(.bg-body)>.overlay{background-color:var(--ec-background-color-body)}:host(.bg-body).is-translucent>.overlay{background-color:var(--ec-background-color-overlay)}:host(.bg-content)>.overlay{background-color:var(--ec-background-color)}:host(.bg-content).is-translucent>.overlay{background-color:var(--ec-background-color-overlay)}.overlay{align-items:center;background-color:var(--ec-overlay-background-color, var(--ec-background-color));display:flex;flex-direction:column;justify-content:center;padding:3rem 4rem;z-index:var(--ec-z-index-overlay);position:absolute;inset:0}.overlay.not-mask{position:relative;min-height:100%}.message{color:var(--ec-color-secondary-dark);font-size:var(--ec-font-size-title)}.message.error{color:var(--ec-color-danger);font-size:var(--ec-font-size-title)}\n"] }]
1930
+ }], propDecorators: { status: [{
1931
+ type: Input
1932
+ }], message: [{
1933
+ type: Input
1934
+ }], action: [{
1935
+ type: Input
1936
+ }], noDataTemplate: [{
1937
+ type: Input
1938
+ }], displayAsMask: [{
1939
+ type: Input
1940
+ }], overlayClassList: [{
1941
+ type: Input
1942
+ }] } });
1943
+
1944
+ /**
1945
+ * Service to help with interfacing with the window object
1946
+ * and navigating around the application (going outside of the Angular 2+ router)
1947
+ */
1948
+ class WindowService {
1858
1949
  /**
1859
- * Helper function to return a flat list of all selectable items in the provided menu items. Filters out headings and divided-sections.
1860
- * This makes it much easier to keep track of currently highlighted items for keyboard navigation.
1950
+ * Tracks if there are any unsaved changes that the user could lose.
1951
+ *
1952
+ * It is set up as `get` only because it is set with `addNavigateAwayPrompt`.
1953
+ *
1954
+ * This also includes adding a prompt to the window itself (in addition to
1955
+ * working with the `CanDeactivateUnsavedChanges` guard) to cover page reloads
1956
+ * which do not trigger router events.
1861
1957
  */
1862
- static getSelectableItems(items) {
1863
- return items.reduce((selectableItems, item) => {
1864
- if (item.display !== 'heading' && item.display !== 'divided-section') {
1865
- selectableItems.push(item);
1866
- }
1867
- else if (item.items) {
1868
- selectableItems.push(...item.items.filter(childItem => childItem.display !== 'heading' && childItem.display !== 'divided-section'));
1869
- }
1870
- return selectableItems;
1871
- }, []);
1958
+ get hasUnsavedChanges() {
1959
+ return this._hasUnsavedChanges;
1872
1960
  }
1873
1961
  /**
1874
- * Returns an ID for the provided item based on its index in the provided items array. This mimics the behavior of the MenuComponent's
1875
- * generated IDs for items that don't have provided IDs. This is used in MenuComponent and ComboboxComponent to scroll to specific items.
1876
- * NOTE: If the items array does not match what is displayed in the menu, this function will not return the correct ID.
1877
- *
1878
- * Returns null if the not found
1879
- * @param items The MenuItems array to search through.
1880
- * @param item The item to generate the ID for.
1881
- * @param menuComponentId Used to prefix the generated ID. This should be the ID of the menu component the item is present in.
1882
- * @memberof MenuComponent
1962
+ * Expose the innerWidth on the window global. Protects against errors when code
1963
+ * is running on a non-browser platform.
1883
1964
  */
1884
- static getIndexedItemId(items, item, menuComponentId) {
1885
- if (item) {
1886
- for (let i = 0; i < items.length; i++) {
1887
- const itemInList = items[i];
1888
- if (itemInList.label === item.label) {
1889
- return `${menuComponentId}_item${i}`;
1890
- }
1891
- // If the item is a heading or divided section, check its children
1892
- if (itemInList.items && (itemInList.display === 'heading' || itemInList.display === 'divided-section')) {
1893
- for (let j = 0; j < itemInList.items.length; j++) {
1894
- const childItem = itemInList.items[j];
1895
- // Fall back to checking only the label if the item doesn't have an id
1896
- if (childItem.label === item.label) {
1897
- return `${menuComponentId}_item${i}-${j}`;
1898
- }
1899
- }
1900
- }
1901
- }
1902
- }
1903
- return null;
1965
+ get innerWidth() {
1966
+ return window ? window.innerWidth : undefined;
1904
1967
  }
1905
- constructor(el, renderer, windowService, scrollService) {
1906
- this.el = el;
1907
- this.renderer = renderer;
1908
- this.windowService = windowService;
1909
- this.scrollService = scrollService;
1910
- /**
1911
- * Array of items to display
1912
- *
1913
- * @memberof MenuComponent
1914
- */
1915
- this.items = [];
1916
- /**
1917
- * Selected item; annotates the item
1918
- * when displayed with 'selected' class
1919
- *
1920
- * @memberof MenuComponent
1921
- */
1922
- this.selected = null;
1968
+ constructor(router, activatedRoute) {
1969
+ this.router = router;
1970
+ this.activatedRoute = activatedRoute;
1971
+ this._hasUnsavedChanges = false;
1923
1972
  /**
1924
- * Display template
1973
+ * Function called when the window `beforeunload` event is fired.
1925
1974
  *
1926
- * @memberof MenuComponent
1927
- */
1928
- this.templateType = 'label';
1929
- /**
1930
- * Show message when there are no items
1931
- */
1932
- this.showNoItems = false;
1933
- /**
1934
- * Text to show when menu is empty and showNoItems is true
1935
- */
1936
- this.noDataText = 'NoItems_TC';
1937
- /**
1938
- * Controls whether keyboard navigation is enabled
1939
- */
1940
- this.enableKeyNav = false;
1941
- /**
1942
- * Item currently highlighted by keyboard navigation
1943
- */
1944
- this.highlightedItem = null;
1945
- /**
1946
- * Tells the menu to maintain the selected/lastSelected item. Turning this off is useful for
1947
- * action type menus that are displayed on the screen at all times and you do not
1948
- * want the item to be selected when clicked.
1949
- */
1950
- this.maintainSelectedItem = true;
1951
- /**
1952
- * Will prevent text-wrapping of menu items and truncate instead. Also turns on a tooltip for the menu item. Default: false;
1953
- */
1954
- this.truncateItems = false;
1955
- /**
1956
- * When true, the space for the icon is preserved for menu items that do not have icons.
1957
- * Only applicable for iconAndLabel menus.
1958
- */
1959
- this.preserveIconSpace = false;
1960
- /**
1961
- * Emitted when `selected` is changed. Emits the referenced object.
1975
+ * A reference to the function that was passed to `window.addEventListener`
1976
+ * must be retained for `window.removeEventListener` to function properly.
1962
1977
  *
1963
- * @memberof MenuComponent
1964
- */
1965
- this.selectedChanged = new EventEmitter();
1966
- /**
1967
- * Emitted when the menu has a parent and back is clicked
1968
- * @memberof MenuComponent
1969
- */
1970
- this.menuClosed = new EventEmitter();
1971
- /**
1972
- * Index of the item currently highlighted using keyboard nav
1973
- */
1974
- this.highlightedItemIndex = -1;
1975
- /**
1976
- * Last item this.selected was set to via selectItem().
1977
- * This isn't necessarily the same as this.selected, because this.selected is an input property
1978
- * and could have been changed by a consumer through some means other than selectItem().
1979
- * This allows us to prevent double-calls to selectItem() with the same input.
1980
- */
1981
- this.lastSelected = null;
1982
- /**
1983
- * Flattened array of all selectable items in the menu. Makes it easier to keep track of the currently highlighted item for keyboard navigation.
1978
+ * Some browsers require the event's `returnValue` to be set to show the confirmation
1979
+ * dialog.
1980
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
1984
1981
  */
1985
- this.selectableItems = [];
1986
- }
1987
- ngOnChanges(changes) {
1988
- if (changes.items && this.items) {
1989
- this.selectableItems = MenuComponent.getSelectableItems(this.items);
1982
+ this.beforeUnloadFunction = (event) => {
1983
+ // Cancel the event as stated by the standard.
1984
+ event.preventDefault();
1985
+ // Chrome requires returnValue to be set.
1986
+ event.returnValue = '';
1987
+ };
1988
+ if (window) {
1989
+ this.resized = fromEvent(window, 'resize');
1990
1990
  }
1991
1991
  }
1992
1992
  /**
1993
- * Sets & displays the interalized template based on
1994
- * the set template.
1995
- * @see { @link https://angular.io/guide/lifecycle-hooks|Angular Lifecycle Hooks}
1996
- *
1997
- * @memberof MenuComponent
1993
+ * Navigates to the previous page the user had visited
1998
1994
  */
1999
- ngAfterContentInit() {
2000
- switch (this.templateType) {
2001
- case ("label"):
2002
- this.internalizedTemplate = this.iconAndLabelTemplate;
2003
- break;
2004
- case ("iconAndLabel"):
2005
- this.internalizedTemplate = this.iconAndLabelTemplate;
2006
- break;
2007
- case ("checkAndLabel"):
2008
- this.internalizedTemplate = this.checkAndLabelTemplate;
2009
- break;
2010
- case ("iconLabelCaption"):
2011
- this.internalizedTemplate = this.iconLabelCaptionTemplate;
2012
- break;
2013
- default:
2014
- throw new Error(`Invalid templateType for MenuComponent. Please use either: 'label', 'iconAndLabel' or 'checkAndLabel'`);
2015
- }
2016
- //if the consumer provided a menuItemTemplate, override the internalizedTemplate with that.
2017
- if (this.customMenuTemplate) {
2018
- this.internalizedTemplate = this.customMenuTemplate;
2019
- }
2020
- if (this.id) {
2021
- this.attrId = this.id;
2022
- }
2023
- this.setItemIds();
2024
- if (this.highlightedItem && this.selectableItems.length) {
2025
- this.highlightedItemIndex = this.selectableItems.findIndex(item => { return this.highlightedItem === item; });
2026
- }
2027
- this.addKeydownListener();
1995
+ goBack() {
1996
+ window.history.back();
2028
1997
  }
2029
- ngOnDestroy() {
2030
- // Remove the listener when the component is destroyed
2031
- if (this.removeKeydownListener) {
2032
- this.removeKeydownListener();
2033
- }
1998
+ /**An abstraction around the browsers window history length.
1999
+ * Returns zero if unable to access or running outside a browser context
2000
+ */
2001
+ getHistoryLength() {
2002
+ var _a;
2003
+ return ((_a = window === null || window === void 0 ? void 0 : window.history) === null || _a === void 0 ? void 0 : _a.length) || 0;
2034
2004
  }
2035
2005
  /**
2036
- * When a menu item is selected, open a child menu if the item has items, call
2037
- * the item's click method if defined, or emit the selected item.
2006
+ * Navigate to any url you know the path to
2007
+ * @param url The URL to navigate to
2038
2008
  *
2039
- * @param item The selected item
2040
- * @memberof MenuComponent
2009
+ * @deprecated For legacy support only; use `router.navigateByUrl` instead
2041
2010
  */
2042
- selectItem(event, item, isKeyEvent) {
2043
- var _a;
2044
- event.stopPropagation();
2045
- //In the case that the user clicks an item, selectItem() will be called from the click handler
2046
- //and through onRouterLinkActivated. Only one of these will make it through this if statement
2047
- //because the first one will set this.lastSelected = item.
2048
- if (!item.disabled && !item.readonly && this.lastSelected !== item) {
2049
- if (!item.url) {
2050
- if (item.onClick) {
2051
- item.onClick(item, false);
2052
- }
2053
- if (item.items && item.display !== 'heading' && item.display !== 'divided-section') {
2054
- this.toggleChildMenu(true);
2055
- }
2056
- else {
2057
- this.onSelection(item);
2058
- }
2059
- // We need to manually handle the url navigation if the keyboard was used
2060
- }
2061
- else if (isKeyEvent || ((_a = event.target) === null || _a === void 0 ? void 0 : _a.tagName) === 'LI') {
2062
- if (item.target) {
2063
- window.open(item.url, item.target);
2011
+ navigateToUrl(url) {
2012
+ return __awaiter(this, void 0, void 0, function* () {
2013
+ try {
2014
+ if (url.indexOf('/app/') === 0) {
2015
+ yield this.router.navigateByUrl(url.substring(5));
2064
2016
  }
2065
2017
  else {
2066
- this.windowService.navigateToUrl(item.url);
2018
+ yield this.router.navigateByUrl(url);
2067
2019
  }
2068
- // Emit so upstream components know an item was selected
2069
- this.onSelection(item);
2070
- }
2071
- else {
2072
- this.onSelection(item);
2073
- }
2074
- if (this.maintainSelectedItem) {
2075
- this.selected = item;
2076
- this.lastSelected = item;
2077
2020
  }
2078
- else {
2079
- this.selected = null;
2080
- this.lastSelected = null;
2021
+ catch (e) {
2022
+ // If the router throws we will try to navigate to the fully qualified url as a last ditch effort.
2023
+ // This can happen if we missed a link that needs to be converted to ng5 or our ng1Href directive
2024
+ // didn't handle a link correctly
2025
+ window.location.href = url;
2081
2026
  }
2082
- }
2027
+ });
2083
2028
  }
2084
2029
  /**
2085
- * Close the current menu and open the parent menu
2086
- * @memberof MenuComponent
2030
+ * Adds a `beforeunload` function to the window to alert the user that there are about to leave
2031
+ * the current page and ask if they'd like to leave or stay
2087
2032
  */
2088
- back(event) {
2089
- event.stopPropagation();
2090
- if (this.parent && this.parent.onClick) {
2091
- this.parent.onClick(null, true);
2092
- }
2093
- this.menuClosed.emit();
2033
+ addNavigateAwayPrompt() {
2034
+ this._hasUnsavedChanges = true;
2035
+ window.addEventListener("beforeunload", this.beforeUnloadFunction);
2094
2036
  }
2095
2037
  /**
2096
- * Emit the selected item
2097
- * @param item The selected item
2038
+ * Removes the `beforeunload` function added to the window
2098
2039
  */
2099
- onSelection(item) {
2100
- if (item.display !== 'heading' && item.display !== 'divided-section') {
2101
- this.selectedChanged.emit(item);
2102
- }
2040
+ removeNavigateAwayPrompt() {
2041
+ this._hasUnsavedChanges = false;
2042
+ window.removeEventListener("beforeunload", this.beforeUnloadFunction);
2103
2043
  }
2104
2044
  /**
2105
- * Open or close the child menu. When the child menu closes, the selected
2106
- * item is reset.
2107
- * @memberof MenuComponent
2045
+ * Send data to another window.
2046
+ *
2047
+ * __SECURITY RISK__ - Always use a specific target origin. Failing to provide a specific target origin can allow
2048
+ * malicious sites to receive the message.
2049
+ *
2050
+ * @param targetWindow - Window to send the message to
2051
+ * @param message - Data to send
2052
+ * @param targetOrigin - What the URI of the target window must be for the message to be sent.
2053
+ * If sending data to another EnergyCAP window, this should always be `window.location.origin` to ensure
2054
+ * that only instances of EnergyCAP app receive the message.
2108
2055
  */
2109
- toggleChildMenu(open) {
2110
- let navEl = this.el.nativeElement.querySelector('nav');
2111
- if (open) {
2112
- // Remove the listener on the parent menu when a child menu is opened
2113
- // This is to avoid interference between the parent and child menus
2114
- if (this.removeKeydownListener) {
2115
- this.removeKeydownListener();
2116
- }
2117
- let height = navEl.offsetHeight;
2118
- let width = navEl.offsetWidth;
2119
- // In order to animate the child menu, we need to set height on the nav element
2120
- // so we can absolutely position the two menus and maintain the current menu's height
2121
- this.renderer.setStyle(navEl, 'height', `${height}px`);
2122
- this.renderer.setStyle(navEl, 'width', `${width}px`);
2123
- this.renderer.addClass(this.el.nativeElement, 'open');
2124
- setTimeout(() => {
2125
- this.renderer.addClass(this.el.nativeElement, 'open-active');
2056
+ postMessage(targetWindow, message, targetOrigin) {
2057
+ targetWindow.postMessage(message, targetOrigin);
2058
+ }
2059
+ /**
2060
+ * Open a new window
2061
+ * @param url - The URL of the resource to be loaded
2062
+ */
2063
+ openNew(url) {
2064
+ window.open(url, '_blank');
2065
+ }
2066
+ /**
2067
+ * A wrapper around the router for changing the query params for the current url
2068
+ * without creating a new history entry or removing any existing query parameters.
2069
+ * The provided params are updated if they already exist or added to the url if they don't
2070
+ *
2071
+ * @returns a promise that resolves to true if the navigation succeeds, false if something (like a guard) blocks it.
2072
+ * In normal use, the navigation should succeed unless we use query params to block access to a route the user is already on
2073
+ */
2074
+ modifyHistoryQueryParamsSubset(queryParams) {
2075
+ return __awaiter(this, void 0, void 0, function* () {
2076
+ return this.router.navigate([], {
2077
+ relativeTo: this.activatedRoute,
2078
+ replaceUrl: true,
2079
+ queryParams: queryParams,
2080
+ queryParamsHandling: 'merge',
2126
2081
  });
2082
+ });
2083
+ }
2084
+ /**A wrapper around the default javascript confirm dialog to allow us to unit test dependent code.
2085
+ * Of course eventually we'd like to have pretty confirmations for everything, but in some cases it wasn't worth the extra time
2086
+ * so we're using this instead.
2087
+ */
2088
+ confirm(prompt) {
2089
+ return Promise.resolve(confirm(prompt));
2090
+ }
2091
+ /**
2092
+ * Close the current window or a window instance if one is provided
2093
+ * @param windowInstance - Window to close (optional)
2094
+ */
2095
+ closeWindow(windowInstance) {
2096
+ if (windowInstance) {
2097
+ windowInstance.close();
2127
2098
  }
2128
2099
  else {
2129
- // Re-add the listener once the child menu closes
2130
- this.addKeydownListener();
2131
- this.renderer.removeClass(this.el.nativeElement, 'open-active');
2132
- setTimeout(() => {
2133
- this.renderer.removeClass(this.el.nativeElement, 'open');
2134
- // Reset the nav element's height to auto
2135
- this.renderer.setStyle(navEl, 'height', '100%');
2136
- this.selected = null;
2137
- }, menuAnimationSpeed);
2100
+ window.close();
2138
2101
  }
2139
2102
  }
2103
+ getLocation() {
2104
+ return window.location.pathname + window.location.hash;
2105
+ }
2106
+ /** Get the current value of the full url, including protocol, host and path */
2107
+ getFullUrl() {
2108
+ return window.location.href;
2109
+ }
2110
+ /** Get the current value of the base url, including protocol, domain and port (if explicitly specified) */
2111
+ getBaseUrl() {
2112
+ return window.location.origin;
2113
+ }
2140
2114
  /**
2141
- * Handle key presses to navigate the menu
2115
+ * Reloads the browser window.
2116
+ * NOT RECOMMENDED. Seek other options for reloading content within Angular before resorting to this.
2142
2117
  */
2143
- keyNavigate(event) {
2144
- var _a;
2145
- if (this.enableKeyNav && event.target === ((_a = this.dropdownToggleButton) === null || _a === void 0 ? void 0 : _a.nativeElement)) {
2146
- switch (event.key) {
2147
- case 'ArrowUp':
2148
- case 'Up':
2149
- case 'ArrowDown':
2150
- case 'Down':
2151
- event.stopPropagation();
2152
- event.preventDefault();
2153
- this.moveHighlightedUpOrDown(event);
2154
- break;
2155
- case 'ArrowRight':
2156
- case 'Right':
2157
- event.stopPropagation();
2158
- event.preventDefault();
2159
- // Select the item if it has child items
2160
- if (this.highlightedItem && this.highlightedItem.items) {
2161
- this.selectItem(event, this.highlightedItem, true);
2162
- }
2163
- break;
2164
- case 'ArrowLeft':
2165
- case 'Left':
2166
- event.stopPropagation();
2167
- event.preventDefault();
2168
- // Close the menu if it is a child menu
2169
- if (this.parent) {
2170
- this.back(event);
2171
- }
2172
- break;
2173
- case ' ':
2174
- case 'Spacebar':
2175
- case 'Enter':
2176
- // Prevent 'enter' from doing whatever it does on the currently focused element
2177
- event.preventDefault();
2178
- if (this.highlightedItemIndex > -1 && this.highlightedItem) {
2179
- this.selectItem(event, this.highlightedItem, true);
2180
- // If the header is highlighted
2181
- }
2182
- else if (this.highlightedItemIndex === -1) {
2183
- // Close the menu if it's a child
2184
- if (this.parent) {
2185
- this.back(event);
2186
- }
2187
- }
2188
- break;
2189
- default:
2190
- return;
2191
- }
2192
- }
2118
+ reloadWindow() {
2119
+ window.location.reload();
2193
2120
  }
2121
+ }
2122
+ WindowService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: WindowService, deps: [{ token: i1$2.Router }, { token: i1$2.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Injectable });
2123
+ WindowService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: WindowService, providedIn: 'root' });
2124
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: WindowService, decorators: [{
2125
+ type: Injectable,
2126
+ args: [{
2127
+ providedIn: 'root'
2128
+ }]
2129
+ }], ctorParameters: function () { return [{ type: i1$2.Router }, { type: i1$2.ActivatedRoute }]; } });
2130
+
2131
+ class NavItemActiveDirective {
2194
2132
  /**
2195
- * Scroll to the item currently marked as 'is-selected'. Wait a tick for the
2196
- * NgClassDirecitve or NavItemActiveDirective to respond to the model changes
2197
- * and update the view.
2133
+ * Determines whether the directive will try to make an exact match on the url or not
2134
+ * If false, the directive will add the active class if the first part of the url matches
2135
+ * the active route.
2136
+ * see: https://angular.io/api/router/Router#isactive
2198
2137
  */
2199
- scrollToSelectedItem() {
2200
- window.setTimeout(() => {
2201
- const linkSelector = `li.is-selected`;
2202
- this.scrollService.scrollToItem(`#${this.id}_list`, linkSelector);
2203
- });
2204
- }
2205
- moveHighlightedUpOrDown(event) {
2206
- switch (event.key) {
2207
- case 'ArrowUp':
2208
- case 'Up':
2209
- if (this.highlightedItemIndex > -1) {
2210
- this.highlightedItemIndex--;
2211
- }
2212
- break;
2213
- case 'ArrowDown':
2214
- case 'Down':
2215
- if (this.highlightedItemIndex < this.selectableItems.length - 1) {
2216
- this.highlightedItemIndex++;
2217
- }
2218
- break;
2219
- default:
2220
- return;
2221
- }
2222
- if (this.highlightedItemIndex > -1) {
2223
- // Store the item at the current highlight index
2224
- this.highlightedItem = this.selectableItems[this.highlightedItemIndex];
2138
+ set exact(value) {
2139
+ if (value === undefined) {
2140
+ this._exact = true;
2225
2141
  }
2226
2142
  else {
2227
- this.highlightedItem = null;
2143
+ this._exact = value;
2228
2144
  }
2229
- this.scrollToHighlightedItem();
2145
+ this.update();
2230
2146
  }
2231
2147
  /**
2232
- * Scroll to the specified menu item.
2233
- * If no item is provided, it will scroll to the first item.
2234
- *
2235
- * @param item The menu item to scroll to.
2236
- * @memberof MenuComponent
2148
+ * The url of the NavItem to check for activeness. Convert the item url into a
2149
+ * UrlTree relative to the ActivatedRoute so router#isActive works even with relative urls.
2150
+ * See Angular's [routerLink](https://github.com/angular/angular/blob/8282e15c2becbe42a49befa07d6407247e8243d8/packages/router/src/directives/router_link.ts#L249)
2151
+ * and [routerLinkActive](https://github.com/angular/angular/blob/8282e15c2becbe42a49befa07d6407247e8243d8/packages/router/src/directives/router_link_active.ts#L139)
2152
+ * for a similiar implementation.
2237
2153
  */
2238
- scrollMenu(item) {
2239
- if (this.items.length > 0 && this.id) {
2240
- item = item ? item : this.items[0];
2241
- let itemId = item.id ? item.id : MenuComponent.getIndexedItemId(this.items, item, this.id);
2242
- this.scrollService.scrollItemCentered(`#${this.id}_list`, `#${itemId}`);
2154
+ set url(value) {
2155
+ if (value !== null && value !== undefined) {
2156
+ this._url = this.router.createUrlTree([value], { relativeTo: this.route, queryParams: this.queryParams });
2157
+ this.update();
2243
2158
  }
2244
2159
  }
2245
- scrollToHighlightedItem() {
2246
- this.scrollMenu(this.highlightedItem);
2160
+ constructor(router, el, renderer, route) {
2161
+ this.router = router;
2162
+ this.el = el;
2163
+ this.renderer = renderer;
2164
+ this.route = route;
2165
+ this._exact = true;
2166
+ /** Emits when the url becomes active */
2167
+ this.routerLinkActivated = new EventEmitter();
2168
+ /** Subject that emits when component is destroyed to unsubscribe from any subscriptions */
2169
+ this.destroyed = new Subject();
2247
2170
  }
2248
- addKeydownListener() {
2249
- // Only attempt to add the listener if keyboard nav is enabled
2250
- if (this.enableKeyNav) {
2251
- // renderer.listen adds the listener and returns a function to remove it from the renderer.
2252
- // The listener remains active until this function is called.
2253
- this.removeKeydownListener = this.renderer.listen('document', 'keydown', (event) => this.keyNavigate(event));
2254
- }
2171
+ /** Check if url is active on NavigationEnd events */
2172
+ ngOnInit() {
2173
+ this.router.events.pipe(takeUntil(this.destroyed), filter(e => e instanceof NavigationEnd)).subscribe(() => {
2174
+ this.update();
2175
+ });
2255
2176
  }
2256
- /**
2257
- * Sets the menu item ids using its index if item doesn't already have one
2258
- */
2259
- setItemIds() {
2260
- if (this.items) {
2261
- this.items.forEach((item, index) => {
2262
- item.id = item.id ? item.id : this.id + '_item' + index;
2263
- });
2177
+ ngOnDestroy() {
2178
+ this.destroyed.next();
2179
+ this.destroyed.unsubscribe();
2180
+ }
2181
+ /** If url is active apply the defined class to the element, otherwise remove it */
2182
+ update() {
2183
+ if (this._url && this.classValue) {
2184
+ if (this.router.isActive(this._url, { matrixParams: 'ignored', queryParams: this._exact ? 'exact' : 'subset', paths: this._exact ? 'exact' : 'subset', fragment: 'ignored' })) {
2185
+ this.renderer.addClass(this.el.nativeElement, this.classValue);
2186
+ this.routerLinkActivated.emit(new Event('routerLinkActivated'));
2187
+ }
2188
+ else {
2189
+ this.renderer.removeClass(this.el.nativeElement, this.classValue);
2190
+ }
2264
2191
  }
2265
2192
  }
2266
2193
  }
2267
- MenuComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MenuComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: WindowService }, { token: ScrollService }], target: i0.ɵɵFactoryTarget.Component });
2268
- MenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: MenuComponent, selector: "ec-menu", inputs: { id: "id", items: "items", selected: "selected", parent: "parent", templateType: "templateType", customMenuTemplate: "customMenuTemplate", title: "title", showNoItems: "showNoItems", noDataText: "noDataText", enableKeyNav: "enableKeyNav", highlightedItem: "highlightedItem", maintainSelectedItem: "maintainSelectedItem", truncateItems: "truncateItems", preserveIconSpace: "preserveIconSpace", dropdownToggleButton: "dropdownToggleButton" }, outputs: { selectedChanged: "selectedChanged", menuClosed: "menuClosed" }, host: { properties: { "attr.id": "this.attrId" } }, viewQueries: [{ propertyName: "labelTemplate", first: true, predicate: ["label"], descendants: true, static: true }, { propertyName: "iconAndLabelTemplate", first: true, predicate: ["iconAndLabel"], descendants: true, static: true }, { propertyName: "checkAndLabelTemplate", first: true, predicate: ["checkAndLabel"], descendants: true, static: true }, { propertyName: "iconLabelCaptionTemplate", first: true, predicate: ["iconLabelCaption"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<nav>\r\n <div class=\"parent\"\r\n [class.no-data]=\"showNoItems && (!items || items.length === 0)\">\r\n <header id=\"{{id}}_header\"\r\n class=\"text-heading-3 p-1\"\r\n [class.is-selected]=\"highlightedItemIndex === -1\"\r\n *ngIf=\"parent\"\r\n (click)=\"back($event)\">\r\n <div class=\"item-wrapper\">\r\n <i class=\"ec-icon icon-angle-down rotate-90 flex-shrink\"></i>\r\n <span class=\"label text-truncate flex-grow\">{{parent?.label}}</span>\r\n </div>\r\n </header>\r\n\r\n <ul id=\"{{id}}_list\"\r\n class=\"py-1\">\r\n <ng-container *ngFor=\"let item of items; index as i\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: {$implicit: item, index: i}\"></ng-container>\r\n\r\n <!-- Show child items under parent item if the item is a heading or divided-section -->\r\n <ng-container *ngIf=\"item.items?.length && (item.display === 'heading' || item.display === 'divided-section')\">\r\n <ng-container *ngFor=\"let childItem of item.items; index as j; first as isFirst; last as isLast\"\r\n [ngTemplateOutlet]=\"itemTemplate\"\r\n [ngTemplateOutletContext]=\"{$implicit: childItem, index: i + '-' + j, isDividedSectionChild: item.display === 'divided-section', isFirst: isFirst, isLast: isLast}\">\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n </ul>\r\n\r\n <p class=\"no-data-message\">{{noDataText | translate}}</p>\r\n </div>\r\n\r\n <!-- Child menu (Rendered to the right) -->\r\n <ec-menu *ngIf=\"selected?.items && selected?.display !== 'heading' && selected?.display !== 'divided-section'\"\r\n id=\"{{id}}_child\"\r\n class=\"child\"\r\n [parent]=\"selected\"\r\n [items]=\"selected?.items\"\r\n [showNoItems]=\"true\"\r\n [templateType]=\"templateType\"\r\n [enableKeyNav]=\"true\"\r\n [truncateItems]=\"truncateItems\"\r\n (selectedChanged)=\"onSelection($event)\"\r\n (menuClosed)=\"toggleChildMenu(false)\">\r\n </ec-menu>\r\n</nav>\r\n\r\n<ng-template #itemTemplate\r\n let-item\r\n let-i=\"index\"\r\n let-isDividedSectionChild=\"isDividedSectionChild\"\r\n let-isFirst=\"isFirst\"\r\n let-isLast=\"isLast\">\r\n <li *ngIf=\"!(item.hideIfNoItems && !item.items?.length) && item.display !== 'divided-section'\"\r\n id=\"{{item.id || id + '_item' + i}}\"\r\n class=\"{{item.display || 'item'}} {{item.classList}}\"\r\n [class.divider-top]=\"item.display === 'divider-top' || (isDividedSectionChild && isFirst)\"\r\n [class.divider]=\"item.display === 'divider' || (isDividedSectionChild && isLast)\"\r\n [attr.disabled]=\"item.disabled\"\r\n [hidden]=\"item.hidden\"\r\n ecNavItemActive=\"is-selected\"\r\n [ecNavItemActiveQueryParams]=\"item.queryParams\"\r\n [ecNavItemActiveUrl]=\"item.url\"\r\n [ecNavItemActiveExactMatch]='item.isActiveExactMatch'\r\n (routerLinkActivated)=\"selectItem($event, item)\"\r\n [ngClass]=\"{'is-highlighted':(selected === item && item?.display !== 'heading') || highlightedItem === item, 'is-link': item.url, 'is-disabled': item.disabled, 'is-readonly': item.readonly, 'is-checked': item.checked, 'text-heading-3': item?.display === 'heading'}\"\r\n (click)=\"selectItem($event, item)\">\r\n\r\n <a *ngIf=\"item.url && !item.externalLink\"\r\n id=\"{{item.id}}_link\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\"\r\n [routerLink]=\"item.url\"\r\n [queryParams]=\"item.queryParams || null\"\r\n target=\"{{item.target || '_self'}}\">\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </a>\r\n\r\n <a *ngIf=\"item.url && item.externalLink\"\r\n id=\"{{item.id}}_link\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\"\r\n href=\"{{item.url}}\"\r\n target=\"{{item.target || '_self'}}\">\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </a>\r\n\r\n <div *ngIf=\"!item.url\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\">\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </div>\r\n </li>\r\n</ng-template>\r\n\r\n<!-- 'label' Item Template -->\r\n<ng-template #label\r\n let-item>\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items && item.display !== 'heading' && item.display !== 'divided-section'\"></i>\r\n</ng-template>\r\n\r\n<!-- 'checkAndLabel' Item Template -->\r\n<ng-template #checkAndLabel\r\n let-item>\r\n\r\n <i class=\"ec-icon icon-check ec-icon-sm\"\r\n *ngIf=\"item.display !== 'heading'\"></i>\r\n\r\n <i class=\"ec-icon {{item.icon}} ml-2\"\r\n *ngIf=\"item.icon\"></i>\r\n\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items && item.display !== 'heading' && item.display !== 'divided-section'\"></i>\r\n</ng-template>\r\n\r\n<!-- 'iconAndLabel' Item Template -->\r\n<ng-template #iconAndLabel\r\n let-item>\r\n <!-- If menuItem.icon exists and is not blank, show the icon in the menu -->\r\n <i class=\"ec-icon {{item.icon}}\"\r\n *ngIf=\"(item.icon && item.icon !== '') || preserveIconSpace\"></i>\r\n\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items && item.display !== 'heading' && item.display !== 'divided-section'\"></i>\r\n</ng-template>\r\n\r\n<ng-template #iconLabelCaption\r\n let-item>\r\n <i class=\"ec-icon {{item.icon}}\"\r\n *ngIf=\"(item.icon && item.icon !== '') || preserveIconSpace\"></i>\r\n <div *ngIf=\"item.display !== 'heading'\"\r\n class=\"label flex-grow\">\r\n <div id=\"{{item.id}}_label\"\r\n class=\"text-body-1\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</div>\r\n <div id=\"{{item.id}}_caption\"\r\n *ngIf=\"item.caption\"\r\n class=\"text-caption-1\"\r\n [class.text-truncate]=\"truncateItems\">{{item.caption}}</div>\r\n </div>\r\n <h3 *ngIf=\"item.display === 'heading'\"\r\n class=\"flex-grow text-heading-3 align-self-center\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</h3>\r\n <i class=\"ec-icon icon-angle-down rotate-270 align-self-center\"\r\n *ngIf=\"item?.items && item.display !== 'heading' && item.display !== 'divided-section'\"></i>\r\n</ng-template>", styles: ["@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(1turn)}}:host{display:block;font-size:var(--ec-menu-font-size, var(--ec-font-size-action));font-weight:400;background-color:var(--ec-menu-background-color, var(--ec-background-color))}:host.open>nav>.parent,:host.open>nav>.child{position:absolute;left:0;top:0;right:0;height:100%;transition:transform .25s ease}:host.open>nav>.parent{transform:translate(0)}:host.open>nav>.child{transform:translate(100%)}:host.open-active>nav>.parent{transform:translate(-100%)}:host.open-active>nav>.child{transform:translate(0)}:host(.bg-transparent){background-color:transparent}:host-context(.is-always-open){height:100%}:host-context(.is-always-open) .item-wrapper{padding-left:1rem;padding-right:1rem}nav{display:flex;position:relative;height:100%;overflow:hidden}.parent{display:flex;flex-direction:column;flex:auto;position:relative;max-width:100%}.parent>header{cursor:pointer}.parent>header.is-selected .item-wrapper,.parent>header.is-highlighted .item-wrapper{background-color:var(--ec-background-color-selected)}.parent>header:hover .item-wrapper{background-color:var(--ec-background-color-hover)}.parent.no-data ul{display:none}.parent.no-data .no-data-message{display:block}ul{padding:0;margin:0;list-style:none;flex:auto;height:100%;overflow-y:auto}ul li{cursor:pointer;padding:0 .25rem}ul li a{color:inherit;border-bottom:0;text-decoration:none}ul li.is-selected .item-wrapper,ul li.is-highlighted .item-wrapper{background-color:var(--ec-background-color-selected)}ul li:hover .item-wrapper{background-color:var(--ec-background-color-hover)}ul li:focus .item-wrapper{outline:none;background-color:var(--ec-color-disabled-dark);position:relative;z-index:1}ul li.is-disabled .item-wrapper{color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled)}ul li.is-disabled,ul li.is-readonly{cursor:default}ul li.is-disabled .item-wrapper,ul li.is-readonly .item-wrapper{background-color:transparent;color:inherit}ul li.is-checked .icon-check{opacity:1}ul li.heading{cursor:default}ul li.heading .item-wrapper{background-color:transparent}ul li.heading:not(:first-child){margin-top:.5rem}ul li.divider:not(:last-child){border-bottom:1px solid var(--ec-border-color);padding-bottom:.25rem;margin-bottom:.25rem}ul li.divider-top:not(:first-child):not(.divider + .divider-top){border-top:1px solid var(--ec-border-color);padding-top:.25rem;margin-top:.25rem}ul li.indent-1 .item-wrapper{padding-left:1.5rem}ul li.indent-2 .item-wrapper{padding-left:2.5rem}ul li.indent-3 .item-wrapper{padding-left:3.5rem}.item-wrapper{cursor:inherit;line-height:1.25rem;min-height:1.75rem;padding:.25rem .5rem;border-radius:var(--ec-border-radius);display:flex;color:inherit}.item-wrapper .label{margin-right:auto}.item-wrapper .label+.ec-icon{margin-left:.5rem}.item-wrapper .ec-icon{margin-top:calc((1.25rem - var(--ec-font-size-icon)) / 2);flex:none}.item-wrapper .ec-icon+.label{margin-left:.5rem}.item-wrapper .ec-icon-sm{margin-top:calc((1.25rem - calc(var(--ec-font-size-icon) * .75)) / 2)}.item-wrapper .icon-check{opacity:0}.no-data-message{display:none;text-align:center;padding:1rem;color:var(--ec-color-hint-dark);margin-bottom:0;font-size:var(--ec-font-size-body)}:host-context(ec-tree) ul{overflow-x:hidden}:host-context(ec-tree) li.is-selected,:host-context(ec-tree) li.is-highlighted{font-weight:700;color:var(--ec-menu-color-highlighted, inherit)}:host-context(ec-tree) li.is-selected:not(:hover),:host-context(ec-tree) li.is-highlighted:not(:hover){background-color:transparent}\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", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: NavItemActiveDirective, selector: "[ecNavItemActive]", inputs: ["ecNavItemActive", "ecNavItemActiveExactMatch", "ecNavItemActiveQueryParams", "ecNavItemActiveUrl"], outputs: ["routerLinkActivated"] }, { kind: "component", type: MenuComponent, selector: "ec-menu", inputs: ["id", "items", "selected", "parent", "templateType", "customMenuTemplate", "title", "showNoItems", "noDataText", "enableKeyNav", "highlightedItem", "maintainSelectedItem", "truncateItems", "preserveIconSpace", "dropdownToggleButton"], outputs: ["selectedChanged", "menuClosed"] }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] });
2269
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MenuComponent, decorators: [{
2270
- type: Component,
2271
- args: [{ selector: 'ec-menu', template: "<nav>\r\n <div class=\"parent\"\r\n [class.no-data]=\"showNoItems && (!items || items.length === 0)\">\r\n <header id=\"{{id}}_header\"\r\n class=\"text-heading-3 p-1\"\r\n [class.is-selected]=\"highlightedItemIndex === -1\"\r\n *ngIf=\"parent\"\r\n (click)=\"back($event)\">\r\n <div class=\"item-wrapper\">\r\n <i class=\"ec-icon icon-angle-down rotate-90 flex-shrink\"></i>\r\n <span class=\"label text-truncate flex-grow\">{{parent?.label}}</span>\r\n </div>\r\n </header>\r\n\r\n <ul id=\"{{id}}_list\"\r\n class=\"py-1\">\r\n <ng-container *ngFor=\"let item of items; index as i\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: {$implicit: item, index: i}\"></ng-container>\r\n\r\n <!-- Show child items under parent item if the item is a heading or divided-section -->\r\n <ng-container *ngIf=\"item.items?.length && (item.display === 'heading' || item.display === 'divided-section')\">\r\n <ng-container *ngFor=\"let childItem of item.items; index as j; first as isFirst; last as isLast\"\r\n [ngTemplateOutlet]=\"itemTemplate\"\r\n [ngTemplateOutletContext]=\"{$implicit: childItem, index: i + '-' + j, isDividedSectionChild: item.display === 'divided-section', isFirst: isFirst, isLast: isLast}\">\r\n </ng-container>\r\n </ng-container>\r\n </ng-container>\r\n </ul>\r\n\r\n <p class=\"no-data-message\">{{noDataText | translate}}</p>\r\n </div>\r\n\r\n <!-- Child menu (Rendered to the right) -->\r\n <ec-menu *ngIf=\"selected?.items && selected?.display !== 'heading' && selected?.display !== 'divided-section'\"\r\n id=\"{{id}}_child\"\r\n class=\"child\"\r\n [parent]=\"selected\"\r\n [items]=\"selected?.items\"\r\n [showNoItems]=\"true\"\r\n [templateType]=\"templateType\"\r\n [enableKeyNav]=\"true\"\r\n [truncateItems]=\"truncateItems\"\r\n (selectedChanged)=\"onSelection($event)\"\r\n (menuClosed)=\"toggleChildMenu(false)\">\r\n </ec-menu>\r\n</nav>\r\n\r\n<ng-template #itemTemplate\r\n let-item\r\n let-i=\"index\"\r\n let-isDividedSectionChild=\"isDividedSectionChild\"\r\n let-isFirst=\"isFirst\"\r\n let-isLast=\"isLast\">\r\n <li *ngIf=\"!(item.hideIfNoItems && !item.items?.length) && item.display !== 'divided-section'\"\r\n id=\"{{item.id || id + '_item' + i}}\"\r\n class=\"{{item.display || 'item'}} {{item.classList}}\"\r\n [class.divider-top]=\"item.display === 'divider-top' || (isDividedSectionChild && isFirst)\"\r\n [class.divider]=\"item.display === 'divider' || (isDividedSectionChild && isLast)\"\r\n [attr.disabled]=\"item.disabled\"\r\n [hidden]=\"item.hidden\"\r\n ecNavItemActive=\"is-selected\"\r\n [ecNavItemActiveQueryParams]=\"item.queryParams\"\r\n [ecNavItemActiveUrl]=\"item.url\"\r\n [ecNavItemActiveExactMatch]='item.isActiveExactMatch'\r\n (routerLinkActivated)=\"selectItem($event, item)\"\r\n [ngClass]=\"{'is-highlighted':(selected === item && item?.display !== 'heading') || highlightedItem === item, 'is-link': item.url, 'is-disabled': item.disabled, 'is-readonly': item.readonly, 'is-checked': item.checked, 'text-heading-3': item?.display === 'heading'}\"\r\n (click)=\"selectItem($event, item)\">\r\n\r\n <a *ngIf=\"item.url && !item.externalLink\"\r\n id=\"{{item.id}}_link\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\"\r\n [routerLink]=\"item.url\"\r\n [queryParams]=\"item.queryParams || null\"\r\n target=\"{{item.target || '_self'}}\">\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </a>\r\n\r\n <a *ngIf=\"item.url && item.externalLink\"\r\n id=\"{{item.id}}_link\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\"\r\n href=\"{{item.url}}\"\r\n target=\"{{item.target || '_self'}}\">\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </a>\r\n\r\n <div *ngIf=\"!item.url\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\">\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </div>\r\n </li>\r\n</ng-template>\r\n\r\n<!-- 'label' Item Template -->\r\n<ng-template #label\r\n let-item>\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items && item.display !== 'heading' && item.display !== 'divided-section'\"></i>\r\n</ng-template>\r\n\r\n<!-- 'checkAndLabel' Item Template -->\r\n<ng-template #checkAndLabel\r\n let-item>\r\n\r\n <i class=\"ec-icon icon-check ec-icon-sm\"\r\n *ngIf=\"item.display !== 'heading'\"></i>\r\n\r\n <i class=\"ec-icon {{item.icon}} ml-2\"\r\n *ngIf=\"item.icon\"></i>\r\n\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items && item.display !== 'heading' && item.display !== 'divided-section'\"></i>\r\n</ng-template>\r\n\r\n<!-- 'iconAndLabel' Item Template -->\r\n<ng-template #iconAndLabel\r\n let-item>\r\n <!-- If menuItem.icon exists and is not blank, show the icon in the menu -->\r\n <i class=\"ec-icon {{item.icon}}\"\r\n *ngIf=\"(item.icon && item.icon !== '') || preserveIconSpace\"></i>\r\n\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items && item.display !== 'heading' && item.display !== 'divided-section'\"></i>\r\n</ng-template>\r\n\r\n<ng-template #iconLabelCaption\r\n let-item>\r\n <i class=\"ec-icon {{item.icon}}\"\r\n *ngIf=\"(item.icon && item.icon !== '') || preserveIconSpace\"></i>\r\n <div *ngIf=\"item.display !== 'heading'\"\r\n class=\"label flex-grow\">\r\n <div id=\"{{item.id}}_label\"\r\n class=\"text-body-1\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</div>\r\n <div id=\"{{item.id}}_caption\"\r\n *ngIf=\"item.caption\"\r\n class=\"text-caption-1\"\r\n [class.text-truncate]=\"truncateItems\">{{item.caption}}</div>\r\n </div>\r\n <h3 *ngIf=\"item.display === 'heading'\"\r\n class=\"flex-grow text-heading-3 align-self-center\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</h3>\r\n <i class=\"ec-icon icon-angle-down rotate-270 align-self-center\"\r\n *ngIf=\"item?.items && item.display !== 'heading' && item.display !== 'divided-section'\"></i>\r\n</ng-template>", styles: ["@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(1turn)}}:host{display:block;font-size:var(--ec-menu-font-size, var(--ec-font-size-action));font-weight:400;background-color:var(--ec-menu-background-color, var(--ec-background-color))}:host.open>nav>.parent,:host.open>nav>.child{position:absolute;left:0;top:0;right:0;height:100%;transition:transform .25s ease}:host.open>nav>.parent{transform:translate(0)}:host.open>nav>.child{transform:translate(100%)}:host.open-active>nav>.parent{transform:translate(-100%)}:host.open-active>nav>.child{transform:translate(0)}:host(.bg-transparent){background-color:transparent}:host-context(.is-always-open){height:100%}:host-context(.is-always-open) .item-wrapper{padding-left:1rem;padding-right:1rem}nav{display:flex;position:relative;height:100%;overflow:hidden}.parent{display:flex;flex-direction:column;flex:auto;position:relative;max-width:100%}.parent>header{cursor:pointer}.parent>header.is-selected .item-wrapper,.parent>header.is-highlighted .item-wrapper{background-color:var(--ec-background-color-selected)}.parent>header:hover .item-wrapper{background-color:var(--ec-background-color-hover)}.parent.no-data ul{display:none}.parent.no-data .no-data-message{display:block}ul{padding:0;margin:0;list-style:none;flex:auto;height:100%;overflow-y:auto}ul li{cursor:pointer;padding:0 .25rem}ul li a{color:inherit;border-bottom:0;text-decoration:none}ul li.is-selected .item-wrapper,ul li.is-highlighted .item-wrapper{background-color:var(--ec-background-color-selected)}ul li:hover .item-wrapper{background-color:var(--ec-background-color-hover)}ul li:focus .item-wrapper{outline:none;background-color:var(--ec-color-disabled-dark);position:relative;z-index:1}ul li.is-disabled .item-wrapper{color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled)}ul li.is-disabled,ul li.is-readonly{cursor:default}ul li.is-disabled .item-wrapper,ul li.is-readonly .item-wrapper{background-color:transparent;color:inherit}ul li.is-checked .icon-check{opacity:1}ul li.heading{cursor:default}ul li.heading .item-wrapper{background-color:transparent}ul li.heading:not(:first-child){margin-top:.5rem}ul li.divider:not(:last-child){border-bottom:1px solid var(--ec-border-color);padding-bottom:.25rem;margin-bottom:.25rem}ul li.divider-top:not(:first-child):not(.divider + .divider-top){border-top:1px solid var(--ec-border-color);padding-top:.25rem;margin-top:.25rem}ul li.indent-1 .item-wrapper{padding-left:1.5rem}ul li.indent-2 .item-wrapper{padding-left:2.5rem}ul li.indent-3 .item-wrapper{padding-left:3.5rem}.item-wrapper{cursor:inherit;line-height:1.25rem;min-height:1.75rem;padding:.25rem .5rem;border-radius:var(--ec-border-radius);display:flex;color:inherit}.item-wrapper .label{margin-right:auto}.item-wrapper .label+.ec-icon{margin-left:.5rem}.item-wrapper .ec-icon{margin-top:calc((1.25rem - var(--ec-font-size-icon)) / 2);flex:none}.item-wrapper .ec-icon+.label{margin-left:.5rem}.item-wrapper .ec-icon-sm{margin-top:calc((1.25rem - calc(var(--ec-font-size-icon) * .75)) / 2)}.item-wrapper .icon-check{opacity:0}.no-data-message{display:none;text-align:center;padding:1rem;color:var(--ec-color-hint-dark);margin-bottom:0;font-size:var(--ec-font-size-body)}:host-context(ec-tree) ul{overflow-x:hidden}:host-context(ec-tree) li.is-selected,:host-context(ec-tree) li.is-highlighted{font-weight:700;color:var(--ec-menu-color-highlighted, inherit)}:host-context(ec-tree) li.is-selected:not(:hover),:host-context(ec-tree) li.is-highlighted:not(:hover){background-color:transparent}\n"] }]
2272
- }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: WindowService }, { type: ScrollService }]; }, propDecorators: { id: [{
2273
- type: Input
2274
- }], attrId: [{
2275
- type: HostBinding,
2276
- args: ['attr.id']
2277
- }], items: [{
2278
- type: Input
2279
- }], selected: [{
2280
- type: Input
2281
- }], parent: [{
2282
- type: Input
2283
- }], templateType: [{
2284
- type: Input
2285
- }], customMenuTemplate: [{
2286
- type: Input
2287
- }], title: [{
2288
- type: Input
2289
- }], showNoItems: [{
2290
- type: Input
2291
- }], noDataText: [{
2292
- type: Input
2293
- }], enableKeyNav: [{
2294
- type: Input
2295
- }], highlightedItem: [{
2296
- type: Input
2297
- }], maintainSelectedItem: [{
2298
- type: Input
2299
- }], truncateItems: [{
2300
- type: Input
2301
- }], preserveIconSpace: [{
2302
- type: Input
2303
- }], dropdownToggleButton: [{
2304
- type: Input
2305
- }], selectedChanged: [{
2306
- type: Output
2307
- }], menuClosed: [{
2194
+ NavItemActiveDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NavItemActiveDirective, deps: [{ token: i1$2.Router }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1$2.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Directive });
2195
+ NavItemActiveDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: NavItemActiveDirective, selector: "[ecNavItemActive]", inputs: { classValue: ["ecNavItemActive", "classValue"], exact: ["ecNavItemActiveExactMatch", "exact"], queryParams: ["ecNavItemActiveQueryParams", "queryParams"], url: ["ecNavItemActiveUrl", "url"] }, outputs: { routerLinkActivated: "routerLinkActivated" }, ngImport: i0 });
2196
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NavItemActiveDirective, decorators: [{
2197
+ type: Directive,
2198
+ args: [{
2199
+ selector: '[ecNavItemActive]'
2200
+ }]
2201
+ }], ctorParameters: function () { return [{ type: i1$2.Router }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1$2.ActivatedRoute }]; }, propDecorators: { classValue: [{
2202
+ type: Input,
2203
+ args: ['ecNavItemActive']
2204
+ }], exact: [{
2205
+ type: Input,
2206
+ args: ['ecNavItemActiveExactMatch']
2207
+ }], queryParams: [{
2208
+ type: Input,
2209
+ args: ['ecNavItemActiveQueryParams']
2210
+ }], url: [{
2211
+ type: Input,
2212
+ args: ['ecNavItemActiveUrl']
2213
+ }], routerLinkActivated: [{
2308
2214
  type: Output
2309
- }], labelTemplate: [{
2310
- type: ViewChild,
2311
- args: ['label', { static: true }]
2312
- }], iconAndLabelTemplate: [{
2313
- type: ViewChild,
2314
- args: ['iconAndLabel', { static: true }]
2315
- }], checkAndLabelTemplate: [{
2316
- type: ViewChild,
2317
- args: ['checkAndLabel', { static: true }]
2318
- }], iconLabelCaptionTemplate: [{
2319
- type: ViewChild,
2320
- args: ['iconLabelCaption', { static: true }]
2321
2215
  }] } });
2322
2216
 
2217
+ ;
2218
+ const menuAnimationSpeed = 350;
2323
2219
  /**
2324
- * Primitive directive that popups a container using PopperJS
2220
+ * Primitive Menu component that encapsulates known templates
2325
2221
  *
2326
2222
  * @export
2327
2223
  */
2328
- class PopupContainerDirective {
2329
- /**
2330
- * Creates an instance of PopupContainerDirective.
2331
- * @param templateRef Reference to the popup template
2332
- * @param viewContainer Reference to the view container
2333
- * @param document Reference to Document
2334
- * @memberof PopupContainerDirective
2335
- */
2336
- constructor(templateRef, viewContainer, document, renderer) {
2337
- this.templateRef = templateRef;
2338
- this.viewContainer = viewContainer;
2339
- this.document = document;
2224
+ class MenuComponent {
2225
+ constructor(el, renderer, windowService, scrollService) {
2226
+ this.el = el;
2340
2227
  this.renderer = renderer;
2228
+ this.windowService = windowService;
2229
+ this.scrollService = scrollService;
2341
2230
  /**
2342
- * Emit the {@link PopupStatus} when it changes
2231
+ * Array of items to display
2232
+ *
2233
+ * @memberof MenuComponent
2343
2234
  */
2344
- this.popperStatusChange = new EventEmitter();
2345
- }
2346
- /**
2347
- * Angular onInit lifecycle hook
2348
- * @see https://angular.io/guide/lifecycle-hooks
2349
- */
2350
- ngOnInit() {
2351
- this.templateViewRef = this.viewContainer.createEmbeddedView(this.templateRef);
2352
- }
2353
- /**
2354
- * Angular onDestroy lifecycle hook. Close and delete references. Unsubscribe observables
2355
- * @see https://angular.io/guide/lifecycle-hooks
2356
- */
2357
- ngOnDestroy() {
2358
- this.hide();
2235
+ this.items = [];
2236
+ /**
2237
+ * Selected item; annotates the item
2238
+ * when displayed with 'selected' class
2239
+ *
2240
+ * @memberof MenuComponent
2241
+ */
2242
+ this.selected = null;
2243
+ /**
2244
+ * Display template
2245
+ *
2246
+ * @memberof MenuComponent
2247
+ */
2248
+ this.templateType = 'label';
2249
+ /**
2250
+ * Show message when there are no items
2251
+ */
2252
+ this.showNoItems = false;
2253
+ /**
2254
+ * Text to show when menu is empty and showNoItems is true
2255
+ */
2256
+ this.noDataText = 'NoItems_TC';
2257
+ /**
2258
+ * Controls whether keyboard navigation is enabled
2259
+ */
2260
+ this.enableKeyNav = false;
2261
+ /**
2262
+ * Item currently highlighted by keyboard navigation
2263
+ */
2264
+ this.highlightedItem = null;
2265
+ /**
2266
+ * Tells the menu to maintain the selected/lastSelected item. Turning this off is useful for
2267
+ * action type menus that are displayed on the screen at all times and you do not
2268
+ * want the item to be selected when clicked.
2269
+ */
2270
+ this.maintainSelectedItem = true;
2271
+ /**
2272
+ * Will prevent text-wrapping of menu items and truncate instead. Also turns on a tooltip for the menu item. Default: false;
2273
+ */
2274
+ this.truncateItems = false;
2275
+ /**
2276
+ * When true, the space for the icon is preserved for menu items that do not have icons.
2277
+ * Only applicable for iconAndLabel menus.
2278
+ */
2279
+ this.preserveIconSpace = false;
2280
+ /**
2281
+ * Emitted when `selected` is changed. Emits the referenced object.
2282
+ *
2283
+ * @memberof MenuComponent
2284
+ */
2285
+ this.selectedChanged = new EventEmitter();
2286
+ /**
2287
+ * Emitted when the menu has a parent and back is clicked
2288
+ * @memberof MenuComponent
2289
+ */
2290
+ this.menuClosed = new EventEmitter();
2291
+ /**
2292
+ * Index of the item currently highlighted using keyboard nav
2293
+ */
2294
+ this.highlightedItemIndex = -1;
2295
+ /**
2296
+ * Last item this.selected was set to via selectItem().
2297
+ * This isn't necessarily the same as this.selected, because this.selected is an input property
2298
+ * and could have been changed by a consumer through some means other than selectItem().
2299
+ * This allows us to prevent double-calls to selectItem() with the same input.
2300
+ */
2301
+ this.lastSelected = null;
2359
2302
  }
2360
2303
  /**
2361
- * Displays the templateRef as a popup
2304
+ * Sets & displays the interalized template based on
2305
+ * the set template.
2306
+ * @see { @link https://angular.io/guide/lifecycle-hooks|Angular Lifecycle Hooks}
2362
2307
  *
2363
- * @memberof PopupContainerDirective
2308
+ * @memberof MenuComponent
2364
2309
  */
2365
- show() {
2366
- if (PopupContainerDirective.GlobalPopupRef) {
2367
- if (PopupContainerDirective.GlobalPopupRef != this) {
2368
- PopupContainerDirective.GlobalPopupRef.hide();
2369
- PopupContainerDirective.GlobalPopupRef = undefined;
2370
- }
2371
- }
2372
- if (!this.globalCloseSubscription) {
2373
- this.globalCloseSubscription = fromEvent(this.document.body, "click").subscribe((event) => {
2374
- this.hide();
2375
- });
2376
- }
2377
- if (!this.popperRef) {
2378
- // Add the popper template as an embedded view since PopperJS
2379
- // manipulates DOM elements.
2380
- this.popupViewRef = this.viewContainer.createEmbeddedView(this.popup);
2381
- // Since popper needs real DOM elements, grab the first non-comment
2382
- // DOM element to use as our anchor.
2383
- let anchorElement = this.popupViewRef.rootNodes.find(elem => { return elem.nodeName !== "#text"; });
2384
- // Use the parents elements as our DOM elements to Popper
2385
- this.popperRef = new Popper(this.templateViewRef.rootNodes[0], anchorElement, this.popperOptions);
2386
- PopupContainerDirective.GlobalPopupRef = this;
2387
- this.popperStatusChange.emit('visible');
2310
+ ngAfterContentInit() {
2311
+ switch (this.templateType) {
2312
+ case ("label"):
2313
+ this.internalizedTemplate = this.iconAndLabelTemplate;
2314
+ break;
2315
+ case ("iconAndLabel"):
2316
+ this.internalizedTemplate = this.iconAndLabelTemplate;
2317
+ break;
2318
+ case ("checkAndLabel"):
2319
+ this.internalizedTemplate = this.checkAndLabelTemplate;
2320
+ break;
2321
+ case ("iconLabelCaption"):
2322
+ this.internalizedTemplate = this.iconLabelCaptionTemplate;
2323
+ break;
2324
+ default:
2325
+ throw new Error(`Invalid templateType for MenuComponent. Please use either: 'label', 'iconAndLabel' or 'checkAndLabel'`);
2388
2326
  }
2389
- }
2390
- /**
2391
- * Hides the templateRef
2392
- *
2393
- * @memberof PopupContainerDirective
2394
- */
2395
- hide() {
2396
- if (this.globalCloseSubscription) {
2397
- this.globalCloseSubscription.unsubscribe();
2398
- this.globalCloseSubscription = undefined;
2327
+ //if the consumer provided a menuItemTemplate, override the internalizedTemplate with that.
2328
+ if (this.customMenuTemplate) {
2329
+ this.internalizedTemplate = this.customMenuTemplate;
2399
2330
  }
2400
- if (this.popperRef && this.popupViewRef) {
2401
- this.popupViewRef.destroy();
2402
- this.popperRef.destroy();
2403
- this.popperRef = undefined;
2404
- this.popperStatusChange.emit('hidden');
2331
+ if (this.id) {
2332
+ this.attrId = this.id;
2333
+ }
2334
+ this.setItemIds();
2335
+ if (this.highlightedItem && this.items.length) {
2336
+ this.highlightedItemIndex = this.items.findIndex(item => { return this.highlightedItem === item; });
2405
2337
  }
2338
+ this.addKeydownListener();
2406
2339
  }
2407
- /**
2408
- * Updates the popup container position
2409
- */
2410
- update() {
2411
- if (this.popperRef) {
2412
- this.popperRef.update();
2340
+ ngOnDestroy() {
2341
+ // Remove the listener when the component is destroyed
2342
+ if (this.removeKeydownListener) {
2343
+ this.removeKeydownListener();
2413
2344
  }
2414
2345
  }
2415
- fixPosition(minWidthNone, appendToBody = false) {
2416
- if (this.popperRef && this.popperRef['reference'] && this.popperRef['popper']) {
2417
- let popupEl = this.popperRef['popper'];
2418
- // Reset width style previously assigned because the content may have
2419
- // changed and the auto width would be different
2420
- this.renderer.removeStyle(popupEl, 'width');
2421
- this.renderer.setStyle(popupEl, 'position', 'fixed');
2422
- if (appendToBody) {
2423
- const bodyEl = this.document.querySelector('body');
2424
- const popupParent = this.renderer.parentNode(popupEl);
2425
- if (popupParent !== bodyEl) {
2426
- this.renderer.appendChild(bodyEl, popupEl);
2346
+ /**
2347
+ * When a menu item is selected, open a child menu if the item has items, call
2348
+ * the item's click method if defined, or emit the selected item.
2349
+ *
2350
+ * @param item The selected item
2351
+ * @memberof MenuComponent
2352
+ */
2353
+ selectItem(event, item, isKeyEvent) {
2354
+ var _a;
2355
+ event.stopPropagation();
2356
+ //In the case that the user clicks an item, selectItem() will be called from the click handler
2357
+ //and through onRouterLinkActivated. Only one of these will make it through this if statement
2358
+ //because the first one will set this.lastSelected = item.
2359
+ if (!item.disabled && !item.readonly && this.lastSelected !== item) {
2360
+ if (!item.url) {
2361
+ if (item.onClick) {
2362
+ item.onClick(item, false);
2363
+ }
2364
+ if (item.items) {
2365
+ this.toggleChildMenu(true);
2366
+ }
2367
+ else {
2368
+ this.onSelection(item);
2427
2369
  }
2370
+ // We need to manually handle the url navigation if the keyboard was used
2428
2371
  }
2429
- let toggleEl = this.popperRef['reference'];
2430
- let width = popupEl.offsetWidth;
2431
- let boundaries = popupEl.getBoundingClientRect();
2432
- let left = boundaries.left;
2433
- let coords = toggleEl.getBoundingClientRect();
2434
- // Set the top of our menu to the bottom of the toggle element
2435
- let top = coords.bottom;
2436
- if (this.popperOptions && this.popperOptions.placement) {
2437
- if (this.popperOptions.placement === 'bottom-start' || this.popperOptions.placement === 'top-start') {
2438
- left = coords.left;
2372
+ else if (isKeyEvent || ((_a = event.target) === null || _a === void 0 ? void 0 : _a.tagName) === 'LI') {
2373
+ if (item.target) {
2374
+ window.open(item.url, item.target);
2439
2375
  }
2440
2376
  else {
2441
- left = coords.right - ((minWidthNone || width > coords.width) ? width : coords.width);
2377
+ this.windowService.navigateToUrl(item.url);
2442
2378
  }
2379
+ // Emit so upstream components know an item was selected
2380
+ this.onSelection(item);
2443
2381
  }
2444
- // if it won't fit (with 10px space before hitting the window edge), flip it
2445
- if (boundaries.height + top + 10 > window.innerHeight) {
2446
- top = coords.top - boundaries.height;
2382
+ else {
2383
+ this.onSelection(item);
2447
2384
  }
2448
- this.renderer.setStyle(popupEl, 'transform', 'none');
2449
- this.renderer.setStyle(popupEl, 'left', left + 'px');
2450
- this.renderer.setStyle(popupEl, 'top', top + 'px');
2451
- this.renderer.setStyle(popupEl, 'width', width + 'px');
2452
- if (!minWidthNone) {
2453
- this.renderer.setStyle(popupEl, 'min-width', coords.width + 'px');
2385
+ if (this.maintainSelectedItem) {
2386
+ this.selected = item;
2387
+ this.lastSelected = item;
2388
+ }
2389
+ else {
2390
+ this.selected = null;
2391
+ this.lastSelected = null;
2454
2392
  }
2455
2393
  }
2456
2394
  }
2457
- }
2458
- /**
2459
- * Global reference to the currently displayed popup; only
2460
- * one popup directive can be in `show` state at a given time.
2461
- *
2462
- * @memberof PopupContainerDirective
2463
- */
2464
- PopupContainerDirective.GlobalPopupRef = undefined;
2465
- PopupContainerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: PopupContainerDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: DOCUMENT }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
2466
- PopupContainerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: PopupContainerDirective, selector: "[ecPopup]", inputs: { popup: ["ecPopup", "popup"], popperOptions: ["options", "popperOptions"] }, ngImport: i0 });
2467
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: PopupContainerDirective, decorators: [{
2468
- type: Directive,
2469
- args: [{ selector: '[ecPopup]' }]
2470
- }], ctorParameters: function () {
2471
- return [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{
2472
- type: Inject,
2473
- args: [DOCUMENT]
2474
- }] }, { type: i0.Renderer2 }];
2475
- }, propDecorators: { popup: [{
2476
- type: Input,
2477
- args: ['ecPopup']
2478
- }], popperOptions: [{
2479
- type: Input,
2480
- args: ['options']
2481
- }] } });
2482
-
2483
- /** Advanced validation for textbox form controls */
2484
- const textboxValidation = (validatorParams) => {
2485
- return (control) => {
2486
- let validators = [];
2487
- // Innocent until proven guilty
2488
- validatorParams.valid = true;
2489
- if (validatorParams.required) {
2490
- validators.push(Validators.required);
2491
- }
2492
- if (validatorParams.minLength !== undefined) {
2493
- validators.push(Validators.minLength(validatorParams.minLength));
2494
- }
2495
- if (validatorParams.maxLength !== undefined) {
2496
- validators.push(Validators.maxLength(validatorParams.maxLength));
2395
+ /**
2396
+ * Close the current menu and open the parent menu
2397
+ * @memberof MenuComponent
2398
+ */
2399
+ back(event) {
2400
+ event.stopPropagation();
2401
+ if (this.parent && this.parent.onClick) {
2402
+ this.parent.onClick(null, true);
2497
2403
  }
2498
- if (validatorParams.pattern !== undefined) {
2499
- validators.push(Validators.pattern(validatorParams.pattern));
2404
+ this.menuClosed.emit();
2405
+ }
2406
+ /**
2407
+ * Emit the selected item
2408
+ * @param item The selected item
2409
+ */
2410
+ onSelection(item) {
2411
+ if (item.display !== 'heading') {
2412
+ this.selectedChanged.emit(item);
2500
2413
  }
2501
- validators.forEach(validator => {
2502
- let validationResult = validator(control);
2503
- if (validationResult) {
2504
- validatorParams.valid = false;
2414
+ }
2415
+ /**
2416
+ * Open or close the child menu. When the child menu closes, the selected
2417
+ * item is reset.
2418
+ * @memberof MenuComponent
2419
+ */
2420
+ toggleChildMenu(open) {
2421
+ let navEl = this.el.nativeElement.querySelector('nav');
2422
+ if (open) {
2423
+ // Remove the listener on the parent menu when a child menu is opened
2424
+ // This is to avoid interference between the parent and child menus
2425
+ if (this.removeKeydownListener) {
2426
+ this.removeKeydownListener();
2505
2427
  }
2506
- });
2507
- if (validatorParams.valid) {
2508
- return null;
2428
+ let height = navEl.offsetHeight;
2429
+ let width = navEl.offsetWidth;
2430
+ // In order to animate the child menu, we need to set height on the nav element
2431
+ // so we can absolutely position the two menus and maintain the current menu's height
2432
+ this.renderer.setStyle(navEl, 'height', `${height}px`);
2433
+ this.renderer.setStyle(navEl, 'width', `${width}px`);
2434
+ this.renderer.addClass(this.el.nativeElement, 'open');
2435
+ setTimeout(() => {
2436
+ this.renderer.addClass(this.el.nativeElement, 'open-active');
2437
+ });
2509
2438
  }
2510
2439
  else {
2511
- return {
2512
- textbox: validatorParams
2513
- };
2440
+ // Re-add the listener once the child menu closes
2441
+ this.addKeydownListener();
2442
+ this.renderer.removeClass(this.el.nativeElement, 'open-active');
2443
+ setTimeout(() => {
2444
+ this.renderer.removeClass(this.el.nativeElement, 'open');
2445
+ // Reset the nav element's height to auto
2446
+ this.renderer.setStyle(navEl, 'height', '100%');
2447
+ this.selected = null;
2448
+ }, menuAnimationSpeed);
2449
+ }
2450
+ }
2451
+ /**
2452
+ * Handle key presses to navigate the menu
2453
+ */
2454
+ keyNavigate(event) {
2455
+ var _a;
2456
+ if (this.enableKeyNav && event.target === ((_a = this.dropdownToggleButton) === null || _a === void 0 ? void 0 : _a.nativeElement)) {
2457
+ switch (event.key) {
2458
+ case 'ArrowUp':
2459
+ case 'Up':
2460
+ case 'ArrowDown':
2461
+ case 'Down':
2462
+ event.stopPropagation();
2463
+ event.preventDefault();
2464
+ this.moveHighlightedUpOrDown(event);
2465
+ break;
2466
+ case 'ArrowRight':
2467
+ case 'Right':
2468
+ event.stopPropagation();
2469
+ event.preventDefault();
2470
+ // Select the item if it has child items
2471
+ if (this.highlightedItem && this.highlightedItem.items) {
2472
+ this.selectItem(event, this.highlightedItem, true);
2473
+ }
2474
+ break;
2475
+ case 'ArrowLeft':
2476
+ case 'Left':
2477
+ event.stopPropagation();
2478
+ event.preventDefault();
2479
+ // Close the menu if it is a child menu
2480
+ if (this.parent) {
2481
+ this.back(event);
2482
+ }
2483
+ break;
2484
+ case ' ':
2485
+ case 'Spacebar':
2486
+ case 'Enter':
2487
+ // Prevent 'enter' from doing whatever it does on the currently focused element
2488
+ event.preventDefault();
2489
+ if (this.highlightedItemIndex > -1 && this.highlightedItem) {
2490
+ this.selectItem(event, this.highlightedItem, true);
2491
+ // If the header is highlighted
2492
+ }
2493
+ else if (this.highlightedItemIndex === -1) {
2494
+ // Close the menu if it's a child
2495
+ if (this.parent) {
2496
+ this.back(event);
2497
+ }
2498
+ }
2499
+ break;
2500
+ default:
2501
+ return;
2502
+ }
2514
2503
  }
2515
- };
2516
- };
2517
- const phoneNumberValidationPattern = '^\\s*(?:\\+?(\\d{1,3}))?[-. (]*(\\d{3})[-. )]*(\\d{3})[-. ]*(\\d{4})(?: *x(\\d+))?\\s*$';
2518
- const urlValidationPattern = '([A-Za-z])+(:\/\/)+[^\\s]*';
2519
- class TextboxComponent extends FormControlBase {
2520
- constructor(validationMessageService, formGroupHelper, translate) {
2521
- super(validationMessageService, formGroupHelper);
2522
- this.validationMessageService = validationMessageService;
2523
- this.formGroupHelper = formGroupHelper;
2524
- this.translate = translate;
2525
- /**
2526
- * Set the value of the input's autocomplete attribute
2527
- */
2528
- this.autocomplete = 'off';
2529
- /**
2530
- * The textbox type
2531
- */
2532
- this.type = "text";
2533
- /**
2534
- * The value of the rows attribute for a textarea. Only applies to multi-line type
2535
- */
2536
- this.rows = 3;
2537
- /**
2538
- * If set to true, we will select all text within the input if
2539
- * autofocus is also set to true
2540
- */
2541
- this.selectOnAutofocus = false;
2542
- /**
2543
- * If set to true, we will upper case on focus out
2544
- */
2545
- this.upperCase = false;
2546
- /**
2547
- * Validation pattern for the input. This is determined on the input type specified
2548
- */
2549
- this.validationPattern = '';
2550
- }
2551
- ngOnChanges(changes) {
2552
- super.ngOnChanges(changes);
2553
2504
  }
2554
2505
  /**
2555
- * The angular onInit lifecycle hook
2506
+ * Scroll to the item currently marked as 'is-selected'. Wait a tick for the
2507
+ * NgClassDirecitve or NavItemActiveDirective to respond to the model changes
2508
+ * and update the view.
2556
2509
  */
2557
- ngOnInit() {
2558
- super.ngOnInit();
2559
- this.validationPattern = '';
2560
- if (this.type === 'tel') {
2561
- this.validationPattern = phoneNumberValidationPattern;
2510
+ scrollToSelectedItem() {
2511
+ window.setTimeout(() => {
2512
+ const linkSelector = `li.is-selected`;
2513
+ this.scrollService.scrollToItem(`#${this.id}_list`, linkSelector);
2514
+ });
2515
+ }
2516
+ moveHighlightedUpOrDown(event) {
2517
+ switch (event.key) {
2518
+ case 'ArrowUp':
2519
+ case 'Up':
2520
+ if (this.highlightedItemIndex > -1) {
2521
+ this.highlightedItemIndex--;
2522
+ // Skip any in-menu heading items
2523
+ if (this.highlightedItemIndex > -1 && this.items[this.highlightedItemIndex].display === 'heading') {
2524
+ this.highlightedItemIndex--;
2525
+ }
2526
+ }
2527
+ break;
2528
+ case 'ArrowDown':
2529
+ case 'Down':
2530
+ if (this.highlightedItemIndex < this.items.length - 1) {
2531
+ this.highlightedItemIndex++;
2532
+ // Skip any in-menu heading items
2533
+ if (this.highlightedItemIndex < this.items.length - 1 && this.items[this.highlightedItemIndex].display === 'heading') {
2534
+ this.highlightedItemIndex++;
2535
+ }
2536
+ }
2537
+ break;
2538
+ default:
2539
+ return;
2562
2540
  }
2563
- else if (this.type === 'url') {
2564
- this.validationPattern = urlValidationPattern;
2541
+ if (this.highlightedItemIndex > -1) {
2542
+ // Store the item at the current highlight index
2543
+ this.highlightedItem = this.items[this.highlightedItemIndex];
2565
2544
  }
2566
- if (this.placeholder) {
2567
- this.translate.get(this.placeholder)
2568
- .subscribe((translated) => {
2569
- this.placeholder = translated;
2570
- });
2545
+ else {
2546
+ this.highlightedItem = null;
2571
2547
  }
2548
+ this.scrollToHighlightedItem();
2572
2549
  }
2573
2550
  /**
2574
- * The angular afterViewInit lifecycle hook
2551
+ * Scroll to the specified menu item.
2552
+ * If no item is provided, it will scroll to the first item.
2553
+ *
2554
+ * @param item The menu item to scroll to.
2555
+ * @memberof MenuComponent
2575
2556
  */
2576
- ngAfterViewInit() {
2577
- if (this.autofocus) {
2578
- this.setFocus(this.selectOnAutofocus);
2557
+ scrollMenu(item) {
2558
+ if (this.items.length > 0) {
2559
+ item = item ? item : this.items[0];
2560
+ let itemIndex = this.findItemIndex(item);
2561
+ if (this.id) {
2562
+ let itemSelector = item.id ? `#${item.id}` : `#${this.id}_item${itemIndex}`;
2563
+ this.scrollService.scrollItemCentered(`#${this.id}_list`, itemSelector);
2564
+ }
2579
2565
  }
2580
2566
  }
2567
+ scrollToHighlightedItem() {
2568
+ this.scrollMenu(this.highlightedItem);
2569
+ }
2581
2570
  /**
2582
- * Function to set focus on an input programmatically after the page
2583
- * had been rendered. The highlight text flag will select the text
2584
- * within the input if passed in and true
2571
+ * Find a given item's index in the filtered items array.
2572
+ *
2573
+ * Returns -1 if not found
2574
+ * @param itemToFind The matching item to find in the items array.
2575
+ * @memberof MenuComponent
2585
2576
  */
2586
- setFocus(highlightText) {
2587
- this.inputElement.nativeElement.focus();
2588
- if (highlightText) {
2589
- this.inputElement.nativeElement.select();
2577
+ findItemIndex(itemToFind) {
2578
+ if (itemToFind) {
2579
+ return this.items.findIndex(item => {
2580
+ return item.label === itemToFind.label;
2581
+ });
2582
+ }
2583
+ else {
2584
+ return -1;
2585
+ }
2586
+ }
2587
+ addKeydownListener() {
2588
+ // Only attempt to add the listener if keyboard nav is enabled
2589
+ if (this.enableKeyNav) {
2590
+ // renderer.listen adds the listener and returns a function to remove it from the renderer.
2591
+ // The listener remains active until this function is called.
2592
+ this.removeKeydownListener = this.renderer.listen('document', 'keydown', (event) => this.keyNavigate(event));
2590
2593
  }
2591
2594
  }
2592
2595
  /**
2593
- * Focus out event handler
2594
- * will upper case and trim value if upperCase is true (this is what we do on the apis)
2595
- */
2596
- focusOutEvent() {
2597
- if (this.upperCase && this.formModel.value) {
2598
- this.formModel.setValue(this.formModel.value.toUpperCase().trim());
2596
+ * Sets the menu item ids using its index if item doesn't already have one
2597
+ */
2598
+ setItemIds() {
2599
+ if (this.items) {
2600
+ this.items.forEach((item, index) => {
2601
+ item.id = item.id ? item.id : this.id + '_item' + index;
2602
+ });
2599
2603
  }
2600
2604
  }
2601
2605
  }
2602
- TextboxComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TextboxComponent, deps: [{ token: ValidationMessageService }, { token: FormGroupHelper }, { token: i2.TranslateService }], target: i0.ɵɵFactoryTarget.Component });
2603
- TextboxComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: TextboxComponent, selector: "ec-textbox", inputs: { autocomplete: "autocomplete", type: "type", placeholder: "placeholder", maxlength: "maxlength", minlength: "minlength", rows: "rows", selectOnAutofocus: "selectOnAutofocus", upperCase: "upperCase" }, viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["textboxInput"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"control control-label-{{labelPosition}}\"\r\n [ngClass]=\"{'is-readonly': readonly}\">\r\n\r\n <label *ngIf=\"label\">\r\n <span>{{label | translate}}</span>\r\n <span *ngIf=\"validationErrors.length > 0 && formModel.touched && formModel.invalid\">&nbsp;{{validationErrors |\r\n translate}}</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=\"input-wrapper control-input\">\r\n <input *ngIf=\"type !== 'multi_line'\"\r\n #textboxInput\r\n email=\"{{type === 'email' ? true : false}}\"\r\n pattern=\"{{validationPattern}}\"\r\n type=\"{{type}}\"\r\n tabindex=\"{{tabindex}}\"\r\n title=\"{{tooltip}}\"\r\n [attr.id]=\"inputId\"\r\n [attr.autocomplete]=\"autocomplete\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [attr.required]=\"required ? required : null\"\r\n [formControl]=\"formModel\"\r\n [ngClass]=\"{'is-empty': !formModel?.value, 'is-pending': pending, 'is-uppercase': upperCase}\"\r\n (focusout)=\"focusOutEvent()\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n\r\n <textarea *ngIf=\"type === 'multi_line'\"\r\n [attr.rows]=\"rows\"\r\n #textboxInput\r\n tabindex=\"{{tabindex}}\"\r\n [attr.id]=\"inputId\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [attr.required]=\"required ? required : null\"\r\n [formControl]=\"formModel\"\r\n [ngClass]=\"{'is-empty': formModel?.value === '', 'is-pending': pending}\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n </textarea>\r\n\r\n <i class=\"ec-icon icon-required\"></i>\r\n <i class=\"ec-icon icon-invalid\"></i>\r\n <i class=\"ec-icon icon-loading\"></i>\r\n </div>\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 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}:host input{background-color:var(--ec-form-control-background-color);border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);background-image:none;background-clip:padding-box;width:100%;line-height:1.25rem;padding:.3125rem .5rem;height:2rem}:host input::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}:host input::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host input::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host input:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host input:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host input~.icon-required,:host input~.icon-invalid{color:var(--ec-form-control-border-color-invalid)}:host input:required.is-empty{background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host input:required.is-empty~.icon-required{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.ng-invalid.ng-touched{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 input.ng-invalid.ng-touched:focus{border-color:var(--ec-form-control-background-color-invalid)}:host input.ng-invalid.ng-touched~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.ng-invalid.ng-touched~.icon-required{display:none}:host input.is-pending.ng-valid,:host input.is-pending.ng-invalid,:host input.is-pending.ng-pending{background-image:\"\";background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem}:host input.is-pending.ng-valid~.icon-loading,:host input.is-pending.ng-invalid~.icon-loading,:host input.is-pending.ng-pending~.icon-loading{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.is-pending.ng-valid~.icon-required,:host input.is-pending.ng-valid~.icon-invalid,:host input.is-pending.ng-invalid~.icon-required,:host input.is-pending.ng-invalid~.icon-invalid,:host input.is-pending.ng-pending~.icon-required,:host input.is-pending.ng-pending~.icon-invalid{display:none}:host input:focus,:host input:focus.is-empty{border-color:var(--ec-form-control-border-color-focus);box-shadow:var(--ec-form-control-box-shadow-focus);position:relative;z-index:1}:host input:disabled{background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}:host input:disabled:required,:host input:disabled:required.is-empty{background-image:none;padding-left:.5rem;background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled)}:host input:disabled:required+.icon-required,:host input:disabled:required.is-empty+.icon-required{display:none}:host input.is-uppercase:not(.is-empty){text-transform:uppercase}:host textarea{background-color:var(--ec-form-control-background-color);border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);background-image:none;background-clip:padding-box;width:100%;line-height:1.25rem;padding:.3125rem .5rem;height:auto;resize:none;display:block}:host textarea::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}:host textarea::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host textarea::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host textarea:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host textarea:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host textarea~.icon-required,:host textarea~.icon-invalid{color:var(--ec-form-control-border-color-invalid)}:host textarea:required.is-empty{background-repeat:no-repeat;background-position:.5rem .5rem;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host textarea:required.is-empty~.icon-required{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.ng-invalid.ng-touched{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 .5rem;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host textarea.ng-invalid.ng-touched:focus{border-color:var(--ec-form-control-background-color-invalid)}:host textarea.ng-invalid.ng-touched~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.ng-invalid.ng-touched~.icon-required{display:none}:host textarea.is-pending.ng-valid,:host textarea.is-pending.ng-invalid,:host textarea.is-pending.ng-pending{background-image:\"\";background-repeat:no-repeat;background-position:.5rem .5rem;background-size:1rem,1rem;padding-left:1.75rem}:host textarea.is-pending.ng-valid~.icon-loading,:host textarea.is-pending.ng-invalid~.icon-loading,:host textarea.is-pending.ng-pending~.icon-loading{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.is-pending.ng-valid~.icon-required,:host textarea.is-pending.ng-valid~.icon-invalid,:host textarea.is-pending.ng-invalid~.icon-required,:host textarea.is-pending.ng-invalid~.icon-invalid,:host textarea.is-pending.ng-pending~.icon-required,:host textarea.is-pending.ng-pending~.icon-invalid{display:none}:host textarea:focus,:host textarea:focus.is-empty{border-color:var(--ec-form-control-border-color-focus);box-shadow:var(--ec-form-control-box-shadow-focus);position:relative;z-index:1}:host textarea:disabled{background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}:host textarea:disabled:required,:host textarea:disabled:required.is-empty{background-image:none;padding-left:.5rem;background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled)}:host textarea:disabled:required+.icon-required,:host textarea:disabled:required.is-empty+.icon-required{display:none}:host textarea.is-uppercase:not(.is-empty){text-transform:uppercase}.input-wrapper{position:relative}.input-wrapper>.ec-icon{display:none}:host(.textbox-group-input:not(:last-child)){flex:1 1 0%;width:1px}:host(.textbox-group-input:not(:last-child)) .control{margin-bottom:0}:host(.textbox-group-input:not(:last-child)) .control.is-readonly input{border-right-width:1px}:host(.textbox-group-input:not(:last-child)) input{border-top-right-radius:0;border-bottom-right-radius:0;border-right-width:0}:host(.textbox-group-input:not(:last-child)) input:focus{position:relative;z-index:1;border-right-width:1px}:host(.text-truncate) input{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host(.is-monospace) input,:host(.is-monospace) textarea,:host-context(.is-monospace) input,:host-context(.is-monospace) textarea{font-family:var(--ec-font-family-monospace)}\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.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.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i4.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i4.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i4.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i4.EmailValidator, selector: "[email][formControlName],[email][formControl],[email][ngModel]", inputs: ["email"] }, { 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: i2.TranslatePipe, name: "translate" }] });
2604
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TextboxComponent, decorators: [{
2606
+ MenuComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MenuComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: WindowService }, { token: ScrollService }], target: i0.ɵɵFactoryTarget.Component });
2607
+ MenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: MenuComponent, selector: "ec-menu", inputs: { id: "id", items: "items", selected: "selected", parent: "parent", templateType: "templateType", customMenuTemplate: "customMenuTemplate", title: "title", showNoItems: "showNoItems", noDataText: "noDataText", enableKeyNav: "enableKeyNav", highlightedItem: "highlightedItem", maintainSelectedItem: "maintainSelectedItem", truncateItems: "truncateItems", preserveIconSpace: "preserveIconSpace", dropdownToggleButton: "dropdownToggleButton" }, outputs: { selectedChanged: "selectedChanged", menuClosed: "menuClosed" }, host: { properties: { "attr.id": "this.attrId" } }, viewQueries: [{ propertyName: "labelTemplate", first: true, predicate: ["label"], descendants: true, static: true }, { propertyName: "iconAndLabelTemplate", first: true, predicate: ["iconAndLabel"], descendants: true, static: true }, { propertyName: "checkAndLabelTemplate", first: true, predicate: ["checkAndLabel"], descendants: true, static: true }, { propertyName: "iconLabelCaptionTemplate", first: true, predicate: ["iconLabelCaption"], descendants: true, static: true }], ngImport: i0, template: "<nav>\r\n <div class=\"parent\"\r\n [class.no-data]=\"showNoItems && (!items || items.length === 0)\">\r\n <header id=\"{{id}}_header\"\r\n class=\"text-heading-3 p-1\"\r\n [class.is-selected]=\"highlightedItemIndex === -1\"\r\n *ngIf=\"parent\"\r\n (click)=\"back($event)\">\r\n <div class=\"item-wrapper\">\r\n <i class=\"ec-icon icon-angle-down rotate-90 flex-shrink\"></i>\r\n <span class=\"label text-truncate flex-grow\">{{parent?.label}}</span>\r\n </div>\r\n </header>\r\n\r\n <ul id=\"{{id}}_list\"\r\n class=\"py-1\">\r\n <li *ngFor=\"let item of items; index as i\"\r\n id=\"{{item.id || id + '_item' + i}}\"\r\n class=\"{{item.display || 'item'}} {{item.classList}}\"\r\n [attr.disabled]=\"item.disabled\"\r\n [hidden]=\"item.hidden\"\r\n ecNavItemActive=\"is-selected\"\r\n [ecNavItemActiveQueryParams]=\"item.queryParams\"\r\n [ecNavItemActiveUrl]=\"item.url\"\r\n [ecNavItemActiveExactMatch]='item.isActiveExactMatch'\r\n (routerLinkActivated)=\"selectItem($event, item)\"\r\n [ngClass]=\"{'is-highlighted':(selected === item && item?.display !== 'heading') || highlightedItem === item, 'is-link': item.url, 'is-disabled': item.disabled, 'is-readonly': item.readonly, 'is-checked': item.checked, 'text-heading-3': item?.display === 'heading'}\"\r\n (click)=\"selectItem($event, item)\">\r\n\r\n <a *ngIf=\"item.url && !item.externalLink\"\r\n id=\"{{item.id}}_link\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\"\r\n [routerLink]=\"item.url\"\r\n [queryParams]=\"item.queryParams || null\"\r\n target=\"{{item.target || '_self'}}\">\r\n\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </a>\r\n\r\n <a *ngIf=\"item.url && item.externalLink\"\r\n id=\"{{item.id}}_link\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\"\r\n href=\"{{item.url}}\"\r\n target=\"{{item.target || '_self'}}\">\r\n\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </a>\r\n\r\n <div *ngIf=\"!item.url\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\">\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </div>\r\n </li>\r\n </ul>\r\n\r\n <p class=\"no-data-message\">{{noDataText | translate}}</p>\r\n </div>\r\n\r\n <!-- Child menu (Rendered to the right) -->\r\n <ec-menu *ngIf=\"selected?.items\"\r\n id=\"{{id}}_child\"\r\n class=\"child\"\r\n [parent]=\"selected\"\r\n [items]=\"selected?.items\"\r\n [showNoItems]=\"true\"\r\n [templateType]=\"templateType\"\r\n [enableKeyNav]=\"true\"\r\n [truncateItems]=\"truncateItems\"\r\n (selectedChanged)=\"onSelection($event)\"\r\n (menuClosed)=\"toggleChildMenu(false)\">\r\n </ec-menu>\r\n</nav>\r\n\r\n<!-- 'label' Item Template -->\r\n<ng-template #label\r\n let-item>\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items\"></i>\r\n</ng-template>\r\n\r\n<!-- 'checkAndLabel' Item Template -->\r\n<ng-template #checkAndLabel\r\n let-item>\r\n\r\n <i class=\"ec-icon icon-check ec-icon-sm\"\r\n *ngIf=\"item.display !== 'heading'\"></i>\r\n\r\n <i class=\"ec-icon {{item.icon}} ml-2\"\r\n *ngIf=\"item.icon\"></i>\r\n\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items\"></i>\r\n</ng-template>\r\n\r\n<!-- 'iconAndLabel' Item Template -->\r\n<ng-template #iconAndLabel\r\n let-item>\r\n <!-- If menuItem.icon exists and is not blank, show the icon in the menu -->\r\n <i class=\"ec-icon {{item.icon}}\"\r\n *ngIf=\"(item.icon && item.icon !== '') || preserveIconSpace\"></i>\r\n\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items\"></i>\r\n</ng-template>\r\n\r\n<ng-template #iconLabelCaption\r\n let-item>\r\n <i class=\"ec-icon {{item.icon}}\"\r\n *ngIf=\"(item.icon && item.icon !== '') || preserveIconSpace\"></i>\r\n <div *ngIf=\"item.display !== 'heading'\"\r\n class=\"label flex-grow\">\r\n <div id=\"{{item.id}}_label\"\r\n class=\"text-body-1\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</div>\r\n <div id=\"{{item.id}}_caption\"\r\n *ngIf=\"item.caption\"\r\n class=\"text-caption-1\"\r\n [class.text-truncate]=\"truncateItems\">{{item.caption}}</div>\r\n </div>\r\n <h3 *ngIf=\"item.display === 'heading'\"\r\n class=\"flex-grow text-heading-3 align-self-center\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</h3>\r\n <i class=\"ec-icon icon-angle-down rotate-270 align-self-center\"\r\n *ngIf=\"item?.items\"></i>\r\n</ng-template>", styles: ["@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(1turn)}}:host{display:block;font-size:var(--ec-menu-font-size, var(--ec-font-size-action));font-weight:400;background-color:var(--ec-menu-background-color, var(--ec-background-color))}:host.open>nav>.parent,:host.open>nav>.child{position:absolute;left:0;top:0;right:0;height:100%;transition:transform .25s ease}:host.open>nav>.parent{transform:translate(0)}:host.open>nav>.child{transform:translate(100%)}:host.open-active>nav>.parent{transform:translate(-100%)}:host.open-active>nav>.child{transform:translate(0)}:host(.bg-transparent){background-color:transparent}:host-context(.is-always-open){height:100%}:host-context(.is-always-open) .item-wrapper{padding-left:1rem;padding-right:1rem}nav{display:flex;position:relative;height:100%;overflow:hidden}.parent{display:flex;flex-direction:column;flex:auto;position:relative;max-width:100%}.parent>header{cursor:pointer}.parent>header.is-selected .item-wrapper,.parent>header.is-highlighted .item-wrapper{background-color:var(--ec-background-color-selected)}.parent>header:hover .item-wrapper{background-color:var(--ec-background-color-hover)}.parent.no-data ul{display:none}.parent.no-data .no-data-message{display:block}ul{padding:0;margin:0;list-style:none;flex:auto;height:100%;overflow-y:auto}ul li{cursor:pointer;padding:0 .25rem}ul li a{color:inherit;border-bottom:0;text-decoration:none}ul li.is-selected .item-wrapper,ul li.is-highlighted .item-wrapper{background-color:var(--ec-background-color-selected)}ul li:hover .item-wrapper{background-color:var(--ec-background-color-hover)}ul li:focus .item-wrapper{outline:none;background-color:var(--ec-color-disabled-dark);position:relative;z-index:1}ul li.is-disabled .item-wrapper{color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled)}ul li.is-disabled,ul li.is-readonly{cursor:default}ul li.is-disabled .item-wrapper,ul li.is-readonly .item-wrapper{background-color:transparent;color:inherit}ul li.is-checked .icon-check{opacity:1}ul li.heading{cursor:default}ul li.heading .item-wrapper{background-color:transparent}ul li.heading:not(:first-child){margin-top:.5rem}ul li.divider{border-bottom:1px solid var(--ec-border-color);padding-bottom:.25rem;margin-bottom:.25rem}ul li.indent-1 .item-wrapper{padding-left:1.5rem}ul li.indent-2 .item-wrapper{padding-left:2.5rem}ul li.indent-3 .item-wrapper{padding-left:3.5rem}.item-wrapper{cursor:inherit;line-height:1.25rem;min-height:1.75rem;padding:.25rem .5rem;border-radius:var(--ec-border-radius);display:flex;color:inherit}.item-wrapper .label{margin-right:auto}.item-wrapper .label+.ec-icon{margin-left:.5rem}.item-wrapper .ec-icon{margin-top:calc((1.25rem - var(--ec-font-size-icon)) / 2);flex:none}.item-wrapper .ec-icon+.label{margin-left:.5rem}.item-wrapper .ec-icon-sm{margin-top:calc((1.25rem - calc(var(--ec-font-size-icon) * .75)) / 2)}.item-wrapper .icon-check{opacity:0}.no-data-message{display:none;text-align:center;padding:1rem;color:var(--ec-color-hint-dark);margin-bottom:0;font-size:var(--ec-font-size-body)}:host-context(ec-tree) ul{overflow-x:hidden}:host-context(ec-tree) li.is-selected,:host-context(ec-tree) li.is-highlighted{font-weight:700;color:var(--ec-menu-color-highlighted, inherit)}:host-context(ec-tree) li.is-selected:not(:hover),:host-context(ec-tree) li.is-highlighted:not(:hover){background-color:transparent}\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", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: NavItemActiveDirective, selector: "[ecNavItemActive]", inputs: ["ecNavItemActive", "ecNavItemActiveExactMatch", "ecNavItemActiveQueryParams", "ecNavItemActiveUrl"], outputs: ["routerLinkActivated"] }, { kind: "component", type: MenuComponent, selector: "ec-menu", inputs: ["id", "items", "selected", "parent", "templateType", "customMenuTemplate", "title", "showNoItems", "noDataText", "enableKeyNav", "highlightedItem", "maintainSelectedItem", "truncateItems", "preserveIconSpace", "dropdownToggleButton"], outputs: ["selectedChanged", "menuClosed"] }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] });
2608
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MenuComponent, decorators: [{
2605
2609
  type: Component,
2606
- args: [{ selector: 'ec-textbox', template: "<div class=\"control control-label-{{labelPosition}}\"\r\n [ngClass]=\"{'is-readonly': readonly}\">\r\n\r\n <label *ngIf=\"label\">\r\n <span>{{label | translate}}</span>\r\n <span *ngIf=\"validationErrors.length > 0 && formModel.touched && formModel.invalid\">&nbsp;{{validationErrors |\r\n translate}}</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=\"input-wrapper control-input\">\r\n <input *ngIf=\"type !== 'multi_line'\"\r\n #textboxInput\r\n email=\"{{type === 'email' ? true : false}}\"\r\n pattern=\"{{validationPattern}}\"\r\n type=\"{{type}}\"\r\n tabindex=\"{{tabindex}}\"\r\n title=\"{{tooltip}}\"\r\n [attr.id]=\"inputId\"\r\n [attr.autocomplete]=\"autocomplete\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [attr.required]=\"required ? required : null\"\r\n [formControl]=\"formModel\"\r\n [ngClass]=\"{'is-empty': !formModel?.value, 'is-pending': pending, 'is-uppercase': upperCase}\"\r\n (focusout)=\"focusOutEvent()\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n\r\n <textarea *ngIf=\"type === 'multi_line'\"\r\n [attr.rows]=\"rows\"\r\n #textboxInput\r\n tabindex=\"{{tabindex}}\"\r\n [attr.id]=\"inputId\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.maxlength]=\"maxlength\"\r\n [attr.minlength]=\"minlength\"\r\n [attr.required]=\"required ? required : null\"\r\n [formControl]=\"formModel\"\r\n [ngClass]=\"{'is-empty': formModel?.value === '', 'is-pending': pending}\"\r\n [attr.cdkFocusInitial]=\"autofocus || null\">\r\n </textarea>\r\n\r\n <i class=\"ec-icon icon-required\"></i>\r\n <i class=\"ec-icon icon-invalid\"></i>\r\n <i class=\"ec-icon icon-loading\"></i>\r\n </div>\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 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}:host input{background-color:var(--ec-form-control-background-color);border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);background-image:none;background-clip:padding-box;width:100%;line-height:1.25rem;padding:.3125rem .5rem;height:2rem}:host input::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}:host input::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host input::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host input:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host input:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host input~.icon-required,:host input~.icon-invalid{color:var(--ec-form-control-border-color-invalid)}:host input:required.is-empty{background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host input:required.is-empty~.icon-required{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.ng-invalid.ng-touched{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 input.ng-invalid.ng-touched:focus{border-color:var(--ec-form-control-background-color-invalid)}:host input.ng-invalid.ng-touched~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.ng-invalid.ng-touched~.icon-required{display:none}:host input.is-pending.ng-valid,:host input.is-pending.ng-invalid,:host input.is-pending.ng-pending{background-image:\"\";background-repeat:no-repeat;background-position:.5rem center;background-size:1rem,1rem;padding-left:1.75rem}:host input.is-pending.ng-valid~.icon-loading,:host input.is-pending.ng-invalid~.icon-loading,:host input.is-pending.ng-pending~.icon-loading{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host input.is-pending.ng-valid~.icon-required,:host input.is-pending.ng-valid~.icon-invalid,:host input.is-pending.ng-invalid~.icon-required,:host input.is-pending.ng-invalid~.icon-invalid,:host input.is-pending.ng-pending~.icon-required,:host input.is-pending.ng-pending~.icon-invalid{display:none}:host input:focus,:host input:focus.is-empty{border-color:var(--ec-form-control-border-color-focus);box-shadow:var(--ec-form-control-box-shadow-focus);position:relative;z-index:1}:host input:disabled{background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}:host input:disabled:required,:host input:disabled:required.is-empty{background-image:none;padding-left:.5rem;background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled)}:host input:disabled:required+.icon-required,:host input:disabled:required.is-empty+.icon-required{display:none}:host input.is-uppercase:not(.is-empty){text-transform:uppercase}:host textarea{background-color:var(--ec-form-control-background-color);border:1px solid var(--ec-form-control-border-color);border-radius:var(--ec-border-radius);background-image:none;background-clip:padding-box;width:100%;line-height:1.25rem;padding:.3125rem .5rem;height:auto;resize:none;display:block}:host textarea::selection{background-color:var(--ec-form-control-background-color-selection);color:var(--ec-form-control-color-selection)}:host textarea::-webkit-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host textarea::-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host textarea:-ms-input-placeholder{color:var(--ec-form-control-color-placeholder)}:host textarea:-moz-placeholder{color:var(--ec-form-control-color-placeholder);opacity:1}:host textarea~.icon-required,:host textarea~.icon-invalid{color:var(--ec-form-control-border-color-invalid)}:host textarea:required.is-empty{background-repeat:no-repeat;background-position:.5rem .5rem;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host textarea:required.is-empty~.icon-required{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.ng-invalid.ng-touched{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 .5rem;background-size:1rem,1rem;padding-left:1.75rem;background-image:none}:host textarea.ng-invalid.ng-touched:focus{border-color:var(--ec-form-control-background-color-invalid)}:host textarea.ng-invalid.ng-touched~.icon-invalid{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.ng-invalid.ng-touched~.icon-required{display:none}:host textarea.is-pending.ng-valid,:host textarea.is-pending.ng-invalid,:host textarea.is-pending.ng-pending{background-image:\"\";background-repeat:no-repeat;background-position:.5rem .5rem;background-size:1rem,1rem;padding-left:1.75rem}:host textarea.is-pending.ng-valid~.icon-loading,:host textarea.is-pending.ng-invalid~.icon-loading,:host textarea.is-pending.ng-pending~.icon-loading{display:inline-flex;position:absolute;left:.5rem;top:.5rem;z-index:1}:host textarea.is-pending.ng-valid~.icon-required,:host textarea.is-pending.ng-valid~.icon-invalid,:host textarea.is-pending.ng-invalid~.icon-required,:host textarea.is-pending.ng-invalid~.icon-invalid,:host textarea.is-pending.ng-pending~.icon-required,:host textarea.is-pending.ng-pending~.icon-invalid{display:none}:host textarea:focus,:host textarea:focus.is-empty{border-color:var(--ec-form-control-border-color-focus);box-shadow:var(--ec-form-control-box-shadow-focus);position:relative;z-index:1}:host textarea:disabled{background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled);color:var(--ec-form-control-color-disabled);opacity:var(--ec-form-control-opacity-disabled)}:host textarea:disabled:required,:host textarea:disabled:required.is-empty{background-image:none;padding-left:.5rem;background-color:var(--ec-form-control-background-color-disabled);border-color:var(--ec-form-control-border-color-disabled)}:host textarea:disabled:required+.icon-required,:host textarea:disabled:required.is-empty+.icon-required{display:none}:host textarea.is-uppercase:not(.is-empty){text-transform:uppercase}.input-wrapper{position:relative}.input-wrapper>.ec-icon{display:none}:host(.textbox-group-input:not(:last-child)){flex:1 1 0%;width:1px}:host(.textbox-group-input:not(:last-child)) .control{margin-bottom:0}:host(.textbox-group-input:not(:last-child)) .control.is-readonly input{border-right-width:1px}:host(.textbox-group-input:not(:last-child)) input{border-top-right-radius:0;border-bottom-right-radius:0;border-right-width:0}:host(.textbox-group-input:not(:last-child)) input:focus{position:relative;z-index:1;border-right-width:1px}:host(.text-truncate) input{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host(.is-monospace) input,:host(.is-monospace) textarea,:host-context(.is-monospace) input,:host-context(.is-monospace) textarea{font-family:var(--ec-font-family-monospace)}\n"] }]
2607
- }], ctorParameters: function () { return [{ type: ValidationMessageService }, { type: FormGroupHelper }, { type: i2.TranslateService }]; }, propDecorators: { autocomplete: [{
2610
+ args: [{ selector: 'ec-menu', template: "<nav>\r\n <div class=\"parent\"\r\n [class.no-data]=\"showNoItems && (!items || items.length === 0)\">\r\n <header id=\"{{id}}_header\"\r\n class=\"text-heading-3 p-1\"\r\n [class.is-selected]=\"highlightedItemIndex === -1\"\r\n *ngIf=\"parent\"\r\n (click)=\"back($event)\">\r\n <div class=\"item-wrapper\">\r\n <i class=\"ec-icon icon-angle-down rotate-90 flex-shrink\"></i>\r\n <span class=\"label text-truncate flex-grow\">{{parent?.label}}</span>\r\n </div>\r\n </header>\r\n\r\n <ul id=\"{{id}}_list\"\r\n class=\"py-1\">\r\n <li *ngFor=\"let item of items; index as i\"\r\n id=\"{{item.id || id + '_item' + i}}\"\r\n class=\"{{item.display || 'item'}} {{item.classList}}\"\r\n [attr.disabled]=\"item.disabled\"\r\n [hidden]=\"item.hidden\"\r\n ecNavItemActive=\"is-selected\"\r\n [ecNavItemActiveQueryParams]=\"item.queryParams\"\r\n [ecNavItemActiveUrl]=\"item.url\"\r\n [ecNavItemActiveExactMatch]='item.isActiveExactMatch'\r\n (routerLinkActivated)=\"selectItem($event, item)\"\r\n [ngClass]=\"{'is-highlighted':(selected === item && item?.display !== 'heading') || highlightedItem === item, 'is-link': item.url, 'is-disabled': item.disabled, 'is-readonly': item.readonly, 'is-checked': item.checked, 'text-heading-3': item?.display === 'heading'}\"\r\n (click)=\"selectItem($event, item)\">\r\n\r\n <a *ngIf=\"item.url && !item.externalLink\"\r\n id=\"{{item.id}}_link\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\"\r\n [routerLink]=\"item.url\"\r\n [queryParams]=\"item.queryParams || null\"\r\n target=\"{{item.target || '_self'}}\">\r\n\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </a>\r\n\r\n <a *ngIf=\"item.url && item.externalLink\"\r\n id=\"{{item.id}}_link\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\"\r\n href=\"{{item.url}}\"\r\n target=\"{{item.target || '_self'}}\">\r\n\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </a>\r\n\r\n <div *ngIf=\"!item.url\"\r\n title=\"{{truncateItems ? item.label : ''}}\"\r\n class=\"item-wrapper\">\r\n <ng-container *ngTemplateOutlet=\"internalizedTemplate; context: {$implicit: item}\"></ng-container>\r\n </div>\r\n </li>\r\n </ul>\r\n\r\n <p class=\"no-data-message\">{{noDataText | translate}}</p>\r\n </div>\r\n\r\n <!-- Child menu (Rendered to the right) -->\r\n <ec-menu *ngIf=\"selected?.items\"\r\n id=\"{{id}}_child\"\r\n class=\"child\"\r\n [parent]=\"selected\"\r\n [items]=\"selected?.items\"\r\n [showNoItems]=\"true\"\r\n [templateType]=\"templateType\"\r\n [enableKeyNav]=\"true\"\r\n [truncateItems]=\"truncateItems\"\r\n (selectedChanged)=\"onSelection($event)\"\r\n (menuClosed)=\"toggleChildMenu(false)\">\r\n </ec-menu>\r\n</nav>\r\n\r\n<!-- 'label' Item Template -->\r\n<ng-template #label\r\n let-item>\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items\"></i>\r\n</ng-template>\r\n\r\n<!-- 'checkAndLabel' Item Template -->\r\n<ng-template #checkAndLabel\r\n let-item>\r\n\r\n <i class=\"ec-icon icon-check ec-icon-sm\"\r\n *ngIf=\"item.display !== 'heading'\"></i>\r\n\r\n <i class=\"ec-icon {{item.icon}} ml-2\"\r\n *ngIf=\"item.icon\"></i>\r\n\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items\"></i>\r\n</ng-template>\r\n\r\n<!-- 'iconAndLabel' Item Template -->\r\n<ng-template #iconAndLabel\r\n let-item>\r\n <!-- If menuItem.icon exists and is not blank, show the icon in the menu -->\r\n <i class=\"ec-icon {{item.icon}}\"\r\n *ngIf=\"(item.icon && item.icon !== '') || preserveIconSpace\"></i>\r\n\r\n <span id=\"{{item.id}}_label\"\r\n class=\"label\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</span>\r\n\r\n <i class=\"ec-icon icon-angle-down rotate-270\"\r\n *ngIf=\"item?.items\"></i>\r\n</ng-template>\r\n\r\n<ng-template #iconLabelCaption\r\n let-item>\r\n <i class=\"ec-icon {{item.icon}}\"\r\n *ngIf=\"(item.icon && item.icon !== '') || preserveIconSpace\"></i>\r\n <div *ngIf=\"item.display !== 'heading'\"\r\n class=\"label flex-grow\">\r\n <div id=\"{{item.id}}_label\"\r\n class=\"text-body-1\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</div>\r\n <div id=\"{{item.id}}_caption\"\r\n *ngIf=\"item.caption\"\r\n class=\"text-caption-1\"\r\n [class.text-truncate]=\"truncateItems\">{{item.caption}}</div>\r\n </div>\r\n <h3 *ngIf=\"item.display === 'heading'\"\r\n class=\"flex-grow text-heading-3 align-self-center\"\r\n [class.text-truncate]=\"truncateItems\">{{item.label}}</h3>\r\n <i class=\"ec-icon icon-angle-down rotate-270 align-self-center\"\r\n *ngIf=\"item?.items\"></i>\r\n</ng-template>", styles: ["@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(1turn)}}:host{display:block;font-size:var(--ec-menu-font-size, var(--ec-font-size-action));font-weight:400;background-color:var(--ec-menu-background-color, var(--ec-background-color))}:host.open>nav>.parent,:host.open>nav>.child{position:absolute;left:0;top:0;right:0;height:100%;transition:transform .25s ease}:host.open>nav>.parent{transform:translate(0)}:host.open>nav>.child{transform:translate(100%)}:host.open-active>nav>.parent{transform:translate(-100%)}:host.open-active>nav>.child{transform:translate(0)}:host(.bg-transparent){background-color:transparent}:host-context(.is-always-open){height:100%}:host-context(.is-always-open) .item-wrapper{padding-left:1rem;padding-right:1rem}nav{display:flex;position:relative;height:100%;overflow:hidden}.parent{display:flex;flex-direction:column;flex:auto;position:relative;max-width:100%}.parent>header{cursor:pointer}.parent>header.is-selected .item-wrapper,.parent>header.is-highlighted .item-wrapper{background-color:var(--ec-background-color-selected)}.parent>header:hover .item-wrapper{background-color:var(--ec-background-color-hover)}.parent.no-data ul{display:none}.parent.no-data .no-data-message{display:block}ul{padding:0;margin:0;list-style:none;flex:auto;height:100%;overflow-y:auto}ul li{cursor:pointer;padding:0 .25rem}ul li a{color:inherit;border-bottom:0;text-decoration:none}ul li.is-selected .item-wrapper,ul li.is-highlighted .item-wrapper{background-color:var(--ec-background-color-selected)}ul li:hover .item-wrapper{background-color:var(--ec-background-color-hover)}ul li:focus .item-wrapper{outline:none;background-color:var(--ec-color-disabled-dark);position:relative;z-index:1}ul li.is-disabled .item-wrapper{color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled)}ul li.is-disabled,ul li.is-readonly{cursor:default}ul li.is-disabled .item-wrapper,ul li.is-readonly .item-wrapper{background-color:transparent;color:inherit}ul li.is-checked .icon-check{opacity:1}ul li.heading{cursor:default}ul li.heading .item-wrapper{background-color:transparent}ul li.heading:not(:first-child){margin-top:.5rem}ul li.divider{border-bottom:1px solid var(--ec-border-color);padding-bottom:.25rem;margin-bottom:.25rem}ul li.indent-1 .item-wrapper{padding-left:1.5rem}ul li.indent-2 .item-wrapper{padding-left:2.5rem}ul li.indent-3 .item-wrapper{padding-left:3.5rem}.item-wrapper{cursor:inherit;line-height:1.25rem;min-height:1.75rem;padding:.25rem .5rem;border-radius:var(--ec-border-radius);display:flex;color:inherit}.item-wrapper .label{margin-right:auto}.item-wrapper .label+.ec-icon{margin-left:.5rem}.item-wrapper .ec-icon{margin-top:calc((1.25rem - var(--ec-font-size-icon)) / 2);flex:none}.item-wrapper .ec-icon+.label{margin-left:.5rem}.item-wrapper .ec-icon-sm{margin-top:calc((1.25rem - calc(var(--ec-font-size-icon) * .75)) / 2)}.item-wrapper .icon-check{opacity:0}.no-data-message{display:none;text-align:center;padding:1rem;color:var(--ec-color-hint-dark);margin-bottom:0;font-size:var(--ec-font-size-body)}:host-context(ec-tree) ul{overflow-x:hidden}:host-context(ec-tree) li.is-selected,:host-context(ec-tree) li.is-highlighted{font-weight:700;color:var(--ec-menu-color-highlighted, inherit)}:host-context(ec-tree) li.is-selected:not(:hover),:host-context(ec-tree) li.is-highlighted:not(:hover){background-color:transparent}\n"] }]
2611
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: WindowService }, { type: ScrollService }]; }, propDecorators: { id: [{
2608
2612
  type: Input
2609
- }], type: [{
2613
+ }], attrId: [{
2614
+ type: HostBinding,
2615
+ args: ['attr.id']
2616
+ }], items: [{
2610
2617
  type: Input
2611
- }], placeholder: [{
2618
+ }], selected: [{
2612
2619
  type: Input
2613
- }], maxlength: [{
2620
+ }], parent: [{
2614
2621
  type: Input
2615
- }], minlength: [{
2622
+ }], templateType: [{
2616
2623
  type: Input
2617
- }], rows: [{
2624
+ }], customMenuTemplate: [{
2618
2625
  type: Input
2619
- }], selectOnAutofocus: [{
2626
+ }], title: [{
2620
2627
  type: Input
2621
- }], upperCase: [{
2628
+ }], showNoItems: [{
2622
2629
  type: Input
2623
- }], inputElement: [{
2624
- type: ViewChild,
2625
- args: ['textboxInput']
2626
- }] } });
2627
-
2628
- /** Exposes the markup and styles that represent the spinner. No inputs or outputs defined because it is just a visual component*/
2629
- class SpinnerComponent {
2630
- }
2631
- SpinnerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2632
- SpinnerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: SpinnerComponent, selector: "ec-spinner", ngImport: i0, template: "<div class=\"spinner\">\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n</div>", styles: ["@keyframes sk-bouncedelay{0%,80%,to{opacity:0}40%{opacity:1}}.spinner{display:flex}.spinner-dot{width:.75rem;height:.75rem;background-color:var(--ec-color-interactive);animation:sk-bouncedelay 1.7s infinite ease-in-out both;margin-right:.25rem}.spinner-dot:nth-child(1){animation-delay:-.6s}.spinner-dot:nth-child(2){animation-delay:-.4s}.spinner-dot:nth-child(3){animation-delay:-.2s}:host(.spinner-small) .spinner-dot{width:.5rem;height:.5rem;background-color:var(--ec-color-interactive);animation:sk-bouncedelay 1.7s infinite ease-in-out both;margin-right:.1666666667rem}:host(.spinner-small) .spinner-dot:nth-child(1){animation-delay:-.6s}:host(.spinner-small) .spinner-dot:nth-child(2){animation-delay:-.4s}:host(.spinner-small) .spinner-dot:nth-child(3){animation-delay:-.2s}\n"] });
2633
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SpinnerComponent, decorators: [{
2634
- type: Component,
2635
- args: [{ selector: 'ec-spinner', template: "<div class=\"spinner\">\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n <span class=\"spinner-dot\"></span>\r\n</div>", styles: ["@keyframes sk-bouncedelay{0%,80%,to{opacity:0}40%{opacity:1}}.spinner{display:flex}.spinner-dot{width:.75rem;height:.75rem;background-color:var(--ec-color-interactive);animation:sk-bouncedelay 1.7s infinite ease-in-out both;margin-right:.25rem}.spinner-dot:nth-child(1){animation-delay:-.6s}.spinner-dot:nth-child(2){animation-delay:-.4s}.spinner-dot:nth-child(3){animation-delay:-.2s}:host(.spinner-small) .spinner-dot{width:.5rem;height:.5rem;background-color:var(--ec-color-interactive);animation:sk-bouncedelay 1.7s infinite ease-in-out both;margin-right:.1666666667rem}:host(.spinner-small) .spinner-dot:nth-child(1){animation-delay:-.6s}:host(.spinner-small) .spinner-dot:nth-child(2){animation-delay:-.4s}:host(.spinner-small) .spinner-dot:nth-child(3){animation-delay:-.2s}\n"] }]
2636
- }] });
2637
-
2638
- class Overlay {
2639
- constructor(status, message) {
2640
- this.status = 'hasData';
2641
- this.message = '';
2642
- this.setStatus(status, message);
2643
- }
2644
- setStatus(status, message, action, noDataTemplate, overlayClassList) {
2645
- this.status = status;
2646
- this.message = message || '';
2647
- this.action = action || undefined;
2648
- this.noDataTemplate = noDataTemplate || undefined;
2649
- this.overlayClassList = overlayClassList || '';
2650
- }
2651
- }
2652
- /**
2653
- * Wraps content in order to show pending, error, and no data states with an optional message/noDataTemplate
2654
- */
2655
- class ViewOverlayComponent {
2656
- constructor() {
2657
- this.status = 'hasData';
2658
- }
2659
- setStatus(status, message, action, noDataTemplate) {
2660
- this.status = status;
2661
- this.message = message || '';
2662
- this.action = action || undefined;
2663
- this.noDataTemplate = noDataTemplate || undefined;
2664
- }
2665
- actionClicked(event) {
2666
- if (this.action && this.action.onClick) {
2667
- this.action.onClick(event);
2668
- }
2669
- }
2670
- }
2671
- ViewOverlayComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ViewOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2672
- ViewOverlayComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: ViewOverlayComponent, selector: "[ecOverlay]", inputs: { status: "status", message: "message", action: "action", noDataTemplate: "noDataTemplate", displayAsMask: "displayAsMask", overlayClassList: "overlayClassList" }, ngImport: i0, template: "<!-- Transcluded Content -->\r\n<ng-content *ngIf=\"displayAsMask || (!displayAsMask && status === 'hasData')\"></ng-content>\r\n<!--Used by GI tests to know the overlay status whether we use ngIf or mask version. No visual impact-->\r\n<span [hidden]=\"true\"\r\n\t class=\"overlay-status-{{status}}\"></span>\r\n<!-- Overlay goes last so it is rendered on top of preceding content due to source order -->\r\n<div *ngIf=\"status !== 'hasData'\"\r\n\t class=\"overlay flex-grow {{overlayClassList}}\"\r\n\t [ngClass]=\"{'not-mask': !displayAsMask,\r\n\t\t\t\t'overlay-error': status === 'error',\r\n\t\t\t\t'overlay-nodata': status === 'noData',\r\n\t\t\t\t'overlay-pending': status === 'pending'}\">\r\n\r\n\t<!--Pending Spinner-->\r\n\t<ec-spinner [hidden]=\"status !== 'pending'\"></ec-spinner>\r\n\r\n\t<ng-template [ngIf]=\"status === 'noData' && noDataTemplate\">\r\n\t\t<ng-container *ngTemplateOutlet=\"noDataTemplate\"></ng-container>\r\n\t</ng-template>\r\n\r\n\t<ng-container *ngIf=\"(status === 'noData' && !noDataTemplate) || status !== 'noData'\">\r\n\t\t<!--Status Message-->\r\n\t\t<div id=\"statusMessage\"\r\n\t\t\t class=\"message\"\r\n\t\t\t *ngIf=\"message\"\r\n\t\t\t [ngClass]=\"{'error': status === 'error', 'mt-1': status === 'pending'}\"\r\n\t\t\t [innerHtml]=\"message | translate\">\r\n\t\t</div>\r\n\r\n\t\t<!-- Action -->\r\n\t\t<ec-button type=\"common\"\r\n\t\t\t\t class=\"mt-3\"\r\n\t\t\t\t *ngIf=\"action?.onClick\"\r\n\t\t\t\t [icon]=\"action?.icon\"\r\n\t\t\t\t (clicked)=\"actionClicked($event)\"\r\n\t\t\t\t [label]=\"action?.label\"\r\n\t\t\t\t [hidden]=\"status === 'pending'\">\r\n\t\t</ec-button>\r\n\t</ng-container>\r\n\r\n</div>", styles: [":host{position:relative}:host(.bg-body)>.overlay{background-color:var(--ec-background-color-body)}:host(.bg-body).is-translucent>.overlay{background-color:var(--ec-background-color-overlay)}:host(.bg-content)>.overlay{background-color:var(--ec-background-color)}:host(.bg-content).is-translucent>.overlay{background-color:var(--ec-background-color-overlay)}.overlay{align-items:center;background-color:var(--ec-overlay-background-color, var(--ec-background-color));display:flex;flex-direction:column;justify-content:center;padding:3rem 4rem;z-index:var(--ec-z-index-overlay);position:absolute;inset:0}.overlay.not-mask{position:relative;min-height:100%}.message{color:var(--ec-color-secondary-dark);font-size:var(--ec-font-size-title)}.message.error{color:var(--ec-color-danger);font-size:var(--ec-font-size-title)}\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: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: SpinnerComponent, selector: "ec-spinner" }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] });
2673
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ViewOverlayComponent, decorators: [{
2674
- type: Component,
2675
- args: [{ selector: '[ecOverlay]', template: "<!-- Transcluded Content -->\r\n<ng-content *ngIf=\"displayAsMask || (!displayAsMask && status === 'hasData')\"></ng-content>\r\n<!--Used by GI tests to know the overlay status whether we use ngIf or mask version. No visual impact-->\r\n<span [hidden]=\"true\"\r\n\t class=\"overlay-status-{{status}}\"></span>\r\n<!-- Overlay goes last so it is rendered on top of preceding content due to source order -->\r\n<div *ngIf=\"status !== 'hasData'\"\r\n\t class=\"overlay flex-grow {{overlayClassList}}\"\r\n\t [ngClass]=\"{'not-mask': !displayAsMask,\r\n\t\t\t\t'overlay-error': status === 'error',\r\n\t\t\t\t'overlay-nodata': status === 'noData',\r\n\t\t\t\t'overlay-pending': status === 'pending'}\">\r\n\r\n\t<!--Pending Spinner-->\r\n\t<ec-spinner [hidden]=\"status !== 'pending'\"></ec-spinner>\r\n\r\n\t<ng-template [ngIf]=\"status === 'noData' && noDataTemplate\">\r\n\t\t<ng-container *ngTemplateOutlet=\"noDataTemplate\"></ng-container>\r\n\t</ng-template>\r\n\r\n\t<ng-container *ngIf=\"(status === 'noData' && !noDataTemplate) || status !== 'noData'\">\r\n\t\t<!--Status Message-->\r\n\t\t<div id=\"statusMessage\"\r\n\t\t\t class=\"message\"\r\n\t\t\t *ngIf=\"message\"\r\n\t\t\t [ngClass]=\"{'error': status === 'error', 'mt-1': status === 'pending'}\"\r\n\t\t\t [innerHtml]=\"message | translate\">\r\n\t\t</div>\r\n\r\n\t\t<!-- Action -->\r\n\t\t<ec-button type=\"common\"\r\n\t\t\t\t class=\"mt-3\"\r\n\t\t\t\t *ngIf=\"action?.onClick\"\r\n\t\t\t\t [icon]=\"action?.icon\"\r\n\t\t\t\t (clicked)=\"actionClicked($event)\"\r\n\t\t\t\t [label]=\"action?.label\"\r\n\t\t\t\t [hidden]=\"status === 'pending'\">\r\n\t\t</ec-button>\r\n\t</ng-container>\r\n\r\n</div>", styles: [":host{position:relative}:host(.bg-body)>.overlay{background-color:var(--ec-background-color-body)}:host(.bg-body).is-translucent>.overlay{background-color:var(--ec-background-color-overlay)}:host(.bg-content)>.overlay{background-color:var(--ec-background-color)}:host(.bg-content).is-translucent>.overlay{background-color:var(--ec-background-color-overlay)}.overlay{align-items:center;background-color:var(--ec-overlay-background-color, var(--ec-background-color));display:flex;flex-direction:column;justify-content:center;padding:3rem 4rem;z-index:var(--ec-z-index-overlay);position:absolute;inset:0}.overlay.not-mask{position:relative;min-height:100%}.message{color:var(--ec-color-secondary-dark);font-size:var(--ec-font-size-title)}.message.error{color:var(--ec-color-danger);font-size:var(--ec-font-size-title)}\n"] }]
2676
- }], propDecorators: { status: [{
2630
+ }], noDataText: [{
2677
2631
  type: Input
2678
- }], message: [{
2632
+ }], enableKeyNav: [{
2679
2633
  type: Input
2680
- }], action: [{
2634
+ }], highlightedItem: [{
2681
2635
  type: Input
2682
- }], noDataTemplate: [{
2636
+ }], maintainSelectedItem: [{
2683
2637
  type: Input
2684
- }], displayAsMask: [{
2638
+ }], truncateItems: [{
2685
2639
  type: Input
2686
- }], overlayClassList: [{
2640
+ }], preserveIconSpace: [{
2641
+ type: Input
2642
+ }], dropdownToggleButton: [{
2687
2643
  type: Input
2644
+ }], selectedChanged: [{
2645
+ type: Output
2646
+ }], menuClosed: [{
2647
+ type: Output
2648
+ }], labelTemplate: [{
2649
+ type: ViewChild,
2650
+ args: ['label', { static: true }]
2651
+ }], iconAndLabelTemplate: [{
2652
+ type: ViewChild,
2653
+ args: ['iconAndLabel', { static: true }]
2654
+ }], checkAndLabelTemplate: [{
2655
+ type: ViewChild,
2656
+ args: ['checkAndLabel', { static: true }]
2657
+ }], iconLabelCaptionTemplate: [{
2658
+ type: ViewChild,
2659
+ args: ['iconLabelCaption', { static: true }]
2688
2660
  }] } });
2689
2661
 
2690
2662
  /**
@@ -2840,11 +2812,6 @@ class ComboboxComponent extends FormControlBase {
2840
2812
  * Number of filtered options to display in the footer. Excludes headings.
2841
2813
  */
2842
2814
  this.filteredOptionCount = 0;
2843
- /**
2844
- * Flat list of selectable items in the combobox.
2845
- * Does not include headings or divider-section items.
2846
- */
2847
- this.selectableItems = [];
2848
2815
  /**
2849
2816
  * Index of the currently-selected options
2850
2817
  */
@@ -2982,14 +2949,13 @@ class ComboboxComponent extends FormControlBase {
2982
2949
  resetOptions(options) {
2983
2950
  var _a;
2984
2951
  this.filteredOptions = options || this.options;
2985
- this.selectableItems = MenuComponent.getSelectableItems(this.filteredOptions);
2986
2952
  // do not count headings
2987
- this.filteredOptionCount = ((_a = this.filteredOptions) === null || _a === void 0 ? void 0 : _a.filter(o => o.display !== 'heading' && o.display !== 'divided-section').length) || 0;
2953
+ this.filteredOptionCount = ((_a = this.filteredOptions) === null || _a === void 0 ? void 0 : _a.filter(o => o.display !== 'heading').length) || 0;
2988
2954
  //if they have no search term, don't try to select anything so they can clear the box out by hitting enter
2989
2955
  //if they have a search term and the options changed, select an option from the menu so they will get it automatically if they hit enter
2990
2956
  if (this.textboxFormModel.value !== '') {
2991
- this.selectedItemIndex = this.findDefaultSelectionIndex(this.selectableItems, this.textboxFormModel.value);
2992
- this.selectedItem = this.selectableItems[this.selectedItemIndex] || null;
2957
+ this.selectedItemIndex = this.findDefaultSelectionIndex(this.filteredOptions, this.textboxFormModel.value);
2958
+ this.selectedItem = this.filteredOptions[this.selectedItemIndex] || null;
2993
2959
  this.scrollMenu(this.selectedItemIndex);
2994
2960
  }
2995
2961
  else {
@@ -3186,11 +3152,18 @@ class ComboboxComponent extends FormControlBase {
3186
3152
  if (this.selectedItemIndex === -1 && this.addNewButton && !this.addNewButton.nativeElement.hidden && !this.addNewSelected) {
3187
3153
  this.addNewSelected = true;
3188
3154
  }
3189
- else if (this.selectedItemIndex < this.selectableItems.length - 1) {
3190
- this.selectedItemIndex++;
3155
+ else if (this.selectedItemIndex < this.filteredOptions.length - 1) {
3191
3156
  if (this.addNewSelected) {
3192
3157
  this.addNewSelected = false;
3193
3158
  }
3159
+ //if the last item is a heading and we are on the second last item, we shouldn't increment the selectedItemIndex because that would select the heading
3160
+ if (!(this.selectedItemIndex == this.filteredOptions.length - 2 && this.filteredOptions[this.selectedItemIndex + 1].display === 'heading')) {
3161
+ this.selectedItemIndex++;
3162
+ // Skip any in-menu heading items
3163
+ if (this.selectedItemIndex < this.filteredOptions.length - 1 && this.filteredOptions[this.selectedItemIndex].display === 'heading') {
3164
+ this.selectedItemIndex++;
3165
+ }
3166
+ }
3194
3167
  }
3195
3168
  break;
3196
3169
  case "ArrowUp":
@@ -3199,16 +3172,30 @@ class ComboboxComponent extends FormControlBase {
3199
3172
  this.addNewSelected = false;
3200
3173
  }
3201
3174
  else if (this.selectedItemIndex > -1) {
3202
- this.selectedItemIndex--;
3203
- if (this.selectedItemIndex === -1 && this.addNewButton && !this.addNewButton.nativeElement.hidden) {
3175
+ if (this.selectedItemIndex === 0 && this.addNewButton && !this.addNewButton.nativeElement.hidden) {
3204
3176
  this.addNewSelected = true;
3205
3177
  }
3178
+ this.selectedItemIndex--;
3179
+ // Skip any in-menu heading items
3180
+ if (this.selectedItemIndex > -1 && this.filteredOptions[this.selectedItemIndex].display === 'heading') {
3181
+ this.selectedItemIndex--;
3182
+ //if the selectedItemIndex is -1, that means the very first item was a heading and we just skipped over it.
3183
+ if (this.selectedItemIndex == -1) {
3184
+ //if there is an add new button we should select it. otherwise we should lock them at index 1 (right before the heading)
3185
+ if (this.addNewButton && !this.addNewButton.nativeElement.hidden) {
3186
+ this.addNewSelected = true;
3187
+ }
3188
+ else {
3189
+ this.selectedItemIndex = 1;
3190
+ }
3191
+ }
3192
+ }
3206
3193
  }
3207
3194
  break;
3208
3195
  default:
3209
3196
  return;
3210
3197
  }
3211
- this.selectedItem = this.selectableItems[this.selectedItemIndex];
3198
+ this.selectedItem = this.filteredOptions[this.selectedItemIndex];
3212
3199
  if (this.menuStatus === 'hidden') {
3213
3200
  this.setFormModelValue(this.selectedItem);
3214
3201
  }
@@ -3227,23 +3214,10 @@ class ComboboxComponent extends FormControlBase {
3227
3214
  filterOptionsArray(filterText) {
3228
3215
  let searchText = filterText.toLowerCase();
3229
3216
  if (filterText && filterText !== '') {
3230
- const matchesSearch = (item) => item.label.toLowerCase().indexOf(searchText) >= 0 || (item.caption && item.caption.toLowerCase().indexOf(searchText) >= 0);
3231
- return this.options.reduce((filteredItems, item) => {
3232
- var _a, _b;
3233
- // Match the item itself if it doesn't have any children
3234
- if (!((_a = item.items) === null || _a === void 0 ? void 0 : _a.length) && matchesSearch(item)) {
3235
- filteredItems.push(item);
3236
- // If we have children, filter them and add the parent if it has any children that match
3237
- }
3238
- else if (((_b = item.items) === null || _b === void 0 ? void 0 : _b.length) && (item.display === 'heading' || item.display === 'divided-section')) {
3239
- const filteredChildItems = item.items.filter(matchesSearch);
3240
- if (filteredChildItems.length) {
3241
- // Need to clone the parent item with the filtered children so we don't modify the original
3242
- filteredItems.push(Object.assign(Object.assign({}, item), { items: filteredChildItems }));
3243
- }
3244
- }
3245
- return filteredItems;
3246
- }, []);
3217
+ return this.options.filter(item => {
3218
+ return item.label.toLowerCase().indexOf(searchText) >= 0 ||
3219
+ (item.caption && item.caption.toLowerCase().indexOf(searchText) >= 0);
3220
+ });
3247
3221
  }
3248
3222
  else {
3249
3223
  return this.options;
@@ -3260,7 +3234,7 @@ class ComboboxComponent extends FormControlBase {
3260
3234
  findSelectedItemIndex(item) {
3261
3235
  let itemToFind = item ? item : this.selectedItem;
3262
3236
  if (itemToFind) {
3263
- return this.selectableItems.findIndex(item => {
3237
+ return this.filteredOptions.findIndex(item => {
3264
3238
  if (item.id && itemToFind.id) {
3265
3239
  return item.label === itemToFind.label && item.id === itemToFind.id;
3266
3240
  }
@@ -3286,7 +3260,7 @@ class ComboboxComponent extends FormControlBase {
3286
3260
  this.textboxFormModel.setValue(data.selectedLabel || data.label);
3287
3261
  this.selectedItemIndex = this.findSelectedItemIndex(data);
3288
3262
  if (this.selectedItemIndex >= 0) {
3289
- this.selectedItem = this.selectableItems[this.selectedItemIndex];
3263
+ this.selectedItem = this.filteredOptions[this.selectedItemIndex];
3290
3264
  }
3291
3265
  }
3292
3266
  else {
@@ -3307,10 +3281,10 @@ class ComboboxComponent extends FormControlBase {
3307
3281
  if (this.selectedItemIndex > -1 && this.selectedItem) {
3308
3282
  // The menu component will automatically generate ids for the menu items if they dont have them,
3309
3283
  // so they need to be accounted for here since the combobox doesn't know about those ids
3310
- let itemId = this.selectedItem.id ? this.selectedItem.id : MenuComponent.getIndexedItemId(this.filteredOptions, this.selectedItem, `${this.id}_menu`);
3284
+ let itemSelector = this.selectedItem.id ? `#${this.selectedItem.id}` : `#${this.id}_menu_item${this.selectedItemIndex}`;
3311
3285
  //trigger the scrolling after a tick to allow the menu to be up to date (and pending mask cleared) before measuring
3312
3286
  setTimeout(() => {
3313
- this.scrollService.scrollItemCentered(`#${this.id}_menu_list`, `#${itemId}`);
3287
+ this.scrollService.scrollItemCentered(`#${this.id}_menu_list`, itemSelector);
3314
3288
  }, 0);
3315
3289
  }
3316
3290
  else {
@@ -3477,10 +3451,10 @@ class ComboboxComponent extends FormControlBase {
3477
3451
  findDefaultSelectionIndex(options, searchText) {
3478
3452
  let index = -1;
3479
3453
  if (options && options.length) {
3480
- index = options.findIndex(option => option != null);
3454
+ index = options.findIndex(option => option != null && option.display !== 'heading');
3481
3455
  if (searchText) {
3482
3456
  searchText = searchText.toLowerCase().trim();
3483
- let exactMatchIndex = options.findIndex(option => option.label.toLowerCase() == searchText);
3457
+ let exactMatchIndex = options.findIndex(option => option.label.toLowerCase() == searchText && option.display !== 'heading');
3484
3458
  if (exactMatchIndex >= 0) {
3485
3459
  index = exactMatchIndex;
3486
3460
  }
@@ -3820,10 +3794,10 @@ class FormControlComponent {
3820
3794
  }
3821
3795
  }
3822
3796
  FormControlComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FormControlComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
3823
- FormControlComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: FormControlComponent, selector: "ec-form-control", inputs: { id: "id", icon: "icon", actionIcon: "actionIcon", showClear: "showClear", 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: "formModel", 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<i id=\"{{id + '_clear'}}\" *ngIf=\"showClear\" class=\"ec-form-control-clear ec-icon icon-cancel\" (click)=\"clear()\"></i>\r\n<i id=\"{{id + '_action'}}\" *ngIf=\"actionIcon\" class=\"ec-form-control-action ec-icon {{actionIcon}}\" (click)=\"actionClicked.emit()\"></i>\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{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{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{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{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{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{color:var(--ec-form-control-color-placeholder);opacity:1}ec-form-control>input:focus,ec-form-control>select:focus,ec-form-control>textarea: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{display:block}ec-form-control>input,ec-form-control>textarea,ec-form-control>select,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{cursor:pointer;flex:none;height:1.875rem;width:2rem;order:3}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,ec-form-control .ec-form-control-action:hover{background-color:var(--ec-background-color-hover)}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-form-control-border-color-focus);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 });
3797
+ FormControlComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: FormControlComponent, selector: "ec-form-control", inputs: { id: "id", icon: "icon", actionIcon: "actionIcon", showClear: "showClear", 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: "formModel", 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<i id=\"{{id + '_clear'}}\" *ngIf=\"showClear\" class=\"ec-form-control-clear ec-icon icon-cancel\" (click)=\"clear()\"></i>\r\n<i id=\"{{id + '_action'}}\" *ngIf=\"actionIcon\" class=\"ec-form-control-action ec-icon {{actionIcon}}\" (click)=\"actionClicked.emit()\"></i>\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{cursor:pointer;flex:none;height:1.875rem;width:2rem;order:3}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,ec-form-control .ec-form-control-action:hover{background-color:var(--ec-background-color-hover)}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-form-control-border-color-focus);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 });
3824
3798
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FormControlComponent, decorators: [{
3825
3799
  type: Component,
3826
- 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<i id=\"{{id + '_clear'}}\" *ngIf=\"showClear\" class=\"ec-form-control-clear ec-icon icon-cancel\" (click)=\"clear()\"></i>\r\n<i id=\"{{id + '_action'}}\" *ngIf=\"actionIcon\" class=\"ec-form-control-action ec-icon {{actionIcon}}\" (click)=\"actionClicked.emit()\"></i>\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{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{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{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{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{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{color:var(--ec-form-control-color-placeholder);opacity:1}ec-form-control>input:focus,ec-form-control>select:focus,ec-form-control>textarea: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{display:block}ec-form-control>input,ec-form-control>textarea,ec-form-control>select,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{cursor:pointer;flex:none;height:1.875rem;width:2rem;order:3}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,ec-form-control .ec-form-control-action:hover{background-color:var(--ec-background-color-hover)}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-form-control-border-color-focus);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"] }]
3800
+ 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<i id=\"{{id + '_clear'}}\" *ngIf=\"showClear\" class=\"ec-form-control-clear ec-icon icon-cancel\" (click)=\"clear()\"></i>\r\n<i id=\"{{id + '_action'}}\" *ngIf=\"actionIcon\" class=\"ec-form-control-action ec-icon {{actionIcon}}\" (click)=\"actionClicked.emit()\"></i>\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{cursor:pointer;flex:none;height:1.875rem;width:2rem;order:3}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,ec-form-control .ec-form-control-action:hover{background-color:var(--ec-background-color-hover)}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-form-control-border-color-focus);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"] }]
3827
3801
  }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { formModel: [{
3828
3802
  type: ContentChild,
3829
3803
  args: [FormControlDirective]