@eui/ecl 22.0.0-alpha.7 → 22.0.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/docs/changelog.html +35 -0
  2. package/docs/components/EclMegaMenuComponent.html +5 -203
  3. package/docs/components/EclMegaMenuFeaturedComponent.html +10 -126
  4. package/docs/components/EclMegaMenuInfoComponent.html +0 -91
  5. package/docs/components/EclMegaMenuItemComponent.html +38 -115
  6. package/docs/components/EclMegaMenuSubitemComponent.html +4 -68
  7. package/docs/directives/EclMegaMenuContainerDirective.html +0 -104
  8. package/docs/directives/EclMegaMenuFeaturedImageDirective.html +0 -104
  9. package/docs/directives/EclMegaMenuFeaturedListDirective.html +0 -104
  10. package/docs/directives/EclMegaMenuFeaturedListItemDescriptionDirective.html +0 -104
  11. package/docs/directives/EclMegaMenuFeaturedListItemDirective.html +0 -104
  12. package/docs/directives/EclMegaMenuFeaturedPictureDirective.html +0 -39
  13. package/docs/directives/EclMegaMenuListDirective.html +0 -104
  14. package/docs/directives/EclMegaMenuSpacerDirective.html +0 -104
  15. package/docs/directives/EclMegaMenuSublistDirective.html +0 -165
  16. package/docs/js/search/search_index.js +2 -2
  17. package/docs/json/documentation.json +273 -851
  18. package/docs/llms.txt +2 -27
  19. package/docs/properties.html +1 -1
  20. package/fesm2022/eui-ecl-components-ecl-inpage-navigation.mjs +4 -2
  21. package/fesm2022/eui-ecl-components-ecl-inpage-navigation.mjs.map +1 -1
  22. package/fesm2022/eui-ecl-components-ecl-mega-menu.mjs +100 -159
  23. package/fesm2022/eui-ecl-components-ecl-mega-menu.mjs.map +1 -1
  24. package/package.json +1 -1
  25. package/types/eui-ecl-components-ecl-inpage-navigation.d.ts.map +1 -1
  26. package/types/eui-ecl-components-ecl-mega-menu.d.ts +12 -22
  27. package/types/eui-ecl-components-ecl-mega-menu.d.ts.map +1 -1
@@ -5407,13 +5407,13 @@
5407
5407
  },
5408
5408
  {
5409
5409
  "name": "EclInpageNavigationSectionEnterEvent",
5410
- "id": "class-EclInpageNavigationSectionEnterEvent-5daafc90fdb4dbac03101fb1ec926edaec22dde8c7ba4699dcece0f2c2d48f01b9c51ed69bb59e72fd63be3a46eae2803257a7e8309d6a6dc7f5932d3148a469",
5410
+ "id": "class-EclInpageNavigationSectionEnterEvent-906af88767bb0883baf4a3fa0272ddc605be045eba82e54505a7ed5052ca75dd4912d410edb6b1ebd61164ec4f483083128aa648e00be47dbc4458c5d1e5365f",
5411
5411
  "file": "packages/ecl/components/ecl-inpage-navigation/ecl-inpage-navigation.component.ts",
5412
5412
  "coverageIgnore": false,
5413
5413
  "deprecated": false,
5414
5414
  "deprecationMessage": "",
5415
5415
  "type": "class",
5416
- "sourceCode": "import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';\nimport { ScrollDispatcher, ViewportRuler } from '@angular/cdk/scrolling';\nimport { isPlatformBrowser } from '@angular/common';\nimport { AfterViewInit, ChangeDetectorRef, Component, DOCUMENT, DoCheck, ElementRef, IterableDiffer, IterableDiffers, NgZone, OnDestroy, OnInit, PLATFORM_ID, afterNextRender, contentChild, contentChildren, inject, input, numberAttribute, output, viewChild } from '@angular/core';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EUI_ECL_STICKY_CONTAINER } from '@eui/ecl/components/ecl-sticky-container';\nimport { ECLBaseDirective, EclBaseEvent, EclRtlService, EclThemeService } from '@eui/ecl/core';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { EclInpageNavigationItemComponent } from './ecl-inpage-navigation-item.component';\nimport { EclInpageNavigationListDirective } from './ecl-inpage-navigation-list.directive';\nimport { EclInpageNavigationService } from './services/ecl-inpage-navigation.service';\n\nexport class EclInpageNavigationSectionEnterEvent extends EclBaseEvent {\n constructor(public sectionId: string) {\n super();\n }\n}\n\n/**\n * The in-page navigation is a vertical menu containing (anchored) links to H2-headings on long content pages.\n * It gives the user an overview of the page contents and has a fixed position (does not move while scrolling) at either the left\n * side of a page on desktop or top-bar on mobile. This component helps users scan of the page quickly contents and may potentially\n * reduce vertical scrolling, allowing users to easily jump straight to the segment of the page.\n */\n@Component({\n selector: 'ecl-inpage-navigation',\n templateUrl: './ecl-inpage-navigation.component.html',\n imports: [TranslatePipe, ...EUI_ECL_STICKY_CONTAINER, ...EUI_ECL_ICON],\n styles: [\n `\n @media (min-width: 996px) {\n .ecl-inpage-navigation__list {\n display: block !important;\n }\n }\n `,\n ],\n})\nexport class EclInpageNavigationComponent extends ECLBaseDirective implements OnInit, AfterViewInit, OnDestroy, DoCheck {\n eclThemeService = inject(EclThemeService);\n\n readonly eclTitle = input<string>(undefined);\n /**\n * Used to calculate component's position.\n */\n readonly marginTop = input<number>(undefined);\n readonly marginBottom = input<number>(undefined);\n /**\n * Sets the offset from the top of the page (for example if there is a toolbar or header). Used to calculate scrolling behaviour.\n */\n readonly offsetTop = input<number, unknown>(undefined, { transform: numberAttribute });\n readonly togglerButton = viewChild<ElementRef<HTMLButtonElement>>('togglerButton');\n readonly toggleWrapper = viewChild<ElementRef<HTMLDivElement>>('toggleWrapper');\n readonly navTittle = viewChild<ElementRef<HTMLDivElement>>('navTittle');\n /**\n * This event will be emitted, when onscroll a new section becomes active.\n */\n readonly sectionEnter = output<EclInpageNavigationSectionEnterEvent>();\n\n readonly eclNavigationLinkItems = contentChildren(EclInpageNavigationItemComponent, { descendants: true });\n readonly eclNavigationList = contentChild(EclInpageNavigationListDirective);\n\n /**\n * Used for the mobile view, where user can select a section from the dropdown.\n */\n isButtonExpanded = false;\n currentSectionElement: HTMLElement | null = null;\n public isRtl = false;\n public listMaxHeight: number;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclInpageNavigationItemComponent>;\n private isMobileBreakpoint = false;\n private MIN_DISTANCE_TOP = 10;\n /**\n * Extra spacing (px) kept between the sticky toggler and the target heading when scrolling to a section on mobile,\n * so the heading is not flush against the toggler. Mirrors the spacing buffer used by the vanilla ECL\n * `scroll-margin-top` rule (trigger height + spacing).\n */\n private readonly MOBILE_SCROLL_SPACING = 16;\n private readonly ICON_SIZE_EC_THEME = '2xs';\n private readonly ICON_SIZE_EU_THEME = 's';\n private readonly TABLET_BREAKPOINT = 996;\n private intersectionObserver: IntersectionObserver;\n private eclRtlService = inject(EclRtlService);\n private differs = inject(IterableDiffers);\n private scrollDispatcher: ScrollDispatcher = inject(ScrollDispatcher);\n private zone = inject(NgZone);\n private cdkBreakpointObserver = inject(BreakpointObserver);\n private viewportRuler = inject(ViewportRuler);\n private eclInpageNavigationService = inject(EclInpageNavigationService);\n private cdr = inject(ChangeDetectorRef);\n private readonly platformId = inject(PLATFORM_ID);\n private readonly doc = inject(DOCUMENT);\n private readonly win = this.doc.defaultView; // Window | null\n private readonly isBrowser = isPlatformBrowser(this.platformId);\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.zone.run(() => this.setListHeight());\n });\n }\n\n ngOnInit(): void {\n this.handleRtlChangeState();\n }\n\n ngAfterViewInit() {\n if (!this.isBrowser) return;\n\n this.subscribeToCDKScrollEvent();\n this.observeBreakpointChanges();\n this.viewportRuler.change(300)\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => this.zone.run(() => this.setListHeight()));\n\n const togglerButton = this.togglerButton();\n if (typeof IntersectionObserver !== 'undefined' && togglerButton?.nativeElement) {\n this.intersectionObserver = new IntersectionObserver(() => this.setListHeight());\n this.intersectionObserver.observe(togglerButton.nativeElement);\n }\n }\n\n get hasNavigationList(): boolean {\n return !!this.eclNavigationList();\n }\n\n get currentNavigationLinkItem(): EclInpageNavigationItemComponent {\n return this.eclNavigationLinkItems().find((item) => item.sectionElement === this.currentSectionElement);\n }\n\n /**\n * the size of the arrow-down icon, used in mobile view. There are different sizes for EC and EU themes.\n */\n get sizeIcon(): string {\n if (this.eclThemeService.isECTheme()) {\n return this.ICON_SIZE_EC_THEME;\n } else {\n return this.ICON_SIZE_EU_THEME;\n }\n }\n\n get hasActiveSection(): boolean {\n return !!this.currentSectionElement;\n }\n\n ngDoCheck(): void {\n const diff = this.differ.diff(this.eclNavigationLinkItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n const togglerButton = this.togglerButton();\n if (this.intersectionObserver && togglerButton?.nativeElement) {\n this.intersectionObserver.unobserve(togglerButton.nativeElement);\n this.intersectionObserver.disconnect();\n }\n }\n\n /**\n * On mobile view - handle the dropdown toggle.\n */\n onExpandButtonClick(): void {\n this.setButtonExpanded(!this.isButtonExpanded);\n }\n\n /**\n * Single entry point for changing the dropdown expanded state. Keeps the local flag (used for the button's\n * aria-expanded) and the shared service state (that drives the list's visibility class) in sync.\n */\n private setButtonExpanded(isExpanded: boolean): void {\n this.isButtonExpanded = isExpanded;\n this.eclInpageNavigationService.eclInpageNavigationToggle(isExpanded);\n }\n\n /**\n * Dropdown keyboard navigation on mobile view.\n * @param evt\n */\n onExpandButtonKeydown(evt: Event): void {\n switch ((evt as KeyboardEvent).key) {\n case 'Tab':\n this.onExpandButtonTab(evt);\n break;\n case 'ArrowDown':\n this.onExpandButtonArrowDown(evt);\n break;\n default:\n break;\n }\n }\n\n private handleRtlChangeState(): void {\n this.eclRtlService.currentRtlState$.pipe(takeUntil(this.destroy$)).subscribe((rtlState) => {\n this.isRtl = rtlState;\n });\n }\n\n /**\n * Set the height of the list with the navigation items in px. So in case the full list cannot be displayed, a scroll will appear.\n */\n private setListHeight(): void {\n if (!this.isBrowser) return;\n const eclNavigationList = this.eclNavigationList();\n if (!eclNavigationList) return;\n if (!this.win) return;\n\n const viewportHeight = this.win.innerHeight;\n const viewportWidth = this.win.innerWidth;\n let topPosition = 0;\n\n if (viewportWidth < this.TABLET_BREAKPOINT) {\n const toggleWrapper = this.toggleWrapper()?.nativeElement;\n if (toggleWrapper) {\n const styles = this.win.getComputedStyle(toggleWrapper);\n topPosition =\n toggleWrapper.getBoundingClientRect().bottom +\n parseFloat(styles.marginBottom || '0');\n }\n } else if (this.eclTitle()) {\n const titleEl = this.navTittle()?.nativeElement;\n if (titleEl) topPosition = titleEl.getBoundingClientRect().bottom;\n } else {\n const listEl = eclNavigationList?.el?.nativeElement;\n if (listEl) topPosition = listEl.getBoundingClientRect().top;\n }\n\n const availableSpace = viewportHeight - topPosition;\n if (availableSpace > 0) {\n this.listMaxHeight = availableSpace;\n eclNavigationList.maxHeight.set(this.listMaxHeight);\n }\n }\n\n private onExpandButtonArrowDown(evt: Event): void {\n evt.preventDefault();\n this.setButtonExpanded(true);\n this.eclNavigationLinkItems().at(0).onFocus();\n }\n\n private onExpandButtonTab(evt: Event): void {\n if ((evt as KeyboardEvent).shiftKey) {\n evt.preventDefault();\n this.eclNavigationLinkItems().at(this.eclNavigationLinkItems().length - 1).onFocus();\n }\n }\n\n private connectItemEvents(item: EclInpageNavigationItemComponent): void {\n item.itemArrowDown.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemArrowDown(item);\n });\n\n item.itemArrowUp.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemArrowUp(item);\n });\n\n item.itemTab.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.onItemTab(item, evt);\n });\n\n item.itemEnter.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemEnter(item);\n });\n\n item.itemClick.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.selectNavigationItem(item.sectionElement);\n if (item.sectionElement) {\n this.scrollToSection(item.sectionElement);\n item.sectionElement.focus();\n }\n this.setButtonExpanded(false);\n });\n }\n\n private onItemEnter(item: EclInpageNavigationItemComponent): void {\n this.selectNavigationItem(item.sectionElement);\n if (item.sectionElement) {\n this.scrollToSection(item.sectionElement);\n if (item.sectionElement.tabIndex === -1) {\n item.sectionElement.tabIndex = 0;\n item.sectionElement.focus();\n item.sectionElement.tabIndex = -1;\n }\n }\n this.setButtonExpanded(false);\n }\n\n /**\n * Scrolls the target section into view. On desktop this is a plain scrollIntoView() (unchanged behaviour). On\n * mobile the in-page navigation toggler is sticky at the top, so a top-aligned scroll would hide the heading\n * underneath it; we therefore set `scroll-margin-top` on the target (sticky toggler height + spacing buffer) and\n * let scrollIntoView() honour it. Using scroll-margin-top instead of a manual window.scrollTo() keeps this working\n * regardless of which element is the actual scroll container (window or a nested scrollable wrapper).\n */\n private scrollToSection(sectionElement: HTMLElement): void {\n if (!this.isBrowser) return;\n const offset = this.getMobileScrollOffset();\n sectionElement.style.scrollMarginTop = offset > 0 ? `${offset}px` : '';\n sectionElement.scrollIntoView();\n }\n\n /**\n * The offset (px) applied on mobile so that a scrolled-to heading clears the sticky toggler: the toggler height\n * plus a spacing buffer. Returns 0 on desktop (no sticky toggler). Shared by the scroll logic and the scroll-spy\n * so the heading lands exactly where the spy expects it, keeping the active item in sync after a click.\n */\n private getMobileScrollOffset(): number {\n if (!this.isMobileBreakpoint) return 0;\n const toggleWrapper = this.toggleWrapper()?.nativeElement;\n if (!toggleWrapper) return 0;\n return toggleWrapper.getBoundingClientRect().height + this.MOBILE_SCROLL_SPACING;\n }\n\n private onItemArrowDown(item: EclInpageNavigationItemComponent): void {\n const index = this.eclNavigationLinkItems().indexOf(item);\n const eclNavigationLinkItems = this.eclNavigationLinkItems();\n if (index !== eclNavigationLinkItems.length - 1) {\n eclNavigationLinkItems.at(index + 1).onFocus();\n }\n }\n\n private onItemArrowUp(item: EclInpageNavigationItemComponent): void {\n const index = this.eclNavigationLinkItems().indexOf(item);\n if (index !== 0) {\n this.eclNavigationLinkItems().at(index - 1).onFocus();\n } else {\n const togglerButton = this.togglerButton();\n if (this.isMobileBreakpoint && togglerButton) {\n this.setButtonExpanded(false);\n togglerButton.nativeElement.focus();\n }\n }\n }\n\n private onItemTab(item: EclInpageNavigationItemComponent, evt: Event): void {\n if (this.isMobileBreakpoint) {\n if (!(evt as KeyboardEvent).shiftKey) {\n const index = this.eclNavigationLinkItems().indexOf(item);\n if (index === this.eclNavigationLinkItems().length - 1) {\n evt.preventDefault();\n this.togglerButton().nativeElement.focus();\n }\n }\n }\n }\n\n private subscribeToCDKScrollEvent(): void {\n if (!this.isBrowser) return;\n\n this.scrollDispatcher\n .scrolled()\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => {\n this.zone.run(() => {\n const ids = this.eclNavigationLinkItems().map((item) => item.sectionId());\n\n const sectionElements = ids\n .map((id) => this.doc.querySelector<HTMLElement>(`#${id}`))\n .filter((el): el is HTMLElement => !!el);\n\n this.handleNavigationLinksHighlight(sectionElements);\n this.setListHeight();\n });\n });\n }\n\n private selectNavigationItem(itemElement: HTMLElement): void {\n this.eclNavigationLinkItems().forEach((it) => {\n it.isActive.set(it.sectionElement === itemElement);\n });\n this.cdr.markForCheck();\n }\n\n private handleNavigationLinksHighlight(sectionElements: HTMLElement[]): void {\n const currentSectionElement = this.findActiveSectionElement(sectionElements);\n\n if (currentSectionElement !== this.currentSectionElement) {\n this.currentSectionElement = currentSectionElement ?? undefined as HTMLElement | null;\n if (currentSectionElement) this.selectNavigationItem(currentSectionElement);\n\n const sectionId = this.currentNavigationLinkItem?.sectionId();\n this.sectionEnter.emit(new EclInpageNavigationSectionEnterEvent(sectionId));\n }\n }\n\n private findActiveSectionElement(sectionElements: HTMLElement[]): HTMLElement | null {\n if (!this.isBrowser || !this.win) return null;\n\n let currentSection: HTMLElement | null = null;\n // On mobile the heading is scrolled to sit just below the sticky toggler, so the spy must use that same\n // offset; otherwise it would highlight the previous section. On desktop keep the original threshold.\n const offset = this.isMobileBreakpoint\n ? this.getMobileScrollOffset()\n : this.MIN_DISTANCE_TOP + (this.offsetTop() ?? 0);\n\n const isNearBottom =\n this.win.innerHeight + this.win.scrollY >=\n this.doc.documentElement.scrollHeight - 10;\n\n for (const sectionElement of sectionElements) {\n const rect = sectionElement.getBoundingClientRect();\n const isAboveOffset = rect.top <= offset;\n const isVisibleInViewport = rect.top < this.win.innerHeight;\n\n if (isAboveOffset || (isVisibleInViewport && isNearBottom)) {\n currentSection = sectionElement;\n }\n }\n\n return currentSection;\n }\n\n private observeBreakpointChanges(): void {\n this.cdkBreakpointObserver\n .observe([Breakpoints.Handset, Breakpoints.Tablet, Breakpoints.Small])\n .pipe(takeUntil(this.destroy$))\n .subscribe((result) => {\n this.isMobileBreakpoint = result.matches;\n });\n }\n}\n",
5416
+ "sourceCode": "import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';\nimport { ScrollDispatcher, ViewportRuler } from '@angular/cdk/scrolling';\nimport { isPlatformBrowser } from '@angular/common';\nimport { AfterViewInit, ChangeDetectorRef, Component, DOCUMENT, DoCheck, ElementRef, IterableDiffer, IterableDiffers, NgZone, OnDestroy, OnInit, PLATFORM_ID, afterNextRender, contentChild, contentChildren, inject, input, numberAttribute, output, viewChild } from '@angular/core';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EUI_ECL_STICKY_CONTAINER } from '@eui/ecl/components/ecl-sticky-container';\nimport { ECLBaseDirective, EclBaseEvent, EclRtlService, EclThemeService } from '@eui/ecl/core';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { EclInpageNavigationItemComponent } from './ecl-inpage-navigation-item.component';\nimport { EclInpageNavigationListDirective } from './ecl-inpage-navigation-list.directive';\nimport { EclInpageNavigationService } from './services/ecl-inpage-navigation.service';\n\nexport class EclInpageNavigationSectionEnterEvent extends EclBaseEvent {\n constructor(public sectionId: string) {\n super();\n }\n}\n\n/**\n * The in-page navigation is a vertical menu containing (anchored) links to H2-headings on long content pages.\n * It gives the user an overview of the page contents and has a fixed position (does not move while scrolling) at either the left\n * side of a page on desktop or top-bar on mobile. This component helps users scan of the page quickly contents and may potentially\n * reduce vertical scrolling, allowing users to easily jump straight to the segment of the page.\n */\n@Component({\n selector: 'ecl-inpage-navigation',\n templateUrl: './ecl-inpage-navigation.component.html',\n imports: [TranslatePipe, ...EUI_ECL_STICKY_CONTAINER, ...EUI_ECL_ICON],\n styles: [\n `\n @media (min-width: 996px) {\n .ecl-inpage-navigation__list {\n display: block !important;\n }\n }\n `,\n ],\n})\nexport class EclInpageNavigationComponent extends ECLBaseDirective implements OnInit, AfterViewInit, OnDestroy, DoCheck {\n eclThemeService = inject(EclThemeService);\n\n readonly eclTitle = input<string>(undefined);\n /**\n * Used to calculate component's position.\n */\n readonly marginTop = input<number>(undefined);\n readonly marginBottom = input<number>(undefined);\n /**\n * Sets the offset from the top of the page (for example if there is a toolbar or header). Used to calculate scrolling behaviour.\n */\n readonly offsetTop = input<number, unknown>(undefined, { transform: numberAttribute });\n readonly togglerButton = viewChild<ElementRef<HTMLButtonElement>>('togglerButton');\n readonly toggleWrapper = viewChild<ElementRef<HTMLDivElement>>('toggleWrapper');\n readonly navTittle = viewChild<ElementRef<HTMLDivElement>>('navTittle');\n /**\n * This event will be emitted, when onscroll a new section becomes active.\n */\n readonly sectionEnter = output<EclInpageNavigationSectionEnterEvent>();\n\n readonly eclNavigationLinkItems = contentChildren(EclInpageNavigationItemComponent, { descendants: true });\n readonly eclNavigationList = contentChild(EclInpageNavigationListDirective);\n\n /**\n * Used for the mobile view, where user can select a section from the dropdown.\n */\n isButtonExpanded = false;\n currentSectionElement: HTMLElement | null = null;\n public isRtl = false;\n public listMaxHeight: number;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclInpageNavigationItemComponent>;\n private isMobileBreakpoint = false;\n private MIN_DISTANCE_TOP = 10;\n /**\n * Extra spacing (px) kept between the sticky toggler and the target heading when scrolling to a section on mobile,\n * so the heading is not flush against the toggler. Mirrors the spacing buffer used by the vanilla ECL\n * `scroll-margin-top` rule (trigger height + spacing).\n */\n private readonly MOBILE_SCROLL_SPACING = 16;\n private readonly ICON_SIZE_EC_THEME = '2xs';\n private readonly ICON_SIZE_EU_THEME = 's';\n private readonly TABLET_BREAKPOINT = 996;\n private intersectionObserver: IntersectionObserver;\n private eclRtlService = inject(EclRtlService);\n private differs = inject(IterableDiffers);\n private scrollDispatcher: ScrollDispatcher = inject(ScrollDispatcher);\n private zone = inject(NgZone);\n private cdkBreakpointObserver = inject(BreakpointObserver);\n private viewportRuler = inject(ViewportRuler);\n private eclInpageNavigationService = inject(EclInpageNavigationService);\n private cdr = inject(ChangeDetectorRef);\n private readonly platformId = inject(PLATFORM_ID);\n private readonly doc = inject(DOCUMENT);\n private readonly win = this.doc.defaultView; // Window | null\n private readonly isBrowser = isPlatformBrowser(this.platformId);\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.zone.run(() => this.setListHeight());\n });\n }\n\n ngOnInit(): void {\n this.handleRtlChangeState();\n }\n\n ngAfterViewInit() {\n if (!this.isBrowser) return;\n\n this.subscribeToCDKScrollEvent();\n this.observeBreakpointChanges();\n this.viewportRuler.change(300)\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => this.zone.run(() => this.setListHeight()));\n\n const togglerButton = this.togglerButton();\n if (typeof IntersectionObserver !== 'undefined' && togglerButton?.nativeElement) {\n this.intersectionObserver = new IntersectionObserver(() => this.setListHeight());\n this.intersectionObserver.observe(togglerButton.nativeElement);\n }\n }\n\n get hasNavigationList(): boolean {\n return !!this.eclNavigationList();\n }\n\n get currentNavigationLinkItem(): EclInpageNavigationItemComponent {\n return this.eclNavigationLinkItems().find((item) => item.sectionElement === this.currentSectionElement);\n }\n\n /**\n * the size of the arrow-down icon, used in mobile view. There are different sizes for EC and EU themes.\n */\n get sizeIcon(): string {\n if (this.eclThemeService.isECTheme()) {\n return this.ICON_SIZE_EC_THEME;\n } else {\n return this.ICON_SIZE_EU_THEME;\n }\n }\n\n get hasActiveSection(): boolean {\n return !!this.currentSectionElement;\n }\n\n ngDoCheck(): void {\n const diff = this.differ.diff(this.eclNavigationLinkItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n const togglerButton = this.togglerButton();\n if (this.intersectionObserver && togglerButton?.nativeElement) {\n this.intersectionObserver.unobserve(togglerButton.nativeElement);\n this.intersectionObserver.disconnect();\n }\n }\n\n /**\n * On mobile view - handle the dropdown toggle.\n */\n onExpandButtonClick(): void {\n this.setButtonExpanded(!this.isButtonExpanded);\n }\n\n /**\n * Single entry point for changing the dropdown expanded state. Keeps the local flag (used for the button's\n * aria-expanded) and the shared service state (that drives the list's visibility class) in sync.\n */\n private setButtonExpanded(isExpanded: boolean): void {\n this.isButtonExpanded = isExpanded;\n this.eclInpageNavigationService.eclInpageNavigationToggle(isExpanded);\n }\n\n /**\n * Dropdown keyboard navigation on mobile view.\n * @param evt\n */\n onExpandButtonKeydown(evt: Event): void {\n switch ((evt as KeyboardEvent).key) {\n case 'Tab':\n this.onExpandButtonTab(evt);\n break;\n case 'ArrowDown':\n this.onExpandButtonArrowDown(evt);\n break;\n default:\n break;\n }\n }\n\n private handleRtlChangeState(): void {\n this.eclRtlService.currentRtlState$.pipe(takeUntil(this.destroy$)).subscribe((rtlState) => {\n this.isRtl = rtlState;\n });\n }\n\n /**\n * Set the height of the list with the navigation items in px. So in case the full list cannot be displayed, a scroll will appear.\n */\n private setListHeight(): void {\n if (!this.isBrowser) return;\n const eclNavigationList = this.eclNavigationList();\n if (!eclNavigationList) return;\n if (!this.win) return;\n\n const viewportHeight = this.win.innerHeight;\n const viewportWidth = this.win.innerWidth;\n let topPosition = 0;\n\n if (viewportWidth < this.TABLET_BREAKPOINT) {\n const toggleWrapper = this.toggleWrapper()?.nativeElement;\n if (toggleWrapper) {\n const styles = this.win.getComputedStyle(toggleWrapper);\n topPosition =\n toggleWrapper.getBoundingClientRect().bottom +\n parseFloat(styles.marginBottom || '0');\n }\n } else if (this.eclTitle()) {\n const titleEl = this.navTittle()?.nativeElement;\n if (titleEl) topPosition = titleEl.getBoundingClientRect().bottom;\n } else {\n const listEl = eclNavigationList?.el?.nativeElement;\n if (listEl) topPosition = listEl.getBoundingClientRect().top;\n }\n\n const availableSpace = viewportHeight - topPosition;\n if (availableSpace > 0) {\n this.listMaxHeight = availableSpace;\n eclNavigationList.maxHeight.set(this.listMaxHeight);\n }\n }\n\n private onExpandButtonArrowDown(evt: Event): void {\n evt.preventDefault();\n this.setButtonExpanded(true);\n this.eclNavigationLinkItems().at(0).onFocus();\n }\n\n private onExpandButtonTab(evt: Event): void {\n if ((evt as KeyboardEvent).shiftKey) {\n evt.preventDefault();\n this.eclNavigationLinkItems().at(this.eclNavigationLinkItems().length - 1).onFocus();\n }\n }\n\n private connectItemEvents(item: EclInpageNavigationItemComponent): void {\n item.itemArrowDown.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemArrowDown(item);\n });\n\n item.itemArrowUp.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemArrowUp(item);\n });\n\n item.itemTab.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.onItemTab(item, evt);\n });\n\n item.itemEnter.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemEnter(item);\n });\n\n item.itemClick.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.selectNavigationItem(item.sectionElement);\n if (item.sectionElement) {\n this.scrollToSection(item.sectionElement);\n item.sectionElement.focus();\n }\n this.setButtonExpanded(false);\n });\n }\n\n private onItemEnter(item: EclInpageNavigationItemComponent): void {\n this.selectNavigationItem(item.sectionElement);\n if (item.sectionElement) {\n this.scrollToSection(item.sectionElement);\n if (item.sectionElement.tabIndex === -1) {\n item.sectionElement.tabIndex = 0;\n item.sectionElement.focus();\n item.sectionElement.tabIndex = -1;\n }\n }\n this.setButtonExpanded(false);\n }\n\n /**\n * Scrolls the target section into view. On desktop this is a plain scrollIntoView() (unchanged behaviour). On\n * mobile the in-page navigation toggler is sticky at the top, so a top-aligned scroll would hide the heading\n * underneath it; we therefore set `scroll-margin-top` on the target (sticky toggler height + spacing buffer) and\n * let scrollIntoView() honour it. Using scroll-margin-top instead of a manual window.scrollTo() keeps this working\n * regardless of which element is the actual scroll container (window or a nested scrollable wrapper).\n */\n private scrollToSection(sectionElement: HTMLElement): void {\n if (!this.isBrowser) return;\n const offset = this.getMobileScrollOffset();\n sectionElement.style.scrollMarginTop = offset > 0 ? `${offset}px` : '';\n sectionElement.scrollIntoView();\n }\n\n /**\n * The offset (px) applied on mobile so that a scrolled-to heading clears the sticky toggler: the toggler height\n * plus a spacing buffer. Returns 0 on desktop (no sticky toggler). Shared by the scroll logic and the scroll-spy\n * so the heading lands exactly where the spy expects it, keeping the active item in sync after a click.\n */\n private getMobileScrollOffset(): number {\n if (!this.isMobileBreakpoint) return 0;\n const toggleWrapper = this.toggleWrapper()?.nativeElement;\n if (!toggleWrapper) return 0;\n return toggleWrapper.getBoundingClientRect().height + this.MOBILE_SCROLL_SPACING;\n }\n\n private onItemArrowDown(item: EclInpageNavigationItemComponent): void {\n const index = this.eclNavigationLinkItems().indexOf(item);\n const eclNavigationLinkItems = this.eclNavigationLinkItems();\n if (index !== eclNavigationLinkItems.length - 1) {\n eclNavigationLinkItems.at(index + 1).onFocus();\n }\n }\n\n private onItemArrowUp(item: EclInpageNavigationItemComponent): void {\n const index = this.eclNavigationLinkItems().indexOf(item);\n if (index !== 0) {\n this.eclNavigationLinkItems().at(index - 1).onFocus();\n } else {\n const togglerButton = this.togglerButton();\n if (this.isMobileBreakpoint && togglerButton) {\n this.setButtonExpanded(false);\n togglerButton.nativeElement.focus();\n }\n }\n }\n\n private onItemTab(item: EclInpageNavigationItemComponent, evt: Event): void {\n if (this.isMobileBreakpoint) {\n if (!(evt as KeyboardEvent).shiftKey) {\n const index = this.eclNavigationLinkItems().indexOf(item);\n if (index === this.eclNavigationLinkItems().length - 1) {\n evt.preventDefault();\n this.togglerButton().nativeElement.focus();\n }\n }\n }\n }\n\n private subscribeToCDKScrollEvent(): void {\n if (!this.isBrowser) return;\n\n this.scrollDispatcher\n .scrolled()\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => {\n this.zone.run(() => {\n const ids = this.eclNavigationLinkItems().map((item) => item.sectionId());\n\n const sectionElements = ids\n .map((id) => this.doc.querySelector<HTMLElement>(`#${id}`))\n .filter((el): el is HTMLElement => !!el);\n\n this.handleNavigationLinksHighlight(sectionElements);\n this.setListHeight();\n });\n });\n }\n\n private selectNavigationItem(itemElement: HTMLElement): void {\n this.eclNavigationLinkItems().forEach((it) => {\n it.isActive.set(it.sectionElement === itemElement);\n });\n this.cdr.markForCheck();\n }\n\n private handleNavigationLinksHighlight(sectionElements: HTMLElement[]): void {\n const currentSectionElement = this.findActiveSectionElement(sectionElements);\n\n if (currentSectionElement !== this.currentSectionElement) {\n this.currentSectionElement = currentSectionElement ?? undefined as HTMLElement | null;\n if (currentSectionElement) this.selectNavigationItem(currentSectionElement);\n\n const sectionId = this.currentNavigationLinkItem?.sectionId();\n this.sectionEnter.emit(new EclInpageNavigationSectionEnterEvent(sectionId));\n }\n }\n\n private findActiveSectionElement(sectionElements: HTMLElement[]): HTMLElement | null {\n if (!this.isBrowser || !this.win) return null;\n\n let currentSection: HTMLElement | null = null;\n // On mobile the heading is scrolled to sit just below the sticky toggler, so the spy must use that same\n // offset; otherwise it would highlight the previous section. The extra MIN_DISTANCE_TOP is a cushion so a\n // heading that lands right on the boundary (sub-pixel rounding) is still treated as \"reached\". On desktop\n // keep the original threshold.\n const offset = this.isMobileBreakpoint\n ? this.getMobileScrollOffset() + this.MIN_DISTANCE_TOP\n : this.MIN_DISTANCE_TOP + (this.offsetTop() ?? 0);\n\n const isNearBottom =\n this.win.innerHeight + this.win.scrollY >=\n this.doc.documentElement.scrollHeight - 10;\n\n for (const sectionElement of sectionElements) {\n const rect = sectionElement.getBoundingClientRect();\n const isAboveOffset = rect.top <= offset;\n const isVisibleInViewport = rect.top < this.win.innerHeight;\n\n if (isAboveOffset || (isVisibleInViewport && isNearBottom)) {\n currentSection = sectionElement;\n }\n }\n\n return currentSection;\n }\n\n private observeBreakpointChanges(): void {\n this.cdkBreakpointObserver\n .observe([Breakpoints.Handset, Breakpoints.Tablet, Breakpoints.Small])\n .pipe(takeUntil(this.destroy$))\n .subscribe((result) => {\n this.isMobileBreakpoint = result.matches;\n });\n }\n}\n",
5417
5417
  "displayName": "EclInpageNavigationSectionEnterEvent",
5418
5418
  "constructorObj": {
5419
5419
  "name": "constructor",
@@ -24999,12 +24999,12 @@
24999
24999
  },
25000
25000
  {
25001
25001
  "name": "EclMegaMenuContainerDirective",
25002
- "id": "directive-EclMegaMenuContainerDirective-1e5d3c093e2b8e37b451626dfb7a379b4bee63ab33c5637064bd25d153eb43349c2863da225fe5d8ae25978b71cad22ae01f4d93dbacd512bad964aabc3c262a",
25002
+ "id": "directive-EclMegaMenuContainerDirective-22c6911e935dac97d20ff07f3836e767527e534fdde634b561ceca8e3d6c6fb9e8c04a7344bf6b5b9bd44c71d0947370ff25f8765bb908e3060ce255b398676f",
25003
25003
  "file": "packages/ecl/components/ecl-mega-menu/directives/ecl-mega-menu-container.directive.ts",
25004
25004
  "type": "directive",
25005
25005
  "description": "<p>Directive that adds specific class to the mega-menu container.</p>\n",
25006
25006
  "rawdescription": "\n\nDirective that adds specific class to the mega-menu container.\n",
25007
- "sourceCode": "import { Directive, HostBinding } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu container.\n */\n@Directive({\n \n selector: 'div[eclMegaMenuContainer]',\n})\n\nexport class EclMegaMenuContainerDirective extends ECLBaseDirective {\n\n @HostBinding('class.ecl') hasClass = true;\n}\n",
25007
+ "sourceCode": "import { Directive } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu container.\n */\n@Directive({\n selector: 'div[eclMegaMenuContainer]',\n host: {\n class: 'ecl',\n },\n})\n\nexport class EclMegaMenuContainerDirective extends ECLBaseDirective {\n}\n",
25008
25008
  "selector": "div[eclMegaMenuContainer]",
25009
25009
  "providers": [],
25010
25010
  "hostDirectives": [],
@@ -25057,46 +25057,9 @@
25057
25057
  "outputsClass": [],
25058
25058
  "deprecated": false,
25059
25059
  "deprecationMessage": "",
25060
- "hostBindings": [
25061
- {
25062
- "coverageIgnore": false,
25063
- "name": "class.ecl",
25064
- "actualName": "hasClass",
25065
- "defaultValue": "true",
25066
- "deprecated": false,
25067
- "deprecationMessage": "",
25068
- "rawdescription": "\n",
25069
- "description": "",
25070
- "line": 14,
25071
- "type": "boolean",
25072
- "decorators": []
25073
- }
25074
- ],
25060
+ "hostBindings": [],
25075
25061
  "hostListeners": [],
25076
- "propertiesClass": [
25077
- {
25078
- "name": "hasClass",
25079
- "coverageIgnore": false,
25080
- "defaultValue": "true",
25081
- "deprecated": false,
25082
- "deprecationMessage": "",
25083
- "type": "unknown",
25084
- "indexKey": "",
25085
- "optional": false,
25086
- "description": "",
25087
- "line": 14,
25088
- "rawdescription": "\n",
25089
- "decorators": [
25090
- {
25091
- "name": "HostBinding",
25092
- "stringifiedArguments": "'class.ecl'"
25093
- }
25094
- ],
25095
- "modifierKind": [
25096
- 171
25097
- ]
25098
- }
25099
- ],
25062
+ "propertiesClass": [],
25100
25063
  "methodsClass": [
25101
25064
  {
25102
25065
  "name": "getCssClasses",
@@ -25140,8 +25103,8 @@
25140
25103
  "coverageIgnore": false,
25141
25104
  "jsdoctags": [
25142
25105
  {
25143
- "pos": 107,
25144
- "end": 180,
25106
+ "pos": 94,
25107
+ "end": 167,
25145
25108
  "kind": 321,
25146
25109
  "id": 0,
25147
25110
  "flags": 16777216,
@@ -25165,12 +25128,12 @@
25165
25128
  },
25166
25129
  {
25167
25130
  "name": "EclMegaMenuFeaturedImageDirective",
25168
- "id": "directive-EclMegaMenuFeaturedImageDirective-7360f4dbf768522edcfd43953e3e42e787ddf9fe181363fed08235b9734661e9e7e8d0464ec6348524ff5781a1457c239339fae9edae146b7c4be9425f4c1471",
25131
+ "id": "directive-EclMegaMenuFeaturedImageDirective-ba38ee88ef7cb65e7a7680d7cc622ba992dd904ac7f0f272600f3cbdb9ee72e8aff4d4f96f0df076b708c33c90b403c8354677f2d6c9f5355286a3afaf0fb06a",
25169
25132
  "file": "packages/ecl/components/ecl-mega-menu/directives/ecl-mega-menu-featured-picture.directive.ts",
25170
25133
  "type": "directive",
25171
25134
  "description": "<p>Directive that adds specific class to the mega-menu featured image.</p>\n",
25172
25135
  "rawdescription": "\n\nDirective that adds specific class to the mega-menu featured image.\n",
25173
- "sourceCode": "import { Directive, HostBinding } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu featured picture.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedPicture]',\n})\nexport class EclMegaMenuFeaturedPictureDirective extends ECLBaseDirective {\n @HostBinding('class')\n get cssClasses(): string {\n return [super.getCssClasses('ecl-picture ecl-mega-menu__featured-picture')].join(' ').trim();\n }\n}\n\n/**\n * Directive that adds specific class to the mega-menu featured image.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedImage]',\n})\nexport class EclMegaMenuFeaturedImageDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-image') cmpClass = true;\n}\n",
25136
+ "sourceCode": "import { Directive } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu featured picture.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedPicture]',\n host: {\n '[class]': 'cssClasses',\n },\n})\nexport class EclMegaMenuFeaturedPictureDirective extends ECLBaseDirective {\n get cssClasses(): string {\n return [super.getCssClasses('ecl-picture ecl-mega-menu__featured-picture')].join(' ').trim();\n }\n}\n\n/**\n * Directive that adds specific class to the mega-menu featured image.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedImage]',\n host: {\n class: 'ecl-mega-menu__featured-image',\n },\n})\nexport class EclMegaMenuFeaturedImageDirective extends ECLBaseDirective {\n}\n",
25174
25137
  "selector": "[eclMegaMenuFeaturedImage]",
25175
25138
  "providers": [],
25176
25139
  "hostDirectives": [],
@@ -25223,46 +25186,9 @@
25223
25186
  "outputsClass": [],
25224
25187
  "deprecated": false,
25225
25188
  "deprecationMessage": "",
25226
- "hostBindings": [
25227
- {
25228
- "coverageIgnore": false,
25229
- "name": "class.ecl-mega-menu__featured-image",
25230
- "actualName": "cmpClass",
25231
- "defaultValue": "true",
25232
- "deprecated": false,
25233
- "deprecationMessage": "",
25234
- "rawdescription": "\n",
25235
- "description": "",
25236
- "line": 24,
25237
- "type": "boolean",
25238
- "decorators": []
25239
- }
25240
- ],
25189
+ "hostBindings": [],
25241
25190
  "hostListeners": [],
25242
- "propertiesClass": [
25243
- {
25244
- "name": "cmpClass",
25245
- "coverageIgnore": false,
25246
- "defaultValue": "true",
25247
- "deprecated": false,
25248
- "deprecationMessage": "",
25249
- "type": "unknown",
25250
- "indexKey": "",
25251
- "optional": false,
25252
- "description": "",
25253
- "line": 24,
25254
- "rawdescription": "\n",
25255
- "decorators": [
25256
- {
25257
- "name": "HostBinding",
25258
- "stringifiedArguments": "'class.ecl-mega-menu__featured-image'"
25259
- }
25260
- ],
25261
- "modifierKind": [
25262
- 171
25263
- ]
25264
- }
25265
- ],
25191
+ "propertiesClass": [],
25266
25192
  "methodsClass": [
25267
25193
  {
25268
25194
  "name": "getCssClasses",
@@ -25306,8 +25232,8 @@
25306
25232
  "coverageIgnore": false,
25307
25233
  "jsdoctags": [
25308
25234
  {
25309
- "pos": 494,
25310
- "end": 572,
25235
+ "pos": 507,
25236
+ "end": 585,
25311
25237
  "kind": 321,
25312
25238
  "id": 0,
25313
25239
  "flags": 16777216,
@@ -25331,12 +25257,12 @@
25331
25257
  },
25332
25258
  {
25333
25259
  "name": "EclMegaMenuFeaturedListDirective",
25334
- "id": "directive-EclMegaMenuFeaturedListDirective-8c5a53f3bf58dcf67627aae2b9411f4caaf0ebe7ab2df1e1c8b00aa9e08d190b8306b8eb1a79fd61fc62324fdc39f48fb604c316b58c75f9a4ad2c65be26dd6a",
25260
+ "id": "directive-EclMegaMenuFeaturedListDirective-e6dcc6add426bd26cffc669cd287c91721bddaef3eea809b9f5180cbadd117aabb1eb6506c3e8081640d4173c08818444474ba0a9110da3dbc4c5b52c6d081d3",
25335
25261
  "file": "packages/ecl/components/ecl-mega-menu/directives/ecl-mega-menu-featured-list.directive.ts",
25336
25262
  "type": "directive",
25337
25263
  "description": "<p>Directive that adds specific class to the mega-menu featured list.</p>\n",
25338
25264
  "rawdescription": "\n\nDirective that adds specific class to the mega-menu featured list.\n",
25339
- "sourceCode": "import { Directive, HostBinding, ElementRef, inject, Input, booleanAttribute } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu featured list.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedList]',\n})\nexport class EclMegaMenuFeaturedListDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-list') cmpClass = true;\n}\n\n/**\n * Directive that adds specific class to a mega-menu featured list item.\n * Also has method that returns item height.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedListItem]',\n})\nexport class EclMegaMenuFeaturedListItemDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-list__item') cmpClass = true;\n\n @HostBinding('class.ecl-mega-menu__featured-list__item--image-only')\n @Input({ transform: booleanAttribute }) isImageOnly = false;\n\n @HostBinding('class.ecl-mega-menu__featured-list__item--combo')\n @Input({ transform: booleanAttribute }) isCombo = false;\n\n private el = inject(ElementRef);\n\n getEclMegaMenuFeaturedItemHeight(): number {\n const computedStyle = window.getComputedStyle(this.el.nativeElement);\n return this.el.nativeElement.scrollHeight + parseFloat(computedStyle.marginBottom) + parseFloat(computedStyle.marginTop);\n }\n}\n\n@Directive({\n selector: '[eclMegaMenuFeaturedListItemDescription]',\n})\nexport class EclMegaMenuFeaturedListItemDescriptionDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-list__item-description') cmpClass = true;\n}\n",
25265
+ "sourceCode": "import { Directive, ElementRef, inject, input, booleanAttribute } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu featured list.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedList]',\n host: {\n class: 'ecl-mega-menu__featured-list',\n },\n})\nexport class EclMegaMenuFeaturedListDirective extends ECLBaseDirective {\n}\n\n/**\n * Directive that adds specific class to a mega-menu featured list item.\n * Also has method that returns item height.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedListItem]',\n host: {\n class: 'ecl-mega-menu__featured-list__item',\n '[class.ecl-mega-menu__featured-list__item--image-only]': 'isImageOnly()',\n '[class.ecl-mega-menu__featured-list__item--combo]': 'isCombo()',\n },\n})\nexport class EclMegaMenuFeaturedListItemDirective extends ECLBaseDirective {\n readonly isImageOnly = input(false, { transform: booleanAttribute });\n\n readonly isCombo = input(false, { transform: booleanAttribute });\n\n private el = inject(ElementRef);\n\n getEclMegaMenuFeaturedItemHeight(): number {\n const computedStyle = window.getComputedStyle(this.el.nativeElement);\n return this.el.nativeElement.scrollHeight + parseFloat(computedStyle.marginBottom) + parseFloat(computedStyle.marginTop);\n }\n}\n\n@Directive({\n selector: '[eclMegaMenuFeaturedListItemDescription]',\n host: {\n class: 'ecl-mega-menu__featured-list__item-description',\n },\n})\nexport class EclMegaMenuFeaturedListItemDescriptionDirective extends ECLBaseDirective {\n}\n",
25340
25266
  "selector": "[eclMegaMenuFeaturedList]",
25341
25267
  "providers": [],
25342
25268
  "hostDirectives": [],
@@ -25389,46 +25315,9 @@
25389
25315
  "outputsClass": [],
25390
25316
  "deprecated": false,
25391
25317
  "deprecationMessage": "",
25392
- "hostBindings": [
25393
- {
25394
- "coverageIgnore": false,
25395
- "name": "class.ecl-mega-menu__featured-list",
25396
- "actualName": "cmpClass",
25397
- "defaultValue": "true",
25398
- "deprecated": false,
25399
- "deprecationMessage": "",
25400
- "rawdescription": "\n",
25401
- "description": "",
25402
- "line": 11,
25403
- "type": "boolean",
25404
- "decorators": []
25405
- }
25406
- ],
25318
+ "hostBindings": [],
25407
25319
  "hostListeners": [],
25408
- "propertiesClass": [
25409
- {
25410
- "name": "cmpClass",
25411
- "coverageIgnore": false,
25412
- "defaultValue": "true",
25413
- "deprecated": false,
25414
- "deprecationMessage": "",
25415
- "type": "unknown",
25416
- "indexKey": "",
25417
- "optional": false,
25418
- "description": "",
25419
- "line": 11,
25420
- "rawdescription": "\n",
25421
- "decorators": [
25422
- {
25423
- "name": "HostBinding",
25424
- "stringifiedArguments": "'class.ecl-mega-menu__featured-list'"
25425
- }
25426
- ],
25427
- "modifierKind": [
25428
- 171
25429
- ]
25430
- }
25431
- ],
25320
+ "propertiesClass": [],
25432
25321
  "methodsClass": [
25433
25322
  {
25434
25323
  "name": "getCssClasses",
@@ -25472,8 +25361,8 @@
25472
25361
  "coverageIgnore": false,
25473
25362
  "jsdoctags": [
25474
25363
  {
25475
- "pos": 152,
25476
- "end": 229,
25364
+ "pos": 139,
25365
+ "end": 216,
25477
25366
  "kind": 321,
25478
25367
  "id": 0,
25479
25368
  "flags": 16777216,
@@ -25497,12 +25386,12 @@
25497
25386
  },
25498
25387
  {
25499
25388
  "name": "EclMegaMenuFeaturedListItemDescriptionDirective",
25500
- "id": "directive-EclMegaMenuFeaturedListItemDescriptionDirective-8c5a53f3bf58dcf67627aae2b9411f4caaf0ebe7ab2df1e1c8b00aa9e08d190b8306b8eb1a79fd61fc62324fdc39f48fb604c316b58c75f9a4ad2c65be26dd6a",
25389
+ "id": "directive-EclMegaMenuFeaturedListItemDescriptionDirective-e6dcc6add426bd26cffc669cd287c91721bddaef3eea809b9f5180cbadd117aabb1eb6506c3e8081640d4173c08818444474ba0a9110da3dbc4c5b52c6d081d3",
25501
25390
  "file": "packages/ecl/components/ecl-mega-menu/directives/ecl-mega-menu-featured-list.directive.ts",
25502
25391
  "type": "directive",
25503
25392
  "description": "",
25504
25393
  "rawdescription": "\n",
25505
- "sourceCode": "import { Directive, HostBinding, ElementRef, inject, Input, booleanAttribute } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu featured list.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedList]',\n})\nexport class EclMegaMenuFeaturedListDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-list') cmpClass = true;\n}\n\n/**\n * Directive that adds specific class to a mega-menu featured list item.\n * Also has method that returns item height.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedListItem]',\n})\nexport class EclMegaMenuFeaturedListItemDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-list__item') cmpClass = true;\n\n @HostBinding('class.ecl-mega-menu__featured-list__item--image-only')\n @Input({ transform: booleanAttribute }) isImageOnly = false;\n\n @HostBinding('class.ecl-mega-menu__featured-list__item--combo')\n @Input({ transform: booleanAttribute }) isCombo = false;\n\n private el = inject(ElementRef);\n\n getEclMegaMenuFeaturedItemHeight(): number {\n const computedStyle = window.getComputedStyle(this.el.nativeElement);\n return this.el.nativeElement.scrollHeight + parseFloat(computedStyle.marginBottom) + parseFloat(computedStyle.marginTop);\n }\n}\n\n@Directive({\n selector: '[eclMegaMenuFeaturedListItemDescription]',\n})\nexport class EclMegaMenuFeaturedListItemDescriptionDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-list__item-description') cmpClass = true;\n}\n",
25394
+ "sourceCode": "import { Directive, ElementRef, inject, input, booleanAttribute } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu featured list.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedList]',\n host: {\n class: 'ecl-mega-menu__featured-list',\n },\n})\nexport class EclMegaMenuFeaturedListDirective extends ECLBaseDirective {\n}\n\n/**\n * Directive that adds specific class to a mega-menu featured list item.\n * Also has method that returns item height.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedListItem]',\n host: {\n class: 'ecl-mega-menu__featured-list__item',\n '[class.ecl-mega-menu__featured-list__item--image-only]': 'isImageOnly()',\n '[class.ecl-mega-menu__featured-list__item--combo]': 'isCombo()',\n },\n})\nexport class EclMegaMenuFeaturedListItemDirective extends ECLBaseDirective {\n readonly isImageOnly = input(false, { transform: booleanAttribute });\n\n readonly isCombo = input(false, { transform: booleanAttribute });\n\n private el = inject(ElementRef);\n\n getEclMegaMenuFeaturedItemHeight(): number {\n const computedStyle = window.getComputedStyle(this.el.nativeElement);\n return this.el.nativeElement.scrollHeight + parseFloat(computedStyle.marginBottom) + parseFloat(computedStyle.marginTop);\n }\n}\n\n@Directive({\n selector: '[eclMegaMenuFeaturedListItemDescription]',\n host: {\n class: 'ecl-mega-menu__featured-list__item-description',\n },\n})\nexport class EclMegaMenuFeaturedListItemDescriptionDirective extends ECLBaseDirective {\n}\n",
25506
25395
  "selector": "[eclMegaMenuFeaturedListItemDescription]",
25507
25396
  "providers": [],
25508
25397
  "hostDirectives": [],
@@ -25555,46 +25444,9 @@
25555
25444
  "outputsClass": [],
25556
25445
  "deprecated": false,
25557
25446
  "deprecationMessage": "",
25558
- "hostBindings": [
25559
- {
25560
- "coverageIgnore": false,
25561
- "name": "class.ecl-mega-menu__featured-list__item-description",
25562
- "actualName": "cmpClass",
25563
- "defaultValue": "true",
25564
- "deprecated": false,
25565
- "deprecationMessage": "",
25566
- "rawdescription": "\n",
25567
- "description": "",
25568
- "line": 42,
25569
- "type": "boolean",
25570
- "decorators": []
25571
- }
25572
- ],
25447
+ "hostBindings": [],
25573
25448
  "hostListeners": [],
25574
- "propertiesClass": [
25575
- {
25576
- "name": "cmpClass",
25577
- "coverageIgnore": false,
25578
- "defaultValue": "true",
25579
- "deprecated": false,
25580
- "deprecationMessage": "",
25581
- "type": "unknown",
25582
- "indexKey": "",
25583
- "optional": false,
25584
- "description": "",
25585
- "line": 42,
25586
- "rawdescription": "\n",
25587
- "decorators": [
25588
- {
25589
- "name": "HostBinding",
25590
- "stringifiedArguments": "'class.ecl-mega-menu__featured-list__item-description'"
25591
- }
25592
- ],
25593
- "modifierKind": [
25594
- 171
25595
- ]
25596
- }
25597
- ],
25449
+ "propertiesClass": [],
25598
25450
  "methodsClass": [
25599
25451
  {
25600
25452
  "name": "getCssClasses",
@@ -25651,42 +25503,50 @@
25651
25503
  },
25652
25504
  {
25653
25505
  "name": "EclMegaMenuFeaturedListItemDirective",
25654
- "id": "directive-EclMegaMenuFeaturedListItemDirective-8c5a53f3bf58dcf67627aae2b9411f4caaf0ebe7ab2df1e1c8b00aa9e08d190b8306b8eb1a79fd61fc62324fdc39f48fb604c316b58c75f9a4ad2c65be26dd6a",
25506
+ "id": "directive-EclMegaMenuFeaturedListItemDirective-e6dcc6add426bd26cffc669cd287c91721bddaef3eea809b9f5180cbadd117aabb1eb6506c3e8081640d4173c08818444474ba0a9110da3dbc4c5b52c6d081d3",
25655
25507
  "file": "packages/ecl/components/ecl-mega-menu/directives/ecl-mega-menu-featured-list.directive.ts",
25656
25508
  "type": "directive",
25657
25509
  "description": "<p>Directive that adds specific class to a mega-menu featured list item.\nAlso has method that returns item height.</p>\n",
25658
25510
  "rawdescription": "\n\nDirective that adds specific class to a mega-menu featured list item.\nAlso has method that returns item height.\n",
25659
- "sourceCode": "import { Directive, HostBinding, ElementRef, inject, Input, booleanAttribute } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu featured list.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedList]',\n})\nexport class EclMegaMenuFeaturedListDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-list') cmpClass = true;\n}\n\n/**\n * Directive that adds specific class to a mega-menu featured list item.\n * Also has method that returns item height.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedListItem]',\n})\nexport class EclMegaMenuFeaturedListItemDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-list__item') cmpClass = true;\n\n @HostBinding('class.ecl-mega-menu__featured-list__item--image-only')\n @Input({ transform: booleanAttribute }) isImageOnly = false;\n\n @HostBinding('class.ecl-mega-menu__featured-list__item--combo')\n @Input({ transform: booleanAttribute }) isCombo = false;\n\n private el = inject(ElementRef);\n\n getEclMegaMenuFeaturedItemHeight(): number {\n const computedStyle = window.getComputedStyle(this.el.nativeElement);\n return this.el.nativeElement.scrollHeight + parseFloat(computedStyle.marginBottom) + parseFloat(computedStyle.marginTop);\n }\n}\n\n@Directive({\n selector: '[eclMegaMenuFeaturedListItemDescription]',\n})\nexport class EclMegaMenuFeaturedListItemDescriptionDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-list__item-description') cmpClass = true;\n}\n",
25511
+ "sourceCode": "import { Directive, ElementRef, inject, input, booleanAttribute } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu featured list.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedList]',\n host: {\n class: 'ecl-mega-menu__featured-list',\n },\n})\nexport class EclMegaMenuFeaturedListDirective extends ECLBaseDirective {\n}\n\n/**\n * Directive that adds specific class to a mega-menu featured list item.\n * Also has method that returns item height.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedListItem]',\n host: {\n class: 'ecl-mega-menu__featured-list__item',\n '[class.ecl-mega-menu__featured-list__item--image-only]': 'isImageOnly()',\n '[class.ecl-mega-menu__featured-list__item--combo]': 'isCombo()',\n },\n})\nexport class EclMegaMenuFeaturedListItemDirective extends ECLBaseDirective {\n readonly isImageOnly = input(false, { transform: booleanAttribute });\n\n readonly isCombo = input(false, { transform: booleanAttribute });\n\n private el = inject(ElementRef);\n\n getEclMegaMenuFeaturedItemHeight(): number {\n const computedStyle = window.getComputedStyle(this.el.nativeElement);\n return this.el.nativeElement.scrollHeight + parseFloat(computedStyle.marginBottom) + parseFloat(computedStyle.marginTop);\n }\n}\n\n@Directive({\n selector: '[eclMegaMenuFeaturedListItemDescription]',\n host: {\n class: 'ecl-mega-menu__featured-list__item-description',\n },\n})\nexport class EclMegaMenuFeaturedListItemDescriptionDirective extends ECLBaseDirective {\n}\n",
25660
25512
  "selector": "[eclMegaMenuFeaturedListItem]",
25661
25513
  "providers": [],
25662
25514
  "hostDirectives": [],
25663
25515
  "standalone": false,
25664
25516
  "inputsClass": [
25665
25517
  {
25666
- "coverageIgnore": false,
25667
- "required": false,
25668
25518
  "name": "isCombo",
25519
+ "coverageIgnore": false,
25669
25520
  "defaultValue": "false",
25670
25521
  "deprecated": false,
25671
25522
  "deprecationMessage": "",
25672
- "rawdescription": "\n",
25673
- "description": "",
25674
- "line": 28,
25675
25523
  "type": "boolean",
25676
- "decorators": []
25524
+ "indexKey": "",
25525
+ "optional": false,
25526
+ "description": "",
25527
+ "line": 31,
25528
+ "rawdescription": "\n",
25529
+ "modifierKind": [
25530
+ 148
25531
+ ],
25532
+ "required": false
25677
25533
  },
25678
25534
  {
25679
- "coverageIgnore": false,
25680
- "required": false,
25681
25535
  "name": "isImageOnly",
25536
+ "coverageIgnore": false,
25682
25537
  "defaultValue": "false",
25683
25538
  "deprecated": false,
25684
25539
  "deprecationMessage": "",
25685
- "rawdescription": "\n",
25686
- "description": "",
25687
- "line": 25,
25688
25540
  "type": "boolean",
25689
- "decorators": []
25541
+ "indexKey": "",
25542
+ "optional": false,
25543
+ "description": "",
25544
+ "line": 29,
25545
+ "rawdescription": "\n",
25546
+ "modifierKind": [
25547
+ 148
25548
+ ],
25549
+ "required": false
25690
25550
  },
25691
25551
  {
25692
25552
  "coverageIgnore": false,
@@ -25735,46 +25595,9 @@
25735
25595
  "outputsClass": [],
25736
25596
  "deprecated": false,
25737
25597
  "deprecationMessage": "",
25738
- "hostBindings": [
25739
- {
25740
- "coverageIgnore": false,
25741
- "name": "class.ecl-mega-menu__featured-list__item",
25742
- "actualName": "cmpClass",
25743
- "defaultValue": "true",
25744
- "deprecated": false,
25745
- "deprecationMessage": "",
25746
- "rawdescription": "\n",
25747
- "description": "",
25748
- "line": 22,
25749
- "type": "boolean",
25750
- "decorators": []
25751
- }
25752
- ],
25598
+ "hostBindings": [],
25753
25599
  "hostListeners": [],
25754
- "propertiesClass": [
25755
- {
25756
- "name": "cmpClass",
25757
- "coverageIgnore": false,
25758
- "defaultValue": "true",
25759
- "deprecated": false,
25760
- "deprecationMessage": "",
25761
- "type": "unknown",
25762
- "indexKey": "",
25763
- "optional": false,
25764
- "description": "",
25765
- "line": 22,
25766
- "rawdescription": "\n",
25767
- "decorators": [
25768
- {
25769
- "name": "HostBinding",
25770
- "stringifiedArguments": "'class.ecl-mega-menu__featured-list__item'"
25771
- }
25772
- ],
25773
- "modifierKind": [
25774
- 171
25775
- ]
25776
- }
25777
- ],
25600
+ "propertiesClass": [],
25778
25601
  "methodsClass": [
25779
25602
  {
25780
25603
  "name": "getEclMegaMenuFeaturedItemHeight",
@@ -25783,7 +25606,7 @@
25783
25606
  "optional": false,
25784
25607
  "returnType": "number",
25785
25608
  "typeParameters": [],
25786
- "line": 32,
25609
+ "line": 35,
25787
25610
  "deprecated": false,
25788
25611
  "deprecationMessage": "",
25789
25612
  "rawdescription": "\n",
@@ -25831,8 +25654,8 @@
25831
25654
  "coverageIgnore": false,
25832
25655
  "jsdoctags": [
25833
25656
  {
25834
- "pos": 437,
25835
- "end": 562,
25657
+ "pos": 418,
25658
+ "end": 543,
25836
25659
  "kind": 321,
25837
25660
  "id": 0,
25838
25661
  "flags": 16777216,
@@ -25856,12 +25679,12 @@
25856
25679
  },
25857
25680
  {
25858
25681
  "name": "EclMegaMenuFeaturedPictureDirective",
25859
- "id": "directive-EclMegaMenuFeaturedPictureDirective-7360f4dbf768522edcfd43953e3e42e787ddf9fe181363fed08235b9734661e9e7e8d0464ec6348524ff5781a1457c239339fae9edae146b7c4be9425f4c1471",
25682
+ "id": "directive-EclMegaMenuFeaturedPictureDirective-ba38ee88ef7cb65e7a7680d7cc622ba992dd904ac7f0f272600f3cbdb9ee72e8aff4d4f96f0df076b708c33c90b403c8354677f2d6c9f5355286a3afaf0fb06a",
25860
25683
  "file": "packages/ecl/components/ecl-mega-menu/directives/ecl-mega-menu-featured-picture.directive.ts",
25861
25684
  "type": "directive",
25862
25685
  "description": "<p>Directive that adds specific class to the mega-menu featured picture.</p>\n",
25863
25686
  "rawdescription": "\n\nDirective that adds specific class to the mega-menu featured picture.\n",
25864
- "sourceCode": "import { Directive, HostBinding } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu featured picture.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedPicture]',\n})\nexport class EclMegaMenuFeaturedPictureDirective extends ECLBaseDirective {\n @HostBinding('class')\n get cssClasses(): string {\n return [super.getCssClasses('ecl-picture ecl-mega-menu__featured-picture')].join(' ').trim();\n }\n}\n\n/**\n * Directive that adds specific class to the mega-menu featured image.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedImage]',\n})\nexport class EclMegaMenuFeaturedImageDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__featured-image') cmpClass = true;\n}\n",
25687
+ "sourceCode": "import { Directive } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that adds specific class to the mega-menu featured picture.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedPicture]',\n host: {\n '[class]': 'cssClasses',\n },\n})\nexport class EclMegaMenuFeaturedPictureDirective extends ECLBaseDirective {\n get cssClasses(): string {\n return [super.getCssClasses('ecl-picture ecl-mega-menu__featured-picture')].join(' ').trim();\n }\n}\n\n/**\n * Directive that adds specific class to the mega-menu featured image.\n */\n@Directive({\n selector: '[eclMegaMenuFeaturedImage]',\n host: {\n class: 'ecl-mega-menu__featured-image',\n },\n})\nexport class EclMegaMenuFeaturedImageDirective extends ECLBaseDirective {\n}\n",
25865
25688
  "selector": "[eclMegaMenuFeaturedPicture]",
25866
25689
  "providers": [],
25867
25690
  "hostDirectives": [],
@@ -25914,20 +25737,7 @@
25914
25737
  "outputsClass": [],
25915
25738
  "deprecated": false,
25916
25739
  "deprecationMessage": "",
25917
- "hostBindings": [
25918
- {
25919
- "coverageIgnore": false,
25920
- "name": "class",
25921
- "actualName": "cssClasses",
25922
- "deprecated": false,
25923
- "deprecationMessage": "",
25924
- "rawdescription": "\n",
25925
- "description": "",
25926
- "line": 12,
25927
- "type": "string",
25928
- "decorators": []
25929
- }
25930
- ],
25740
+ "hostBindings": [],
25931
25741
  "hostListeners": [],
25932
25742
  "propertiesClass": [],
25933
25743
  "methodsClass": [
@@ -25973,8 +25783,8 @@
25973
25783
  "coverageIgnore": false,
25974
25784
  "jsdoctags": [
25975
25785
  {
25976
- "pos": 107,
25977
- "end": 187,
25786
+ "pos": 94,
25787
+ "end": 174,
25978
25788
  "kind": 321,
25979
25789
  "id": 0,
25980
25790
  "flags": 16777216,
@@ -25993,7 +25803,7 @@
25993
25803
  "name": "cssClasses",
25994
25804
  "type": "string",
25995
25805
  "returnType": "string",
25996
- "line": 12,
25806
+ "line": 14,
25997
25807
  "rawdescription": "\n",
25998
25808
  "description": ""
25999
25809
  }
@@ -26011,12 +25821,12 @@
26011
25821
  },
26012
25822
  {
26013
25823
  "name": "EclMegaMenuListDirective",
26014
- "id": "directive-EclMegaMenuListDirective-02469b11ffd64d49ecd3a01aba8e2d5bc27d5e6a3c139bd7261cc1f0148c8e1c6e35c2987e9829efbe4d088d62862ad081d63d5ccb1dbc35aab8d1ab646e7bc6",
25824
+ "id": "directive-EclMegaMenuListDirective-77213061afcb1f49414790da69d7b7992f3b21c97c9304055a0fb9b584252f05f352f85411151061cb3c36136d74ab16d680fc3a8d9fca8461076c60f1b0ddb3",
26015
25825
  "file": "packages/ecl/components/ecl-mega-menu/directives/ecl-mega-menu-list.directive.ts",
26016
25826
  "type": "directive",
26017
25827
  "description": "<p>Directive that adds specific class to the mega-menu list.</p>\n",
26018
25828
  "rawdescription": "\n\nDirective that adds specific class to the mega-menu list.\n",
26019
- "sourceCode": "import { Directive, DoCheck, ElementRef, EventEmitter, HostBinding, IterableDiffer, IterableDiffers, OnDestroy, Output, afterNextRender, forwardRef, inject, signal, contentChildren, contentChild } from '@angular/core';\nimport { EuiAppShellService } from '@eui/core';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { distinctUntilChanged, map, Subject, takeUntil } from 'rxjs';\nimport { EclMegaMenuSubitemComponent } from '../ecl-mega-menu-subitem/ecl-mega-menu-subitem.component';\n\n/**\n * Directive that adds specific class to the mega-menu list.\n */\n@Directive({\n selector: 'ul[eclMegaMenuList]',\n})\nexport class EclMegaMenuListDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__list') cmpClass = true;\n}\n\n/**\n * Directive that adds specific class to the mega-menu spacer.\n */\n@Directive({\n selector: 'li[eclMegaMenuSpacer]',\n})\nexport class EclMegaMenuSpacerDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__spacer') cmpClass = true;\n}\n\n/**\n * Directive that adds specific classes and functionality to the mega-menu sublist.\n */\n@Directive({\n selector: 'ul[eclMegaMenuSublist]',\n host: {\n '[style.height.px]': 'styleHeight()',\n },\n})\nexport class EclMegaMenuSublistDirective extends ECLBaseDirective implements OnDestroy, DoCheck {\n el = inject(ElementRef);\n\n @HostBinding('class.ecl-mega-menu__sublist') cmpClass = true;\n @HostBinding('class.ecl-mega-menu__sublist--scrollable') isScrollable = false;\n @HostBinding('style.top.px') styleTop: number | null = null;\n styleHeight = signal<number | null>(null);\n\n readonly submenuItems = contentChildren(forwardRef(() => EclMegaMenuSubitemComponent));\n readonly spacer = contentChild(forwardRef(() => EclMegaMenuSpacerDirective));\n @Output() megaMenuSubItemClicked = new EventEmitter();\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclMegaMenuSubitemComponent>;\n private isMobileBreakpoint = false;\n private differs = inject(IterableDiffers);\n private appShell = inject(EuiAppShellService);\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.observeBreakpointChanges();\n });\n }\n\n ngDoCheck(): void {\n // When a new item is added -> subscribe to item's events.\n const diff = this.differ.diff(this.submenuItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectMegaMenuItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * When parent mega-menu item is clicked.\n * @param isExpanded - 'true', if parent item is expanded, 'false' if item is collapsed.\n */\n onParentMegaMenuItemClick(isExpanded: boolean): void {\n if (!isExpanded) {\n this.submenuItems().forEach(item => {\n if (item.isExpanded) {\n item.onSubMenuItemCollapse();\n }\n });\n }\n }\n\n private connectMegaMenuItemEvents(item: EclMegaMenuSubitemComponent): void {\n item.megaMenuSubItemClicked.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onMegaMenuSubItemClicked(item);\n });\n\n item.megaMenuSubItemKeydown.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.onMegaMenuSubItemKeydown(item, evt);\n });\n }\n\n private onMegaMenuSubItemClicked(item: EclMegaMenuSubitemComponent): void {\n this.submenuItems().filter(subItem => subItem !== item).forEach(el => {\n el.onSubMenuItemCollapse();\n if (this.isMobileBreakpoint && item.hasChildren) {\n el.onHide();\n }\n });\n this.megaMenuSubItemClicked.emit();\n }\n\n private onMegaMenuSubItemKeydown(item: EclMegaMenuSubitemComponent, evt: KeyboardEvent): void {\n\n const itemIndex = this.submenuItems().findIndex(elem => elem === item);\n switch (evt.key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n this.focusOnNextSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.focusOnPrevSibling(itemIndex);\n break;\n }\n default: {\n break;\n }\n }\n }\n\n private focusOnPrevSibling(index: number): void {\n if (index > 0) {\n this.submenuItems().at(index - 1).onFocus();\n }\n }\n\n private focusOnNextSibling(index: number): void {\n if (index < this.submenuItems().length - 1) {\n this.submenuItems().at(index + 1).onFocus();\n }\n }\n\n private observeBreakpointChanges(): void {\n this.appShell.getState<any>('breakpoints')\n .pipe(\n map(bp => !!bp?.isLtLargeTablet), // xs/sm/md/lg => <= 996px boundary\n distinctUntilChanged(),\n takeUntil(this.destroy$),\n )\n .subscribe((isMobile) => {\n const wasMobile = this.isMobileBreakpoint;\n this.isMobileBreakpoint = isMobile;\n\n // Reset height/position values when switching between breakpoints\n // to avoid stale pixel values from the previous layout mode\n if (wasMobile !== isMobile) {\n this.styleHeight.set(null);\n this.styleTop = null;\n this.isScrollable = false;\n }\n });\n }\n}\n",
25829
+ "sourceCode": "import { Directive, DoCheck, ElementRef, EventEmitter, IterableDiffer, IterableDiffers, OnDestroy, Output, afterNextRender, forwardRef, inject, signal, contentChildren, contentChild } from '@angular/core';\nimport { EuiAppShellService } from '@eui/core';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { distinctUntilChanged, map, Subject, takeUntil } from 'rxjs';\nimport { EclMegaMenuSubitemComponent } from '../ecl-mega-menu-subitem/ecl-mega-menu-subitem.component';\n\n/**\n * Directive that adds specific class to the mega-menu list.\n */\n@Directive({\n selector: 'ul[eclMegaMenuList]',\n host: {\n class: 'ecl-mega-menu__list',\n },\n})\nexport class EclMegaMenuListDirective extends ECLBaseDirective {\n}\n\n/**\n * Directive that adds specific class to the mega-menu spacer.\n */\n@Directive({\n selector: 'li[eclMegaMenuSpacer]',\n host: {\n class: 'ecl-mega-menu__spacer',\n },\n})\nexport class EclMegaMenuSpacerDirective extends ECLBaseDirective {\n}\n\n/**\n * Directive that adds specific classes and functionality to the mega-menu sublist.\n */\n@Directive({\n selector: 'ul[eclMegaMenuSublist]',\n host: {\n class: 'ecl-mega-menu__sublist',\n '[class.ecl-mega-menu__sublist--scrollable]': 'isScrollable',\n '[style.top.px]': 'styleTop',\n '[style.height.px]': 'styleHeight()',\n },\n})\nexport class EclMegaMenuSublistDirective extends ECLBaseDirective implements OnDestroy, DoCheck {\n el = inject(ElementRef);\n\n isScrollable = false;\n styleTop: number | null = null;\n styleHeight = signal<number | null>(null);\n\n readonly submenuItems = contentChildren(forwardRef(() => EclMegaMenuSubitemComponent));\n readonly spacer = contentChild(forwardRef(() => EclMegaMenuSpacerDirective));\n @Output() megaMenuSubItemClicked = new EventEmitter();\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclMegaMenuSubitemComponent>;\n private isMobileBreakpoint = false;\n private differs = inject(IterableDiffers);\n private appShell = inject(EuiAppShellService);\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.observeBreakpointChanges();\n });\n }\n\n ngDoCheck(): void {\n // When a new item is added -> subscribe to item's events.\n const diff = this.differ.diff(this.submenuItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectMegaMenuItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * When parent mega-menu item is clicked.\n * @param isExpanded - 'true', if parent item is expanded, 'false' if item is collapsed.\n */\n onParentMegaMenuItemClick(isExpanded: boolean): void {\n if (!isExpanded) {\n this.submenuItems().forEach(item => {\n if (item.isExpanded) {\n item.onSubMenuItemCollapse();\n }\n });\n }\n }\n\n private connectMegaMenuItemEvents(item: EclMegaMenuSubitemComponent): void {\n item.megaMenuSubItemClicked.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onMegaMenuSubItemClicked(item);\n });\n\n item.megaMenuSubItemKeydown.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.onMegaMenuSubItemKeydown(item, evt);\n });\n }\n\n private onMegaMenuSubItemClicked(item: EclMegaMenuSubitemComponent): void {\n this.submenuItems().filter(subItem => subItem !== item).forEach(el => {\n el.onSubMenuItemCollapse();\n if (this.isMobileBreakpoint && item.hasChildren) {\n el.onHide();\n }\n });\n this.megaMenuSubItemClicked.emit();\n }\n\n private onMegaMenuSubItemKeydown(item: EclMegaMenuSubitemComponent, evt: KeyboardEvent): void {\n\n const itemIndex = this.submenuItems().findIndex(elem => elem === item);\n switch (evt.key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n this.focusOnNextSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.focusOnPrevSibling(itemIndex);\n break;\n }\n default: {\n break;\n }\n }\n }\n\n private focusOnPrevSibling(index: number): void {\n if (index > 0) {\n this.submenuItems().at(index - 1).onFocus();\n }\n }\n\n private focusOnNextSibling(index: number): void {\n if (index < this.submenuItems().length - 1) {\n this.submenuItems().at(index + 1).onFocus();\n }\n }\n\n private observeBreakpointChanges(): void {\n this.appShell.getState<any>('breakpoints')\n .pipe(\n map(bp => !!bp?.isLtLargeTablet), // xs/sm/md/lg => <= 996px boundary\n distinctUntilChanged(),\n takeUntil(this.destroy$),\n )\n .subscribe((isMobile) => {\n const wasMobile = this.isMobileBreakpoint;\n this.isMobileBreakpoint = isMobile;\n\n // Reset height/position values when switching between breakpoints\n // to avoid stale pixel values from the previous layout mode\n if (wasMobile !== isMobile) {\n this.styleHeight.set(null);\n this.styleTop = null;\n this.isScrollable = false;\n }\n });\n }\n}\n",
26020
25830
  "selector": "ul[eclMegaMenuList]",
26021
25831
  "providers": [],
26022
25832
  "hostDirectives": [],
@@ -26069,46 +25879,9 @@
26069
25879
  "outputsClass": [],
26070
25880
  "deprecated": false,
26071
25881
  "deprecationMessage": "",
26072
- "hostBindings": [
26073
- {
26074
- "coverageIgnore": false,
26075
- "name": "class.ecl-mega-menu__list",
26076
- "actualName": "cmpClass",
26077
- "defaultValue": "true",
26078
- "deprecated": false,
26079
- "deprecationMessage": "",
26080
- "rawdescription": "\n",
26081
- "description": "",
26082
- "line": 14,
26083
- "type": "boolean",
26084
- "decorators": []
26085
- }
26086
- ],
25882
+ "hostBindings": [],
26087
25883
  "hostListeners": [],
26088
- "propertiesClass": [
26089
- {
26090
- "name": "cmpClass",
26091
- "coverageIgnore": false,
26092
- "defaultValue": "true",
26093
- "deprecated": false,
26094
- "deprecationMessage": "",
26095
- "type": "unknown",
26096
- "indexKey": "",
26097
- "optional": false,
26098
- "description": "",
26099
- "line": 14,
26100
- "rawdescription": "\n",
26101
- "decorators": [
26102
- {
26103
- "name": "HostBinding",
26104
- "stringifiedArguments": "'class.ecl-mega-menu__list'"
26105
- }
26106
- ],
26107
- "modifierKind": [
26108
- 171
26109
- ]
26110
- }
26111
- ],
25884
+ "propertiesClass": [],
26112
25885
  "methodsClass": [
26113
25886
  {
26114
25887
  "name": "getCssClasses",
@@ -26152,8 +25925,8 @@
26152
25925
  "coverageIgnore": false,
26153
25926
  "jsdoctags": [
26154
25927
  {
26155
- "pos": 501,
26156
- "end": 569,
25928
+ "pos": 488,
25929
+ "end": 556,
26157
25930
  "kind": 321,
26158
25931
  "id": 0,
26159
25932
  "flags": 16777216,
@@ -26177,12 +25950,12 @@
26177
25950
  },
26178
25951
  {
26179
25952
  "name": "EclMegaMenuSpacerDirective",
26180
- "id": "directive-EclMegaMenuSpacerDirective-02469b11ffd64d49ecd3a01aba8e2d5bc27d5e6a3c139bd7261cc1f0148c8e1c6e35c2987e9829efbe4d088d62862ad081d63d5ccb1dbc35aab8d1ab646e7bc6",
25953
+ "id": "directive-EclMegaMenuSpacerDirective-77213061afcb1f49414790da69d7b7992f3b21c97c9304055a0fb9b584252f05f352f85411151061cb3c36136d74ab16d680fc3a8d9fca8461076c60f1b0ddb3",
26181
25954
  "file": "packages/ecl/components/ecl-mega-menu/directives/ecl-mega-menu-list.directive.ts",
26182
25955
  "type": "directive",
26183
25956
  "description": "<p>Directive that adds specific class to the mega-menu spacer.</p>\n",
26184
25957
  "rawdescription": "\n\nDirective that adds specific class to the mega-menu spacer.\n",
26185
- "sourceCode": "import { Directive, DoCheck, ElementRef, EventEmitter, HostBinding, IterableDiffer, IterableDiffers, OnDestroy, Output, afterNextRender, forwardRef, inject, signal, contentChildren, contentChild } from '@angular/core';\nimport { EuiAppShellService } from '@eui/core';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { distinctUntilChanged, map, Subject, takeUntil } from 'rxjs';\nimport { EclMegaMenuSubitemComponent } from '../ecl-mega-menu-subitem/ecl-mega-menu-subitem.component';\n\n/**\n * Directive that adds specific class to the mega-menu list.\n */\n@Directive({\n selector: 'ul[eclMegaMenuList]',\n})\nexport class EclMegaMenuListDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__list') cmpClass = true;\n}\n\n/**\n * Directive that adds specific class to the mega-menu spacer.\n */\n@Directive({\n selector: 'li[eclMegaMenuSpacer]',\n})\nexport class EclMegaMenuSpacerDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__spacer') cmpClass = true;\n}\n\n/**\n * Directive that adds specific classes and functionality to the mega-menu sublist.\n */\n@Directive({\n selector: 'ul[eclMegaMenuSublist]',\n host: {\n '[style.height.px]': 'styleHeight()',\n },\n})\nexport class EclMegaMenuSublistDirective extends ECLBaseDirective implements OnDestroy, DoCheck {\n el = inject(ElementRef);\n\n @HostBinding('class.ecl-mega-menu__sublist') cmpClass = true;\n @HostBinding('class.ecl-mega-menu__sublist--scrollable') isScrollable = false;\n @HostBinding('style.top.px') styleTop: number | null = null;\n styleHeight = signal<number | null>(null);\n\n readonly submenuItems = contentChildren(forwardRef(() => EclMegaMenuSubitemComponent));\n readonly spacer = contentChild(forwardRef(() => EclMegaMenuSpacerDirective));\n @Output() megaMenuSubItemClicked = new EventEmitter();\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclMegaMenuSubitemComponent>;\n private isMobileBreakpoint = false;\n private differs = inject(IterableDiffers);\n private appShell = inject(EuiAppShellService);\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.observeBreakpointChanges();\n });\n }\n\n ngDoCheck(): void {\n // When a new item is added -> subscribe to item's events.\n const diff = this.differ.diff(this.submenuItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectMegaMenuItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * When parent mega-menu item is clicked.\n * @param isExpanded - 'true', if parent item is expanded, 'false' if item is collapsed.\n */\n onParentMegaMenuItemClick(isExpanded: boolean): void {\n if (!isExpanded) {\n this.submenuItems().forEach(item => {\n if (item.isExpanded) {\n item.onSubMenuItemCollapse();\n }\n });\n }\n }\n\n private connectMegaMenuItemEvents(item: EclMegaMenuSubitemComponent): void {\n item.megaMenuSubItemClicked.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onMegaMenuSubItemClicked(item);\n });\n\n item.megaMenuSubItemKeydown.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.onMegaMenuSubItemKeydown(item, evt);\n });\n }\n\n private onMegaMenuSubItemClicked(item: EclMegaMenuSubitemComponent): void {\n this.submenuItems().filter(subItem => subItem !== item).forEach(el => {\n el.onSubMenuItemCollapse();\n if (this.isMobileBreakpoint && item.hasChildren) {\n el.onHide();\n }\n });\n this.megaMenuSubItemClicked.emit();\n }\n\n private onMegaMenuSubItemKeydown(item: EclMegaMenuSubitemComponent, evt: KeyboardEvent): void {\n\n const itemIndex = this.submenuItems().findIndex(elem => elem === item);\n switch (evt.key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n this.focusOnNextSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.focusOnPrevSibling(itemIndex);\n break;\n }\n default: {\n break;\n }\n }\n }\n\n private focusOnPrevSibling(index: number): void {\n if (index > 0) {\n this.submenuItems().at(index - 1).onFocus();\n }\n }\n\n private focusOnNextSibling(index: number): void {\n if (index < this.submenuItems().length - 1) {\n this.submenuItems().at(index + 1).onFocus();\n }\n }\n\n private observeBreakpointChanges(): void {\n this.appShell.getState<any>('breakpoints')\n .pipe(\n map(bp => !!bp?.isLtLargeTablet), // xs/sm/md/lg => <= 996px boundary\n distinctUntilChanged(),\n takeUntil(this.destroy$),\n )\n .subscribe((isMobile) => {\n const wasMobile = this.isMobileBreakpoint;\n this.isMobileBreakpoint = isMobile;\n\n // Reset height/position values when switching between breakpoints\n // to avoid stale pixel values from the previous layout mode\n if (wasMobile !== isMobile) {\n this.styleHeight.set(null);\n this.styleTop = null;\n this.isScrollable = false;\n }\n });\n }\n}\n",
25958
+ "sourceCode": "import { Directive, DoCheck, ElementRef, EventEmitter, IterableDiffer, IterableDiffers, OnDestroy, Output, afterNextRender, forwardRef, inject, signal, contentChildren, contentChild } from '@angular/core';\nimport { EuiAppShellService } from '@eui/core';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { distinctUntilChanged, map, Subject, takeUntil } from 'rxjs';\nimport { EclMegaMenuSubitemComponent } from '../ecl-mega-menu-subitem/ecl-mega-menu-subitem.component';\n\n/**\n * Directive that adds specific class to the mega-menu list.\n */\n@Directive({\n selector: 'ul[eclMegaMenuList]',\n host: {\n class: 'ecl-mega-menu__list',\n },\n})\nexport class EclMegaMenuListDirective extends ECLBaseDirective {\n}\n\n/**\n * Directive that adds specific class to the mega-menu spacer.\n */\n@Directive({\n selector: 'li[eclMegaMenuSpacer]',\n host: {\n class: 'ecl-mega-menu__spacer',\n },\n})\nexport class EclMegaMenuSpacerDirective extends ECLBaseDirective {\n}\n\n/**\n * Directive that adds specific classes and functionality to the mega-menu sublist.\n */\n@Directive({\n selector: 'ul[eclMegaMenuSublist]',\n host: {\n class: 'ecl-mega-menu__sublist',\n '[class.ecl-mega-menu__sublist--scrollable]': 'isScrollable',\n '[style.top.px]': 'styleTop',\n '[style.height.px]': 'styleHeight()',\n },\n})\nexport class EclMegaMenuSublistDirective extends ECLBaseDirective implements OnDestroy, DoCheck {\n el = inject(ElementRef);\n\n isScrollable = false;\n styleTop: number | null = null;\n styleHeight = signal<number | null>(null);\n\n readonly submenuItems = contentChildren(forwardRef(() => EclMegaMenuSubitemComponent));\n readonly spacer = contentChild(forwardRef(() => EclMegaMenuSpacerDirective));\n @Output() megaMenuSubItemClicked = new EventEmitter();\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclMegaMenuSubitemComponent>;\n private isMobileBreakpoint = false;\n private differs = inject(IterableDiffers);\n private appShell = inject(EuiAppShellService);\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.observeBreakpointChanges();\n });\n }\n\n ngDoCheck(): void {\n // When a new item is added -> subscribe to item's events.\n const diff = this.differ.diff(this.submenuItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectMegaMenuItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * When parent mega-menu item is clicked.\n * @param isExpanded - 'true', if parent item is expanded, 'false' if item is collapsed.\n */\n onParentMegaMenuItemClick(isExpanded: boolean): void {\n if (!isExpanded) {\n this.submenuItems().forEach(item => {\n if (item.isExpanded) {\n item.onSubMenuItemCollapse();\n }\n });\n }\n }\n\n private connectMegaMenuItemEvents(item: EclMegaMenuSubitemComponent): void {\n item.megaMenuSubItemClicked.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onMegaMenuSubItemClicked(item);\n });\n\n item.megaMenuSubItemKeydown.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.onMegaMenuSubItemKeydown(item, evt);\n });\n }\n\n private onMegaMenuSubItemClicked(item: EclMegaMenuSubitemComponent): void {\n this.submenuItems().filter(subItem => subItem !== item).forEach(el => {\n el.onSubMenuItemCollapse();\n if (this.isMobileBreakpoint && item.hasChildren) {\n el.onHide();\n }\n });\n this.megaMenuSubItemClicked.emit();\n }\n\n private onMegaMenuSubItemKeydown(item: EclMegaMenuSubitemComponent, evt: KeyboardEvent): void {\n\n const itemIndex = this.submenuItems().findIndex(elem => elem === item);\n switch (evt.key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n this.focusOnNextSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.focusOnPrevSibling(itemIndex);\n break;\n }\n default: {\n break;\n }\n }\n }\n\n private focusOnPrevSibling(index: number): void {\n if (index > 0) {\n this.submenuItems().at(index - 1).onFocus();\n }\n }\n\n private focusOnNextSibling(index: number): void {\n if (index < this.submenuItems().length - 1) {\n this.submenuItems().at(index + 1).onFocus();\n }\n }\n\n private observeBreakpointChanges(): void {\n this.appShell.getState<any>('breakpoints')\n .pipe(\n map(bp => !!bp?.isLtLargeTablet), // xs/sm/md/lg => <= 996px boundary\n distinctUntilChanged(),\n takeUntil(this.destroy$),\n )\n .subscribe((isMobile) => {\n const wasMobile = this.isMobileBreakpoint;\n this.isMobileBreakpoint = isMobile;\n\n // Reset height/position values when switching between breakpoints\n // to avoid stale pixel values from the previous layout mode\n if (wasMobile !== isMobile) {\n this.styleHeight.set(null);\n this.styleTop = null;\n this.isScrollable = false;\n }\n });\n }\n}\n",
26186
25959
  "selector": "li[eclMegaMenuSpacer]",
26187
25960
  "providers": [],
26188
25961
  "hostDirectives": [],
@@ -26235,46 +26008,9 @@
26235
26008
  "outputsClass": [],
26236
26009
  "deprecated": false,
26237
26010
  "deprecationMessage": "",
26238
- "hostBindings": [
26239
- {
26240
- "coverageIgnore": false,
26241
- "name": "class.ecl-mega-menu__spacer",
26242
- "actualName": "cmpClass",
26243
- "defaultValue": "true",
26244
- "deprecated": false,
26245
- "deprecationMessage": "",
26246
- "rawdescription": "\n",
26247
- "description": "",
26248
- "line": 24,
26249
- "type": "boolean",
26250
- "decorators": []
26251
- }
26252
- ],
26011
+ "hostBindings": [],
26253
26012
  "hostListeners": [],
26254
- "propertiesClass": [
26255
- {
26256
- "name": "cmpClass",
26257
- "coverageIgnore": false,
26258
- "defaultValue": "true",
26259
- "deprecated": false,
26260
- "deprecationMessage": "",
26261
- "type": "unknown",
26262
- "indexKey": "",
26263
- "optional": false,
26264
- "description": "",
26265
- "line": 24,
26266
- "rawdescription": "\n",
26267
- "decorators": [
26268
- {
26269
- "name": "HostBinding",
26270
- "stringifiedArguments": "'class.ecl-mega-menu__spacer'"
26271
- }
26272
- ],
26273
- "modifierKind": [
26274
- 171
26275
- ]
26276
- }
26277
- ],
26013
+ "propertiesClass": [],
26278
26014
  "methodsClass": [
26279
26015
  {
26280
26016
  "name": "getCssClasses",
@@ -26318,8 +26054,8 @@
26318
26054
  "coverageIgnore": false,
26319
26055
  "jsdoctags": [
26320
26056
  {
26321
- "pos": 754,
26322
- "end": 824,
26057
+ "pos": 735,
26058
+ "end": 805,
26323
26059
  "kind": 321,
26324
26060
  "id": 0,
26325
26061
  "flags": 16777216,
@@ -26343,12 +26079,12 @@
26343
26079
  },
26344
26080
  {
26345
26081
  "name": "EclMegaMenuSublistDirective",
26346
- "id": "directive-EclMegaMenuSublistDirective-02469b11ffd64d49ecd3a01aba8e2d5bc27d5e6a3c139bd7261cc1f0148c8e1c6e35c2987e9829efbe4d088d62862ad081d63d5ccb1dbc35aab8d1ab646e7bc6",
26082
+ "id": "directive-EclMegaMenuSublistDirective-77213061afcb1f49414790da69d7b7992f3b21c97c9304055a0fb9b584252f05f352f85411151061cb3c36136d74ab16d680fc3a8d9fca8461076c60f1b0ddb3",
26347
26083
  "file": "packages/ecl/components/ecl-mega-menu/directives/ecl-mega-menu-list.directive.ts",
26348
26084
  "type": "directive",
26349
26085
  "description": "<p>Directive that adds specific classes and functionality to the mega-menu sublist.</p>\n",
26350
26086
  "rawdescription": "\n\nDirective that adds specific classes and functionality to the mega-menu sublist.\n",
26351
- "sourceCode": "import { Directive, DoCheck, ElementRef, EventEmitter, HostBinding, IterableDiffer, IterableDiffers, OnDestroy, Output, afterNextRender, forwardRef, inject, signal, contentChildren, contentChild } from '@angular/core';\nimport { EuiAppShellService } from '@eui/core';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { distinctUntilChanged, map, Subject, takeUntil } from 'rxjs';\nimport { EclMegaMenuSubitemComponent } from '../ecl-mega-menu-subitem/ecl-mega-menu-subitem.component';\n\n/**\n * Directive that adds specific class to the mega-menu list.\n */\n@Directive({\n selector: 'ul[eclMegaMenuList]',\n})\nexport class EclMegaMenuListDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__list') cmpClass = true;\n}\n\n/**\n * Directive that adds specific class to the mega-menu spacer.\n */\n@Directive({\n selector: 'li[eclMegaMenuSpacer]',\n})\nexport class EclMegaMenuSpacerDirective extends ECLBaseDirective {\n @HostBinding('class.ecl-mega-menu__spacer') cmpClass = true;\n}\n\n/**\n * Directive that adds specific classes and functionality to the mega-menu sublist.\n */\n@Directive({\n selector: 'ul[eclMegaMenuSublist]',\n host: {\n '[style.height.px]': 'styleHeight()',\n },\n})\nexport class EclMegaMenuSublistDirective extends ECLBaseDirective implements OnDestroy, DoCheck {\n el = inject(ElementRef);\n\n @HostBinding('class.ecl-mega-menu__sublist') cmpClass = true;\n @HostBinding('class.ecl-mega-menu__sublist--scrollable') isScrollable = false;\n @HostBinding('style.top.px') styleTop: number | null = null;\n styleHeight = signal<number | null>(null);\n\n readonly submenuItems = contentChildren(forwardRef(() => EclMegaMenuSubitemComponent));\n readonly spacer = contentChild(forwardRef(() => EclMegaMenuSpacerDirective));\n @Output() megaMenuSubItemClicked = new EventEmitter();\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclMegaMenuSubitemComponent>;\n private isMobileBreakpoint = false;\n private differs = inject(IterableDiffers);\n private appShell = inject(EuiAppShellService);\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.observeBreakpointChanges();\n });\n }\n\n ngDoCheck(): void {\n // When a new item is added -> subscribe to item's events.\n const diff = this.differ.diff(this.submenuItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectMegaMenuItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * When parent mega-menu item is clicked.\n * @param isExpanded - 'true', if parent item is expanded, 'false' if item is collapsed.\n */\n onParentMegaMenuItemClick(isExpanded: boolean): void {\n if (!isExpanded) {\n this.submenuItems().forEach(item => {\n if (item.isExpanded) {\n item.onSubMenuItemCollapse();\n }\n });\n }\n }\n\n private connectMegaMenuItemEvents(item: EclMegaMenuSubitemComponent): void {\n item.megaMenuSubItemClicked.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onMegaMenuSubItemClicked(item);\n });\n\n item.megaMenuSubItemKeydown.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.onMegaMenuSubItemKeydown(item, evt);\n });\n }\n\n private onMegaMenuSubItemClicked(item: EclMegaMenuSubitemComponent): void {\n this.submenuItems().filter(subItem => subItem !== item).forEach(el => {\n el.onSubMenuItemCollapse();\n if (this.isMobileBreakpoint && item.hasChildren) {\n el.onHide();\n }\n });\n this.megaMenuSubItemClicked.emit();\n }\n\n private onMegaMenuSubItemKeydown(item: EclMegaMenuSubitemComponent, evt: KeyboardEvent): void {\n\n const itemIndex = this.submenuItems().findIndex(elem => elem === item);\n switch (evt.key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n this.focusOnNextSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.focusOnPrevSibling(itemIndex);\n break;\n }\n default: {\n break;\n }\n }\n }\n\n private focusOnPrevSibling(index: number): void {\n if (index > 0) {\n this.submenuItems().at(index - 1).onFocus();\n }\n }\n\n private focusOnNextSibling(index: number): void {\n if (index < this.submenuItems().length - 1) {\n this.submenuItems().at(index + 1).onFocus();\n }\n }\n\n private observeBreakpointChanges(): void {\n this.appShell.getState<any>('breakpoints')\n .pipe(\n map(bp => !!bp?.isLtLargeTablet), // xs/sm/md/lg => <= 996px boundary\n distinctUntilChanged(),\n takeUntil(this.destroy$),\n )\n .subscribe((isMobile) => {\n const wasMobile = this.isMobileBreakpoint;\n this.isMobileBreakpoint = isMobile;\n\n // Reset height/position values when switching between breakpoints\n // to avoid stale pixel values from the previous layout mode\n if (wasMobile !== isMobile) {\n this.styleHeight.set(null);\n this.styleTop = null;\n this.isScrollable = false;\n }\n });\n }\n}\n",
26087
+ "sourceCode": "import { Directive, DoCheck, ElementRef, EventEmitter, IterableDiffer, IterableDiffers, OnDestroy, Output, afterNextRender, forwardRef, inject, signal, contentChildren, contentChild } from '@angular/core';\nimport { EuiAppShellService } from '@eui/core';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { distinctUntilChanged, map, Subject, takeUntil } from 'rxjs';\nimport { EclMegaMenuSubitemComponent } from '../ecl-mega-menu-subitem/ecl-mega-menu-subitem.component';\n\n/**\n * Directive that adds specific class to the mega-menu list.\n */\n@Directive({\n selector: 'ul[eclMegaMenuList]',\n host: {\n class: 'ecl-mega-menu__list',\n },\n})\nexport class EclMegaMenuListDirective extends ECLBaseDirective {\n}\n\n/**\n * Directive that adds specific class to the mega-menu spacer.\n */\n@Directive({\n selector: 'li[eclMegaMenuSpacer]',\n host: {\n class: 'ecl-mega-menu__spacer',\n },\n})\nexport class EclMegaMenuSpacerDirective extends ECLBaseDirective {\n}\n\n/**\n * Directive that adds specific classes and functionality to the mega-menu sublist.\n */\n@Directive({\n selector: 'ul[eclMegaMenuSublist]',\n host: {\n class: 'ecl-mega-menu__sublist',\n '[class.ecl-mega-menu__sublist--scrollable]': 'isScrollable',\n '[style.top.px]': 'styleTop',\n '[style.height.px]': 'styleHeight()',\n },\n})\nexport class EclMegaMenuSublistDirective extends ECLBaseDirective implements OnDestroy, DoCheck {\n el = inject(ElementRef);\n\n isScrollable = false;\n styleTop: number | null = null;\n styleHeight = signal<number | null>(null);\n\n readonly submenuItems = contentChildren(forwardRef(() => EclMegaMenuSubitemComponent));\n readonly spacer = contentChild(forwardRef(() => EclMegaMenuSpacerDirective));\n @Output() megaMenuSubItemClicked = new EventEmitter();\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclMegaMenuSubitemComponent>;\n private isMobileBreakpoint = false;\n private differs = inject(IterableDiffers);\n private appShell = inject(EuiAppShellService);\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.observeBreakpointChanges();\n });\n }\n\n ngDoCheck(): void {\n // When a new item is added -> subscribe to item's events.\n const diff = this.differ.diff(this.submenuItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectMegaMenuItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * When parent mega-menu item is clicked.\n * @param isExpanded - 'true', if parent item is expanded, 'false' if item is collapsed.\n */\n onParentMegaMenuItemClick(isExpanded: boolean): void {\n if (!isExpanded) {\n this.submenuItems().forEach(item => {\n if (item.isExpanded) {\n item.onSubMenuItemCollapse();\n }\n });\n }\n }\n\n private connectMegaMenuItemEvents(item: EclMegaMenuSubitemComponent): void {\n item.megaMenuSubItemClicked.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onMegaMenuSubItemClicked(item);\n });\n\n item.megaMenuSubItemKeydown.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.onMegaMenuSubItemKeydown(item, evt);\n });\n }\n\n private onMegaMenuSubItemClicked(item: EclMegaMenuSubitemComponent): void {\n this.submenuItems().filter(subItem => subItem !== item).forEach(el => {\n el.onSubMenuItemCollapse();\n if (this.isMobileBreakpoint && item.hasChildren) {\n el.onHide();\n }\n });\n this.megaMenuSubItemClicked.emit();\n }\n\n private onMegaMenuSubItemKeydown(item: EclMegaMenuSubitemComponent, evt: KeyboardEvent): void {\n\n const itemIndex = this.submenuItems().findIndex(elem => elem === item);\n switch (evt.key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n this.focusOnNextSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.focusOnPrevSibling(itemIndex);\n break;\n }\n default: {\n break;\n }\n }\n }\n\n private focusOnPrevSibling(index: number): void {\n if (index > 0) {\n this.submenuItems().at(index - 1).onFocus();\n }\n }\n\n private focusOnNextSibling(index: number): void {\n if (index < this.submenuItems().length - 1) {\n this.submenuItems().at(index + 1).onFocus();\n }\n }\n\n private observeBreakpointChanges(): void {\n this.appShell.getState<any>('breakpoints')\n .pipe(\n map(bp => !!bp?.isLtLargeTablet), // xs/sm/md/lg => <= 996px boundary\n distinctUntilChanged(),\n takeUntil(this.destroy$),\n )\n .subscribe((isMobile) => {\n const wasMobile = this.isMobileBreakpoint;\n this.isMobileBreakpoint = isMobile;\n\n // Reset height/position values when switching between breakpoints\n // to avoid stale pixel values from the previous layout mode\n if (wasMobile !== isMobile) {\n this.styleHeight.set(null);\n this.styleTop = null;\n this.isScrollable = false;\n }\n });\n }\n}\n",
26352
26088
  "selector": "ul[eclMegaMenuSublist]",
26353
26089
  "providers": [],
26354
26090
  "hostDirectives": [],
@@ -26405,77 +26141,15 @@
26405
26141
  "defaultValue": "new EventEmitter()",
26406
26142
  "deprecated": false,
26407
26143
  "deprecationMessage": "",
26408
- "line": 46,
26144
+ "line": 52,
26409
26145
  "type": "EventEmitter"
26410
26146
  }
26411
26147
  ],
26412
26148
  "deprecated": false,
26413
26149
  "deprecationMessage": "",
26414
- "hostBindings": [
26415
- {
26416
- "coverageIgnore": false,
26417
- "name": "class.ecl-mega-menu__sublist",
26418
- "actualName": "cmpClass",
26419
- "defaultValue": "true",
26420
- "deprecated": false,
26421
- "deprecationMessage": "",
26422
- "rawdescription": "\n",
26423
- "description": "",
26424
- "line": 39,
26425
- "type": "boolean",
26426
- "decorators": []
26427
- },
26428
- {
26429
- "coverageIgnore": false,
26430
- "name": "class.ecl-mega-menu__sublist--scrollable",
26431
- "actualName": "isScrollable",
26432
- "defaultValue": "false",
26433
- "deprecated": false,
26434
- "deprecationMessage": "",
26435
- "rawdescription": "\n",
26436
- "description": "",
26437
- "line": 40,
26438
- "type": "boolean",
26439
- "decorators": []
26440
- },
26441
- {
26442
- "coverageIgnore": false,
26443
- "name": "style.top.px",
26444
- "actualName": "styleTop",
26445
- "defaultValue": "null",
26446
- "deprecated": false,
26447
- "deprecationMessage": "",
26448
- "rawdescription": "\n",
26449
- "description": "",
26450
- "line": 41,
26451
- "type": "number | null",
26452
- "decorators": []
26453
- }
26454
- ],
26150
+ "hostBindings": [],
26455
26151
  "hostListeners": [],
26456
26152
  "propertiesClass": [
26457
- {
26458
- "name": "cmpClass",
26459
- "coverageIgnore": false,
26460
- "defaultValue": "true",
26461
- "deprecated": false,
26462
- "deprecationMessage": "",
26463
- "type": "unknown",
26464
- "indexKey": "",
26465
- "optional": false,
26466
- "description": "",
26467
- "line": 39,
26468
- "rawdescription": "\n",
26469
- "decorators": [
26470
- {
26471
- "name": "HostBinding",
26472
- "stringifiedArguments": "'class.ecl-mega-menu__sublist'"
26473
- }
26474
- ],
26475
- "modifierKind": [
26476
- 171
26477
- ]
26478
- },
26479
26153
  {
26480
26154
  "name": "el",
26481
26155
  "coverageIgnore": false,
@@ -26486,7 +26160,7 @@
26486
26160
  "indexKey": "",
26487
26161
  "optional": false,
26488
26162
  "description": "",
26489
- "line": 37,
26163
+ "line": 44,
26490
26164
  "rawdescription": "\n"
26491
26165
  },
26492
26166
  {
@@ -26499,17 +26173,8 @@
26499
26173
  "indexKey": "",
26500
26174
  "optional": false,
26501
26175
  "description": "",
26502
- "line": 40,
26503
- "rawdescription": "\n",
26504
- "decorators": [
26505
- {
26506
- "name": "HostBinding",
26507
- "stringifiedArguments": "'class.ecl-mega-menu__sublist--scrollable'"
26508
- }
26509
- ],
26510
- "modifierKind": [
26511
- 171
26512
- ]
26176
+ "line": 46,
26177
+ "rawdescription": "\n"
26513
26178
  },
26514
26179
  {
26515
26180
  "name": "spacer",
@@ -26521,7 +26186,7 @@
26521
26186
  "indexKey": "",
26522
26187
  "optional": false,
26523
26188
  "description": "",
26524
- "line": 45,
26189
+ "line": 51,
26525
26190
  "rawdescription": "\n",
26526
26191
  "modifierKind": [
26527
26192
  148
@@ -26537,7 +26202,7 @@
26537
26202
  "indexKey": "",
26538
26203
  "optional": false,
26539
26204
  "description": "",
26540
- "line": 42,
26205
+ "line": 48,
26541
26206
  "rawdescription": "\n"
26542
26207
  },
26543
26208
  {
@@ -26550,17 +26215,8 @@
26550
26215
  "indexKey": "",
26551
26216
  "optional": false,
26552
26217
  "description": "",
26553
- "line": 41,
26554
- "rawdescription": "\n",
26555
- "decorators": [
26556
- {
26557
- "name": "HostBinding",
26558
- "stringifiedArguments": "'style.top.px'"
26559
- }
26560
- ],
26561
- "modifierKind": [
26562
- 171
26563
- ]
26218
+ "line": 47,
26219
+ "rawdescription": "\n"
26564
26220
  },
26565
26221
  {
26566
26222
  "name": "submenuItems",
@@ -26572,7 +26228,7 @@
26572
26228
  "indexKey": "",
26573
26229
  "optional": false,
26574
26230
  "description": "",
26575
- "line": 44,
26231
+ "line": 50,
26576
26232
  "rawdescription": "\n",
26577
26233
  "modifierKind": [
26578
26234
  148
@@ -26587,7 +26243,7 @@
26587
26243
  "optional": false,
26588
26244
  "returnType": "void",
26589
26245
  "typeParameters": [],
26590
- "line": 61,
26246
+ "line": 67,
26591
26247
  "deprecated": false,
26592
26248
  "deprecationMessage": "",
26593
26249
  "rawdescription": "\n",
@@ -26600,7 +26256,7 @@
26600
26256
  "optional": false,
26601
26257
  "returnType": "void",
26602
26258
  "typeParameters": [],
26603
- "line": 71,
26259
+ "line": 77,
26604
26260
  "deprecated": false,
26605
26261
  "deprecationMessage": "",
26606
26262
  "rawdescription": "\n",
@@ -26622,7 +26278,7 @@
26622
26278
  "optional": false,
26623
26279
  "returnType": "void",
26624
26280
  "typeParameters": [],
26625
- "line": 80,
26281
+ "line": 86,
26626
26282
  "deprecated": false,
26627
26283
  "deprecationMessage": "",
26628
26284
  "rawdescription": "\n\nWhen parent mega-menu item is clicked.\n",
@@ -26630,8 +26286,8 @@
26630
26286
  "jsdoctags": [
26631
26287
  {
26632
26288
  "name": {
26633
- "pos": 2783,
26634
- "end": 2793,
26289
+ "pos": 2755,
26290
+ "end": 2765,
26635
26291
  "kind": 80,
26636
26292
  "id": 0,
26637
26293
  "flags": 16842752,
@@ -26644,8 +26300,8 @@
26644
26300
  "deprecated": false,
26645
26301
  "deprecationMessage": "",
26646
26302
  "tagName": {
26647
- "pos": 2777,
26648
- "end": 2782,
26303
+ "pos": 2749,
26304
+ "end": 2754,
26649
26305
  "kind": 80,
26650
26306
  "id": 0,
26651
26307
  "flags": 16842752,
@@ -26698,8 +26354,8 @@
26698
26354
  "coverageIgnore": false,
26699
26355
  "jsdoctags": [
26700
26356
  {
26701
- "pos": 1015,
26702
- "end": 1106,
26357
+ "pos": 990,
26358
+ "end": 1081,
26703
26359
  "kind": 321,
26704
26360
  "id": 0,
26705
26361
  "flags": 16777216,
@@ -26721,7 +26377,7 @@
26721
26377
  "deprecated": false,
26722
26378
  "deprecationMessage": "",
26723
26379
  "args": [],
26724
- "line": 51,
26380
+ "line": 57,
26725
26381
  "rawdescription": "\n"
26726
26382
  },
26727
26383
  "relationships": {
@@ -57699,7 +57355,7 @@
57699
57355
  },
57700
57356
  {
57701
57357
  "name": "EclInpageNavigationComponent",
57702
- "id": "component-EclInpageNavigationComponent-5daafc90fdb4dbac03101fb1ec926edaec22dde8c7ba4699dcece0f2c2d48f01b9c51ed69bb59e72fd63be3a46eae2803257a7e8309d6a6dc7f5932d3148a469",
57358
+ "id": "component-EclInpageNavigationComponent-906af88767bb0883baf4a3fa0272ddc605be045eba82e54505a7ed5052ca75dd4912d410edb6b1ebd61164ec4f483083128aa648e00be47dbc4458c5d1e5365f",
57703
57359
  "file": "packages/ecl/components/ecl-inpage-navigation/ecl-inpage-navigation.component.ts",
57704
57360
  "encapsulation": [],
57705
57361
  "entryComponents": [],
@@ -58176,7 +57832,7 @@
58176
57832
  "description": "<p>The in-page navigation is a vertical menu containing (anchored) links to H2-headings on long content pages.\nIt gives the user an overview of the page contents and has a fixed position (does not move while scrolling) at either the left\nside of a page on desktop or top-bar on mobile. This component helps users scan of the page quickly contents and may potentially\nreduce vertical scrolling, allowing users to easily jump straight to the segment of the page.</p>\n",
58177
57833
  "rawdescription": "\n\nThe in-page navigation is a vertical menu containing (anchored) links to H2-headings on long content pages.\nIt gives the user an overview of the page contents and has a fixed position (does not move while scrolling) at either the left\nside of a page on desktop or top-bar on mobile. This component helps users scan of the page quickly contents and may potentially\nreduce vertical scrolling, allowing users to easily jump straight to the segment of the page.\n",
58178
57834
  "type": "component",
58179
- "sourceCode": "import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';\nimport { ScrollDispatcher, ViewportRuler } from '@angular/cdk/scrolling';\nimport { isPlatformBrowser } from '@angular/common';\nimport { AfterViewInit, ChangeDetectorRef, Component, DOCUMENT, DoCheck, ElementRef, IterableDiffer, IterableDiffers, NgZone, OnDestroy, OnInit, PLATFORM_ID, afterNextRender, contentChild, contentChildren, inject, input, numberAttribute, output, viewChild } from '@angular/core';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EUI_ECL_STICKY_CONTAINER } from '@eui/ecl/components/ecl-sticky-container';\nimport { ECLBaseDirective, EclBaseEvent, EclRtlService, EclThemeService } from '@eui/ecl/core';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { EclInpageNavigationItemComponent } from './ecl-inpage-navigation-item.component';\nimport { EclInpageNavigationListDirective } from './ecl-inpage-navigation-list.directive';\nimport { EclInpageNavigationService } from './services/ecl-inpage-navigation.service';\n\nexport class EclInpageNavigationSectionEnterEvent extends EclBaseEvent {\n constructor(public sectionId: string) {\n super();\n }\n}\n\n/**\n * The in-page navigation is a vertical menu containing (anchored) links to H2-headings on long content pages.\n * It gives the user an overview of the page contents and has a fixed position (does not move while scrolling) at either the left\n * side of a page on desktop or top-bar on mobile. This component helps users scan of the page quickly contents and may potentially\n * reduce vertical scrolling, allowing users to easily jump straight to the segment of the page.\n */\n@Component({\n selector: 'ecl-inpage-navigation',\n templateUrl: './ecl-inpage-navigation.component.html',\n imports: [TranslatePipe, ...EUI_ECL_STICKY_CONTAINER, ...EUI_ECL_ICON],\n styles: [\n `\n @media (min-width: 996px) {\n .ecl-inpage-navigation__list {\n display: block !important;\n }\n }\n `,\n ],\n})\nexport class EclInpageNavigationComponent extends ECLBaseDirective implements OnInit, AfterViewInit, OnDestroy, DoCheck {\n eclThemeService = inject(EclThemeService);\n\n readonly eclTitle = input<string>(undefined);\n /**\n * Used to calculate component's position.\n */\n readonly marginTop = input<number>(undefined);\n readonly marginBottom = input<number>(undefined);\n /**\n * Sets the offset from the top of the page (for example if there is a toolbar or header). Used to calculate scrolling behaviour.\n */\n readonly offsetTop = input<number, unknown>(undefined, { transform: numberAttribute });\n readonly togglerButton = viewChild<ElementRef<HTMLButtonElement>>('togglerButton');\n readonly toggleWrapper = viewChild<ElementRef<HTMLDivElement>>('toggleWrapper');\n readonly navTittle = viewChild<ElementRef<HTMLDivElement>>('navTittle');\n /**\n * This event will be emitted, when onscroll a new section becomes active.\n */\n readonly sectionEnter = output<EclInpageNavigationSectionEnterEvent>();\n\n readonly eclNavigationLinkItems = contentChildren(EclInpageNavigationItemComponent, { descendants: true });\n readonly eclNavigationList = contentChild(EclInpageNavigationListDirective);\n\n /**\n * Used for the mobile view, where user can select a section from the dropdown.\n */\n isButtonExpanded = false;\n currentSectionElement: HTMLElement | null = null;\n public isRtl = false;\n public listMaxHeight: number;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclInpageNavigationItemComponent>;\n private isMobileBreakpoint = false;\n private MIN_DISTANCE_TOP = 10;\n /**\n * Extra spacing (px) kept between the sticky toggler and the target heading when scrolling to a section on mobile,\n * so the heading is not flush against the toggler. Mirrors the spacing buffer used by the vanilla ECL\n * `scroll-margin-top` rule (trigger height + spacing).\n */\n private readonly MOBILE_SCROLL_SPACING = 16;\n private readonly ICON_SIZE_EC_THEME = '2xs';\n private readonly ICON_SIZE_EU_THEME = 's';\n private readonly TABLET_BREAKPOINT = 996;\n private intersectionObserver: IntersectionObserver;\n private eclRtlService = inject(EclRtlService);\n private differs = inject(IterableDiffers);\n private scrollDispatcher: ScrollDispatcher = inject(ScrollDispatcher);\n private zone = inject(NgZone);\n private cdkBreakpointObserver = inject(BreakpointObserver);\n private viewportRuler = inject(ViewportRuler);\n private eclInpageNavigationService = inject(EclInpageNavigationService);\n private cdr = inject(ChangeDetectorRef);\n private readonly platformId = inject(PLATFORM_ID);\n private readonly doc = inject(DOCUMENT);\n private readonly win = this.doc.defaultView; // Window | null\n private readonly isBrowser = isPlatformBrowser(this.platformId);\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.zone.run(() => this.setListHeight());\n });\n }\n\n ngOnInit(): void {\n this.handleRtlChangeState();\n }\n\n ngAfterViewInit() {\n if (!this.isBrowser) return;\n\n this.subscribeToCDKScrollEvent();\n this.observeBreakpointChanges();\n this.viewportRuler.change(300)\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => this.zone.run(() => this.setListHeight()));\n\n const togglerButton = this.togglerButton();\n if (typeof IntersectionObserver !== 'undefined' && togglerButton?.nativeElement) {\n this.intersectionObserver = new IntersectionObserver(() => this.setListHeight());\n this.intersectionObserver.observe(togglerButton.nativeElement);\n }\n }\n\n get hasNavigationList(): boolean {\n return !!this.eclNavigationList();\n }\n\n get currentNavigationLinkItem(): EclInpageNavigationItemComponent {\n return this.eclNavigationLinkItems().find((item) => item.sectionElement === this.currentSectionElement);\n }\n\n /**\n * the size of the arrow-down icon, used in mobile view. There are different sizes for EC and EU themes.\n */\n get sizeIcon(): string {\n if (this.eclThemeService.isECTheme()) {\n return this.ICON_SIZE_EC_THEME;\n } else {\n return this.ICON_SIZE_EU_THEME;\n }\n }\n\n get hasActiveSection(): boolean {\n return !!this.currentSectionElement;\n }\n\n ngDoCheck(): void {\n const diff = this.differ.diff(this.eclNavigationLinkItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n const togglerButton = this.togglerButton();\n if (this.intersectionObserver && togglerButton?.nativeElement) {\n this.intersectionObserver.unobserve(togglerButton.nativeElement);\n this.intersectionObserver.disconnect();\n }\n }\n\n /**\n * On mobile view - handle the dropdown toggle.\n */\n onExpandButtonClick(): void {\n this.setButtonExpanded(!this.isButtonExpanded);\n }\n\n /**\n * Single entry point for changing the dropdown expanded state. Keeps the local flag (used for the button's\n * aria-expanded) and the shared service state (that drives the list's visibility class) in sync.\n */\n private setButtonExpanded(isExpanded: boolean): void {\n this.isButtonExpanded = isExpanded;\n this.eclInpageNavigationService.eclInpageNavigationToggle(isExpanded);\n }\n\n /**\n * Dropdown keyboard navigation on mobile view.\n * @param evt\n */\n onExpandButtonKeydown(evt: Event): void {\n switch ((evt as KeyboardEvent).key) {\n case 'Tab':\n this.onExpandButtonTab(evt);\n break;\n case 'ArrowDown':\n this.onExpandButtonArrowDown(evt);\n break;\n default:\n break;\n }\n }\n\n private handleRtlChangeState(): void {\n this.eclRtlService.currentRtlState$.pipe(takeUntil(this.destroy$)).subscribe((rtlState) => {\n this.isRtl = rtlState;\n });\n }\n\n /**\n * Set the height of the list with the navigation items in px. So in case the full list cannot be displayed, a scroll will appear.\n */\n private setListHeight(): void {\n if (!this.isBrowser) return;\n const eclNavigationList = this.eclNavigationList();\n if (!eclNavigationList) return;\n if (!this.win) return;\n\n const viewportHeight = this.win.innerHeight;\n const viewportWidth = this.win.innerWidth;\n let topPosition = 0;\n\n if (viewportWidth < this.TABLET_BREAKPOINT) {\n const toggleWrapper = this.toggleWrapper()?.nativeElement;\n if (toggleWrapper) {\n const styles = this.win.getComputedStyle(toggleWrapper);\n topPosition =\n toggleWrapper.getBoundingClientRect().bottom +\n parseFloat(styles.marginBottom || '0');\n }\n } else if (this.eclTitle()) {\n const titleEl = this.navTittle()?.nativeElement;\n if (titleEl) topPosition = titleEl.getBoundingClientRect().bottom;\n } else {\n const listEl = eclNavigationList?.el?.nativeElement;\n if (listEl) topPosition = listEl.getBoundingClientRect().top;\n }\n\n const availableSpace = viewportHeight - topPosition;\n if (availableSpace > 0) {\n this.listMaxHeight = availableSpace;\n eclNavigationList.maxHeight.set(this.listMaxHeight);\n }\n }\n\n private onExpandButtonArrowDown(evt: Event): void {\n evt.preventDefault();\n this.setButtonExpanded(true);\n this.eclNavigationLinkItems().at(0).onFocus();\n }\n\n private onExpandButtonTab(evt: Event): void {\n if ((evt as KeyboardEvent).shiftKey) {\n evt.preventDefault();\n this.eclNavigationLinkItems().at(this.eclNavigationLinkItems().length - 1).onFocus();\n }\n }\n\n private connectItemEvents(item: EclInpageNavigationItemComponent): void {\n item.itemArrowDown.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemArrowDown(item);\n });\n\n item.itemArrowUp.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemArrowUp(item);\n });\n\n item.itemTab.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.onItemTab(item, evt);\n });\n\n item.itemEnter.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemEnter(item);\n });\n\n item.itemClick.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.selectNavigationItem(item.sectionElement);\n if (item.sectionElement) {\n this.scrollToSection(item.sectionElement);\n item.sectionElement.focus();\n }\n this.setButtonExpanded(false);\n });\n }\n\n private onItemEnter(item: EclInpageNavigationItemComponent): void {\n this.selectNavigationItem(item.sectionElement);\n if (item.sectionElement) {\n this.scrollToSection(item.sectionElement);\n if (item.sectionElement.tabIndex === -1) {\n item.sectionElement.tabIndex = 0;\n item.sectionElement.focus();\n item.sectionElement.tabIndex = -1;\n }\n }\n this.setButtonExpanded(false);\n }\n\n /**\n * Scrolls the target section into view. On desktop this is a plain scrollIntoView() (unchanged behaviour). On\n * mobile the in-page navigation toggler is sticky at the top, so a top-aligned scroll would hide the heading\n * underneath it; we therefore set `scroll-margin-top` on the target (sticky toggler height + spacing buffer) and\n * let scrollIntoView() honour it. Using scroll-margin-top instead of a manual window.scrollTo() keeps this working\n * regardless of which element is the actual scroll container (window or a nested scrollable wrapper).\n */\n private scrollToSection(sectionElement: HTMLElement): void {\n if (!this.isBrowser) return;\n const offset = this.getMobileScrollOffset();\n sectionElement.style.scrollMarginTop = offset > 0 ? `${offset}px` : '';\n sectionElement.scrollIntoView();\n }\n\n /**\n * The offset (px) applied on mobile so that a scrolled-to heading clears the sticky toggler: the toggler height\n * plus a spacing buffer. Returns 0 on desktop (no sticky toggler). Shared by the scroll logic and the scroll-spy\n * so the heading lands exactly where the spy expects it, keeping the active item in sync after a click.\n */\n private getMobileScrollOffset(): number {\n if (!this.isMobileBreakpoint) return 0;\n const toggleWrapper = this.toggleWrapper()?.nativeElement;\n if (!toggleWrapper) return 0;\n return toggleWrapper.getBoundingClientRect().height + this.MOBILE_SCROLL_SPACING;\n }\n\n private onItemArrowDown(item: EclInpageNavigationItemComponent): void {\n const index = this.eclNavigationLinkItems().indexOf(item);\n const eclNavigationLinkItems = this.eclNavigationLinkItems();\n if (index !== eclNavigationLinkItems.length - 1) {\n eclNavigationLinkItems.at(index + 1).onFocus();\n }\n }\n\n private onItemArrowUp(item: EclInpageNavigationItemComponent): void {\n const index = this.eclNavigationLinkItems().indexOf(item);\n if (index !== 0) {\n this.eclNavigationLinkItems().at(index - 1).onFocus();\n } else {\n const togglerButton = this.togglerButton();\n if (this.isMobileBreakpoint && togglerButton) {\n this.setButtonExpanded(false);\n togglerButton.nativeElement.focus();\n }\n }\n }\n\n private onItemTab(item: EclInpageNavigationItemComponent, evt: Event): void {\n if (this.isMobileBreakpoint) {\n if (!(evt as KeyboardEvent).shiftKey) {\n const index = this.eclNavigationLinkItems().indexOf(item);\n if (index === this.eclNavigationLinkItems().length - 1) {\n evt.preventDefault();\n this.togglerButton().nativeElement.focus();\n }\n }\n }\n }\n\n private subscribeToCDKScrollEvent(): void {\n if (!this.isBrowser) return;\n\n this.scrollDispatcher\n .scrolled()\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => {\n this.zone.run(() => {\n const ids = this.eclNavigationLinkItems().map((item) => item.sectionId());\n\n const sectionElements = ids\n .map((id) => this.doc.querySelector<HTMLElement>(`#${id}`))\n .filter((el): el is HTMLElement => !!el);\n\n this.handleNavigationLinksHighlight(sectionElements);\n this.setListHeight();\n });\n });\n }\n\n private selectNavigationItem(itemElement: HTMLElement): void {\n this.eclNavigationLinkItems().forEach((it) => {\n it.isActive.set(it.sectionElement === itemElement);\n });\n this.cdr.markForCheck();\n }\n\n private handleNavigationLinksHighlight(sectionElements: HTMLElement[]): void {\n const currentSectionElement = this.findActiveSectionElement(sectionElements);\n\n if (currentSectionElement !== this.currentSectionElement) {\n this.currentSectionElement = currentSectionElement ?? undefined as HTMLElement | null;\n if (currentSectionElement) this.selectNavigationItem(currentSectionElement);\n\n const sectionId = this.currentNavigationLinkItem?.sectionId();\n this.sectionEnter.emit(new EclInpageNavigationSectionEnterEvent(sectionId));\n }\n }\n\n private findActiveSectionElement(sectionElements: HTMLElement[]): HTMLElement | null {\n if (!this.isBrowser || !this.win) return null;\n\n let currentSection: HTMLElement | null = null;\n // On mobile the heading is scrolled to sit just below the sticky toggler, so the spy must use that same\n // offset; otherwise it would highlight the previous section. On desktop keep the original threshold.\n const offset = this.isMobileBreakpoint\n ? this.getMobileScrollOffset()\n : this.MIN_DISTANCE_TOP + (this.offsetTop() ?? 0);\n\n const isNearBottom =\n this.win.innerHeight + this.win.scrollY >=\n this.doc.documentElement.scrollHeight - 10;\n\n for (const sectionElement of sectionElements) {\n const rect = sectionElement.getBoundingClientRect();\n const isAboveOffset = rect.top <= offset;\n const isVisibleInViewport = rect.top < this.win.innerHeight;\n\n if (isAboveOffset || (isVisibleInViewport && isNearBottom)) {\n currentSection = sectionElement;\n }\n }\n\n return currentSection;\n }\n\n private observeBreakpointChanges(): void {\n this.cdkBreakpointObserver\n .observe([Breakpoints.Handset, Breakpoints.Tablet, Breakpoints.Small])\n .pipe(takeUntil(this.destroy$))\n .subscribe((result) => {\n this.isMobileBreakpoint = result.matches;\n });\n }\n}\n",
57835
+ "sourceCode": "import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';\nimport { ScrollDispatcher, ViewportRuler } from '@angular/cdk/scrolling';\nimport { isPlatformBrowser } from '@angular/common';\nimport { AfterViewInit, ChangeDetectorRef, Component, DOCUMENT, DoCheck, ElementRef, IterableDiffer, IterableDiffers, NgZone, OnDestroy, OnInit, PLATFORM_ID, afterNextRender, contentChild, contentChildren, inject, input, numberAttribute, output, viewChild } from '@angular/core';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EUI_ECL_STICKY_CONTAINER } from '@eui/ecl/components/ecl-sticky-container';\nimport { ECLBaseDirective, EclBaseEvent, EclRtlService, EclThemeService } from '@eui/ecl/core';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { EclInpageNavigationItemComponent } from './ecl-inpage-navigation-item.component';\nimport { EclInpageNavigationListDirective } from './ecl-inpage-navigation-list.directive';\nimport { EclInpageNavigationService } from './services/ecl-inpage-navigation.service';\n\nexport class EclInpageNavigationSectionEnterEvent extends EclBaseEvent {\n constructor(public sectionId: string) {\n super();\n }\n}\n\n/**\n * The in-page navigation is a vertical menu containing (anchored) links to H2-headings on long content pages.\n * It gives the user an overview of the page contents and has a fixed position (does not move while scrolling) at either the left\n * side of a page on desktop or top-bar on mobile. This component helps users scan of the page quickly contents and may potentially\n * reduce vertical scrolling, allowing users to easily jump straight to the segment of the page.\n */\n@Component({\n selector: 'ecl-inpage-navigation',\n templateUrl: './ecl-inpage-navigation.component.html',\n imports: [TranslatePipe, ...EUI_ECL_STICKY_CONTAINER, ...EUI_ECL_ICON],\n styles: [\n `\n @media (min-width: 996px) {\n .ecl-inpage-navigation__list {\n display: block !important;\n }\n }\n `,\n ],\n})\nexport class EclInpageNavigationComponent extends ECLBaseDirective implements OnInit, AfterViewInit, OnDestroy, DoCheck {\n eclThemeService = inject(EclThemeService);\n\n readonly eclTitle = input<string>(undefined);\n /**\n * Used to calculate component's position.\n */\n readonly marginTop = input<number>(undefined);\n readonly marginBottom = input<number>(undefined);\n /**\n * Sets the offset from the top of the page (for example if there is a toolbar or header). Used to calculate scrolling behaviour.\n */\n readonly offsetTop = input<number, unknown>(undefined, { transform: numberAttribute });\n readonly togglerButton = viewChild<ElementRef<HTMLButtonElement>>('togglerButton');\n readonly toggleWrapper = viewChild<ElementRef<HTMLDivElement>>('toggleWrapper');\n readonly navTittle = viewChild<ElementRef<HTMLDivElement>>('navTittle');\n /**\n * This event will be emitted, when onscroll a new section becomes active.\n */\n readonly sectionEnter = output<EclInpageNavigationSectionEnterEvent>();\n\n readonly eclNavigationLinkItems = contentChildren(EclInpageNavigationItemComponent, { descendants: true });\n readonly eclNavigationList = contentChild(EclInpageNavigationListDirective);\n\n /**\n * Used for the mobile view, where user can select a section from the dropdown.\n */\n isButtonExpanded = false;\n currentSectionElement: HTMLElement | null = null;\n public isRtl = false;\n public listMaxHeight: number;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclInpageNavigationItemComponent>;\n private isMobileBreakpoint = false;\n private MIN_DISTANCE_TOP = 10;\n /**\n * Extra spacing (px) kept between the sticky toggler and the target heading when scrolling to a section on mobile,\n * so the heading is not flush against the toggler. Mirrors the spacing buffer used by the vanilla ECL\n * `scroll-margin-top` rule (trigger height + spacing).\n */\n private readonly MOBILE_SCROLL_SPACING = 16;\n private readonly ICON_SIZE_EC_THEME = '2xs';\n private readonly ICON_SIZE_EU_THEME = 's';\n private readonly TABLET_BREAKPOINT = 996;\n private intersectionObserver: IntersectionObserver;\n private eclRtlService = inject(EclRtlService);\n private differs = inject(IterableDiffers);\n private scrollDispatcher: ScrollDispatcher = inject(ScrollDispatcher);\n private zone = inject(NgZone);\n private cdkBreakpointObserver = inject(BreakpointObserver);\n private viewportRuler = inject(ViewportRuler);\n private eclInpageNavigationService = inject(EclInpageNavigationService);\n private cdr = inject(ChangeDetectorRef);\n private readonly platformId = inject(PLATFORM_ID);\n private readonly doc = inject(DOCUMENT);\n private readonly win = this.doc.defaultView; // Window | null\n private readonly isBrowser = isPlatformBrowser(this.platformId);\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.zone.run(() => this.setListHeight());\n });\n }\n\n ngOnInit(): void {\n this.handleRtlChangeState();\n }\n\n ngAfterViewInit() {\n if (!this.isBrowser) return;\n\n this.subscribeToCDKScrollEvent();\n this.observeBreakpointChanges();\n this.viewportRuler.change(300)\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => this.zone.run(() => this.setListHeight()));\n\n const togglerButton = this.togglerButton();\n if (typeof IntersectionObserver !== 'undefined' && togglerButton?.nativeElement) {\n this.intersectionObserver = new IntersectionObserver(() => this.setListHeight());\n this.intersectionObserver.observe(togglerButton.nativeElement);\n }\n }\n\n get hasNavigationList(): boolean {\n return !!this.eclNavigationList();\n }\n\n get currentNavigationLinkItem(): EclInpageNavigationItemComponent {\n return this.eclNavigationLinkItems().find((item) => item.sectionElement === this.currentSectionElement);\n }\n\n /**\n * the size of the arrow-down icon, used in mobile view. There are different sizes for EC and EU themes.\n */\n get sizeIcon(): string {\n if (this.eclThemeService.isECTheme()) {\n return this.ICON_SIZE_EC_THEME;\n } else {\n return this.ICON_SIZE_EU_THEME;\n }\n }\n\n get hasActiveSection(): boolean {\n return !!this.currentSectionElement;\n }\n\n ngDoCheck(): void {\n const diff = this.differ.diff(this.eclNavigationLinkItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n const togglerButton = this.togglerButton();\n if (this.intersectionObserver && togglerButton?.nativeElement) {\n this.intersectionObserver.unobserve(togglerButton.nativeElement);\n this.intersectionObserver.disconnect();\n }\n }\n\n /**\n * On mobile view - handle the dropdown toggle.\n */\n onExpandButtonClick(): void {\n this.setButtonExpanded(!this.isButtonExpanded);\n }\n\n /**\n * Single entry point for changing the dropdown expanded state. Keeps the local flag (used for the button's\n * aria-expanded) and the shared service state (that drives the list's visibility class) in sync.\n */\n private setButtonExpanded(isExpanded: boolean): void {\n this.isButtonExpanded = isExpanded;\n this.eclInpageNavigationService.eclInpageNavigationToggle(isExpanded);\n }\n\n /**\n * Dropdown keyboard navigation on mobile view.\n * @param evt\n */\n onExpandButtonKeydown(evt: Event): void {\n switch ((evt as KeyboardEvent).key) {\n case 'Tab':\n this.onExpandButtonTab(evt);\n break;\n case 'ArrowDown':\n this.onExpandButtonArrowDown(evt);\n break;\n default:\n break;\n }\n }\n\n private handleRtlChangeState(): void {\n this.eclRtlService.currentRtlState$.pipe(takeUntil(this.destroy$)).subscribe((rtlState) => {\n this.isRtl = rtlState;\n });\n }\n\n /**\n * Set the height of the list with the navigation items in px. So in case the full list cannot be displayed, a scroll will appear.\n */\n private setListHeight(): void {\n if (!this.isBrowser) return;\n const eclNavigationList = this.eclNavigationList();\n if (!eclNavigationList) return;\n if (!this.win) return;\n\n const viewportHeight = this.win.innerHeight;\n const viewportWidth = this.win.innerWidth;\n let topPosition = 0;\n\n if (viewportWidth < this.TABLET_BREAKPOINT) {\n const toggleWrapper = this.toggleWrapper()?.nativeElement;\n if (toggleWrapper) {\n const styles = this.win.getComputedStyle(toggleWrapper);\n topPosition =\n toggleWrapper.getBoundingClientRect().bottom +\n parseFloat(styles.marginBottom || '0');\n }\n } else if (this.eclTitle()) {\n const titleEl = this.navTittle()?.nativeElement;\n if (titleEl) topPosition = titleEl.getBoundingClientRect().bottom;\n } else {\n const listEl = eclNavigationList?.el?.nativeElement;\n if (listEl) topPosition = listEl.getBoundingClientRect().top;\n }\n\n const availableSpace = viewportHeight - topPosition;\n if (availableSpace > 0) {\n this.listMaxHeight = availableSpace;\n eclNavigationList.maxHeight.set(this.listMaxHeight);\n }\n }\n\n private onExpandButtonArrowDown(evt: Event): void {\n evt.preventDefault();\n this.setButtonExpanded(true);\n this.eclNavigationLinkItems().at(0).onFocus();\n }\n\n private onExpandButtonTab(evt: Event): void {\n if ((evt as KeyboardEvent).shiftKey) {\n evt.preventDefault();\n this.eclNavigationLinkItems().at(this.eclNavigationLinkItems().length - 1).onFocus();\n }\n }\n\n private connectItemEvents(item: EclInpageNavigationItemComponent): void {\n item.itemArrowDown.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemArrowDown(item);\n });\n\n item.itemArrowUp.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemArrowUp(item);\n });\n\n item.itemTab.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.onItemTab(item, evt);\n });\n\n item.itemEnter.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onItemEnter(item);\n });\n\n item.itemClick.pipe(takeUntil(this.destroy$)).subscribe((evt) => {\n this.selectNavigationItem(item.sectionElement);\n if (item.sectionElement) {\n this.scrollToSection(item.sectionElement);\n item.sectionElement.focus();\n }\n this.setButtonExpanded(false);\n });\n }\n\n private onItemEnter(item: EclInpageNavigationItemComponent): void {\n this.selectNavigationItem(item.sectionElement);\n if (item.sectionElement) {\n this.scrollToSection(item.sectionElement);\n if (item.sectionElement.tabIndex === -1) {\n item.sectionElement.tabIndex = 0;\n item.sectionElement.focus();\n item.sectionElement.tabIndex = -1;\n }\n }\n this.setButtonExpanded(false);\n }\n\n /**\n * Scrolls the target section into view. On desktop this is a plain scrollIntoView() (unchanged behaviour). On\n * mobile the in-page navigation toggler is sticky at the top, so a top-aligned scroll would hide the heading\n * underneath it; we therefore set `scroll-margin-top` on the target (sticky toggler height + spacing buffer) and\n * let scrollIntoView() honour it. Using scroll-margin-top instead of a manual window.scrollTo() keeps this working\n * regardless of which element is the actual scroll container (window or a nested scrollable wrapper).\n */\n private scrollToSection(sectionElement: HTMLElement): void {\n if (!this.isBrowser) return;\n const offset = this.getMobileScrollOffset();\n sectionElement.style.scrollMarginTop = offset > 0 ? `${offset}px` : '';\n sectionElement.scrollIntoView();\n }\n\n /**\n * The offset (px) applied on mobile so that a scrolled-to heading clears the sticky toggler: the toggler height\n * plus a spacing buffer. Returns 0 on desktop (no sticky toggler). Shared by the scroll logic and the scroll-spy\n * so the heading lands exactly where the spy expects it, keeping the active item in sync after a click.\n */\n private getMobileScrollOffset(): number {\n if (!this.isMobileBreakpoint) return 0;\n const toggleWrapper = this.toggleWrapper()?.nativeElement;\n if (!toggleWrapper) return 0;\n return toggleWrapper.getBoundingClientRect().height + this.MOBILE_SCROLL_SPACING;\n }\n\n private onItemArrowDown(item: EclInpageNavigationItemComponent): void {\n const index = this.eclNavigationLinkItems().indexOf(item);\n const eclNavigationLinkItems = this.eclNavigationLinkItems();\n if (index !== eclNavigationLinkItems.length - 1) {\n eclNavigationLinkItems.at(index + 1).onFocus();\n }\n }\n\n private onItemArrowUp(item: EclInpageNavigationItemComponent): void {\n const index = this.eclNavigationLinkItems().indexOf(item);\n if (index !== 0) {\n this.eclNavigationLinkItems().at(index - 1).onFocus();\n } else {\n const togglerButton = this.togglerButton();\n if (this.isMobileBreakpoint && togglerButton) {\n this.setButtonExpanded(false);\n togglerButton.nativeElement.focus();\n }\n }\n }\n\n private onItemTab(item: EclInpageNavigationItemComponent, evt: Event): void {\n if (this.isMobileBreakpoint) {\n if (!(evt as KeyboardEvent).shiftKey) {\n const index = this.eclNavigationLinkItems().indexOf(item);\n if (index === this.eclNavigationLinkItems().length - 1) {\n evt.preventDefault();\n this.togglerButton().nativeElement.focus();\n }\n }\n }\n }\n\n private subscribeToCDKScrollEvent(): void {\n if (!this.isBrowser) return;\n\n this.scrollDispatcher\n .scrolled()\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => {\n this.zone.run(() => {\n const ids = this.eclNavigationLinkItems().map((item) => item.sectionId());\n\n const sectionElements = ids\n .map((id) => this.doc.querySelector<HTMLElement>(`#${id}`))\n .filter((el): el is HTMLElement => !!el);\n\n this.handleNavigationLinksHighlight(sectionElements);\n this.setListHeight();\n });\n });\n }\n\n private selectNavigationItem(itemElement: HTMLElement): void {\n this.eclNavigationLinkItems().forEach((it) => {\n it.isActive.set(it.sectionElement === itemElement);\n });\n this.cdr.markForCheck();\n }\n\n private handleNavigationLinksHighlight(sectionElements: HTMLElement[]): void {\n const currentSectionElement = this.findActiveSectionElement(sectionElements);\n\n if (currentSectionElement !== this.currentSectionElement) {\n this.currentSectionElement = currentSectionElement ?? undefined as HTMLElement | null;\n if (currentSectionElement) this.selectNavigationItem(currentSectionElement);\n\n const sectionId = this.currentNavigationLinkItem?.sectionId();\n this.sectionEnter.emit(new EclInpageNavigationSectionEnterEvent(sectionId));\n }\n }\n\n private findActiveSectionElement(sectionElements: HTMLElement[]): HTMLElement | null {\n if (!this.isBrowser || !this.win) return null;\n\n let currentSection: HTMLElement | null = null;\n // On mobile the heading is scrolled to sit just below the sticky toggler, so the spy must use that same\n // offset; otherwise it would highlight the previous section. The extra MIN_DISTANCE_TOP is a cushion so a\n // heading that lands right on the boundary (sub-pixel rounding) is still treated as \"reached\". On desktop\n // keep the original threshold.\n const offset = this.isMobileBreakpoint\n ? this.getMobileScrollOffset() + this.MIN_DISTANCE_TOP\n : this.MIN_DISTANCE_TOP + (this.offsetTop() ?? 0);\n\n const isNearBottom =\n this.win.innerHeight + this.win.scrollY >=\n this.doc.documentElement.scrollHeight - 10;\n\n for (const sectionElement of sectionElements) {\n const rect = sectionElement.getBoundingClientRect();\n const isAboveOffset = rect.top <= offset;\n const isVisibleInViewport = rect.top < this.win.innerHeight;\n\n if (isAboveOffset || (isVisibleInViewport && isNearBottom)) {\n currentSection = sectionElement;\n }\n }\n\n return currentSection;\n }\n\n private observeBreakpointChanges(): void {\n this.cdkBreakpointObserver\n .observe([Breakpoints.Handset, Breakpoints.Tablet, Breakpoints.Small])\n .pipe(takeUntil(this.destroy$))\n .subscribe((result) => {\n this.isMobileBreakpoint = result.matches;\n });\n }\n}\n",
58180
57836
  "assetsDirs": [],
58181
57837
  "styleUrlsData": "",
58182
57838
  "stylesData": "\n @media (min-width: 996px) {\n .ecl-inpage-navigation__list {\n display: block !important;\n }\n }\n \n",
@@ -60558,10 +60214,11 @@
60558
60214
  },
60559
60215
  {
60560
60216
  "name": "EclMegaMenuComponent",
60561
- "id": "component-EclMegaMenuComponent-9247a57b9fb88d15221371775a1774c85157f41a7fb4a0e7c951085c6fc8037d6767959ec08dd2f3676758096cf5f3595b548aaeb217f761550382da0a56135c",
60217
+ "id": "component-EclMegaMenuComponent-9b62a890775e692b1eb7f0c733b0a94e63ac8865f168eedc15c7b67ed0233589618a08c53d63f8818b5c5bddb11fa80bd61a72da708369552349c854df10855b",
60562
60218
  "file": "packages/ecl/components/ecl-mega-menu/ecl-mega-menu.component.ts",
60563
60219
  "encapsulation": [],
60564
60220
  "entryComponents": [],
60221
+ "host": {},
60565
60222
  "inputs": [],
60566
60223
  "outputs": [],
60567
60224
  "providers": [],
@@ -60642,7 +60299,7 @@
60642
60299
  "indexKey": "",
60643
60300
  "optional": false,
60644
60301
  "description": "<p>The event that is emitted, when a menu item is selected.</p>\n",
60645
- "line": 69,
60302
+ "line": 67,
60646
60303
  "rawdescription": "\n\nThe event that is emitted, when a menu item is selected.\n",
60647
60304
  "modifierKind": [
60648
60305
  148
@@ -60661,7 +60318,7 @@
60661
60318
  "indexKey": "",
60662
60319
  "optional": false,
60663
60320
  "description": "<p>Represents the current viewport breakpoint states.</p>\n",
60664
- "line": 117,
60321
+ "line": 115,
60665
60322
  "rawdescription": "\n\nRepresents the current viewport breakpoint states.\n",
60666
60323
  "modifierKind": [
60667
60324
  125
@@ -60677,7 +60334,7 @@
60677
60334
  "indexKey": "",
60678
60335
  "optional": false,
60679
60336
  "description": "<p>Adds the relative class to the component, when a submenu is opened and this submenu has a featured component child</p>\n",
60680
- "line": 112,
60337
+ "line": 110,
60681
60338
  "rawdescription": "\nAdds the relative class to the component, when a submenu is opened and this submenu has a featured component child"
60682
60339
  },
60683
60340
  {
@@ -60689,7 +60346,7 @@
60689
60346
  "indexKey": "",
60690
60347
  "optional": false,
60691
60348
  "description": "",
60692
- "line": 109,
60349
+ "line": 107,
60693
60350
  "rawdescription": "\n"
60694
60351
  },
60695
60352
  {
@@ -60702,7 +60359,7 @@
60702
60359
  "indexKey": "",
60703
60360
  "optional": false,
60704
60361
  "description": "",
60705
- "line": 53,
60362
+ "line": 58,
60706
60363
  "rawdescription": "\n"
60707
60364
  },
60708
60365
  {
@@ -60715,7 +60372,7 @@
60715
60372
  "indexKey": "",
60716
60373
  "optional": false,
60717
60374
  "description": "<p>If the menu is in mobile mode.</p>\n",
60718
- "line": 75,
60375
+ "line": 73,
60719
60376
  "rawdescription": "\n\nIf the menu is in mobile mode.\n"
60720
60377
  },
60721
60378
  {
@@ -60728,7 +60385,7 @@
60728
60385
  "indexKey": "",
60729
60386
  "optional": false,
60730
60387
  "description": "<p>If the menu is expanded in mobile mode.</p>\n",
60731
- "line": 79,
60388
+ "line": 77,
60732
60389
  "rawdescription": "\n\nIf the menu is expanded in mobile mode.\n"
60733
60390
  },
60734
60391
  {
@@ -60741,7 +60398,7 @@
60741
60398
  "indexKey": "",
60742
60399
  "optional": false,
60743
60400
  "description": "<p>When a menu item is expanded and has only one panel (one sub-level).</p>\n",
60744
- "line": 83,
60401
+ "line": 81,
60745
60402
  "rawdescription": "\n\nWhen a menu item is expanded and has only one panel (one sub-level).\n"
60746
60403
  },
60747
60404
  {
@@ -60754,7 +60411,7 @@
60754
60411
  "indexKey": "",
60755
60412
  "optional": false,
60756
60413
  "description": "<p>If the menu is open, when in mobile mode.</p>\n",
60757
- "line": 87,
60414
+ "line": 85,
60758
60415
  "rawdescription": "\n\nIf the menu is open, when in mobile mode.\n"
60759
60416
  },
60760
60417
  {
@@ -60767,7 +60424,7 @@
60767
60424
  "indexKey": "",
60768
60425
  "optional": false,
60769
60426
  "description": "<p>Used in mobile mode - when the start panel is open (i.e. the hamburger button is clicked).</p>\n",
60770
- "line": 91,
60427
+ "line": 89,
60771
60428
  "rawdescription": "\n\nUsed in mobile mode - when the start panel is open (i.e. the hamburger button is clicked).\n"
60772
60429
  },
60773
60430
  {
@@ -60780,7 +60437,7 @@
60780
60437
  "indexKey": "",
60781
60438
  "optional": false,
60782
60439
  "description": "<p>If a menu item is expanded and has two panels/levels displayed.</p>\n",
60783
- "line": 95,
60440
+ "line": 93,
60784
60441
  "rawdescription": "\n\nIf a menu item is expanded and has two panels/levels displayed.\n"
60785
60442
  },
60786
60443
  {
@@ -60793,7 +60450,7 @@
60793
60450
  "indexKey": "",
60794
60451
  "optional": false,
60795
60452
  "description": "",
60796
- "line": 70,
60453
+ "line": 68,
60797
60454
  "rawdescription": "\n",
60798
60455
  "modifierKind": [
60799
60456
  148
@@ -60808,30 +60465,8 @@
60808
60465
  "indexKey": "",
60809
60466
  "optional": false,
60810
60467
  "description": "<p>Used to position the overlay, when a menu item is expanded.</p>\n",
60811
- "line": 108,
60468
+ "line": 106,
60812
60469
  "rawdescription": "\n\nUsed to position the overlay, when a menu item is expanded.\n"
60813
- },
60814
- {
60815
- "name": "role",
60816
- "coverageIgnore": false,
60817
- "defaultValue": "'navigation'",
60818
- "deprecated": false,
60819
- "deprecationMessage": "",
60820
- "type": "string",
60821
- "indexKey": "",
60822
- "optional": false,
60823
- "description": "<p>The &#39;role&#39; attribute of the component is set to &#39;navigation&#39;. should not be changed.</p>\n",
60824
- "line": 64,
60825
- "rawdescription": "\n\nThe 'role' attribute of the component is set to 'navigation'. should not be changed.\n",
60826
- "decorators": [
60827
- {
60828
- "name": "HostBinding",
60829
- "stringifiedArguments": "'attr.role'"
60830
- }
60831
- ],
60832
- "modifierKind": [
60833
- 171
60834
- ]
60835
60470
  }
60836
60471
  ],
60837
60472
  "methodsClass": [
@@ -60842,7 +60477,7 @@
60842
60477
  "optional": false,
60843
60478
  "returnType": "void",
60844
60479
  "typeParameters": [],
60845
- "line": 151,
60480
+ "line": 150,
60846
60481
  "deprecated": false,
60847
60482
  "deprecationMessage": "",
60848
60483
  "rawdescription": "\n",
@@ -60855,7 +60490,7 @@
60855
60490
  "optional": false,
60856
60491
  "returnType": "void",
60857
60492
  "typeParameters": [],
60858
- "line": 161,
60493
+ "line": 160,
60859
60494
  "deprecated": false,
60860
60495
  "deprecationMessage": "",
60861
60496
  "rawdescription": "\n",
@@ -60868,20 +60503,11 @@
60868
60503
  "optional": false,
60869
60504
  "returnType": "void",
60870
60505
  "typeParameters": [],
60871
- "line": 170,
60506
+ "line": 168,
60872
60507
  "deprecated": false,
60873
60508
  "deprecationMessage": "",
60874
60509
  "rawdescription": "\n\nWhen clicking outside the menu - close any expanded item.\n",
60875
- "description": "<p>When clicking outside the menu - close any expanded item.</p>\n",
60876
- "decorators": [
60877
- {
60878
- "name": "HostListener",
60879
- "stringifiedArguments": "'eclClickOutside'"
60880
- }
60881
- ],
60882
- "modifierKind": [
60883
- 171
60884
- ]
60510
+ "description": "<p>When clicking outside the menu - close any expanded item.</p>\n"
60885
60511
  },
60886
60512
  {
60887
60513
  "name": "onMegaMenuBack",
@@ -60890,7 +60516,7 @@
60890
60516
  "optional": false,
60891
60517
  "returnType": "void",
60892
60518
  "typeParameters": [],
60893
- "line": 223,
60519
+ "line": 221,
60894
60520
  "deprecated": false,
60895
60521
  "deprecationMessage": "",
60896
60522
  "rawdescription": "\n\nUsed for mobile menu - when user clicks on 'Back' button. Returns to the previous state.\n",
@@ -60903,7 +60529,7 @@
60903
60529
  "optional": false,
60904
60530
  "returnType": "void",
60905
60531
  "typeParameters": [],
60906
- "line": 200,
60532
+ "line": 198,
60907
60533
  "deprecated": false,
60908
60534
  "deprecationMessage": "",
60909
60535
  "rawdescription": "\n",
@@ -60916,7 +60542,7 @@
60916
60542
  "optional": false,
60917
60543
  "returnType": "void",
60918
60544
  "typeParameters": [],
60919
- "line": 176,
60545
+ "line": 174,
60920
60546
  "deprecated": false,
60921
60547
  "deprecationMessage": "",
60922
60548
  "rawdescription": "\n",
@@ -60938,7 +60564,7 @@
60938
60564
  "optional": false,
60939
60565
  "returnType": "void",
60940
60566
  "typeParameters": [],
60941
- "line": 231,
60567
+ "line": 229,
60942
60568
  "deprecated": false,
60943
60569
  "deprecationMessage": "",
60944
60570
  "rawdescription": "\n",
@@ -60999,58 +60625,8 @@
60999
60625
  "coverageIgnore": false,
61000
60626
  "deprecated": false,
61001
60627
  "deprecationMessage": "",
61002
- "hostBindings": [
61003
- {
61004
- "coverageIgnore": false,
61005
- "name": "attr.data-expanded",
61006
- "actualName": "expandedAttr",
61007
- "deprecated": false,
61008
- "deprecationMessage": "",
61009
- "rawdescription": "\n",
61010
- "description": "",
61011
- "line": 57,
61012
- "type": "\"true\" | null",
61013
- "decorators": []
61014
- },
61015
- {
61016
- "coverageIgnore": false,
61017
- "name": "attr.role",
61018
- "actualName": "role",
61019
- "defaultValue": "'navigation'",
61020
- "deprecated": false,
61021
- "deprecationMessage": "",
61022
- "rawdescription": "\n\nThe 'role' attribute of the component is set to 'navigation'. should not be changed.\n",
61023
- "description": "<p>The &#39;role&#39; attribute of the component is set to &#39;navigation&#39;. should not be changed.</p>\n",
61024
- "line": 64,
61025
- "type": "string",
61026
- "decorators": []
61027
- },
61028
- {
61029
- "coverageIgnore": false,
61030
- "name": "class",
61031
- "actualName": "cssClasses",
61032
- "deprecated": false,
61033
- "deprecationMessage": "",
61034
- "rawdescription": "\n",
61035
- "description": "",
61036
- "line": 41,
61037
- "type": "string",
61038
- "decorators": []
61039
- }
61040
- ],
61041
- "hostListeners": [
61042
- {
61043
- "coverageIgnore": false,
61044
- "name": "eclClickOutside",
61045
- "args": [],
61046
- "argsDecorator": [],
61047
- "deprecated": false,
61048
- "deprecationMessage": "",
61049
- "rawdescription": "\n\nWhen clicking outside the menu - close any expanded item.\n",
61050
- "description": "<p>When clicking outside the menu - close any expanded item.</p>\n",
61051
- "line": 170
61052
- }
61053
- ],
60628
+ "hostBindings": [],
60629
+ "hostListeners": [],
61054
60630
  "standalone": false,
61055
60631
  "imports": [
61056
60632
  {
@@ -61067,14 +60643,14 @@
61067
60643
  "description": "<p>The &#39;eclMegaMenu&#39; is an advanced navigation component designed for complex sites with deep hierarchies.\nIt can provide descriptive text for first level items, accommodate up to three levels of navigation,\nand additionally allows a featured column that can be used to either promote parent-page specific or site-wide pages,\nhidden deep into the lower levels of the hierarchy.</p>\n",
61068
60644
  "rawdescription": "\n\nThe 'eclMegaMenu' is an advanced navigation component designed for complex sites with deep hierarchies.\nIt can provide descriptive text for first level items, accommodate up to three levels of navigation,\nand additionally allows a featured column that can be used to either promote parent-page specific or site-wide pages,\nhidden deep into the lower levels of the hierarchy.\n",
61069
60645
  "type": "component",
61070
- "sourceCode": "import { Component, DOCUMENT, DoCheck, ElementRef, HostBinding, HostListener, IterableDiffer, IterableDiffers, OnDestroy, Renderer2, afterNextRender, forwardRef, inject, output, contentChildren } from '@angular/core';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { auditTime, fromEvent, Subject, takeUntil } from 'rxjs';\nimport { ECLClickOutsideDirective, EclRtlService } from '@eui/ecl/core';\nimport { EuiAppShellService } from '@eui/core';\nimport { KeyCode } from '@eui/ecl/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EclMegaMenuItem } from './models/ecl-mega-menu-item.model';\nimport { EclMegaMenuDataService } from './services/ecl-mega-menu-data.service';\nimport { EclMegaMenuItemComponent } from './ecl-mega-menu-item/ecl-mega-menu-item.component';\nimport { EclHeaderMenuComunicationService } from '@eui/ecl/shared';\nimport { EUI_ECL_BUTTON } from '@eui/ecl/components/ecl-button';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\n\n/**\n * The 'eclMegaMenu' is an advanced navigation component designed for complex sites with deep hierarchies.\n * It can provide descriptive text for first level items, accommodate up to three levels of navigation,\n * and additionally allows a featured column that can be used to either promote parent-page specific or site-wide pages,\n * hidden deep into the lower levels of the hierarchy.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'nav[eclMegaMenu]',\n templateUrl: './ecl-mega-menu.component.html',\n imports: [TranslatePipe, ...EUI_ECL_BUTTON, ...EUI_ECL_ICON],\n hostDirectives: [\n {\n directive: ECLBaseDirective,\n },\n {\n directive: ECLClickOutsideDirective,\n\n outputs: ['eclClickOutside'],\n },\n ],\n})\n\nexport class EclMegaMenuComponent extends ECLBaseDirective implements DoCheck, OnDestroy {\n\n @HostBinding('class')\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-mega-menu'),\n this.isTwoPanels ? 'ecl-mega-menu--two-panels' : '',\n this.isOnePanel ? 'ecl-mega-menu--one-panel' : '',\n this.isRtl ? 'ecl-mega-menu--rtl' : '',\n this.isTablet ? 'ecl-mega-menu--forced-mobile' : '',\n this.isStartPanel ? 'ecl-mega-menu--start-panel' : '',\n this.hasSecondaryFeatured ? 'ecl-mega-menu--has-secondary-featured' : '',\n ].join(' ');\n }\n\n isExpanded = false;\n private readonly document = inject<Document>(DOCUMENT);\n\n @HostBinding('attr.data-expanded')\n get expandedAttr() {\n return this.isExpanded ? 'true' : null;\n }\n\n /**\n * The 'role' attribute of the component is set to 'navigation'. should not be changed.\n */\n @HostBinding('attr.role') role = 'navigation';\n\n /**\n * The event that is emitted, when a menu item is selected.\n */\n readonly megaMenuItemSelect = output<EclMegaMenuItem>();\n readonly menuItems = contentChildren(forwardRef(() => EclMegaMenuItemComponent), { descendants: true });\n\n /**\n * If the menu is in mobile mode.\n */\n isMobileBreakpoint = false;\n /**\n * If the menu is expanded in mobile mode.\n */\n isMobileExpanded = false;\n /**\n * When a menu item is expanded and has only one panel (one sub-level).\n */\n isOnePanel = false;\n /**\n * If the menu is open, when in mobile mode.\n */\n isOpenMobile = false; // used for mobile only\n /**\n * Used in mobile mode - when the start panel is open (i.e. the hamburger button is clicked).\n */\n isStartPanel = false;\n /**\n * If a menu item is expanded and has two panels/levels displayed.\n */\n isTwoPanels = false;\n\n /**\n * Returns true when the viewport is below the ECL desktop breakpoint (1140px).\n * This covers both mobile (xs/sm) and tablet (md/lg) ranges where the menu\n * should behave in mobile/hamburger mode, matching ECL's breakpointDesktop = 1140.\n */\n get isMobileOrTablet(): boolean {\n return this.isMobileBreakpoint || this.isTablet;\n }\n /**\n * Used to position the overlay, when a menu item is expanded.\n */\n overlayStyleTop: number;\n innerStyleTop: number;\n\n /** Adds the relative class to the component, when a submenu is opened and this submenu has a featured component child */\n hasSecondaryFeatured = false;\n\n /**\n * Represents the current viewport breakpoint states.\n */\n public breakpointsValue: any = {\n isMobile: false,\n isTablet: false,\n isLtDesktop: false,\n isDesktop: false,\n isXL: false,\n isXXL: false,\n };\n\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclMegaMenuItemComponent>;\n private isRtl = false;\n private isTablet = false;\n private parentHeaderBottomSpaceY: number;\n private differs = inject(IterableDiffers);\n private eclRtlService = inject(EclRtlService);\n private euiAppShellService = inject(EuiAppShellService);\n private eclHeaderMenuComunicationService = inject(EclHeaderMenuComunicationService);\n private eclMegaMenuDataService = inject(EclMegaMenuDataService);\n private el = inject(ElementRef);\n private renderer = inject(Renderer2);\n private readonly window = this.document.defaultView;\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.subscribeToAppShellBreakpoints();\n this.handleRtlChangeState();\n this.subscribeToEvents();\n this.observeResizeWindow();\n });\n }\n\n ngDoCheck(): void {\n // For each added menu item - subscribe to item events.\n const diff = this.differ.diff(this.menuItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectMegaMenuItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * When clicking outside the menu - close any expanded item.\n */\n @HostListener('eclClickOutside')\n onClickOutsideMegaMenu(): void {\n if (this.isExpanded) {\n this.closeMenuAndAnyOpenSubMenu();\n }\n }\n\n onMegaMenuMobileOpen(): void {\n if (this.isOpenMobile) {\n this.onMegaMenuMobileClose();\n } else {\n this.disableScroll();\n this.isExpanded = true;\n this.isOnePanel = false;\n this.isTwoPanels = false;\n\n if (this.isMobileOrTablet) {\n this.isStartPanel = true;\n this.isMobileExpanded = true;\n }\n this.isOpenMobile = true;\n\n this.eclHeaderMenuComunicationService.updateOpen(true);\n\n // Focus first element\n if (this.menuItems().length > 0) {\n this.menuItems().at(0)!.onFocus();\n }\n }\n }\n\n onMegaMenuMobileClose(): void {\n this.enableScroll();\n\n // Collapse any expanded menu item (and its sub-items) so that\n // reopening the menu always shows the top-level list cleanly.\n const expandedItem = this.menuItems()?.find(item => item.isExpanded);\n if (expandedItem) {\n expandedItem.onMegaMenuItemCollapse();\n }\n\n this.hasSecondaryFeatured = false;\n this.collapseMenu();\n\n if (this.isMobileOrTablet) {\n this.isStartPanel = false;\n this.isMobileExpanded = false;\n }\n this.isOpenMobile = false;\n }\n\n /**\n * Used for mobile menu - when user clicks on 'Back' button. Returns to the previous state.\n */\n onMegaMenuBack(): void {\n if (this.isOnePanel) {\n this.onMegaMenuBackToStartPanel();\n } else if (this.isTwoPanels) {\n this.onMegaMenuBackToOnePanel();\n }\n }\n\n positionMenuOverlay(parentHeaderBottomSpaceY): void {\n this.parentHeaderBottomSpaceY = parentHeaderBottomSpaceY;\n if (this.isMobileOrTablet && parentHeaderBottomSpaceY) {\n this.overlayStyleTop = parentHeaderBottomSpaceY;\n this.innerStyleTop = parentHeaderBottomSpaceY;\n } else {\n if (this.parentHeaderBottomSpaceY) {\n this.overlayStyleTop = parentHeaderBottomSpaceY;\n } else {\n const menuBottomY = this.el.nativeElement.getBoundingClientRect().bottom;\n this.overlayStyleTop = menuBottomY;\n }\n }\n }\n\n private onMegaMenuBackToOnePanel(): void {\n\n this.isStartPanel = false;\n this.isTwoPanels = false;\n this.isOnePanel = true;\n const currentItem = this.menuItems().find(item => item.isExpanded);\n const currentSubItem = currentItem.eclMegaMenuSublist().submenuItems().find(item => item.isExpanded);\n this.hasSecondaryFeatured = false;\n if (this.isMobileOrTablet) {\n currentItem.eclMegaMenuSublist().submenuItems().filter(item => !item.isExpanded).forEach(el => {\n el.onShow();\n });\n }\n currentSubItem.isCurrent = false;\n currentSubItem.isExpanded = false;\n }\n\n private onMegaMenuBackToStartPanel(): void {\n this.isOnePanel = false;\n this.isStartPanel = true;\n const currentItem = this.menuItems().find(item => item.isExpanded);\n currentItem.isCurrent = false;\n currentItem.isExpanded = false;\n this.eclHeaderMenuComunicationService.updateExpanded(false);\n }\n\n private subscribeToEvents(): void {\n\n this.eclMegaMenuDataService.eclSubItemExpanded$.pipe(takeUntil(this.destroy$)).subscribe(isExpanded => {\n this.isTwoPanels = isExpanded;\n this.isOnePanel = !isExpanded;\n this.isStartPanel = false;\n });\n\n this.eclMegaMenuDataService.eclSubItemClicked$.pipe(takeUntil(this.destroy$)).subscribe(item => {\n this.onSubMenuItemClicked(item);\n this.megaMenuItemSelect.emit(item);\n });\n\n this.eclMegaMenuDataService.eclSubItemEscape$.pipe(takeUntil(this.destroy$)).subscribe(item => {\n this.closeMenuAndAnyOpenSubMenu();\n });\n }\n\n private connectMegaMenuItemEvents(item: EclMegaMenuItemComponent): void {\n item.megaMenuItemClicked.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onMegaMenuItemClicked(item);\n });\n\n item.megaMenuItemKeydown.pipe(takeUntil(this.destroy$)).subscribe((evt: KeyboardEvent) => {\n this.onMegaMenuItemKeydown(item, evt);\n });\n }\n\n private onMegaMenuItemClicked(item: EclMegaMenuItemComponent): void {\n this.hasSecondaryFeatured = false;\n this.menuItems().filter(megaItem => megaItem !== item).forEach(item => item.onMegaMenuItemCollapse());\n if (item.hasChildren) {\n if (item.isExpanded) {\n if (this.isMobileOrTablet) {\n this.isOnePanel = true;\n this.isTwoPanels = false;\n this.isStartPanel = false;\n } else {\n if (item.eclMegaMenuSublist()?.submenuItems().at(0)!.hasChildren) {\n this.isOnePanel = false;\n this.isTwoPanels = true;\n } else {\n this.isOnePanel = true;\n this.isTwoPanels = false;\n }\n }\n this.positionMenuOverlay(this.parentHeaderBottomSpaceY);\n this.isExpanded = true;\n this.disableScroll();\n } else {\n this.collapseMenu();\n }\n } else {\n this.collapseMenu();\n }\n this.megaMenuItemSelect.emit(item as unknown as EclMegaMenuItem);\n }\n\n private onMegaMenuItemKeydown(item: EclMegaMenuItemComponent, evt: KeyboardEvent): void {\n\n const itemIndex = this.menuItems().findIndex(elem => elem === item);\n switch (evt.key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n this.focusOnPrevSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.focusOnNextSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_LEFT: {\n evt.preventDefault();\n this.focusOnPrevSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_RIGHT: {\n evt.preventDefault();\n this.focusOnNextSibling(itemIndex);\n break;\n }\n case KeyCode.ESCAPE: {\n this.closeMenuAndAnyOpenSubMenu();\n break;\n }\n default: {\n break;\n }\n }\n }\n\n private onSubMenuItemClicked(item: EclMegaMenuItem): void {\n if (item.isExpanded && item.hasFeatured) {\n this.hasSecondaryFeatured = true;\n } else {\n this.hasSecondaryFeatured = false;\n }\n if (!item.hasChildren) {\n this.closeMenuAndAnyOpenSubMenu();\n }\n }\n\n private closeMenuAndAnyOpenSubMenu(): void {\n if (this.isExpanded) {\n const expandedItem = this.menuItems().find(item => item.isExpanded);\n if (expandedItem !== undefined) {\n expandedItem.onMegaMenuItemCollapse();\n }\n this.collapseMenu();\n }\n }\n\n private collapseMenu(): void {\n this.isExpanded = false;\n this.isTwoPanels = false;\n this.isOnePanel = false;\n this.enableScroll();\n this.eclHeaderMenuComunicationService.updateExpanded(false);\n }\n\n private focusOnPrevSibling(index: number): void {\n if (index > 0) {\n this.menuItems().at(index-1).onFocus();\n }\n }\n\n private focusOnNextSibling(index: number): void {\n if (index < this.menuItems().length - 1) {\n this.menuItems().at(index+1).onFocus();\n }\n }\n\n private subscribeToAppShellBreakpoints(): void {\n this.euiAppShellService.breakpoints$\n .pipe(takeUntil(this.destroy$))\n .subscribe((bkps: any) => {\n this.breakpointsValue = bkps ?? this.breakpointsValue;\n\n if (typeof bkps?.isMobile !== 'undefined' || typeof bkps?.isTablet !== 'undefined') {\n this.isMobileBreakpoint = !!bkps.isMobile;\n // ECL uses breakpointDesktop = 1140px. Everything below that threshold\n // (md: 768-995px AND lg: 996-1139px) must use mobile/hamburger behavior.\n // isLtLargeTablet covers xs/sm/md/lg (i.e. < 1140px).\n this.isTablet = !!(bkps.isLtLargeTablet && !bkps.isMobile);\n return;\n }\n\n if (typeof bkps?.width === 'number') {\n const w = bkps.width;\n this.isMobileBreakpoint = w <= 415;\n this.isTablet = w > 415 && w < 1140;\n return;\n }\n\n if (bkps && typeof bkps === 'object') {\n this.isMobileBreakpoint = !!(bkps.Handset || bkps.Small || bkps.mobile);\n this.isTablet = !!(bkps.Tablet || bkps.tablet);\n return;\n }\n });\n }\n\n private handleRtlChangeState(): void {\n this.eclRtlService.currentRtlState$.pipe(takeUntil(this.destroy$)).subscribe((rtlState) => {\n if (rtlState !== undefined) {\n this.isRtl = rtlState;\n }\n });\n }\n\n private disableScroll(): void {\n this.renderer.addClass(this.document.body, 'ecl-mega-menu-prevent-scroll');\n }\n\n private enableScroll(): void {\n this.renderer.removeClass(this.document.body, 'ecl-mega-menu-prevent-scroll');\n }\n\n /**\n * On resize - reposition the overlay and recalculate inner top when the menu is expanded.\n * Mirrors ECL's handleResize behavior that calls positionMenuOverlay() on every resize.\n */\n private observeResizeWindow(): void {\n if (this.window) {\n fromEvent(this.window, 'resize').pipe(\n auditTime(200),\n takeUntil(this.destroy$),\n ).subscribe(() => {\n if (this.isExpanded) {\n this.positionMenuOverlay(this.parentHeaderBottomSpaceY);\n }\n });\n }\n }\n}\n",
60646
+ "sourceCode": "import { Component, DOCUMENT, DoCheck, ElementRef, IterableDiffer, IterableDiffers, OnDestroy, Renderer2, afterNextRender, forwardRef, inject, output, contentChildren } from '@angular/core';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { auditTime, fromEvent, Subject, takeUntil } from 'rxjs';\nimport { ECLClickOutsideDirective, EclRtlService } from '@eui/ecl/core';\nimport { EuiAppShellService } from '@eui/core';\nimport { KeyCode } from '@eui/ecl/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EclMegaMenuItem } from './models/ecl-mega-menu-item.model';\nimport { EclMegaMenuDataService } from './services/ecl-mega-menu-data.service';\nimport { EclMegaMenuItemComponent } from './ecl-mega-menu-item/ecl-mega-menu-item.component';\nimport { EclHeaderMenuComunicationService } from '@eui/ecl/shared';\nimport { EUI_ECL_BUTTON } from '@eui/ecl/components/ecl-button';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\n\n/**\n * The 'eclMegaMenu' is an advanced navigation component designed for complex sites with deep hierarchies.\n * It can provide descriptive text for first level items, accommodate up to three levels of navigation,\n * and additionally allows a featured column that can be used to either promote parent-page specific or site-wide pages,\n * hidden deep into the lower levels of the hierarchy.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'nav[eclMegaMenu]',\n templateUrl: './ecl-mega-menu.component.html',\n imports: [TranslatePipe, ...EUI_ECL_BUTTON, ...EUI_ECL_ICON],\n host: {\n role: 'navigation',\n '[class]': 'cssClasses',\n '[attr.data-expanded]': 'expandedAttr',\n '(eclClickOutside)': 'onClickOutsideMegaMenu()',\n },\n hostDirectives: [\n {\n directive: ECLBaseDirective,\n },\n {\n directive: ECLClickOutsideDirective,\n\n outputs: ['eclClickOutside'],\n },\n ],\n})\n\nexport class EclMegaMenuComponent extends ECLBaseDirective implements DoCheck, OnDestroy {\n\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-mega-menu'),\n this.isTwoPanels ? 'ecl-mega-menu--two-panels' : '',\n this.isOnePanel ? 'ecl-mega-menu--one-panel' : '',\n this.isRtl ? 'ecl-mega-menu--rtl' : '',\n this.isTablet ? 'ecl-mega-menu--forced-mobile' : '',\n this.isStartPanel ? 'ecl-mega-menu--start-panel' : '',\n this.hasSecondaryFeatured ? 'ecl-mega-menu--has-secondary-featured' : '',\n ].join(' ');\n }\n\n isExpanded = false;\n\n get expandedAttr() {\n return this.isExpanded ? 'true' : null;\n }\n\n /**\n * The event that is emitted, when a menu item is selected.\n */\n readonly megaMenuItemSelect = output<EclMegaMenuItem>();\n readonly menuItems = contentChildren(forwardRef(() => EclMegaMenuItemComponent), { descendants: true });\n\n /**\n * If the menu is in mobile mode.\n */\n isMobileBreakpoint = false;\n /**\n * If the menu is expanded in mobile mode.\n */\n isMobileExpanded = false;\n /**\n * When a menu item is expanded and has only one panel (one sub-level).\n */\n isOnePanel = false;\n /**\n * If the menu is open, when in mobile mode.\n */\n isOpenMobile = false; // used for mobile only\n /**\n * Used in mobile mode - when the start panel is open (i.e. the hamburger button is clicked).\n */\n isStartPanel = false;\n /**\n * If a menu item is expanded and has two panels/levels displayed.\n */\n isTwoPanels = false;\n\n /**\n * Returns true when the viewport is below the ECL desktop breakpoint (1140px).\n * This covers both mobile (xs/sm) and tablet (md/lg) ranges where the menu\n * should behave in mobile/hamburger mode, matching ECL's breakpointDesktop = 1140.\n */\n get isMobileOrTablet(): boolean {\n return this.isMobileBreakpoint || this.isTablet;\n }\n /**\n * Used to position the overlay, when a menu item is expanded.\n */\n overlayStyleTop: number;\n innerStyleTop: number;\n\n /** Adds the relative class to the component, when a submenu is opened and this submenu has a featured component child */\n hasSecondaryFeatured = false;\n\n /**\n * Represents the current viewport breakpoint states.\n */\n public breakpointsValue: any = {\n isMobile: false,\n isTablet: false,\n isLtDesktop: false,\n isDesktop: false,\n isXL: false,\n isXXL: false,\n };\n\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private differ: IterableDiffer<EclMegaMenuItemComponent>;\n private isRtl = false;\n private isTablet = false;\n private parentHeaderBottomSpaceY: number;\n private differs = inject(IterableDiffers);\n private eclRtlService = inject(EclRtlService);\n private euiAppShellService = inject(EuiAppShellService);\n private eclHeaderMenuComunicationService = inject(EclHeaderMenuComunicationService);\n private eclMegaMenuDataService = inject(EclMegaMenuDataService);\n private el = inject(ElementRef);\n private renderer = inject(Renderer2);\n private readonly document = inject<Document>(DOCUMENT);\n private readonly window = this.document.defaultView;\n\n constructor() {\n super();\n this.differ = this.differs.find([]).create();\n afterNextRender(() => {\n this.subscribeToAppShellBreakpoints();\n this.handleRtlChangeState();\n this.subscribeToEvents();\n this.observeResizeWindow();\n });\n }\n\n ngDoCheck(): void {\n // For each added menu item - subscribe to item events.\n const diff = this.differ.diff(this.menuItems());\n if (diff) {\n diff.forEachItem((item) => {\n this.connectMegaMenuItemEvents(item.item);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * When clicking outside the menu - close any expanded item.\n */\n onClickOutsideMegaMenu(): void {\n if (this.isExpanded) {\n this.closeMenuAndAnyOpenSubMenu();\n }\n }\n\n onMegaMenuMobileOpen(): void {\n if (this.isOpenMobile) {\n this.onMegaMenuMobileClose();\n } else {\n this.disableScroll();\n this.isExpanded = true;\n this.isOnePanel = false;\n this.isTwoPanels = false;\n\n if (this.isMobileOrTablet) {\n this.isStartPanel = true;\n this.isMobileExpanded = true;\n }\n this.isOpenMobile = true;\n\n this.eclHeaderMenuComunicationService.updateOpen(true);\n\n // Focus first element\n if (this.menuItems().length > 0) {\n this.menuItems().at(0)!.onFocus();\n }\n }\n }\n\n onMegaMenuMobileClose(): void {\n this.enableScroll();\n\n // Collapse any expanded menu item (and its sub-items) so that\n // reopening the menu always shows the top-level list cleanly.\n const expandedItem = this.menuItems()?.find(item => item.isExpanded);\n if (expandedItem) {\n expandedItem.onMegaMenuItemCollapse();\n }\n\n this.hasSecondaryFeatured = false;\n this.collapseMenu();\n\n if (this.isMobileOrTablet) {\n this.isStartPanel = false;\n this.isMobileExpanded = false;\n }\n this.isOpenMobile = false;\n }\n\n /**\n * Used for mobile menu - when user clicks on 'Back' button. Returns to the previous state.\n */\n onMegaMenuBack(): void {\n if (this.isOnePanel) {\n this.onMegaMenuBackToStartPanel();\n } else if (this.isTwoPanels) {\n this.onMegaMenuBackToOnePanel();\n }\n }\n\n positionMenuOverlay(parentHeaderBottomSpaceY): void {\n this.parentHeaderBottomSpaceY = parentHeaderBottomSpaceY;\n if (this.isMobileOrTablet && parentHeaderBottomSpaceY) {\n this.overlayStyleTop = parentHeaderBottomSpaceY;\n this.innerStyleTop = parentHeaderBottomSpaceY;\n } else {\n if (this.parentHeaderBottomSpaceY) {\n this.overlayStyleTop = parentHeaderBottomSpaceY;\n } else {\n const menuBottomY = this.el.nativeElement.getBoundingClientRect().bottom;\n this.overlayStyleTop = menuBottomY;\n }\n }\n }\n\n private onMegaMenuBackToOnePanel(): void {\n\n this.isStartPanel = false;\n this.isTwoPanels = false;\n this.isOnePanel = true;\n const currentItem = this.menuItems().find(item => item.isExpanded);\n const currentSubItem = currentItem.eclMegaMenuSublist().submenuItems().find(item => item.isExpanded);\n this.hasSecondaryFeatured = false;\n if (this.isMobileOrTablet) {\n currentItem.eclMegaMenuSublist().submenuItems().filter(item => !item.isExpanded).forEach(el => {\n el.onShow();\n });\n }\n currentSubItem.isCurrent = false;\n currentSubItem.isExpanded = false;\n }\n\n private onMegaMenuBackToStartPanel(): void {\n this.isOnePanel = false;\n this.isStartPanel = true;\n const currentItem = this.menuItems().find(item => item.isExpanded);\n currentItem.isCurrent = false;\n currentItem.isExpanded = false;\n this.eclHeaderMenuComunicationService.updateExpanded(false);\n }\n\n private subscribeToEvents(): void {\n\n this.eclMegaMenuDataService.eclSubItemExpanded$.pipe(takeUntil(this.destroy$)).subscribe(isExpanded => {\n this.isTwoPanels = isExpanded;\n this.isOnePanel = !isExpanded;\n this.isStartPanel = false;\n });\n\n this.eclMegaMenuDataService.eclSubItemClicked$.pipe(takeUntil(this.destroy$)).subscribe(item => {\n this.onSubMenuItemClicked(item);\n this.megaMenuItemSelect.emit(item);\n });\n\n this.eclMegaMenuDataService.eclSubItemEscape$.pipe(takeUntil(this.destroy$)).subscribe(item => {\n this.closeMenuAndAnyOpenSubMenu();\n });\n }\n\n private connectMegaMenuItemEvents(item: EclMegaMenuItemComponent): void {\n item.megaMenuItemClicked.pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.onMegaMenuItemClicked(item);\n });\n\n item.megaMenuItemKeydown.pipe(takeUntil(this.destroy$)).subscribe((evt: KeyboardEvent) => {\n this.onMegaMenuItemKeydown(item, evt);\n });\n }\n\n private onMegaMenuItemClicked(item: EclMegaMenuItemComponent): void {\n this.hasSecondaryFeatured = false;\n this.menuItems().filter(megaItem => megaItem !== item).forEach(item => item.onMegaMenuItemCollapse());\n if (item.hasChildren) {\n if (item.isExpanded) {\n if (this.isMobileOrTablet) {\n this.isOnePanel = true;\n this.isTwoPanels = false;\n this.isStartPanel = false;\n } else {\n if (item.eclMegaMenuSublist()?.submenuItems().at(0)!.hasChildren) {\n this.isOnePanel = false;\n this.isTwoPanels = true;\n } else {\n this.isOnePanel = true;\n this.isTwoPanels = false;\n }\n }\n this.positionMenuOverlay(this.parentHeaderBottomSpaceY);\n this.isExpanded = true;\n this.disableScroll();\n } else {\n this.collapseMenu();\n }\n } else {\n this.collapseMenu();\n }\n this.megaMenuItemSelect.emit(item as unknown as EclMegaMenuItem);\n }\n\n private onMegaMenuItemKeydown(item: EclMegaMenuItemComponent, evt: KeyboardEvent): void {\n\n const itemIndex = this.menuItems().findIndex(elem => elem === item);\n switch (evt.key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n this.focusOnNextSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.focusOnPrevSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_LEFT: {\n evt.preventDefault();\n this.focusOnPrevSibling(itemIndex);\n break;\n }\n case KeyCode.ARROW_RIGHT: {\n evt.preventDefault();\n this.focusOnNextSibling(itemIndex);\n break;\n }\n case KeyCode.ESCAPE: {\n this.closeMenuAndAnyOpenSubMenu();\n break;\n }\n default: {\n break;\n }\n }\n }\n\n private onSubMenuItemClicked(item: EclMegaMenuItem): void {\n if (item.isExpanded && item.hasFeatured) {\n this.hasSecondaryFeatured = true;\n } else {\n this.hasSecondaryFeatured = false;\n }\n if (!item.hasChildren) {\n this.closeMenuAndAnyOpenSubMenu();\n }\n }\n\n private closeMenuAndAnyOpenSubMenu(): void {\n if (this.isExpanded) {\n const expandedItem = this.menuItems().find(item => item.isExpanded);\n if (expandedItem !== undefined) {\n expandedItem.onMegaMenuItemCollapse();\n }\n this.collapseMenu();\n }\n }\n\n private collapseMenu(): void {\n this.isExpanded = false;\n this.isTwoPanels = false;\n this.isOnePanel = false;\n this.enableScroll();\n this.eclHeaderMenuComunicationService.updateExpanded(false);\n }\n\n private focusOnPrevSibling(index: number): void {\n if (index > 0) {\n this.menuItems().at(index-1).onFocus();\n }\n }\n\n private focusOnNextSibling(index: number): void {\n if (index < this.menuItems().length - 1) {\n this.menuItems().at(index+1).onFocus();\n }\n }\n\n private subscribeToAppShellBreakpoints(): void {\n this.euiAppShellService.breakpoints$\n .pipe(takeUntil(this.destroy$))\n .subscribe((bkps: any) => {\n this.breakpointsValue = bkps ?? this.breakpointsValue;\n\n if (typeof bkps?.isMobile !== 'undefined' || typeof bkps?.isTablet !== 'undefined') {\n this.isMobileBreakpoint = !!bkps.isMobile;\n // ECL uses breakpointDesktop = 1140px. Everything below that threshold\n // (md: 768-995px AND lg: 996-1139px) must use mobile/hamburger behavior.\n // isLtLargeTablet covers xs/sm/md/lg (i.e. < 1140px).\n this.isTablet = !!(bkps.isLtLargeTablet && !bkps.isMobile);\n return;\n }\n\n if (typeof bkps?.width === 'number') {\n const w = bkps.width;\n this.isMobileBreakpoint = w <= 415;\n this.isTablet = w > 415 && w < 1140;\n return;\n }\n\n if (bkps && typeof bkps === 'object') {\n this.isMobileBreakpoint = !!(bkps.Handset || bkps.Small || bkps.mobile);\n this.isTablet = !!(bkps.Tablet || bkps.tablet);\n return;\n }\n });\n }\n\n private handleRtlChangeState(): void {\n this.eclRtlService.currentRtlState$.pipe(takeUntil(this.destroy$)).subscribe((rtlState) => {\n if (rtlState !== undefined) {\n this.isRtl = rtlState;\n }\n });\n }\n\n private disableScroll(): void {\n this.renderer.addClass(this.document.body, 'ecl-mega-menu-prevent-scroll');\n }\n\n private enableScroll(): void {\n this.renderer.removeClass(this.document.body, 'ecl-mega-menu-prevent-scroll');\n }\n\n /**\n * On resize - reposition the overlay and recalculate inner top when the menu is expanded.\n * Mirrors ECL's handleResize behavior that calls positionMenuOverlay() on every resize.\n */\n private observeResizeWindow(): void {\n if (this.window) {\n fromEvent(this.window, 'resize').pipe(\n auditTime(200),\n takeUntil(this.destroy$),\n ).subscribe(() => {\n if (this.isExpanded) {\n this.positionMenuOverlay(this.parentHeaderBottomSpaceY);\n }\n });\n }\n }\n}\n",
61071
60647
  "assetsDirs": [],
61072
60648
  "styleUrlsData": "",
61073
60649
  "stylesData": "",
61074
60650
  "jsdoctags": [
61075
60651
  {
61076
- "pos": 986,
61077
- "end": 1380,
60652
+ "pos": 959,
60653
+ "end": 1353,
61078
60654
  "kind": 321,
61079
60655
  "id": 0,
61080
60656
  "flags": 16777216,
@@ -61089,7 +60665,7 @@
61089
60665
  "deprecated": false,
61090
60666
  "deprecationMessage": "",
61091
60667
  "args": [],
61092
- "line": 138,
60668
+ "line": 137,
61093
60669
  "rawdescription": "\n"
61094
60670
  },
61095
60671
  "extends": [
@@ -61106,7 +60682,7 @@
61106
60682
  "name": "cssClasses",
61107
60683
  "type": "string",
61108
60684
  "returnType": "string",
61109
- "line": 41,
60685
+ "line": 46,
61110
60686
  "rawdescription": "\n",
61111
60687
  "description": ""
61112
60688
  }
@@ -61117,7 +60693,7 @@
61117
60693
  "name": "expandedAttr",
61118
60694
  "type": "",
61119
60695
  "returnType": "",
61120
- "line": 57,
60696
+ "line": 60,
61121
60697
  "rawdescription": "\n",
61122
60698
  "description": ""
61123
60699
  }
@@ -61128,7 +60704,7 @@
61128
60704
  "name": "isMobileOrTablet",
61129
60705
  "type": "boolean",
61130
60706
  "returnType": "boolean",
61131
- "line": 102,
60707
+ "line": 100,
61132
60708
  "rawdescription": "\n\nReturns true when the viewport is below the ECL desktop breakpoint (1140px).\nThis covers both mobile (xs/sm) and tablet (md/lg) ranges where the menu\nshould behave in mobile/hamburger mode, matching ECL's breakpointDesktop = 1140.\n",
61133
60709
  "description": "<p>Returns true when the viewport is below the ECL desktop breakpoint (1140px).\nThis covers both mobile (xs/sm) and tablet (md/lg) ranges where the menu\nshould behave in mobile/hamburger mode, matching ECL&#39;s breakpointDesktop = 1140.</p>\n"
61134
60710
  }
@@ -61171,10 +60747,11 @@
61171
60747
  },
61172
60748
  {
61173
60749
  "name": "EclMegaMenuFeaturedComponent",
61174
- "id": "component-EclMegaMenuFeaturedComponent-51504f98754ee92df020c127688c9b55858249e11427bf6f60056addad4576f10a588d7869d15b4b8076b56783af523130b384118b702f61316264a78e75cfa9",
60750
+ "id": "component-EclMegaMenuFeaturedComponent-22e2894b38e6769578bb5e8fdeada1673f26651dbd80cc52876f3496645a6bab413d2a1a7092974c632fed220f6b6c5b41a977f39dd031af593016d2c43148bf",
61175
60751
  "file": "packages/ecl/components/ecl-mega-menu/ecl-mega-menu-featured/ecl-mega-menu-featured.component.ts",
61176
60752
  "encapsulation": [],
61177
60753
  "entryComponents": [],
60754
+ "host": {},
61178
60755
  "inputs": [],
61179
60756
  "outputs": [],
61180
60757
  "providers": [],
@@ -61189,15 +60766,21 @@
61189
60766
  "hostDirectives": [],
61190
60767
  "inputsClass": [
61191
60768
  {
61192
- "coverageIgnore": false,
61193
60769
  "name": "title",
60770
+ "coverageIgnore": false,
60771
+ "defaultValue": "undefined",
61194
60772
  "deprecated": false,
61195
60773
  "deprecationMessage": "",
61196
- "rawdescription": "\n",
61197
- "description": "",
61198
- "line": 20,
61199
60774
  "type": "string",
61200
- "decorators": []
60775
+ "indexKey": "",
60776
+ "optional": false,
60777
+ "description": "",
60778
+ "line": 23,
60779
+ "rawdescription": "\n",
60780
+ "modifierKind": [
60781
+ 148
60782
+ ],
60783
+ "required": false
61201
60784
  },
61202
60785
  {
61203
60786
  "name": "titleId",
@@ -61209,7 +60792,7 @@
61209
60792
  "indexKey": "",
61210
60793
  "optional": false,
61211
60794
  "description": "",
61212
- "line": 21,
60795
+ "line": 24,
61213
60796
  "rawdescription": "\n",
61214
60797
  "modifierKind": [
61215
60798
  148
@@ -61262,28 +60845,6 @@
61262
60845
  ],
61263
60846
  "outputsClass": [],
61264
60847
  "propertiesClass": [
61265
- {
61266
- "name": "cmpClass",
61267
- "coverageIgnore": false,
61268
- "defaultValue": "true",
61269
- "deprecated": false,
61270
- "deprecationMessage": "",
61271
- "type": "unknown",
61272
- "indexKey": "",
61273
- "optional": false,
61274
- "description": "",
61275
- "line": 18,
61276
- "rawdescription": "\n",
61277
- "decorators": [
61278
- {
61279
- "name": "HostBinding",
61280
- "stringifiedArguments": "'class.ecl-mega-menu__featured'"
61281
- }
61282
- ],
61283
- "modifierKind": [
61284
- 171
61285
- ]
61286
- },
61287
60848
  {
61288
60849
  "name": "eclMegaMenuFeaturedStyleHeight",
61289
60850
  "coverageIgnore": false,
@@ -61294,17 +60855,8 @@
61294
60855
  "indexKey": "",
61295
60856
  "optional": false,
61296
60857
  "description": "",
61297
- "line": 19,
61298
- "rawdescription": "\n",
61299
- "decorators": [
61300
- {
61301
- "name": "HostBinding",
61302
- "stringifiedArguments": "'style.height.px'"
61303
- }
61304
- ],
61305
- "modifierKind": [
61306
- 171
61307
- ]
60858
+ "line": 22,
60859
+ "rawdescription": "\n"
61308
60860
  },
61309
60861
  {
61310
60862
  "name": "featuredItems",
@@ -61316,7 +60868,7 @@
61316
60868
  "indexKey": "",
61317
60869
  "optional": false,
61318
60870
  "description": "",
61319
- "line": 23,
60871
+ "line": 26,
61320
60872
  "rawdescription": "\n",
61321
60873
  "modifierKind": [
61322
60874
  148
@@ -61332,7 +60884,7 @@
61332
60884
  "indexKey": "",
61333
60885
  "optional": false,
61334
60886
  "description": "",
61335
- "line": 22,
60887
+ "line": 25,
61336
60888
  "rawdescription": "\n",
61337
60889
  "modifierKind": [
61338
60890
  148
@@ -61348,7 +60900,7 @@
61348
60900
  "indexKey": "",
61349
60901
  "optional": false,
61350
60902
  "description": "",
61351
- "line": 17,
60903
+ "line": 21,
61352
60904
  "rawdescription": "\n",
61353
60905
  "modifierKind": [
61354
60906
  148
@@ -61363,7 +60915,7 @@
61363
60915
  "optional": false,
61364
60916
  "returnType": "number",
61365
60917
  "typeParameters": [],
61366
- "line": 31,
60918
+ "line": 34,
61367
60919
  "deprecated": false,
61368
60920
  "deprecationMessage": "",
61369
60921
  "rawdescription": "\n\nCalculates and returns the height of the component. The total height of all the list items.\n",
@@ -61371,8 +60923,8 @@
61371
60923
  "jsdoctags": [
61372
60924
  {
61373
60925
  "tagName": {
61374
- "pos": 1500,
61375
- "end": 1507,
60926
+ "pos": 1524,
60927
+ "end": 1531,
61376
60928
  "kind": 80,
61377
60929
  "id": 0,
61378
60930
  "flags": 16842752,
@@ -61390,7 +60942,7 @@
61390
60942
  "optional": false,
61391
60943
  "returnType": "void",
61392
60944
  "typeParameters": [],
61393
- "line": 24,
60945
+ "line": 27,
61394
60946
  "deprecated": false,
61395
60947
  "deprecationMessage": "",
61396
60948
  "rawdescription": "\n",
@@ -61438,48 +60990,21 @@
61438
60990
  "coverageIgnore": false,
61439
60991
  "deprecated": false,
61440
60992
  "deprecationMessage": "",
61441
- "hostBindings": [
61442
- {
61443
- "coverageIgnore": false,
61444
- "name": "class.ecl-mega-menu__featured",
61445
- "actualName": "cmpClass",
61446
- "defaultValue": "true",
61447
- "deprecated": false,
61448
- "deprecationMessage": "",
61449
- "rawdescription": "\n",
61450
- "description": "",
61451
- "line": 18,
61452
- "type": "boolean",
61453
- "decorators": []
61454
- },
61455
- {
61456
- "coverageIgnore": false,
61457
- "name": "style.height.px",
61458
- "actualName": "eclMegaMenuFeaturedStyleHeight",
61459
- "defaultValue": "null",
61460
- "deprecated": false,
61461
- "deprecationMessage": "",
61462
- "rawdescription": "\n",
61463
- "description": "",
61464
- "line": 19,
61465
- "type": "number | null",
61466
- "decorators": []
61467
- }
61468
- ],
60993
+ "hostBindings": [],
61469
60994
  "hostListeners": [],
61470
60995
  "standalone": false,
61471
60996
  "imports": [],
61472
60997
  "description": "<p>This component represents the featured items panel.</p>\n",
61473
60998
  "rawdescription": "\n\nThis component represents the featured items panel.\n",
61474
60999
  "type": "component",
61475
- "sourceCode": "import { Component, ElementRef, HostBinding, Input, forwardRef, AfterContentInit, input, viewChild, contentChildren } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EclLinkDirective } from '@eui/ecl/components/ecl-link';\nimport { EclMegaMenuFeaturedListItemDirective } from '../directives/ecl-mega-menu-featured-list.directive';\n\n/**\n * This component represents the featured items panel.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'div[eclMegaMenuFeatured]',\n templateUrl: './ecl-mega-menu-featured.component.html',\n})\n\nexport class EclMegaMenuFeaturedComponent extends ECLBaseDirective implements AfterContentInit {\n\n readonly megaMenuFeaturedScrollable = viewChild<ElementRef>('megaMenuFeaturedScrollable');\n @HostBinding('class.ecl-mega-menu__featured') cmpClass = true;\n @HostBinding('style.height.px') eclMegaMenuFeaturedStyleHeight: number | null = null;\n @Input() title: string;\n readonly titleId = input<string>(undefined);\n readonly links = contentChildren(forwardRef(() => EclLinkDirective), { descendants: true });\n readonly featuredItems = contentChildren(forwardRef(() => EclMegaMenuFeaturedListItemDirective), { descendants: true });\n ngAfterContentInit(): void {\n this.links()?.forEach(link => link.class = 'ecl-mega-menu__featured-link');\n }\n /**\n * Calculates and returns the height of the component. The total height of all the list items.\n * @returns the height of the component\n */\n getEclMegaMenuFeaturedHeight(): number {\n let result = 0;\n this.featuredItems()?.forEach(el => result += el.getEclMegaMenuFeaturedItemHeight());\n return result;\n }\n}\n",
61000
+ "sourceCode": "import { Component, ElementRef, forwardRef, AfterContentInit, input, viewChild, contentChildren } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EclLinkDirective } from '@eui/ecl/components/ecl-link';\nimport { EclMegaMenuFeaturedListItemDirective } from '../directives/ecl-mega-menu-featured-list.directive';\n\n/**\n * This component represents the featured items panel.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'div[eclMegaMenuFeatured]',\n templateUrl: './ecl-mega-menu-featured.component.html',\n host: {\n class: 'ecl-mega-menu__featured',\n '[style.height.px]': 'eclMegaMenuFeaturedStyleHeight',\n },\n})\n\nexport class EclMegaMenuFeaturedComponent extends ECLBaseDirective implements AfterContentInit {\n\n readonly megaMenuFeaturedScrollable = viewChild<ElementRef>('megaMenuFeaturedScrollable');\n eclMegaMenuFeaturedStyleHeight: number | null = null;\n readonly title = input<string>(undefined);\n readonly titleId = input<string>(undefined);\n readonly links = contentChildren(forwardRef(() => EclLinkDirective), { descendants: true });\n readonly featuredItems = contentChildren(forwardRef(() => EclMegaMenuFeaturedListItemDirective), { descendants: true });\n ngAfterContentInit(): void {\n this.links()?.forEach(link => link.class = 'ecl-mega-menu__featured-link');\n }\n /**\n * Calculates and returns the height of the component. The total height of all the list items.\n * @returns the height of the component\n */\n getEclMegaMenuFeaturedHeight(): number {\n let result = 0;\n this.featuredItems()?.forEach(el => result += el.getEclMegaMenuFeaturedItemHeight());\n return result;\n }\n}\n",
61476
61001
  "assetsDirs": [],
61477
61002
  "styleUrlsData": "",
61478
61003
  "stylesData": "",
61479
61004
  "jsdoctags": [
61480
61005
  {
61481
- "pos": 364,
61482
- "end": 426,
61006
+ "pos": 344,
61007
+ "end": 406,
61483
61008
  "kind": 321,
61484
61009
  "id": 0,
61485
61010
  "flags": 16777216,
@@ -61507,11 +61032,11 @@
61507
61032
  }
61508
61033
  ]
61509
61034
  },
61510
- "templateData": "<div class=\"ecl-mega-menu__featured-scrollable\" #megaMenuFeaturedScrollable>\n <ng-content select=\"[eclMegaMenuFeaturedPicture]\"></ng-content>\n @if(title) {\n <span class=\"ecl-mega-menu__featured-title\" id=\"{{titleId()}}\">{{ title }}</span>\n }\n <ng-content select=\"[eclMegaMenuFeaturedList]\"></ng-content>\n</div>"
61035
+ "templateData": "<div class=\"ecl-mega-menu__featured-scrollable\" #megaMenuFeaturedScrollable>\n <ng-content select=\"[eclMegaMenuFeaturedPicture]\"></ng-content>\n @if(title()) {\n <span class=\"ecl-mega-menu__featured-title\" id=\"{{titleId()}}\">{{ title() }}</span>\n }\n <ng-content select=\"[eclMegaMenuFeaturedList]\"></ng-content>\n</div>"
61511
61036
  },
61512
61037
  {
61513
61038
  "name": "EclMegaMenuInfoComponent",
61514
- "id": "component-EclMegaMenuInfoComponent-8b82c8ac032a76ebd7ae30c797f606763622e04f7be1905ee6b55bd2b5a8abf78ea6049a604bfd5777e68e4fdec747fee490d68112c443e331fe4217a5bac6a8",
61039
+ "id": "component-EclMegaMenuInfoComponent-86c6229a159ff6b054705c59fc1bf92f306623386ea4b3f6328a97bd5ecf34066ec7c91f06b1f24ba00e7b5269f51a5b896c7d494ce7bd63d513cc68566ee570",
61515
61040
  "file": "packages/ecl/components/ecl-mega-menu/ecl-mega-menu-info/ecl-mega-menu-info.component.ts",
61516
61041
  "encapsulation": [],
61517
61042
  "entryComponents": [],
@@ -61539,7 +61064,7 @@
61539
61064
  "indexKey": "",
61540
61065
  "optional": false,
61541
61066
  "description": "",
61542
- "line": 44,
61067
+ "line": 45,
61543
61068
  "rawdescription": "\n",
61544
61069
  "modifierKind": [
61545
61070
  148
@@ -61556,7 +61081,7 @@
61556
61081
  "indexKey": "",
61557
61082
  "optional": false,
61558
61083
  "description": "",
61559
- "line": 45,
61084
+ "line": 46,
61560
61085
  "rawdescription": "\n",
61561
61086
  "modifierKind": [
61562
61087
  148
@@ -61619,17 +61144,8 @@
61619
61144
  "indexKey": "",
61620
61145
  "optional": false,
61621
61146
  "description": "<p>Sets the height of the component.</p>\n",
61622
- "line": 38,
61623
- "rawdescription": "\n\nSets the height of the component.\n",
61624
- "decorators": [
61625
- {
61626
- "name": "HostBinding",
61627
- "stringifiedArguments": "'style.height.px'"
61628
- }
61629
- ],
61630
- "modifierKind": [
61631
- 171
61632
- ]
61147
+ "line": 39,
61148
+ "rawdescription": "\n\nSets the height of the component.\n"
61633
61149
  },
61634
61150
  {
61635
61151
  "name": "eclMegaMenuInfoStyleOpacity",
@@ -61641,7 +61157,7 @@
61641
61157
  "indexKey": "",
61642
61158
  "optional": false,
61643
61159
  "description": "<p>Sets the opacity of the component.</p>\n",
61644
- "line": 42,
61160
+ "line": 43,
61645
61161
  "rawdescription": "\n\nSets the opacity of the component.\n"
61646
61162
  },
61647
61163
  {
@@ -61654,7 +61170,7 @@
61654
61170
  "indexKey": "",
61655
61171
  "optional": false,
61656
61172
  "description": "",
61657
- "line": 21,
61173
+ "line": 23,
61658
61174
  "rawdescription": "\n"
61659
61175
  },
61660
61176
  {
@@ -61667,7 +61183,7 @@
61667
61183
  "indexKey": "",
61668
61184
  "optional": false,
61669
61185
  "description": "<p>When the info panel contains link.</p>\n",
61670
- "line": 55,
61186
+ "line": 56,
61671
61187
  "rawdescription": "\n\nWhen the info panel contains link.\n",
61672
61188
  "modifierKind": [
61673
61189
  148
@@ -61682,7 +61198,7 @@
61682
61198
  "optional": false,
61683
61199
  "returnType": "number",
61684
61200
  "typeParameters": [],
61685
- "line": 79,
61201
+ "line": 80,
61686
61202
  "deprecated": false,
61687
61203
  "deprecationMessage": "",
61688
61204
  "rawdescription": "\n\nUsed to calculate the height of the parent element.\n",
@@ -61690,8 +61206,8 @@
61690
61206
  "jsdoctags": [
61691
61207
  {
61692
61208
  "tagName": {
61693
- "pos": 2687,
61694
- "end": 2694,
61209
+ "pos": 2708,
61210
+ "end": 2715,
61695
61211
  "kind": 80,
61696
61212
  "id": 0,
61697
61213
  "flags": 16842752,
@@ -61709,7 +61225,7 @@
61709
61225
  "optional": false,
61710
61226
  "returnType": "void",
61711
61227
  "typeParameters": [],
61712
- "line": 58,
61228
+ "line": 59,
61713
61229
  "deprecated": false,
61714
61230
  "deprecationMessage": "",
61715
61231
  "rawdescription": "\n",
@@ -61722,7 +61238,7 @@
61722
61238
  "optional": false,
61723
61239
  "returnType": "void",
61724
61240
  "typeParameters": [],
61725
- "line": 70,
61241
+ "line": 71,
61726
61242
  "deprecated": false,
61727
61243
  "deprecationMessage": "",
61728
61244
  "rawdescription": "\n",
@@ -61770,47 +61286,21 @@
61770
61286
  "coverageIgnore": false,
61771
61287
  "deprecated": false,
61772
61288
  "deprecationMessage": "",
61773
- "hostBindings": [
61774
- {
61775
- "coverageIgnore": false,
61776
- "name": "class",
61777
- "actualName": "cssClasses",
61778
- "deprecated": false,
61779
- "deprecationMessage": "",
61780
- "rawdescription": "\n\nApplies custom styles for info component.\n",
61781
- "description": "<p>Applies custom styles for info component.</p>\n",
61782
- "line": 27,
61783
- "type": "string",
61784
- "decorators": []
61785
- },
61786
- {
61787
- "coverageIgnore": false,
61788
- "name": "style.height.px",
61789
- "actualName": "eclMegaMenuInfoStyleHeight",
61790
- "defaultValue": "null",
61791
- "deprecated": false,
61792
- "deprecationMessage": "",
61793
- "rawdescription": "\n\nSets the height of the component.\n",
61794
- "description": "<p>Sets the height of the component.</p>\n",
61795
- "line": 38,
61796
- "type": "number | null",
61797
- "decorators": []
61798
- }
61799
- ],
61289
+ "hostBindings": [],
61800
61290
  "hostListeners": [],
61801
61291
  "standalone": false,
61802
61292
  "imports": [],
61803
61293
  "description": "<p>Component for displaying some custom information for the current menu item.</p>\n",
61804
61294
  "rawdescription": "\n\nComponent for displaying some custom information for the current menu item.\n",
61805
61295
  "type": "component",
61806
- "sourceCode": "import { AfterViewInit, Component, ElementRef, HostBinding, OnDestroy, PLATFORM_ID, forwardRef, inject, signal, input, contentChild } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EclLinkDirective } from '@eui/ecl/components/ecl-link';\nimport { EclMegaMenuDataService } from '../services/ecl-mega-menu-data.service';\nimport { isPlatformBrowser, DOCUMENT } from '@angular/common';\nimport { Subject, fromEvent, auditTime, takeUntil } from 'rxjs';\n\n/**\n * Component for displaying some custom information for the current menu item.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'div[eclMegaMenuInfo]',\n templateUrl: './ecl-mega-menu-info.component.html',\n host: {\n '[style.opacity]': 'eclMegaMenuInfoStyleOpacity()',\n },\n})\n\nexport class EclMegaMenuInfoComponent extends ECLBaseDirective implements AfterViewInit, OnDestroy {\n el = inject(ElementRef);\n\n /**\n * Applies custom styles for info component.\n */\n @HostBinding('class')\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-mega-menu__info'),\n this.linkItem() ? 'ecl-mega-menu__info--has-link' : '',\n ]\n .join(' ')\n .trim();\n }\n /**\n * Sets the height of the component.\n */\n @HostBinding('style.height.px') eclMegaMenuInfoStyleHeight: number | null = null;\n /**\n * Sets the opacity of the component.\n */\n eclMegaMenuInfoStyleOpacity = signal<number | null>(null);\n\n readonly title = input<string>(undefined); \n readonly titleId = input<string>(undefined);\n\n private platformId = inject(PLATFORM_ID);\n private readonly doc = inject(DOCUMENT);\n private readonly window = this.doc.defaultView;\n private destroy$ = new Subject<void>();\n\n /**\n * When the info panel contains link.\n */\n readonly linkItem = contentChild(forwardRef(() => EclLinkDirective));\n private eclMegaMenuDataService = inject(EclMegaMenuDataService);\n\n ngAfterViewInit(): void {\n if (isPlatformBrowser(this.platformId)) {\n // Sets class of the sub link, if any.\n if (this.linkItem()) {\n setTimeout(() => this.linkItem().class = 'ecl-mega-menu__info-link');\n }\n // Emits the bottom value of the element. Needed to calculate the size of the sublist. (for the same parent menu item)\n this.publishSize();\n this.observeResize();\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n /**\n * Used to calculate the height of the parent element.\n * @returns the height of the component.\n */\n getInfoPanelScrollHeight() : number {\n return this.el.nativeElement.scrollHeight;\n }\n\n /**\n * Used to calulate the size of the info panel.\n */\n private publishSize(): void {\n const bottomY = this.el.nativeElement.getBoundingClientRect().bottom;\n this.eclMegaMenuDataService.updateEclMegaMenuInfoSize(bottomY);\n }\n\n /**\n * Re-publishes the info panel size on window resize so that dependent\n * components (e.g. sublist positioning) recalculate with current dimensions.\n */\n private observeResize(): void {\n if (this.window) {\n fromEvent(this.window, 'resize').pipe(\n auditTime(100),\n takeUntil(this.destroy$),\n ).subscribe(() => {\n this.publishSize();\n });\n }\n }\n}\n",
61296
+ "sourceCode": "import { AfterViewInit, Component, ElementRef, OnDestroy, PLATFORM_ID, forwardRef, inject, signal, input, contentChild } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EclLinkDirective } from '@eui/ecl/components/ecl-link';\nimport { EclMegaMenuDataService } from '../services/ecl-mega-menu-data.service';\nimport { isPlatformBrowser, DOCUMENT } from '@angular/common';\nimport { Subject, fromEvent, auditTime, takeUntil } from 'rxjs';\n\n/**\n * Component for displaying some custom information for the current menu item.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'div[eclMegaMenuInfo]',\n templateUrl: './ecl-mega-menu-info.component.html',\n host: {\n '[class]': 'cssClasses',\n '[style.height.px]': 'eclMegaMenuInfoStyleHeight',\n '[style.opacity]': 'eclMegaMenuInfoStyleOpacity()',\n },\n})\n\nexport class EclMegaMenuInfoComponent extends ECLBaseDirective implements AfterViewInit, OnDestroy {\n el = inject(ElementRef);\n\n /**\n * Applies custom styles for info component.\n */\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-mega-menu__info'),\n this.linkItem() ? 'ecl-mega-menu__info--has-link' : '',\n ]\n .join(' ')\n .trim();\n }\n /**\n * Sets the height of the component.\n */\n eclMegaMenuInfoStyleHeight: number | null = null;\n /**\n * Sets the opacity of the component.\n */\n eclMegaMenuInfoStyleOpacity = signal<number | null>(null);\n\n readonly title = input<string>(undefined); \n readonly titleId = input<string>(undefined);\n\n private platformId = inject(PLATFORM_ID);\n private readonly doc = inject(DOCUMENT);\n private readonly window = this.doc.defaultView;\n private destroy$ = new Subject<void>();\n\n /**\n * When the info panel contains link.\n */\n readonly linkItem = contentChild(forwardRef(() => EclLinkDirective));\n private eclMegaMenuDataService = inject(EclMegaMenuDataService);\n\n ngAfterViewInit(): void {\n if (isPlatformBrowser(this.platformId)) {\n // Sets class of the sub link, if any.\n if (this.linkItem()) {\n setTimeout(() => this.linkItem().class = 'ecl-mega-menu__info-link');\n }\n // Emits the bottom value of the element. Needed to calculate the size of the sublist. (for the same parent menu item)\n this.publishSize();\n this.observeResize();\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n /**\n * Used to calculate the height of the parent element.\n * @returns the height of the component.\n */\n getInfoPanelScrollHeight() : number {\n return this.el.nativeElement.scrollHeight;\n }\n\n /**\n * Used to calulate the size of the info panel.\n */\n private publishSize(): void {\n const bottomY = this.el.nativeElement.getBoundingClientRect().bottom;\n this.eclMegaMenuDataService.updateEclMegaMenuInfoSize(bottomY);\n }\n\n /**\n * Re-publishes the info panel size on window resize so that dependent\n * components (e.g. sublist positioning) recalculate with current dimensions.\n */\n private observeResize(): void {\n if (this.window) {\n fromEvent(this.window, 'resize').pipe(\n auditTime(100),\n takeUntil(this.destroy$),\n ).subscribe(() => {\n this.publishSize();\n });\n }\n }\n}\n",
61807
61297
  "assetsDirs": [],
61808
61298
  "styleUrlsData": "",
61809
61299
  "stylesData": "",
61810
61300
  "jsdoctags": [
61811
61301
  {
61812
- "pos": 481,
61813
- "end": 567,
61302
+ "pos": 468,
61303
+ "end": 554,
61814
61304
  "kind": 321,
61815
61305
  "id": 0,
61816
61306
  "flags": 16777216,
@@ -61833,7 +61323,7 @@
61833
61323
  "name": "cssClasses",
61834
61324
  "type": "string",
61835
61325
  "returnType": "string",
61836
- "line": 27,
61326
+ "line": 28,
61837
61327
  "rawdescription": "\n\nApplies custom styles for info component.\n",
61838
61328
  "description": "<p>Applies custom styles for info component.</p>\n"
61839
61329
  }
@@ -61860,10 +61350,11 @@
61860
61350
  },
61861
61351
  {
61862
61352
  "name": "EclMegaMenuItemComponent",
61863
- "id": "component-EclMegaMenuItemComponent-28149eb09235eba181b303bb0bcf470178d3263c130b525c6984ad6d91ca7537bb320ddcefa1b9b9318799ae46fed57c53edb70a9394d86344539c367da524a4",
61353
+ "id": "component-EclMegaMenuItemComponent-05018beb3c87a63b8fc2e806c581b7f8ac8ce09503da22c6234ceee275a5f6b5f60d064448f4b07fa67640b848de4e90019f1b0b5e2780b0de71dc41e3375a72",
61864
61354
  "file": "packages/ecl/components/ecl-mega-menu/ecl-mega-menu-item/ecl-mega-menu-item.component.ts",
61865
61355
  "encapsulation": [],
61866
61356
  "entryComponents": [],
61357
+ "host": {},
61867
61358
  "inputs": [],
61868
61359
  "outputs": [],
61869
61360
  "providers": [],
@@ -61885,7 +61376,7 @@
61885
61376
  "deprecationMessage": "",
61886
61377
  "rawdescription": "\n",
61887
61378
  "description": "",
61888
- "line": 74,
61379
+ "line": 84,
61889
61380
  "type": "string",
61890
61381
  "decorators": []
61891
61382
  },
@@ -61899,7 +61390,7 @@
61899
61390
  "indexKey": "",
61900
61391
  "optional": false,
61901
61392
  "description": "<p>This property should be used, when user wants the menu sub-items to use the maximum space available.\nFor example, if we have 10 sub-items, normally they will appear in one column only. If isOneLevelOnly is used, the sub-items\nwill take 2, 3, 4 columns, depending on presence of other sub-components.</p>\n",
61902
- "line": 81,
61393
+ "line": 91,
61903
61394
  "rawdescription": "\n\nThis property should be used, when user wants the menu sub-items to use the maximum space available.\nFor example, if we have 10 sub-items, normally they will appear in one column only. If isOneLevelOnly is used, the sub-items\nwill take 2, 3, 4 columns, depending on presence of other sub-components.\n",
61904
61395
  "required": false
61905
61396
  },
@@ -61913,7 +61404,7 @@
61913
61404
  "indexKey": "",
61914
61405
  "optional": false,
61915
61406
  "description": "",
61916
- "line": 68,
61407
+ "line": 78,
61917
61408
  "rawdescription": "\n",
61918
61409
  "modifierKind": [
61919
61410
  148
@@ -61930,7 +61421,7 @@
61930
61421
  "indexKey": "",
61931
61422
  "optional": false,
61932
61423
  "description": "",
61933
- "line": 69,
61424
+ "line": 79,
61934
61425
  "rawdescription": "\n",
61935
61426
  "modifierKind": [
61936
61427
  148
@@ -61947,7 +61438,7 @@
61947
61438
  "indexKey": "",
61948
61439
  "optional": false,
61949
61440
  "description": "<p>Used in case user wants to set some custom attributes for the anchr tag.</p>\n",
61950
- "line": 85,
61441
+ "line": 95,
61951
61442
  "rawdescription": "\n\nUsed in case user wants to set some custom attributes for the anchr tag.\n",
61952
61443
  "modifierKind": [
61953
61444
  148
@@ -61964,7 +61455,7 @@
61964
61455
  "indexKey": "",
61965
61456
  "optional": false,
61966
61457
  "description": "",
61967
- "line": 72,
61458
+ "line": 82,
61968
61459
  "rawdescription": "\n",
61969
61460
  "modifierKind": [
61970
61461
  148
@@ -61981,7 +61472,7 @@
61981
61472
  "indexKey": "",
61982
61473
  "optional": false,
61983
61474
  "description": "",
61984
- "line": 73,
61475
+ "line": 83,
61985
61476
  "rawdescription": "\n",
61986
61477
  "modifierKind": [
61987
61478
  148
@@ -61998,7 +61489,7 @@
61998
61489
  "indexKey": "",
61999
61490
  "optional": false,
62000
61491
  "description": "",
62001
- "line": 71,
61492
+ "line": 81,
62002
61493
  "rawdescription": "\n",
62003
61494
  "modifierKind": [
62004
61495
  148
@@ -62015,7 +61506,7 @@
62015
61506
  "indexKey": "",
62016
61507
  "optional": false,
62017
61508
  "description": "",
62018
- "line": 75,
61509
+ "line": 85,
62019
61510
  "rawdescription": "\n",
62020
61511
  "modifierKind": [
62021
61512
  148
@@ -62073,7 +61564,7 @@
62073
61564
  "defaultValue": "new EventEmitter()",
62074
61565
  "deprecated": false,
62075
61566
  "deprecationMessage": "",
62076
- "line": 87,
61567
+ "line": 97,
62077
61568
  "type": "EventEmitter"
62078
61569
  },
62079
61570
  {
@@ -62082,7 +61573,7 @@
62082
61573
  "defaultValue": "new EventEmitter<KeyboardEvent>()",
62083
61574
  "deprecated": false,
62084
61575
  "deprecationMessage": "",
62085
- "line": 88,
61576
+ "line": 98,
62086
61577
  "type": "EventEmitter"
62087
61578
  }
62088
61579
  ],
@@ -62097,7 +61588,7 @@
62097
61588
  "indexKey": "",
62098
61589
  "optional": false,
62099
61590
  "description": "",
62100
- "line": 124,
61591
+ "line": 134,
62101
61592
  "rawdescription": "\n"
62102
61593
  },
62103
61594
  {
@@ -62110,7 +61601,7 @@
62110
61601
  "indexKey": "",
62111
61602
  "optional": false,
62112
61603
  "description": "<p>Component, that consist of some custom info, text or whatever. When the menu item has no children, but still some\n sub container is displayed.</p>\n",
62113
- "line": 122,
61604
+ "line": 132,
62114
61605
  "rawdescription": "\n\nComponent, that consist of some custom info, text or whatever. When the menu item has no children, but still some\n sub container is displayed.\n",
62115
61606
  "modifierKind": [
62116
61607
  148
@@ -62126,7 +61617,7 @@
62126
61617
  "indexKey": "",
62127
61618
  "optional": false,
62128
61619
  "description": "",
62129
- "line": 117,
61620
+ "line": 127,
62130
61621
  "rawdescription": "\n",
62131
61622
  "modifierKind": [
62132
61623
  148
@@ -62142,7 +61633,7 @@
62142
61633
  "indexKey": "",
62143
61634
  "optional": false,
62144
61635
  "description": "<p>Element, that would contain some info about the current item or it&#39;s children. First in the container.</p>\n",
62145
- "line": 108,
61636
+ "line": 118,
62146
61637
  "rawdescription": "\n\nElement, that would contain some info about the current item or it's children. First in the container.\n",
62147
61638
  "modifierKind": [
62148
61639
  148
@@ -62158,7 +61649,7 @@
62158
61649
  "indexKey": "",
62159
61650
  "optional": false,
62160
61651
  "description": "<p>The wrapper around the subitems, if any.</p>\n",
62161
- "line": 92,
61652
+ "line": 102,
62162
61653
  "rawdescription": "\n\nThe wrapper around the subitems, if any.\n",
62163
61654
  "modifierKind": [
62164
61655
  148
@@ -62174,7 +61665,7 @@
62174
61665
  "indexKey": "",
62175
61666
  "optional": false,
62176
61667
  "description": "<p>Element, that holds the sub items of the current menu items.</p>\n",
62177
- "line": 112,
61668
+ "line": 122,
62178
61669
  "rawdescription": "\n\nElement, that holds the sub items of the current menu items.\n",
62179
61670
  "modifierKind": [
62180
61671
  148
@@ -62190,7 +61681,7 @@
62190
61681
  "indexKey": "",
62191
61682
  "optional": false,
62192
61683
  "description": "",
62193
- "line": 115,
61684
+ "line": 125,
62194
61685
  "rawdescription": "\n",
62195
61686
  "modifierKind": [
62196
61687
  148
@@ -62206,31 +61697,9 @@
62206
61697
  "indexKey": "",
62207
61698
  "optional": false,
62208
61699
  "description": "",
62209
- "line": 44,
61700
+ "line": 47,
62210
61701
  "rawdescription": "\n"
62211
61702
  },
62212
- {
62213
- "name": "hasPopup",
62214
- "coverageIgnore": false,
62215
- "defaultValue": "this.hasChildren ? true : null",
62216
- "deprecated": false,
62217
- "deprecationMessage": "",
62218
- "type": "unknown",
62219
- "indexKey": "",
62220
- "optional": false,
62221
- "description": "",
62222
- "line": 66,
62223
- "rawdescription": "\n",
62224
- "decorators": [
62225
- {
62226
- "name": "HostBinding",
62227
- "stringifiedArguments": "'attr.aria-haspopup'"
62228
- }
62229
- ],
62230
- "modifierKind": [
62231
- 171
62232
- ]
62233
- },
62234
61703
  {
62235
61704
  "name": "isCurrent",
62236
61705
  "coverageIgnore": false,
@@ -62241,7 +61710,7 @@
62241
61710
  "indexKey": "",
62242
61711
  "optional": false,
62243
61712
  "description": "",
62244
- "line": 125,
61713
+ "line": 135,
62245
61714
  "rawdescription": "\n"
62246
61715
  },
62247
61716
  {
@@ -62254,7 +61723,7 @@
62254
61723
  "indexKey": "",
62255
61724
  "optional": false,
62256
61725
  "description": "",
62257
- "line": 65,
61726
+ "line": 67,
62258
61727
  "rawdescription": "\n"
62259
61728
  },
62260
61729
  {
@@ -62267,7 +61736,7 @@
62267
61736
  "indexKey": "",
62268
61737
  "optional": false,
62269
61738
  "description": "",
62270
- "line": 126,
61739
+ "line": 136,
62271
61740
  "rawdescription": "\n"
62272
61741
  },
62273
61742
  {
@@ -62280,7 +61749,7 @@
62280
61749
  "indexKey": "",
62281
61750
  "optional": false,
62282
61751
  "description": "<p>This elemend hold some extra content, different from subitems. For example just some text or some custom links, etc.</p>\n",
62283
- "line": 96,
61752
+ "line": 106,
62284
61753
  "rawdescription": "\n\nThis elemend hold some extra content, different from subitems. For example just some text or some custom links, etc.\n",
62285
61754
  "modifierKind": [
62286
61755
  148
@@ -62296,7 +61765,7 @@
62296
61765
  "indexKey": "",
62297
61766
  "optional": false,
62298
61767
  "description": "",
62299
- "line": 127,
61768
+ "line": 137,
62300
61769
  "rawdescription": "\n"
62301
61770
  },
62302
61771
  {
@@ -62309,7 +61778,7 @@
62309
61778
  "indexKey": "",
62310
61779
  "optional": false,
62311
61780
  "description": "",
62312
- "line": 128,
61781
+ "line": 138,
62313
61782
  "rawdescription": "\n"
62314
61783
  },
62315
61784
  {
@@ -62322,7 +61791,7 @@
62322
61791
  "indexKey": "",
62323
61792
  "optional": false,
62324
61793
  "description": "<p>Element, tat is rendered if the menu item has children.</p>\n",
62325
- "line": 104,
61794
+ "line": 114,
62326
61795
  "rawdescription": "\n\nElement, tat is rendered if the menu item has children.\n",
62327
61796
  "modifierKind": [
62328
61797
  148
@@ -62338,7 +61807,7 @@
62338
61807
  "indexKey": "",
62339
61808
  "optional": false,
62340
61809
  "description": "<p>Actual link of the menu item. If the menu has no children, but redirects/loads another page.</p>\n",
62341
- "line": 100,
61810
+ "line": 110,
62342
61811
  "rawdescription": "\n\nActual link of the menu item. If the menu has no children, but redirects/loads another page.\n",
62343
61812
  "modifierKind": [
62344
61813
  148
@@ -62354,7 +61823,7 @@
62354
61823
  "indexKey": "",
62355
61824
  "optional": false,
62356
61825
  "description": "",
62357
- "line": 45,
61826
+ "line": 48,
62358
61827
  "rawdescription": "\n"
62359
61828
  },
62360
61829
  {
@@ -62367,7 +61836,7 @@
62367
61836
  "indexKey": "",
62368
61837
  "optional": false,
62369
61838
  "description": "",
62370
- "line": 129,
61839
+ "line": 139,
62371
61840
  "rawdescription": "\n"
62372
61841
  },
62373
61842
  {
@@ -62380,7 +61849,7 @@
62380
61849
  "indexKey": "",
62381
61850
  "optional": false,
62382
61851
  "description": "",
62383
- "line": 130,
61852
+ "line": 140,
62384
61853
  "rawdescription": "\n"
62385
61854
  }
62386
61855
  ],
@@ -62392,7 +61861,7 @@
62392
61861
  "optional": false,
62393
61862
  "returnType": "void",
62394
61863
  "typeParameters": [],
62395
- "line": 157,
61864
+ "line": 167,
62396
61865
  "deprecated": false,
62397
61866
  "deprecationMessage": "",
62398
61867
  "rawdescription": "\n",
@@ -62405,7 +61874,7 @@
62405
61874
  "optional": false,
62406
61875
  "returnType": "void",
62407
61876
  "typeParameters": [],
62408
- "line": 176,
61877
+ "line": 186,
62409
61878
  "deprecated": false,
62410
61879
  "deprecationMessage": "",
62411
61880
  "rawdescription": "\n",
@@ -62418,7 +61887,7 @@
62418
61887
  "optional": false,
62419
61888
  "returnType": "void",
62420
61889
  "typeParameters": [],
62421
- "line": 204,
61890
+ "line": 214,
62422
61891
  "deprecated": false,
62423
61892
  "deprecationMessage": "",
62424
61893
  "rawdescription": "\n\nSet the focus on the sub element - link or button.\n",
@@ -62440,7 +61909,7 @@
62440
61909
  "optional": false,
62441
61910
  "returnType": "void",
62442
61911
  "typeParameters": [],
62443
- "line": 255,
61912
+ "line": 265,
62444
61913
  "deprecated": false,
62445
61914
  "deprecationMessage": "",
62446
61915
  "rawdescription": "\n",
@@ -62466,7 +61935,7 @@
62466
61935
  "optional": false,
62467
61936
  "returnType": "void",
62468
61937
  "typeParameters": [],
62469
- "line": 217,
61938
+ "line": 227,
62470
61939
  "deprecated": false,
62471
61940
  "deprecationMessage": "",
62472
61941
  "rawdescription": "\n\nManage styling and functionality for children and siblings, when item is clicked.\n",
@@ -62479,7 +61948,7 @@
62479
61948
  "optional": false,
62480
61949
  "returnType": "void",
62481
61950
  "typeParameters": [],
62482
- "line": 245,
61951
+ "line": 255,
62483
61952
  "deprecated": false,
62484
61953
  "deprecationMessage": "",
62485
61954
  "rawdescription": "\n\nManage styling and functionality when item is collapsed.\n",
@@ -62527,33 +61996,7 @@
62527
61996
  "coverageIgnore": false,
62528
61997
  "deprecated": false,
62529
61998
  "deprecationMessage": "",
62530
- "hostBindings": [
62531
- {
62532
- "coverageIgnore": false,
62533
- "name": "attr.aria-haspopup",
62534
- "actualName": "hasPopup",
62535
- "defaultValue": "this.hasChildren ? true : null",
62536
- "deprecated": false,
62537
- "deprecationMessage": "",
62538
- "rawdescription": "\n",
62539
- "description": "",
62540
- "line": 66,
62541
- "type": "boolean | null",
62542
- "decorators": []
62543
- },
62544
- {
62545
- "coverageIgnore": false,
62546
- "name": "class",
62547
- "actualName": "cssClasses",
62548
- "deprecated": false,
62549
- "deprecationMessage": "",
62550
- "rawdescription": "\n\nReturns current menu item classes, depending on item's state (it's properties' values).\n",
62551
- "description": "<p>Returns current menu item classes, depending on item&#39;s state (it&#39;s properties&#39; values).</p>\n",
62552
- "line": 51,
62553
- "type": "string",
62554
- "decorators": []
62555
- }
62556
- ],
61999
+ "hostBindings": [],
62557
62000
  "hostListeners": [],
62558
62001
  "standalone": false,
62559
62002
  "imports": [
@@ -62576,14 +62019,14 @@
62576
62019
  "description": "<p>This component represents a mega menu item. Adds functionality and styling, according to ECL standards.</p>\n",
62577
62020
  "rawdescription": "\n\nThis component represents a mega menu item. Adds functionality and styling, according to ECL standards.\n",
62578
62021
  "type": "component",
62579
- "sourceCode": "import {\n AfterContentInit,\n afterNextRender, booleanAttribute,\n Component,\n ElementRef, EventEmitter,\n forwardRef,\n HostBinding,\n inject,\n Input, OnDestroy, Output,\n DOCUMENT,\n Renderer2,\n input,\n signal,\n viewChild,\n contentChild,\n contentChildren,\n} from '@angular/core';\nimport { Params, QueryParamsHandling, RouterLink, RouterLinkWithHref } from '@angular/router';\nimport { EuiAppShellService } from '@eui/core';\nimport { EclButtonComponent, EUI_ECL_BUTTON } from '@eui/ecl/components/ecl-button';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EclLinkDirective, EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { EclHeaderMenuComunicationService } from '@eui/ecl/shared';\nimport { distinctUntilChanged, map, Subject, auditTime, fromEvent, takeUntil } from 'rxjs';\nimport { EclMegaMenuContainerDirective } from '../directives/ecl-mega-menu-container.directive';\nimport { EclMegaMenuSublistDirective } from '../directives/ecl-mega-menu-list.directive';\nimport { EclMegaMenuFeaturedComponent } from '../ecl-mega-menu-featured/ecl-mega-menu-featured.component';\nimport { EclMegaMenuInfoComponent } from '../ecl-mega-menu-info/ecl-mega-menu-info.component';\nimport { EclMegaMenuDataService } from '../services/ecl-mega-menu-data.service';\nimport { EclMegaMenuService } from '../services/ecl-mega-menu.service';\n\n/**\n * This component represents a mega menu item. Adds functionality and styling, according to ECL standards.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'li[eclMegaMenuItem]',\n templateUrl: './ecl-mega-menu-item.component.html',\n imports: [RouterLink, RouterLinkWithHref, ...EUI_ECL_BUTTON, ...EUI_ECL_ICON, ...EUI_ECL_LINK],\n})\n\nexport class EclMegaMenuItemComponent extends ECLBaseDirective implements AfterContentInit, OnDestroy {\n el = inject(ElementRef);\n renderer = inject(Renderer2);\n\n /**\n * Returns current menu item classes, depending on item's state (it's properties' values).\n */\n @HostBinding('class')\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-mega-menu__item'),\n this.eclMegaMenuSublist() ? 'ecl-mega-menu__item--has-children' : '',\n this.eclMegaMenuContainer() ? 'ecl-mega-menu__item--has-container' : '',\n this.isCurrent ? 'ecl-mega-menu__item--current' : '',\n this.isExpanded ? 'ecl-mega-menu__item--expanded' : '',\n this.isPromotional() ? 'ecl-mega-menu__item--promotional' : '',\n this.isOneLevelOnly() ? 'ecl-mega-menu__item--one-level-only' : '',\n ]\n .join(' ')\n .trim();\n }\n\n isExpanded = false;\n @HostBinding('attr.aria-haspopup') hasPopup = this.hasChildren ? true : null;\n\n readonly isPromotional = input(false, { transform: booleanAttribute });\n readonly label = input<string>(undefined);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly routerLink = input<string | any[]>(null);\n readonly queryParams = input<Params | null>(null);\n readonly queryParamsHandling = input<QueryParamsHandling>(null);\n @Input() href = '';\n readonly target = input('');\n /**\n * This property should be used, when user wants the menu sub-items to use the maximum space available.\n * For example, if we have 10 sub-items, normally they will appear in one column only. If isOneLevelOnly is used, the sub-items\n * will take 2, 3, 4 columns, depending on presence of other sub-components.\n */\n isOneLevelOnly = input(false, { transform: booleanAttribute });\n /**\n * Used in case user wants to set some custom attributes for the anchr tag.\n */\n readonly linkExtraAttributes = input<Record<string, string>>(undefined);\n\n @Output() megaMenuItemClicked = new EventEmitter();\n @Output() megaMenuItemKeydown = new EventEmitter<KeyboardEvent>();\n /**\n * The wrapper around the subitems, if any.\n */\n readonly eclMegaMenuMega = viewChild<ElementRef>('eclMegaMenuMega');\n /**\n * This elemend hold some extra content, different from subitems. For example just some text or some custom links, etc.\n */\n readonly mainPanel = viewChild<ElementRef>('mainPanel');\n /**\n * Actual link of the menu item. If the menu has no children, but redirects/loads another page.\n */\n readonly menuLink = viewChild(EclLinkDirective);\n /**\n * Element, tat is rendered if the menu item has children.\n */\n readonly menuBtn = viewChild<EclButtonComponent>('menuBtn');\n /**\n * Element, that would contain some info about the current item or it's children. First in the container.\n */\n readonly eclMegaMenuInfo = contentChild(forwardRef(() => EclMegaMenuInfoComponent));\n /**\n * Element, that holds the sub items of the current menu items.\n */\n readonly eclMegaMenuSublist = contentChild(forwardRef(() => EclMegaMenuSublistDirective));\n\n // Get all the sublists including childrens's sublist, to detect if it's only one level submenu.\n readonly eclMegaMenuSublists = contentChildren(forwardRef(() => EclMegaMenuSublistDirective), { descendants: true });\n\n readonly eclMegaMenuFeatured = contentChild(forwardRef(() => EclMegaMenuFeaturedComponent), { descendants: false });\n /**\n * Component, that consist of some custom info, text or whatever. When the menu item has no children, but still some\n * sub container is displayed.\n */\n readonly eclMegaMenuContainer = contentChild(forwardRef(() => EclMegaMenuContainerDirective));\n\n containerStyleHeight: number | null = null;\n isCurrent = false;\n isMobileBreakpoint = false;\n megaMenuMegaStyleHeight = signal<number | null>(null);\n megaMenuMegaStyleOpacity = signal<number | null>(null);\n wrapperStyleHeight: number | null = null;\n wrapperStyleTop: number | null = null;\n\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private isLarge = false;\n private eclMegaMenuDataService = inject(EclMegaMenuDataService);\n private eclHeaderMenuComunicationService = inject(EclHeaderMenuComunicationService);\n private eclMegaMenuService = inject(EclMegaMenuService);\n private readonly doc = inject(DOCUMENT);\n private readonly window = this.doc.defaultView; // Window | null\n private appShellService = inject(EuiAppShellService);\n\n constructor() {\n super();\n\n afterNextRender(() => {\n this.eclMegaMenuDataService.eclMegaMenuInfoBottomYSubject$.pipe(takeUntil(this.destroy$)).subscribe(value => {\n this.calculateSublistStyle(value);\n });\n const menuLink = this.menuLink();\n if (menuLink) {\n this.eclMegaMenuService.setExtraAttributesForLink(menuLink.el.nativeElement, this.linkExtraAttributes());\n }\n this.observeBreakpointChanges();\n this.observeResizeWindow();\n });\n }\n\n ngAfterContentInit(): void {\n this.eclMegaMenuSublist()?.megaMenuSubItemClicked.pipe(takeUntil(this.destroy$)).subscribe(() => {\n if (!this.isExpanded) {\n return;\n }\n if (!this.isMobileBreakpoint) {\n // Only hide/show the level-2 panel when switching sub-items\n const expandedSubItem = this.eclMegaMenuSublist().submenuItems().find(\n item => item.hasChildren && item.isExpanded\n );\n const megaMenuLevel2 = expandedSubItem.megaMenuLevel2();\n if (expandedSubItem && megaMenuLevel2) {\n megaMenuLevel2.nativeElement.style.opacity = '0';\n }\n }\n setTimeout(() => this.checkDropdownHeight(false), 100);\n });\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n get hasNoInfo(): boolean {\n return !this.eclMegaMenuInfo();\n }\n\n get hasChildren(): boolean {\n return !!this.eclMegaMenuSublist() || !!this.eclMegaMenuContainer();\n }\n\n get hasSublist(): boolean {\n return !!this.eclMegaMenuSublist();\n }\n\n get hasFeatured(): boolean {\n return !!this.eclMegaMenuFeatured();\n }\n\n get hasContainer(): boolean {\n return !!this.eclMegaMenuContainer();\n }\n\n /**\n * Set the focus on the sub element - link or button.\n */\n onFocus(): void {\n const menuLink = this.menuLink();\n const menuBtn = this.menuBtn();\n if (menuLink) {\n menuLink.onFocus();\n } else if (menuBtn) {\n menuBtn.onFocus();\n }\n }\n\n /**\n * Manage styling and functionality for children and siblings, when item is clicked.\n */\n onMegaMenuItemClick(): void {\n if (this.hasChildren) {\n this.isCurrent = !this.isCurrent;\n this.isExpanded = !this.isExpanded;\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (eclMegaMenuSublist) {\n eclMegaMenuSublist.onParentMegaMenuItemClick(this.isExpanded);\n }\n if (this.isExpanded) {\n this.eclHeaderMenuComunicationService.updateExpanded(this.isExpanded);\n this.hidePanels();\n setTimeout(() => {\n this.checkDropdownHeight();\n this.calculateWrapperStyle();\n }, 100);\n } else {\n this.eclHeaderMenuComunicationService.updateExpanded(this.isExpanded);\n this.resetComputedHeights();\n }\n } else {\n this.eclHeaderMenuComunicationService.updateExpanded(this.isExpanded);\n }\n this.megaMenuItemClicked.emit();\n }\n\n /**\n * Manage styling and functionality when item is collapsed.\n */\n onMegaMenuItemCollapse(): void {\n this.isCurrent = false;\n this.isExpanded = false;\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (eclMegaMenuSublist) {\n eclMegaMenuSublist.onParentMegaMenuItemClick(this.isExpanded);\n }\n this.resetComputedHeights();\n }\n\n onKeydown(evt: Event): void {\n if (evt instanceof KeyboardEvent) {\n if ((evt as KeyboardEvent).key === KeyCode.TAB && !(evt as KeyboardEvent).shiftKey) {\n // if menu is open, navigate to children\n } else {\n this.megaMenuItemKeydown.emit(evt as KeyboardEvent);\n }\n }\n }\n\n /**\n * On resize - calculate the size of the dropdown and wrapper (if item is expanded).\n */\n private observeResizeWindow(): void {\n if (this.window) {\n fromEvent(this.window, 'resize').pipe(\n auditTime(50),\n takeUntil(this.destroy$)).subscribe(() => {\n setTimeout(() => {\n if (this.isExpanded) {\n this.checkDropdownHeight();\n this.calculateWrapperStyle();\n } else {\n // Even when not expanded, reset computed heights on resize\n // so stale desktop values don't persist into tablet/mobile layout\n this.resetComputedHeights();\n }\n });\n });\n }\n }\n\n private calculateSublistStyle(bottomInfo: number): void {\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (this.isMobileBreakpoint && eclMegaMenuSublist) {\n const availableHeight = this.window.innerHeight - bottomInfo - 16;\n eclMegaMenuSublist.styleTop = availableHeight;\n }\n }\n\n private calculateWrapperStyle(): void {\n if (!this.isMobileBreakpoint) {\n const height = this.el.nativeElement.getBoundingClientRect().height;\n this.wrapperStyleTop = height;\n }\n }\n\n private resetWrapperStyle(): void {\n if (this.isMobileBreakpoint) {\n this.wrapperStyleHeight = null;\n this.wrapperStyleTop = null;\n }\n }\n\n /**\n * Resets all computed pixel heights on the info panel, mega panel, and wrapper.\n * Called when the viewport changes breakpoint so that stale desktop values\n * (e.g. info height of 227px) don't persist into tablet/mobile layout where\n * the elements should flow naturally.\n */\n private resetComputedHeights(): void {\n const eclMegaMenuInfo = this.eclMegaMenuInfo();\n if (eclMegaMenuInfo) {\n eclMegaMenuInfo.eclMegaMenuInfoStyleHeight = null;\n eclMegaMenuInfo.eclMegaMenuInfoStyleOpacity.set(null);\n }\n this.megaMenuMegaStyleHeight.set(null);\n this.megaMenuMegaStyleOpacity.set(null);\n this.wrapperStyleHeight = null;\n this.wrapperStyleTop = null;\n this.containerStyleHeight = null;\n\n // Reset featured panel height\n const eclMegaMenuFeatured = this.eclMegaMenuFeatured();\n if (eclMegaMenuFeatured) {\n eclMegaMenuFeatured.eclMegaMenuFeaturedStyleHeight = null;\n }\n\n // Reset sublist and sub-items heights\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (eclMegaMenuSublist) {\n eclMegaMenuSublist.styleHeight.set(null);\n eclMegaMenuSublist.styleTop = null;\n eclMegaMenuSublist.isScrollable = false;\n\n // Reset level-2 heights on each subitem\n eclMegaMenuSublist.submenuItems()?.forEach(subItem => {\n subItem.level2StyleHeight = null;\n const eclMegaMenuFeatured = subItem.eclMegaMenuFeatured();\n if (eclMegaMenuFeatured) {\n eclMegaMenuFeatured.eclMegaMenuFeaturedStyleHeight = null;\n }\n });\n }\n }\n\n private hidePanels(): void {\n if (this.isMobileBreakpoint) {\n return;\n }\n if (this.eclMegaMenuMega()) {\n this.megaMenuMegaStyleOpacity.set(0);\n }\n const eclMegaMenuInfo = this.eclMegaMenuInfo();\n if (eclMegaMenuInfo) {\n eclMegaMenuInfo.eclMegaMenuInfoStyleOpacity.set(0);\n }\n }\n\n /**\n * On mobile, calculate the height of the mega panel (level 1).\n * - If the item has a featured panel: set height on the mega div (.ecl-mega-menu__mega--has-featured)\n * - If no featured, panel 1: height is set on the sublist\n * - If no featured, panel 2: height is set on the level-2 div\n */\n private calculateMobileHeight(): void {\n const eclMegaMenuMega = this.eclMegaMenuMega();\n if (!this.isMobileBreakpoint || !eclMegaMenuMega) {\n return;\n }\n const eclMegaMenuSublistValue = this.eclMegaMenuSublist();\n if (this.hasFeatured) {\n // Has featured → set height on the mega div, no scrollable on sublist\n const megaRect = eclMegaMenuMega.nativeElement.getBoundingClientRect();\n const megaTop = megaRect.top;\n this.megaMenuMegaStyleHeight.set(this.window.innerHeight - megaTop);\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (eclMegaMenuSublist) {\n eclMegaMenuSublist.isScrollable = false;\n eclMegaMenuSublist.styleHeight.set(null);\n }\n } else if (eclMegaMenuSublistValue) {\n this.megaMenuMegaStyleHeight.set(null);\n\n // Check if a sub-item with children is expanded (panel 2)\n const expandedSubItem = eclMegaMenuSublistValue.submenuItems().find(\n item => item.hasChildren && item.isExpanded\n );\n\n const megaMenuLevel2 = expandedSubItem.megaMenuLevel2();\n if (expandedSubItem && megaMenuLevel2) {\n // No featured, panel 2 → set height on the level-2 div\n const subMegaRect = megaMenuLevel2.nativeElement.getBoundingClientRect();\n const subMegaTop = subMegaRect.top;\n expandedSubItem.level2StyleHeight = this.window.innerHeight - subMegaTop;\n // Clear sublist height and scrollable since panel 2 is now showing\n eclMegaMenuSublistValue.isScrollable = false;\n eclMegaMenuSublistValue.styleHeight.set(null);\n } else {\n // No featured, panel 1 → set height on the sublist\n const sublistRect = eclMegaMenuSublistValue.el.nativeElement.getBoundingClientRect();\n const sublistTop = sublistRect.top;\n eclMegaMenuSublistValue.styleHeight.set(this.window.innerHeight - sublistTop);\n eclMegaMenuSublistValue.isScrollable = true;\n }\n } else {\n this.megaMenuMegaStyleHeight.set(null);\n }\n }\n\n private checkDropdownHeight(hide = true): void {\n if (this.isMobileBreakpoint) {\n this.calculateMobileHeight();\n return;\n }\n\n if (hide) {\n this.hidePanels();\n }\n let infoPanelHeight = 0;\n const eclMegaMenuInfo = this.eclMegaMenuInfo();\n if (eclMegaMenuInfo) {\n eclMegaMenuInfo.eclMegaMenuInfoStyleHeight = null;\n }\n\n const heights = [];\n let height = 0;\n let itemsHeight = 0;\n let subItemsHeight = 0;\n let featuredHeight = 0;\n let featuredHeight2 = 0;\n\n if (this.hasContainer) {\n const viewportHeight = this.window.innerHeight;\n const mainTop = this.mainPanel().nativeElement.getBoundingClientRect().top;\n this.containerStyleHeight = viewportHeight - mainTop;\n } else {\n if (eclMegaMenuInfo) {\n infoPanelHeight = eclMegaMenuInfo.getInfoPanelScrollHeight() + 16;\n if (this.isLarge) {\n heights.push(infoPanelHeight);\n } else {\n subItemsHeight = infoPanelHeight;\n featuredHeight = infoPanelHeight;\n }\n eclMegaMenuInfo.eclMegaMenuInfoStyleOpacity.set(1);\n }\n\n const eclMegaMenuMega = this.eclMegaMenuMega();\n if (eclMegaMenuMega) {\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (eclMegaMenuSublist && eclMegaMenuSublist.submenuItems().length > 0) {\n if (this.isOneLevelOnly()) {\n itemsHeight = eclMegaMenuSublist.el.nativeElement.offsetHeight;\n } else {\n eclMegaMenuSublist.submenuItems().forEach((item) => {\n itemsHeight += item.getMegaMenuSubItemHeight();\n });\n if (eclMegaMenuSublist.spacer()) {\n itemsHeight += 25;\n }\n }\n heights.push(itemsHeight);\n }\n const expandedSubItem = eclMegaMenuSublist.submenuItems().find(item => item.hasChildren && item.isExpanded);\n const eclMegaMenuFeatured = expandedSubItem.eclMegaMenuFeatured();\n if (expandedSubItem !== undefined) {\n expandedSubItem.submenu().submenuItems().forEach(item => {\n subItemsHeight += item.getMegaMenuSubItemHeight();\n });\n heights.push(subItemsHeight);\n if (eclMegaMenuFeatured) {\n featuredHeight += eclMegaMenuFeatured.getEclMegaMenuFeaturedHeight();\n featuredHeight += 5;\n heights.push(featuredHeight);\n }\n }\n\n const eclMegaMenuFeaturedValue = this.eclMegaMenuFeatured();\n if (eclMegaMenuFeaturedValue) {\n featuredHeight2 = eclMegaMenuFeaturedValue.getEclMegaMenuFeaturedHeight();\n heights.push(featuredHeight2);\n }\n const maxHeight = Math.max(...heights);\n const containerBounding = this.el.nativeElement.getBoundingClientRect();\n const containerBottom = containerBounding.bottom;\n // By requirements, limit the height to the 70% of the available space.\n const availableHeight = (this.window.innerHeight - containerBottom) * 0.9;\n if (maxHeight > availableHeight) {\n height = availableHeight;\n } else {\n height = maxHeight;\n }\n\n this.wrapperStyleHeight = eclMegaMenuMega && eclMegaMenuInfo && !this.isLarge ?\n height + infoPanelHeight : height;\n if (this.wrapperStyleHeight > availableHeight) this.wrapperStyleHeight = availableHeight;\n if (eclMegaMenuMega && this.isLarge) {\n this.megaMenuMegaStyleHeight.set(height);\n } else if (eclMegaMenuMega && eclMegaMenuInfo) {\n this.megaMenuMegaStyleHeight.set(this.wrapperStyleHeight - infoPanelHeight);\n }\n if (eclMegaMenuInfo && this.isLarge) {\n eclMegaMenuInfo.eclMegaMenuInfoStyleHeight = height;\n }\n\n if (expandedSubItem !== undefined) {\n if (this.isLarge) {\n expandedSubItem.level2StyleHeight = height;\n } else {\n expandedSubItem.level2StyleHeight = height - infoPanelHeight;\n }\n\n const megaMenuLevel2 = expandedSubItem.megaMenuLevel2();\n if (megaMenuLevel2) {\n megaMenuLevel2.nativeElement.style.opacity = '1';\n }\n\n if (eclMegaMenuFeatured) {\n if (this.isLarge) {\n eclMegaMenuFeatured.eclMegaMenuFeaturedStyleHeight = height;\n } else {\n eclMegaMenuFeatured.eclMegaMenuFeaturedStyleHeight = height - infoPanelHeight;\n }\n }\n }\n if (eclMegaMenuFeaturedValue) {\n if (this.isLarge) {\n eclMegaMenuFeaturedValue.eclMegaMenuFeaturedStyleHeight = height;\n } else {\n eclMegaMenuFeaturedValue.eclMegaMenuFeaturedStyleHeight = this.wrapperStyleHeight - infoPanelHeight;\n }\n }\n this.megaMenuMegaStyleOpacity.set(1);\n }\n }\n }\n\n private observeBreakpointChanges(): void {\n this.appShellService.state$\n .pipe(\n map((state) => {\n const w = state.windowWidth ?? 0;\n const bp = state.breakpoints;\n return {\n // ECL uses breakpointDesktop = 1140px. Everything below that\n // (xs/sm/md/lg) must use mobile behavior. isLtLargeTablet covers this range.\n isMobile: !!(bp?.isLtLargeTablet),\n isLarge: w >= 1368,\n };\n }),\n distinctUntilChanged(\n (a, b) => a.isMobile === b.isMobile && a.isLarge === b.isLarge\n ),\n takeUntil(this.destroy$),\n )\n .subscribe(({ isMobile, isLarge }) => {\n const wasMobile = this.isMobileBreakpoint;\n const wasLarge = this.isLarge;\n this.isMobileBreakpoint = isMobile;\n this.isLarge = isLarge;\n this.resetWrapperStyle();\n\n // When breakpoint changes, reset all computed heights so they don't\n // carry over stale pixel values from the previous layout mode.\n if (wasMobile !== isMobile || wasLarge !== isLarge) {\n this.resetComputedHeights();\n\n // If transitioning between mobile/desktop while expanded,\n // recalculate with new layout dimensions\n if (this.isExpanded) {\n setTimeout(() => {\n this.checkDropdownHeight();\n this.calculateWrapperStyle();\n }, 100);\n }\n }\n });\n }\n}\n",
62022
+ "sourceCode": "import {\n AfterContentInit,\n afterNextRender, booleanAttribute,\n Component,\n ElementRef, EventEmitter,\n forwardRef,\n inject,\n Input, OnDestroy, Output,\n DOCUMENT,\n Renderer2,\n input,\n signal,\n viewChild,\n contentChild,\n contentChildren,\n} from '@angular/core';\nimport { Params, QueryParamsHandling, RouterLink, RouterLinkWithHref } from '@angular/router';\nimport { EuiAppShellService } from '@eui/core';\nimport { EclButtonComponent, EUI_ECL_BUTTON } from '@eui/ecl/components/ecl-button';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EclLinkDirective, EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { EclHeaderMenuComunicationService } from '@eui/ecl/shared';\nimport { distinctUntilChanged, map, Subject, auditTime, fromEvent, takeUntil } from 'rxjs';\nimport { EclMegaMenuContainerDirective } from '../directives/ecl-mega-menu-container.directive';\nimport { EclMegaMenuSublistDirective } from '../directives/ecl-mega-menu-list.directive';\nimport { EclMegaMenuFeaturedComponent } from '../ecl-mega-menu-featured/ecl-mega-menu-featured.component';\nimport { EclMegaMenuInfoComponent } from '../ecl-mega-menu-info/ecl-mega-menu-info.component';\nimport { EclMegaMenuDataService } from '../services/ecl-mega-menu-data.service';\nimport { EclMegaMenuService } from '../services/ecl-mega-menu.service';\n\n/**\n * This component represents a mega menu item. Adds functionality and styling, according to ECL standards.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'li[eclMegaMenuItem]',\n templateUrl: './ecl-mega-menu-item.component.html',\n imports: [RouterLink, RouterLinkWithHref, ...EUI_ECL_BUTTON, ...EUI_ECL_ICON, ...EUI_ECL_LINK],\n host: {\n '[class]': 'cssClasses',\n '[attr.aria-haspopup]': 'hasPopup',\n },\n})\n\nexport class EclMegaMenuItemComponent extends ECLBaseDirective implements AfterContentInit, OnDestroy {\n el = inject(ElementRef);\n renderer = inject(Renderer2);\n\n /**\n * Returns current menu item classes, depending on item's state (it's properties' values).\n */\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-mega-menu__item'),\n this.eclMegaMenuSublist() ? 'ecl-mega-menu__item--has-children' : '',\n this.eclMegaMenuContainer() ? 'ecl-mega-menu__item--has-container' : '',\n this.isCurrent ? 'ecl-mega-menu__item--current' : '',\n this.isExpanded ? 'ecl-mega-menu__item--expanded' : '',\n this.isPromotional() ? 'ecl-mega-menu__item--promotional' : '',\n this.isOneLevelOnly() ? 'ecl-mega-menu__item--one-level-only' : '',\n ]\n .join(' ')\n .trim();\n }\n\n isExpanded = false;\n\n /**\n * Reflects whether this item has a submenu/container. Evaluated lazily during\n * change detection (not at construction) so the content-query signals are\n * resolved before it is read.\n */\n get hasPopup(): true | null {\n return this.hasChildren ? true : null;\n }\n\n readonly isPromotional = input(false, { transform: booleanAttribute });\n readonly label = input<string>(undefined);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly routerLink = input<string | any[]>(null);\n readonly queryParams = input<Params | null>(null);\n readonly queryParamsHandling = input<QueryParamsHandling>(null);\n @Input() href = '';\n readonly target = input('');\n /**\n * This property should be used, when user wants the menu sub-items to use the maximum space available.\n * For example, if we have 10 sub-items, normally they will appear in one column only. If isOneLevelOnly is used, the sub-items\n * will take 2, 3, 4 columns, depending on presence of other sub-components.\n */\n isOneLevelOnly = input(false, { transform: booleanAttribute });\n /**\n * Used in case user wants to set some custom attributes for the anchr tag.\n */\n readonly linkExtraAttributes = input<Record<string, string>>(undefined);\n\n @Output() megaMenuItemClicked = new EventEmitter();\n @Output() megaMenuItemKeydown = new EventEmitter<KeyboardEvent>();\n /**\n * The wrapper around the subitems, if any.\n */\n readonly eclMegaMenuMega = viewChild<ElementRef>('eclMegaMenuMega');\n /**\n * This elemend hold some extra content, different from subitems. For example just some text or some custom links, etc.\n */\n readonly mainPanel = viewChild<ElementRef>('mainPanel');\n /**\n * Actual link of the menu item. If the menu has no children, but redirects/loads another page.\n */\n readonly menuLink = viewChild(EclLinkDirective);\n /**\n * Element, tat is rendered if the menu item has children.\n */\n readonly menuBtn = viewChild<EclButtonComponent>('menuBtn');\n /**\n * Element, that would contain some info about the current item or it's children. First in the container.\n */\n readonly eclMegaMenuInfo = contentChild(forwardRef(() => EclMegaMenuInfoComponent));\n /**\n * Element, that holds the sub items of the current menu items.\n */\n readonly eclMegaMenuSublist = contentChild(forwardRef(() => EclMegaMenuSublistDirective));\n\n // Get all the sublists including childrens's sublist, to detect if it's only one level submenu.\n readonly eclMegaMenuSublists = contentChildren(forwardRef(() => EclMegaMenuSublistDirective), { descendants: true });\n\n readonly eclMegaMenuFeatured = contentChild(forwardRef(() => EclMegaMenuFeaturedComponent), { descendants: false });\n /**\n * Component, that consist of some custom info, text or whatever. When the menu item has no children, but still some\n * sub container is displayed.\n */\n readonly eclMegaMenuContainer = contentChild(forwardRef(() => EclMegaMenuContainerDirective));\n\n containerStyleHeight: number | null = null;\n isCurrent = false;\n isMobileBreakpoint = false;\n megaMenuMegaStyleHeight = signal<number | null>(null);\n megaMenuMegaStyleOpacity = signal<number | null>(null);\n wrapperStyleHeight: number | null = null;\n wrapperStyleTop: number | null = null;\n\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private isLarge = false;\n private eclMegaMenuDataService = inject(EclMegaMenuDataService);\n private eclHeaderMenuComunicationService = inject(EclHeaderMenuComunicationService);\n private eclMegaMenuService = inject(EclMegaMenuService);\n private readonly doc = inject(DOCUMENT);\n private readonly window = this.doc.defaultView; // Window | null\n private appShellService = inject(EuiAppShellService);\n\n constructor() {\n super();\n\n afterNextRender(() => {\n this.eclMegaMenuDataService.eclMegaMenuInfoBottomYSubject$.pipe(takeUntil(this.destroy$)).subscribe(value => {\n this.calculateSublistStyle(value);\n });\n const menuLink = this.menuLink();\n if (menuLink) {\n this.eclMegaMenuService.setExtraAttributesForLink(menuLink.el.nativeElement, this.linkExtraAttributes());\n }\n this.observeBreakpointChanges();\n this.observeResizeWindow();\n });\n }\n\n ngAfterContentInit(): void {\n this.eclMegaMenuSublist()?.megaMenuSubItemClicked.pipe(takeUntil(this.destroy$)).subscribe(() => {\n if (!this.isExpanded) {\n return;\n }\n if (!this.isMobileBreakpoint) {\n // Only hide/show the level-2 panel when switching sub-items\n const expandedSubItem = this.eclMegaMenuSublist().submenuItems().find(\n item => item.hasChildren && item.isExpanded\n );\n const megaMenuLevel2 = expandedSubItem?.megaMenuLevel2();\n if (expandedSubItem && megaMenuLevel2) {\n megaMenuLevel2.nativeElement.style.opacity = '0';\n }\n }\n setTimeout(() => this.checkDropdownHeight(false), 100);\n });\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n get hasNoInfo(): boolean {\n return !this.eclMegaMenuInfo();\n }\n\n get hasChildren(): boolean {\n return !!this.eclMegaMenuSublist() || !!this.eclMegaMenuContainer();\n }\n\n get hasSublist(): boolean {\n return !!this.eclMegaMenuSublist();\n }\n\n get hasFeatured(): boolean {\n return !!this.eclMegaMenuFeatured();\n }\n\n get hasContainer(): boolean {\n return !!this.eclMegaMenuContainer();\n }\n\n /**\n * Set the focus on the sub element - link or button.\n */\n onFocus(): void {\n const menuLink = this.menuLink();\n const menuBtn = this.menuBtn();\n if (menuLink) {\n menuLink.onFocus();\n } else if (menuBtn) {\n menuBtn.onFocus();\n }\n }\n\n /**\n * Manage styling and functionality for children and siblings, when item is clicked.\n */\n onMegaMenuItemClick(): void {\n if (this.hasChildren) {\n this.isCurrent = !this.isCurrent;\n this.isExpanded = !this.isExpanded;\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (eclMegaMenuSublist) {\n eclMegaMenuSublist.onParentMegaMenuItemClick(this.isExpanded);\n }\n if (this.isExpanded) {\n this.eclHeaderMenuComunicationService.updateExpanded(this.isExpanded);\n this.hidePanels();\n setTimeout(() => {\n this.checkDropdownHeight();\n this.calculateWrapperStyle();\n }, 100);\n } else {\n this.eclHeaderMenuComunicationService.updateExpanded(this.isExpanded);\n this.resetComputedHeights();\n }\n } else {\n this.eclHeaderMenuComunicationService.updateExpanded(this.isExpanded);\n }\n this.megaMenuItemClicked.emit();\n }\n\n /**\n * Manage styling and functionality when item is collapsed.\n */\n onMegaMenuItemCollapse(): void {\n this.isCurrent = false;\n this.isExpanded = false;\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (eclMegaMenuSublist) {\n eclMegaMenuSublist.onParentMegaMenuItemClick(this.isExpanded);\n }\n this.resetComputedHeights();\n }\n\n onKeydown(evt: Event): void {\n if (evt instanceof KeyboardEvent) {\n if ((evt as KeyboardEvent).key === KeyCode.TAB && !(evt as KeyboardEvent).shiftKey) {\n // if menu is open, navigate to children\n } else {\n this.megaMenuItemKeydown.emit(evt as KeyboardEvent);\n }\n }\n }\n\n /**\n * On resize - calculate the size of the dropdown and wrapper (if item is expanded).\n */\n private observeResizeWindow(): void {\n if (this.window) {\n fromEvent(this.window, 'resize').pipe(\n auditTime(50),\n takeUntil(this.destroy$)).subscribe(() => {\n setTimeout(() => {\n if (this.isExpanded) {\n this.checkDropdownHeight();\n this.calculateWrapperStyle();\n } else {\n // Even when not expanded, reset computed heights on resize\n // so stale desktop values don't persist into tablet/mobile layout\n this.resetComputedHeights();\n }\n });\n });\n }\n }\n\n private calculateSublistStyle(bottomInfo: number): void {\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (this.isMobileBreakpoint && eclMegaMenuSublist) {\n const availableHeight = this.window.innerHeight - bottomInfo - 16;\n eclMegaMenuSublist.styleTop = availableHeight;\n }\n }\n\n private calculateWrapperStyle(): void {\n if (!this.isMobileBreakpoint) {\n const height = this.el.nativeElement.getBoundingClientRect().height;\n this.wrapperStyleTop = height;\n }\n }\n\n private resetWrapperStyle(): void {\n if (this.isMobileBreakpoint) {\n this.wrapperStyleHeight = null;\n this.wrapperStyleTop = null;\n }\n }\n\n /**\n * Resets all computed pixel heights on the info panel, mega panel, and wrapper.\n * Called when the viewport changes breakpoint so that stale desktop values\n * (e.g. info height of 227px) don't persist into tablet/mobile layout where\n * the elements should flow naturally.\n */\n private resetComputedHeights(): void {\n const eclMegaMenuInfo = this.eclMegaMenuInfo();\n if (eclMegaMenuInfo) {\n eclMegaMenuInfo.eclMegaMenuInfoStyleHeight = null;\n eclMegaMenuInfo.eclMegaMenuInfoStyleOpacity.set(null);\n }\n this.megaMenuMegaStyleHeight.set(null);\n this.megaMenuMegaStyleOpacity.set(null);\n this.wrapperStyleHeight = null;\n this.wrapperStyleTop = null;\n this.containerStyleHeight = null;\n\n // Reset featured panel height\n const eclMegaMenuFeatured = this.eclMegaMenuFeatured();\n if (eclMegaMenuFeatured) {\n eclMegaMenuFeatured.eclMegaMenuFeaturedStyleHeight = null;\n }\n\n // Reset sublist and sub-items heights\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (eclMegaMenuSublist) {\n eclMegaMenuSublist.styleHeight.set(null);\n eclMegaMenuSublist.styleTop = null;\n eclMegaMenuSublist.isScrollable = false;\n\n // Reset level-2 heights on each subitem\n eclMegaMenuSublist.submenuItems()?.forEach(subItem => {\n subItem.level2StyleHeight = null;\n const eclMegaMenuFeatured = subItem.eclMegaMenuFeatured();\n if (eclMegaMenuFeatured) {\n eclMegaMenuFeatured.eclMegaMenuFeaturedStyleHeight = null;\n }\n });\n }\n }\n\n private hidePanels(): void {\n if (this.isMobileBreakpoint) {\n return;\n }\n if (this.eclMegaMenuMega()) {\n this.megaMenuMegaStyleOpacity.set(0);\n }\n const eclMegaMenuInfo = this.eclMegaMenuInfo();\n if (eclMegaMenuInfo) {\n eclMegaMenuInfo.eclMegaMenuInfoStyleOpacity.set(0);\n }\n }\n\n /**\n * On mobile, calculate the height of the mega panel (level 1).\n * - If the item has a featured panel: set height on the mega div (.ecl-mega-menu__mega--has-featured)\n * - If no featured, panel 1: height is set on the sublist\n * - If no featured, panel 2: height is set on the level-2 div\n */\n private calculateMobileHeight(): void {\n const eclMegaMenuMega = this.eclMegaMenuMega();\n if (!this.isMobileBreakpoint || !eclMegaMenuMega) {\n return;\n }\n const eclMegaMenuSublistValue = this.eclMegaMenuSublist();\n if (this.hasFeatured) {\n // Has featured → set height on the mega div, no scrollable on sublist\n const megaRect = eclMegaMenuMega.nativeElement.getBoundingClientRect();\n const megaTop = megaRect.top;\n this.megaMenuMegaStyleHeight.set(this.window.innerHeight - megaTop);\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (eclMegaMenuSublist) {\n eclMegaMenuSublist.isScrollable = false;\n eclMegaMenuSublist.styleHeight.set(null);\n }\n } else if (eclMegaMenuSublistValue) {\n this.megaMenuMegaStyleHeight.set(null);\n\n // Check if a sub-item with children is expanded (panel 2)\n const expandedSubItem = eclMegaMenuSublistValue.submenuItems().find(\n item => item.hasChildren && item.isExpanded\n );\n\n const megaMenuLevel2 = expandedSubItem?.megaMenuLevel2();\n if (expandedSubItem && megaMenuLevel2) {\n // No featured, panel 2 → set height on the level-2 div\n const subMegaRect = megaMenuLevel2.nativeElement.getBoundingClientRect();\n const subMegaTop = subMegaRect.top;\n expandedSubItem.level2StyleHeight = this.window.innerHeight - subMegaTop;\n // Clear sublist height and scrollable since panel 2 is now showing\n eclMegaMenuSublistValue.isScrollable = false;\n eclMegaMenuSublistValue.styleHeight.set(null);\n } else {\n // No featured, panel 1 → set height on the sublist\n const sublistRect = eclMegaMenuSublistValue.el.nativeElement.getBoundingClientRect();\n const sublistTop = sublistRect.top;\n eclMegaMenuSublistValue.styleHeight.set(this.window.innerHeight - sublistTop);\n eclMegaMenuSublistValue.isScrollable = true;\n }\n } else {\n this.megaMenuMegaStyleHeight.set(null);\n }\n }\n\n private checkDropdownHeight(hide = true): void {\n if (this.isMobileBreakpoint) {\n this.calculateMobileHeight();\n return;\n }\n\n if (hide) {\n this.hidePanels();\n }\n let infoPanelHeight = 0;\n const eclMegaMenuInfo = this.eclMegaMenuInfo();\n if (eclMegaMenuInfo) {\n eclMegaMenuInfo.eclMegaMenuInfoStyleHeight = null;\n }\n\n const heights = [];\n let height = 0;\n let itemsHeight = 0;\n let subItemsHeight = 0;\n let featuredHeight = 0;\n let featuredHeight2 = 0;\n\n if (this.hasContainer) {\n const viewportHeight = this.window.innerHeight;\n const mainTop = this.mainPanel().nativeElement.getBoundingClientRect().top;\n this.containerStyleHeight = viewportHeight - mainTop;\n } else {\n if (eclMegaMenuInfo) {\n infoPanelHeight = eclMegaMenuInfo.getInfoPanelScrollHeight() + 16;\n if (this.isLarge) {\n heights.push(infoPanelHeight);\n } else {\n subItemsHeight = infoPanelHeight;\n featuredHeight = infoPanelHeight;\n }\n eclMegaMenuInfo.eclMegaMenuInfoStyleOpacity.set(1);\n }\n\n const eclMegaMenuMega = this.eclMegaMenuMega();\n if (eclMegaMenuMega) {\n const eclMegaMenuSublist = this.eclMegaMenuSublist();\n if (eclMegaMenuSublist && eclMegaMenuSublist.submenuItems().length > 0) {\n if (this.isOneLevelOnly()) {\n itemsHeight = eclMegaMenuSublist.el.nativeElement.offsetHeight;\n } else {\n eclMegaMenuSublist.submenuItems().forEach((item) => {\n itemsHeight += item.getMegaMenuSubItemHeight();\n });\n if (eclMegaMenuSublist.spacer()) {\n itemsHeight += 25;\n }\n }\n heights.push(itemsHeight);\n }\n const expandedSubItem = eclMegaMenuSublist.submenuItems().find(item => item.hasChildren && item.isExpanded);\n if (expandedSubItem !== undefined) {\n const eclMegaMenuFeatured = expandedSubItem.eclMegaMenuFeatured();\n expandedSubItem.submenu().submenuItems().forEach(item => {\n subItemsHeight += item.getMegaMenuSubItemHeight();\n });\n heights.push(subItemsHeight);\n if (eclMegaMenuFeatured) {\n featuredHeight += eclMegaMenuFeatured.getEclMegaMenuFeaturedHeight();\n featuredHeight += 5;\n heights.push(featuredHeight);\n }\n }\n\n const eclMegaMenuFeaturedValue = this.eclMegaMenuFeatured();\n if (eclMegaMenuFeaturedValue) {\n featuredHeight2 = eclMegaMenuFeaturedValue.getEclMegaMenuFeaturedHeight();\n heights.push(featuredHeight2);\n }\n const maxHeight = Math.max(...heights);\n const containerBounding = this.el.nativeElement.getBoundingClientRect();\n const containerBottom = containerBounding.bottom;\n // By requirements, limit the height to the 70% of the available space.\n const availableHeight = (this.window.innerHeight - containerBottom) * 0.9;\n if (maxHeight > availableHeight) {\n height = availableHeight;\n } else {\n height = maxHeight;\n }\n\n this.wrapperStyleHeight = eclMegaMenuMega && eclMegaMenuInfo && !this.isLarge ?\n height + infoPanelHeight : height;\n if (this.wrapperStyleHeight > availableHeight) this.wrapperStyleHeight = availableHeight;\n if (eclMegaMenuMega && this.isLarge) {\n this.megaMenuMegaStyleHeight.set(height);\n } else if (eclMegaMenuMega && eclMegaMenuInfo) {\n this.megaMenuMegaStyleHeight.set(this.wrapperStyleHeight - infoPanelHeight);\n }\n if (eclMegaMenuInfo && this.isLarge) {\n eclMegaMenuInfo.eclMegaMenuInfoStyleHeight = height;\n }\n\n if (expandedSubItem !== undefined) {\n if (this.isLarge) {\n expandedSubItem.level2StyleHeight = height;\n } else {\n expandedSubItem.level2StyleHeight = height - infoPanelHeight;\n }\n\n const megaMenuLevel2 = expandedSubItem.megaMenuLevel2();\n if (megaMenuLevel2) {\n megaMenuLevel2.nativeElement.style.opacity = '1';\n }\n\n const expandedSubItemFeatured = expandedSubItem.eclMegaMenuFeatured();\n if (expandedSubItemFeatured) {\n if (this.isLarge) {\n expandedSubItemFeatured.eclMegaMenuFeaturedStyleHeight = height;\n } else {\n expandedSubItemFeatured.eclMegaMenuFeaturedStyleHeight = height - infoPanelHeight;\n }\n }\n }\n if (eclMegaMenuFeaturedValue) {\n if (this.isLarge) {\n eclMegaMenuFeaturedValue.eclMegaMenuFeaturedStyleHeight = height;\n } else {\n eclMegaMenuFeaturedValue.eclMegaMenuFeaturedStyleHeight = this.wrapperStyleHeight - infoPanelHeight;\n }\n }\n this.megaMenuMegaStyleOpacity.set(1);\n }\n }\n }\n\n private observeBreakpointChanges(): void {\n this.appShellService.state$\n .pipe(\n map((state) => {\n const w = state.windowWidth ?? 0;\n const bp = state.breakpoints;\n return {\n // ECL uses breakpointDesktop = 1140px. Everything below that\n // (xs/sm/md/lg) must use mobile behavior. isLtLargeTablet covers this range.\n isMobile: !!(bp?.isLtLargeTablet),\n isLarge: w >= 1368,\n };\n }),\n distinctUntilChanged(\n (a, b) => a.isMobile === b.isMobile && a.isLarge === b.isLarge\n ),\n takeUntil(this.destroy$),\n )\n .subscribe(({ isMobile, isLarge }) => {\n const wasMobile = this.isMobileBreakpoint;\n const wasLarge = this.isLarge;\n this.isMobileBreakpoint = isMobile;\n this.isLarge = isLarge;\n this.resetWrapperStyle();\n\n // When breakpoint changes, reset all computed heights so they don't\n // carry over stale pixel values from the previous layout mode.\n if (wasMobile !== isMobile || wasLarge !== isLarge) {\n this.resetComputedHeights();\n\n // If transitioning between mobile/desktop while expanded,\n // recalculate with new layout dimensions\n if (this.isExpanded) {\n setTimeout(() => {\n this.checkDropdownHeight();\n this.calculateWrapperStyle();\n }, 100);\n }\n }\n });\n }\n}\n",
62580
62023
  "assetsDirs": [],
62581
62024
  "styleUrlsData": "",
62582
62025
  "stylesData": "",
62583
62026
  "jsdoctags": [
62584
62027
  {
62585
- "pos": 1450,
62586
- "end": 1564,
62028
+ "pos": 1433,
62029
+ "end": 1547,
62587
62030
  "kind": 321,
62588
62031
  "id": 0,
62589
62032
  "flags": 16777216,
@@ -62598,7 +62041,7 @@
62598
62041
  "deprecated": false,
62599
62042
  "deprecationMessage": "",
62600
62043
  "args": [],
62601
- "line": 139,
62044
+ "line": 149,
62602
62045
  "rawdescription": "\n"
62603
62046
  },
62604
62047
  "extends": [
@@ -62615,18 +62058,29 @@
62615
62058
  "name": "cssClasses",
62616
62059
  "type": "string",
62617
62060
  "returnType": "string",
62618
- "line": 51,
62061
+ "line": 53,
62619
62062
  "rawdescription": "\n\nReturns current menu item classes, depending on item's state (it's properties' values).\n",
62620
62063
  "description": "<p>Returns current menu item classes, depending on item&#39;s state (it&#39;s properties&#39; values).</p>\n"
62621
62064
  }
62622
62065
  },
62066
+ "hasPopup": {
62067
+ "name": "hasPopup",
62068
+ "getSignature": {
62069
+ "name": "hasPopup",
62070
+ "type": "unknown",
62071
+ "returnType": "unknown | null",
62072
+ "line": 74,
62073
+ "rawdescription": "\n\nReflects whether this item has a submenu/container. Evaluated lazily during\nchange detection (not at construction) so the content-query signals are\nresolved before it is read.\n",
62074
+ "description": "<p>Reflects whether this item has a submenu/container. Evaluated lazily during\nchange detection (not at construction) so the content-query signals are\nresolved before it is read.</p>\n"
62075
+ }
62076
+ },
62623
62077
  "hasNoInfo": {
62624
62078
  "name": "hasNoInfo",
62625
62079
  "getSignature": {
62626
62080
  "name": "hasNoInfo",
62627
62081
  "type": "boolean",
62628
62082
  "returnType": "boolean",
62629
- "line": 181,
62083
+ "line": 191,
62630
62084
  "rawdescription": "\n",
62631
62085
  "description": ""
62632
62086
  }
@@ -62637,7 +62091,7 @@
62637
62091
  "name": "hasChildren",
62638
62092
  "type": "boolean",
62639
62093
  "returnType": "boolean",
62640
- "line": 185,
62094
+ "line": 195,
62641
62095
  "rawdescription": "\n",
62642
62096
  "description": ""
62643
62097
  }
@@ -62648,7 +62102,7 @@
62648
62102
  "name": "hasSublist",
62649
62103
  "type": "boolean",
62650
62104
  "returnType": "boolean",
62651
- "line": 189,
62105
+ "line": 199,
62652
62106
  "rawdescription": "\n",
62653
62107
  "description": ""
62654
62108
  }
@@ -62659,7 +62113,7 @@
62659
62113
  "name": "hasFeatured",
62660
62114
  "type": "boolean",
62661
62115
  "returnType": "boolean",
62662
- "line": 193,
62116
+ "line": 203,
62663
62117
  "rawdescription": "\n",
62664
62118
  "description": ""
62665
62119
  }
@@ -62670,7 +62124,7 @@
62670
62124
  "name": "hasContainer",
62671
62125
  "type": "boolean",
62672
62126
  "returnType": "boolean",
62673
- "line": 197,
62127
+ "line": 207,
62674
62128
  "rawdescription": "\n",
62675
62129
  "description": ""
62676
62130
  }
@@ -62717,10 +62171,11 @@
62717
62171
  },
62718
62172
  {
62719
62173
  "name": "EclMegaMenuSubitemComponent",
62720
- "id": "component-EclMegaMenuSubitemComponent-08488f72c8cb6e97ce7de77625b9a572632d348721012d4f2fb1749bfa5b1bc8f74ffa3d044880291e39358f4560843dfa9269de7376207a3a2572ced00c5510",
62174
+ "id": "component-EclMegaMenuSubitemComponent-e7d3f7421346151c385486f2f0113ce4498ea66e5b043956ac5e5410948d7b43f5512184fd3d33e2534207f9d0cc51fad37f88ffc6a03e266058da9e4a86f430",
62721
62175
  "file": "packages/ecl/components/ecl-mega-menu/ecl-mega-menu-subitem/ecl-mega-menu-subitem.component.ts",
62722
62176
  "encapsulation": [],
62723
62177
  "entryComponents": [],
62178
+ "host": {},
62724
62179
  "inputs": [],
62725
62180
  "outputs": [],
62726
62181
  "providers": [],
@@ -62742,7 +62197,7 @@
62742
62197
  "deprecationMessage": "",
62743
62198
  "rawdescription": "\n",
62744
62199
  "description": "",
62745
- "line": 59,
62200
+ "line": 63,
62746
62201
  "type": "string",
62747
62202
  "decorators": []
62748
62203
  },
@@ -62754,7 +62209,7 @@
62754
62209
  "deprecationMessage": "",
62755
62210
  "rawdescription": "\n",
62756
62211
  "description": "",
62757
- "line": 46,
62212
+ "line": 50,
62758
62213
  "type": "string",
62759
62214
  "decorators": []
62760
62215
  },
@@ -62768,7 +62223,7 @@
62768
62223
  "indexKey": "",
62769
62224
  "optional": false,
62770
62225
  "description": "<p>Sets id for the button element.</p>\n",
62771
- "line": 45,
62226
+ "line": 49,
62772
62227
  "rawdescription": "\n\nSets id for the button element.\n",
62773
62228
  "modifierKind": [
62774
62229
  148
@@ -62785,7 +62240,7 @@
62785
62240
  "indexKey": "",
62786
62241
  "optional": false,
62787
62242
  "description": "<p>If the link is external, this will be the title of the external icon.</p>\n",
62788
- "line": 54,
62243
+ "line": 58,
62789
62244
  "rawdescription": "\n\nIf the link is external, this will be the title of the external icon.\n",
62790
62245
  "modifierKind": [
62791
62246
  148
@@ -62802,7 +62257,7 @@
62802
62257
  "indexKey": "",
62803
62258
  "optional": false,
62804
62259
  "description": "<p>If the link redirects to external page. Adds an &#39;external&#39; icon.</p>\n",
62805
- "line": 50,
62260
+ "line": 54,
62806
62261
  "rawdescription": "\n\nIf the link redirects to external page. Adds an 'external' icon.\n",
62807
62262
  "modifierKind": [
62808
62263
  148
@@ -62819,7 +62274,7 @@
62819
62274
  "indexKey": "",
62820
62275
  "optional": false,
62821
62276
  "description": "<p>Used for the &#39;View all&#39; link.</p>\n",
62822
- "line": 64,
62277
+ "line": 68,
62823
62278
  "rawdescription": "\n\nUsed for the 'View all' link.\n",
62824
62279
  "modifierKind": [
62825
62280
  148
@@ -62836,7 +62291,7 @@
62836
62291
  "indexKey": "",
62837
62292
  "optional": false,
62838
62293
  "description": "<p>Adds custom attributes to an anchor element.</p>\n",
62839
- "line": 68,
62294
+ "line": 72,
62840
62295
  "rawdescription": "\n\nAdds custom attributes to an anchor element.\n",
62841
62296
  "modifierKind": [
62842
62297
  148
@@ -62853,7 +62308,7 @@
62853
62308
  "indexKey": "",
62854
62309
  "optional": false,
62855
62310
  "description": "",
62856
- "line": 57,
62311
+ "line": 61,
62857
62312
  "rawdescription": "\n",
62858
62313
  "modifierKind": [
62859
62314
  148
@@ -62870,7 +62325,7 @@
62870
62325
  "indexKey": "",
62871
62326
  "optional": false,
62872
62327
  "description": "",
62873
- "line": 58,
62328
+ "line": 62,
62874
62329
  "rawdescription": "\n",
62875
62330
  "modifierKind": [
62876
62331
  148
@@ -62887,7 +62342,7 @@
62887
62342
  "indexKey": "",
62888
62343
  "optional": false,
62889
62344
  "description": "",
62890
- "line": 56,
62345
+ "line": 60,
62891
62346
  "rawdescription": "\n",
62892
62347
  "modifierKind": [
62893
62348
  148
@@ -62904,7 +62359,7 @@
62904
62359
  "indexKey": "",
62905
62360
  "optional": false,
62906
62361
  "description": "",
62907
- "line": 60,
62362
+ "line": 64,
62908
62363
  "rawdescription": "\n",
62909
62364
  "modifierKind": [
62910
62365
  148
@@ -62962,7 +62417,7 @@
62962
62417
  "defaultValue": "new EventEmitter()",
62963
62418
  "deprecated": false,
62964
62419
  "deprecationMessage": "",
62965
- "line": 92,
62420
+ "line": 96,
62966
62421
  "type": "EventEmitter"
62967
62422
  },
62968
62423
  {
@@ -62971,7 +62426,7 @@
62971
62426
  "defaultValue": "new EventEmitter()",
62972
62427
  "deprecated": false,
62973
62428
  "deprecationMessage": "",
62974
- "line": 93,
62429
+ "line": 97,
62975
62430
  "type": "EventEmitter"
62976
62431
  }
62977
62432
  ],
@@ -62986,16 +62441,9 @@
62986
62441
  "indexKey": "",
62987
62442
  "optional": false,
62988
62443
  "description": "",
62989
- "line": 102,
62444
+ "line": 106,
62990
62445
  "rawdescription": "\n",
62991
- "decorators": [
62992
- {
62993
- "name": "HostBinding",
62994
- "stringifiedArguments": "'style.display'"
62995
- }
62996
- ],
62997
62446
  "modifierKind": [
62998
- 171,
62999
62447
  124
63000
62448
  ]
63001
62449
  },
@@ -63009,7 +62457,7 @@
63009
62457
  "indexKey": "",
63010
62458
  "optional": false,
63011
62459
  "description": "<p>The component for the featured items.</p>\n",
63012
- "line": 90,
62460
+ "line": 94,
63013
62461
  "rawdescription": "\n\nThe component for the featured items.\n",
63014
62462
  "modifierKind": [
63015
62463
  148
@@ -63025,7 +62473,7 @@
63025
62473
  "indexKey": "",
63026
62474
  "optional": false,
63027
62475
  "description": "",
63028
- "line": 95,
62476
+ "line": 99,
63029
62477
  "rawdescription": "\n"
63030
62478
  },
63031
62479
  {
@@ -63038,7 +62486,7 @@
63038
62486
  "indexKey": "",
63039
62487
  "optional": false,
63040
62488
  "description": "",
63041
- "line": 28,
62489
+ "line": 32,
63042
62490
  "rawdescription": "\n"
63043
62491
  },
63044
62492
  {
@@ -63051,7 +62499,7 @@
63051
62499
  "indexKey": "",
63052
62500
  "optional": false,
63053
62501
  "description": "",
63054
- "line": 96,
62502
+ "line": 100,
63055
62503
  "rawdescription": "\n"
63056
62504
  },
63057
62505
  {
@@ -63064,7 +62512,7 @@
63064
62512
  "indexKey": "",
63065
62513
  "optional": false,
63066
62514
  "description": "<p>Used to set the height of the second level subitems container.</p>\n",
63067
- "line": 100,
62515
+ "line": 104,
63068
62516
  "rawdescription": "\n\nUsed to set the height of the second level subitems container.\n"
63069
62517
  },
63070
62518
  {
@@ -63077,7 +62525,7 @@
63077
62525
  "indexKey": "",
63078
62526
  "optional": false,
63079
62527
  "description": "<p>Wrapper div element of the second level sub-items.</p>\n",
63080
- "line": 73,
62528
+ "line": 77,
63081
62529
  "rawdescription": "\n\nWrapper div element of the second level sub-items.\n",
63082
62530
  "modifierKind": [
63083
62531
  148
@@ -63093,7 +62541,7 @@
63093
62541
  "indexKey": "",
63094
62542
  "optional": false,
63095
62543
  "description": "<p>The directive of the submenu lits.</p>\n",
63096
- "line": 86,
62544
+ "line": 90,
63097
62545
  "rawdescription": "\n\nThe directive of the submenu lits.\n",
63098
62546
  "modifierKind": [
63099
62547
  148
@@ -63109,7 +62557,7 @@
63109
62557
  "indexKey": "",
63110
62558
  "optional": false,
63111
62559
  "description": "<p>The button element, if it exists. Item can have either link or button.</p>\n",
63112
- "line": 81,
62560
+ "line": 85,
63113
62561
  "rawdescription": "\n\nThe button element, if it exists. Item can have either link or button.\n",
63114
62562
  "modifierKind": [
63115
62563
  148
@@ -63125,7 +62573,7 @@
63125
62573
  "indexKey": "",
63126
62574
  "optional": false,
63127
62575
  "description": "<p>The link element, if it exists. Item can have either link or button.</p>\n",
63128
- "line": 77,
62576
+ "line": 81,
63129
62577
  "rawdescription": "\n\nThe link element, if it exists. Item can have either link or button.\n",
63130
62578
  "modifierKind": [
63131
62579
  148
@@ -63140,7 +62588,7 @@
63140
62588
  "optional": false,
63141
62589
  "returnType": "number",
63142
62590
  "typeParameters": [],
63143
- "line": 155,
62591
+ "line": 159,
63144
62592
  "deprecated": false,
63145
62593
  "deprecationMessage": "",
63146
62594
  "rawdescription": "\n",
@@ -63153,7 +62601,7 @@
63153
62601
  "optional": false,
63154
62602
  "returnType": "void",
63155
62603
  "typeParameters": [],
63156
- "line": 162,
62604
+ "line": 166,
63157
62605
  "deprecated": false,
63158
62606
  "deprecationMessage": "",
63159
62607
  "rawdescription": "\n\nShow or hide the subitems.\n",
@@ -63166,7 +62614,7 @@
63166
62614
  "optional": false,
63167
62615
  "returnType": "void",
63168
62616
  "typeParameters": [],
63169
- "line": 137,
62617
+ "line": 141,
63170
62618
  "deprecated": false,
63171
62619
  "deprecationMessage": "",
63172
62620
  "rawdescription": "\n\nSets focus on either link or button element.\n",
@@ -63179,7 +62627,7 @@
63179
62627
  "optional": false,
63180
62628
  "returnType": "void",
63181
62629
  "typeParameters": [],
63182
- "line": 147,
62630
+ "line": 151,
63183
62631
  "deprecated": false,
63184
62632
  "deprecationMessage": "",
63185
62633
  "rawdescription": "\n",
@@ -63201,7 +62649,7 @@
63201
62649
  "optional": false,
63202
62650
  "returnType": "void",
63203
62651
  "typeParameters": [],
63204
- "line": 178,
62652
+ "line": 182,
63205
62653
  "deprecated": false,
63206
62654
  "deprecationMessage": "",
63207
62655
  "rawdescription": "\n",
@@ -63227,7 +62675,7 @@
63227
62675
  "optional": false,
63228
62676
  "returnType": "void",
63229
62677
  "typeParameters": [],
63230
- "line": 173,
62678
+ "line": 177,
63231
62679
  "deprecated": false,
63232
62680
  "deprecationMessage": "",
63233
62681
  "rawdescription": "\n\nIf link is clicked -> emit event and close all opened menus and submenus.\n",
@@ -63240,7 +62688,7 @@
63240
62688
  "optional": false,
63241
62689
  "returnType": "void",
63242
62690
  "typeParameters": [],
63243
- "line": 151,
62691
+ "line": 155,
63244
62692
  "deprecated": false,
63245
62693
  "deprecationMessage": "",
63246
62694
  "rawdescription": "\n",
@@ -63253,7 +62701,7 @@
63253
62701
  "optional": false,
63254
62702
  "returnType": "void",
63255
62703
  "typeParameters": [],
63256
- "line": 190,
62704
+ "line": 194,
63257
62705
  "deprecated": false,
63258
62706
  "deprecationMessage": "",
63259
62707
  "rawdescription": "\n",
@@ -63266,7 +62714,7 @@
63266
62714
  "optional": false,
63267
62715
  "returnType": "void",
63268
62716
  "typeParameters": [],
63269
- "line": 199,
62717
+ "line": 203,
63270
62718
  "deprecated": false,
63271
62719
  "deprecationMessage": "",
63272
62720
  "rawdescription": "\n",
@@ -63314,33 +62762,7 @@
63314
62762
  "coverageIgnore": false,
63315
62763
  "deprecated": false,
63316
62764
  "deprecationMessage": "",
63317
- "hostBindings": [
63318
- {
63319
- "coverageIgnore": false,
63320
- "name": "class",
63321
- "actualName": "cssClasses",
63322
- "deprecated": false,
63323
- "deprecationMessage": "",
63324
- "rawdescription": "\n",
63325
- "description": "",
63326
- "line": 30,
63327
- "type": "string",
63328
- "decorators": []
63329
- },
63330
- {
63331
- "coverageIgnore": false,
63332
- "name": "style.display",
63333
- "actualName": "display",
63334
- "defaultValue": "''",
63335
- "deprecated": false,
63336
- "deprecationMessage": "",
63337
- "rawdescription": "\n",
63338
- "description": "",
63339
- "line": 102,
63340
- "type": "string",
63341
- "decorators": []
63342
- }
63343
- ],
62765
+ "hostBindings": [],
63344
62766
  "hostListeners": [],
63345
62767
  "standalone": false,
63346
62768
  "imports": [
@@ -63366,14 +62788,14 @@
63366
62788
  "description": "<p>This component represents a sub-item in the mega-menu component. Applies styling and functionality.</p>\n",
63367
62789
  "rawdescription": "\n\nThis component represents a sub-item in the mega-menu component. Applies styling and functionality.\n",
63368
62790
  "type": "component",
63369
- "sourceCode": "import { NgTemplateOutlet } from '@angular/common';\nimport { afterNextRender, booleanAttribute, Component, DOCUMENT, ElementRef, EventEmitter, forwardRef, HostBinding, inject, Input, Output, input, viewChild, contentChild } from '@angular/core';\nimport { Params, QueryParamsHandling, RouterLink, RouterLinkWithHref } from '@angular/router';\nimport { EuiAppShellService } from '@eui/core';\nimport { EclButtonComponent, EUI_ECL_BUTTON } from '@eui/ecl/components/ecl-button';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EclLinkDirective, EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { distinctUntilChanged, map, Subject, takeUntil } from 'rxjs';\nimport { EclMegaMenuSublistDirective } from '../directives/ecl-mega-menu-list.directive';\nimport { EclMegaMenuFeaturedComponent } from '../ecl-mega-menu-featured/ecl-mega-menu-featured.component';\nimport { EclMegaMenuItem } from '../models/ecl-mega-menu-item.model';\nimport { EclMegaMenuDataService } from '../services/ecl-mega-menu-data.service';\nimport { EclMegaMenuService } from '../services/ecl-mega-menu.service';\n\n/**\n * This component represents a sub-item in the mega-menu component. Applies styling and functionality.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'li[eclMegaMenuSubitem]',\n templateUrl: './ecl-mega-menu-subitem.component.html',\n imports: [NgTemplateOutlet, RouterLink, RouterLinkWithHref, ...EUI_ECL_BUTTON, ...EUI_ECL_ICON, ...EUI_ECL_LINK],\n})\n\nexport class EclMegaMenuSubitemComponent extends ECLBaseDirective implements EclMegaMenuItem {\n\n isExpanded = false;\n @HostBinding('class')\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-mega-menu__subitem'),\n this.isCurrent ? 'ecl-mega-menu__subitem--current' : '',\n this.isExpanded ? 'ecl-mega-menu__subitem--expanded' : '',\n this.isSeeAll() ? 'ecl-mega-menu__see-all' : '',\n this.isParentLink ? 'ecl-mega-menu__parent-link' : '',\n ]\n .join(' ')\n .trim();\n }\n\n /**\n * Sets id for the button element.\n */\n readonly buttonId = input<string>(undefined);\n @Input() label = '';\n /**\n * If the link redirects to external page. Adds an 'external' icon.\n */\n readonly isExternal = input(false, { transform: booleanAttribute });\n /**\n * If the link is external, this will be the title of the external icon.\n */\n readonly externalIconTitle = input<string>(undefined);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly routerLink = input<string | any[]>(null);\n readonly queryParams = input<Params | null>(null);\n readonly queryParamsHandling = input<QueryParamsHandling>(null);\n @Input() href = '';\n readonly target = input('');\n /**\n * Used for the 'View all' link.\n */\n readonly isSeeAll = input(false, { transform: booleanAttribute });\n /**\n * Adds custom attributes to an anchor element.\n */\n readonly linkExtraAttributes = input<Record<string, string>>(undefined);\n\n /**\n * Wrapper div element of the second level sub-items.\n */\n readonly megaMenuLevel2 = viewChild<ElementRef>('megaMenuLevel2');\n /**\n * The link element, if it exists. Item can have either link or button.\n */\n readonly subMenuItemLink = viewChild(EclLinkDirective);\n /**\n * The button element, if it exists. Item can have either link or button.\n */\n readonly subMenuItemBtn = viewChild<EclButtonComponent>('subMenuItemBtn');\n\n /**\n * The directive of the submenu lits.\n */\n readonly submenu = contentChild(forwardRef(() => EclMegaMenuSublistDirective));\n /**\n * The component for the featured items.\n */\n readonly eclMegaMenuFeatured = contentChild(forwardRef(() => EclMegaMenuFeaturedComponent));\n\n @Output() megaMenuSubItemClicked = new EventEmitter();\n @Output() megaMenuSubItemKeydown = new EventEmitter();\n\n isCurrent = false;\n isMobileBreakpoint = false;\n /**\n * Used to set the height of the second level subitems container.\n */\n level2StyleHeight: number | null = null;\n\n @HostBinding('style.display') protected display = '';\n\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private isParentLink = false;\n private eclMegaMenuDataService = inject(EclMegaMenuDataService);\n private el = inject(ElementRef);\n private eclMegaMenuService = inject(EclMegaMenuService);\n private readonly doc = inject(DOCUMENT);\n private readonly window = this.doc.defaultView; // Window | null\n private appShell = inject(EuiAppShellService);\n\n constructor() {\n super();\n const eclMegaMenuService = this.eclMegaMenuService;\n\n afterNextRender(() => {\n const subMenuItemLink = this.subMenuItemLink();\n if (subMenuItemLink) {\n eclMegaMenuService.setExtraAttributesForLink(subMenuItemLink.el.nativeElement, this.linkExtraAttributes());\n }\n this.observeBreakpointChanges();\n });\n }\n\n get hasChildren(): boolean {\n return !!this.submenu();\n }\n\n get hasFeatured(): boolean {\n return !!this.eclMegaMenuFeatured();\n }\n\n /**\n * Sets focus on either link or button element.\n */\n onFocus(): void{\n const subMenuItemLink = this.subMenuItemLink();\n const subMenuItemBtn = this.subMenuItemBtn();\n if (subMenuItemLink) {\n subMenuItemLink.onFocus();\n } else if (subMenuItemBtn) {\n subMenuItemBtn.onFocus();\n }\n }\n\n onHide(): void {\n this.display = 'none';\n }\n\n onShow(): void {\n this.display = '';\n }\n\n getMegaMenuSubItemHeight(): number {\n return this.el.nativeElement.getBoundingClientRect().height;\n }\n\n /**\n * Show or hide the subitems.\n */\n onButtonClick(): void {\n this.isCurrent = !this.isCurrent;\n this.isExpanded = !this.isExpanded;\n this.eclMegaMenuDataService.eclSubItemToggle(this.isExpanded);\n this.eclMegaMenuDataService.eclSubItemClick(this);\n this.megaMenuSubItemClicked.emit();\n }\n\n /**\n * If link is clicked -> emit event and close all opened menus and submenus.\n */\n onLinkClick(): void {\n this.eclMegaMenuDataService.eclSubItemClick(this);\n this.megaMenuSubItemClicked.emit();\n }\n\n onKeydown(evt: Event): void {\n if (evt instanceof KeyboardEvent) {\n if (!((evt as KeyboardEvent).key === KeyCode.TAB)) {\n if ((evt as KeyboardEvent).key === KeyCode.ESCAPE) {\n this.eclMegaMenuDataService.eclSubItemEscapeEvent(true);\n } else {\n this.megaMenuSubItemKeydown.emit(evt as KeyboardEvent);\n }\n }\n }\n }\n\n onSubMenuItemCollapse(): void {\n if (this.isExpanded) {\n this.eclMegaMenuDataService.eclSubItemToggle(false);\n this.isCurrent = false;\n this.isExpanded = false;\n this.isParentLink = false;\n }\n }\n\n onSubMenuItemExpand(): void {\n this.isCurrent = true;\n this.isExpanded = true;\n this.eclMegaMenuDataService.eclSubItemToggle(this.isExpanded);\n }\n\n private observeBreakpointChanges(): void {\n this.appShell.getState<any>('breakpoints')\n .pipe(\n // ECL uses breakpointDesktop = 1140px. isLtLargeTablet covers xs/sm/md/lg (< 1140px).\n map(bp => !!(bp?.isLtLargeTablet)),\n distinctUntilChanged(),\n takeUntil(this.destroy$),\n )\n .subscribe((isMobile) => {\n const wasMobile = this.isMobileBreakpoint;\n this.isMobileBreakpoint = isMobile;\n\n // Reset computed heights when switching breakpoints\n if (wasMobile !== isMobile) {\n this.level2StyleHeight = null;\n const eclMegaMenuFeatured = this.eclMegaMenuFeatured();\n if (eclMegaMenuFeatured) {\n eclMegaMenuFeatured.eclMegaMenuFeaturedStyleHeight = null;\n }\n }\n });\n }\n}\n",
62791
+ "sourceCode": "import { NgTemplateOutlet } from '@angular/common';\nimport { afterNextRender, booleanAttribute, Component, DOCUMENT, ElementRef, EventEmitter, forwardRef, inject, Input, Output, input, viewChild, contentChild } from '@angular/core';\nimport { Params, QueryParamsHandling, RouterLink, RouterLinkWithHref } from '@angular/router';\nimport { EuiAppShellService } from '@eui/core';\nimport { EclButtonComponent, EUI_ECL_BUTTON } from '@eui/ecl/components/ecl-button';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EclLinkDirective, EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { distinctUntilChanged, map, Subject, takeUntil } from 'rxjs';\nimport { EclMegaMenuSublistDirective } from '../directives/ecl-mega-menu-list.directive';\nimport { EclMegaMenuFeaturedComponent } from '../ecl-mega-menu-featured/ecl-mega-menu-featured.component';\nimport { EclMegaMenuItem } from '../models/ecl-mega-menu-item.model';\nimport { EclMegaMenuDataService } from '../services/ecl-mega-menu-data.service';\nimport { EclMegaMenuService } from '../services/ecl-mega-menu.service';\n\n/**\n * This component represents a sub-item in the mega-menu component. Applies styling and functionality.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'li[eclMegaMenuSubitem]',\n templateUrl: './ecl-mega-menu-subitem.component.html',\n imports: [NgTemplateOutlet, RouterLink, RouterLinkWithHref, ...EUI_ECL_BUTTON, ...EUI_ECL_ICON, ...EUI_ECL_LINK],\n host: {\n '[class]': 'cssClasses',\n '[style.display]': 'display',\n },\n})\n\nexport class EclMegaMenuSubitemComponent extends ECLBaseDirective implements EclMegaMenuItem {\n\n isExpanded = false;\n\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-mega-menu__subitem'),\n this.isCurrent ? 'ecl-mega-menu__subitem--current' : '',\n this.isExpanded ? 'ecl-mega-menu__subitem--expanded' : '',\n this.isSeeAll() ? 'ecl-mega-menu__see-all' : '',\n this.isParentLink ? 'ecl-mega-menu__parent-link' : '',\n ]\n .join(' ')\n .trim();\n }\n\n /**\n * Sets id for the button element.\n */\n readonly buttonId = input<string>(undefined);\n @Input() label = '';\n /**\n * If the link redirects to external page. Adds an 'external' icon.\n */\n readonly isExternal = input(false, { transform: booleanAttribute });\n /**\n * If the link is external, this will be the title of the external icon.\n */\n readonly externalIconTitle = input<string>(undefined);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly routerLink = input<string | any[]>(null);\n readonly queryParams = input<Params | null>(null);\n readonly queryParamsHandling = input<QueryParamsHandling>(null);\n @Input() href = '';\n readonly target = input('');\n /**\n * Used for the 'View all' link.\n */\n readonly isSeeAll = input(false, { transform: booleanAttribute });\n /**\n * Adds custom attributes to an anchor element.\n */\n readonly linkExtraAttributes = input<Record<string, string>>(undefined);\n\n /**\n * Wrapper div element of the second level sub-items.\n */\n readonly megaMenuLevel2 = viewChild<ElementRef>('megaMenuLevel2');\n /**\n * The link element, if it exists. Item can have either link or button.\n */\n readonly subMenuItemLink = viewChild(EclLinkDirective);\n /**\n * The button element, if it exists. Item can have either link or button.\n */\n readonly subMenuItemBtn = viewChild<EclButtonComponent>('subMenuItemBtn');\n\n /**\n * The directive of the submenu lits.\n */\n readonly submenu = contentChild(forwardRef(() => EclMegaMenuSublistDirective));\n /**\n * The component for the featured items.\n */\n readonly eclMegaMenuFeatured = contentChild(forwardRef(() => EclMegaMenuFeaturedComponent));\n\n @Output() megaMenuSubItemClicked = new EventEmitter();\n @Output() megaMenuSubItemKeydown = new EventEmitter();\n\n isCurrent = false;\n isMobileBreakpoint = false;\n /**\n * Used to set the height of the second level subitems container.\n */\n level2StyleHeight: number | null = null;\n\n protected display = '';\n\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private isParentLink = false;\n private eclMegaMenuDataService = inject(EclMegaMenuDataService);\n private el = inject(ElementRef);\n private eclMegaMenuService = inject(EclMegaMenuService);\n private readonly doc = inject(DOCUMENT);\n private readonly window = this.doc.defaultView; // Window | null\n private appShell = inject(EuiAppShellService);\n\n constructor() {\n super();\n const eclMegaMenuService = this.eclMegaMenuService;\n\n afterNextRender(() => {\n const subMenuItemLink = this.subMenuItemLink();\n if (subMenuItemLink) {\n eclMegaMenuService.setExtraAttributesForLink(subMenuItemLink.el.nativeElement, this.linkExtraAttributes());\n }\n this.observeBreakpointChanges();\n });\n }\n\n get hasChildren(): boolean {\n return !!this.submenu();\n }\n\n get hasFeatured(): boolean {\n return !!this.eclMegaMenuFeatured();\n }\n\n /**\n * Sets focus on either link or button element.\n */\n onFocus(): void{\n const subMenuItemLink = this.subMenuItemLink();\n const subMenuItemBtn = this.subMenuItemBtn();\n if (subMenuItemLink) {\n subMenuItemLink.onFocus();\n } else if (subMenuItemBtn) {\n subMenuItemBtn.onFocus();\n }\n }\n\n onHide(): void {\n this.display = 'none';\n }\n\n onShow(): void {\n this.display = '';\n }\n\n getMegaMenuSubItemHeight(): number {\n return this.el.nativeElement.getBoundingClientRect().height;\n }\n\n /**\n * Show or hide the subitems.\n */\n onButtonClick(): void {\n this.isCurrent = !this.isCurrent;\n this.isExpanded = !this.isExpanded;\n this.eclMegaMenuDataService.eclSubItemToggle(this.isExpanded);\n this.eclMegaMenuDataService.eclSubItemClick(this);\n this.megaMenuSubItemClicked.emit();\n }\n\n /**\n * If link is clicked -> emit event and close all opened menus and submenus.\n */\n onLinkClick(): void {\n this.eclMegaMenuDataService.eclSubItemClick(this);\n this.megaMenuSubItemClicked.emit();\n }\n\n onKeydown(evt: Event): void {\n if (evt instanceof KeyboardEvent) {\n if (!((evt as KeyboardEvent).key === KeyCode.TAB)) {\n if ((evt as KeyboardEvent).key === KeyCode.ESCAPE) {\n this.eclMegaMenuDataService.eclSubItemEscapeEvent(true);\n } else {\n this.megaMenuSubItemKeydown.emit(evt as KeyboardEvent);\n }\n }\n }\n }\n\n onSubMenuItemCollapse(): void {\n if (this.isExpanded) {\n this.eclMegaMenuDataService.eclSubItemToggle(false);\n this.isCurrent = false;\n this.isExpanded = false;\n this.isParentLink = false;\n }\n }\n\n onSubMenuItemExpand(): void {\n this.isCurrent = true;\n this.isExpanded = true;\n this.eclMegaMenuDataService.eclSubItemToggle(this.isExpanded);\n }\n\n private observeBreakpointChanges(): void {\n this.appShell.getState<any>('breakpoints')\n .pipe(\n // ECL uses breakpointDesktop = 1140px. isLtLargeTablet covers xs/sm/md/lg (< 1140px).\n map(bp => !!(bp?.isLtLargeTablet)),\n distinctUntilChanged(),\n takeUntil(this.destroy$),\n )\n .subscribe((isMobile) => {\n const wasMobile = this.isMobileBreakpoint;\n this.isMobileBreakpoint = isMobile;\n\n // Reset computed heights when switching breakpoints\n if (wasMobile !== isMobile) {\n this.level2StyleHeight = null;\n const eclMegaMenuFeatured = this.eclMegaMenuFeatured();\n if (eclMegaMenuFeatured) {\n eclMegaMenuFeatured.eclMegaMenuFeaturedStyleHeight = null;\n }\n }\n });\n }\n}\n",
63370
62792
  "assetsDirs": [],
63371
62793
  "styleUrlsData": "",
63372
62794
  "stylesData": "",
63373
62795
  "jsdoctags": [
63374
62796
  {
63375
- "pos": 1164,
63376
- "end": 1274,
62797
+ "pos": 1151,
62798
+ "end": 1261,
63377
62799
  "kind": 321,
63378
62800
  "id": 0,
63379
62801
  "flags": 16777216,
@@ -63388,7 +62810,7 @@
63388
62810
  "deprecated": false,
63389
62811
  "deprecationMessage": "",
63390
62812
  "args": [],
63391
- "line": 111,
62813
+ "line": 115,
63392
62814
  "rawdescription": "\n"
63393
62815
  },
63394
62816
  "extends": [
@@ -63404,7 +62826,7 @@
63404
62826
  "name": "cssClasses",
63405
62827
  "type": "string",
63406
62828
  "returnType": "string",
63407
- "line": 30,
62829
+ "line": 34,
63408
62830
  "rawdescription": "\n",
63409
62831
  "description": ""
63410
62832
  }
@@ -63415,7 +62837,7 @@
63415
62837
  "name": "hasChildren",
63416
62838
  "type": "boolean",
63417
62839
  "returnType": "boolean",
63418
- "line": 126,
62840
+ "line": 130,
63419
62841
  "rawdescription": "\n",
63420
62842
  "description": ""
63421
62843
  }
@@ -63426,7 +62848,7 @@
63426
62848
  "name": "hasFeatured",
63427
62849
  "type": "boolean",
63428
62850
  "returnType": "boolean",
63429
- "line": 130,
62851
+ "line": 134,
63430
62852
  "rawdescription": "\n",
63431
62853
  "description": ""
63432
62854
  }