@eui/ecl 22.0.0-alpha.2 → 22.0.0-alpha.4

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 (50) hide show
  1. package/docs/changelog.html +62 -0
  2. package/docs/components/EclDateBlockComponent.html +0 -9
  3. package/docs/components/EclMenuItemComponent.html +46 -0
  4. package/docs/components/EclSiteFooterRowCommonComponent.html +1 -1
  5. package/docs/components/EclSiteHeaderLanguageComponent.html +5 -627
  6. package/docs/components/EclSiteHeaderLanguagePopoverComponent.html +99 -440
  7. package/docs/components/EclSiteHeaderLoginComponent.html +9 -453
  8. package/docs/components/EclSiteHeaderSearchComponent.html +18 -470
  9. package/docs/components/EclSocialMediaFollowComponent.html +28 -39
  10. package/docs/components/EclSocialMediaFollowItemComponent.html +21 -124
  11. package/docs/directives/ECLClickOutsideDirective.html +3 -0
  12. package/docs/directives/EclDividerDirective.html +0 -116
  13. package/docs/directives/EclFileUploadDirective.html +2 -390
  14. package/docs/js/search/search_index.js +2 -2
  15. package/docs/json/EclSiteHeaderLanguagePopoverComponent.md +6 -6
  16. package/docs/json/EclSiteHeaderSearchComponent.md +1 -0
  17. package/docs/json/EclSocialMediaFollowComponent.md +1 -0
  18. package/docs/json/documentation.json +685 -1161
  19. package/docs/llms.txt +20 -43
  20. package/docs/miscellaneous/variables.html +222 -41
  21. package/docs/properties.html +1 -1
  22. package/fesm2022/eui-ecl-components-ecl-date-block.mjs +2 -2
  23. package/fesm2022/eui-ecl-components-ecl-date-block.mjs.map +1 -1
  24. package/fesm2022/eui-ecl-components-ecl-divider.mjs +6 -13
  25. package/fesm2022/eui-ecl-components-ecl-divider.mjs.map +1 -1
  26. package/fesm2022/eui-ecl-components-ecl-file-upload.mjs +13 -27
  27. package/fesm2022/eui-ecl-components-ecl-file-upload.mjs.map +1 -1
  28. package/fesm2022/eui-ecl-components-ecl-inpage-navigation.mjs +53 -9
  29. package/fesm2022/eui-ecl-components-ecl-inpage-navigation.mjs.map +1 -1
  30. package/fesm2022/eui-ecl-components-ecl-menu.mjs +16 -3
  31. package/fesm2022/eui-ecl-components-ecl-menu.mjs.map +1 -1
  32. package/fesm2022/eui-ecl-components-ecl-site-footer.mjs +2 -2
  33. package/fesm2022/eui-ecl-components-ecl-site-footer.mjs.map +1 -1
  34. package/fesm2022/eui-ecl-components-ecl-site-header.mjs +326 -261
  35. package/fesm2022/eui-ecl-components-ecl-site-header.mjs.map +1 -1
  36. package/fesm2022/eui-ecl-components-ecl-social-media-follow.mjs +17 -17
  37. package/fesm2022/eui-ecl-components-ecl-social-media-follow.mjs.map +1 -1
  38. package/package.json +1 -1
  39. package/types/eui-ecl-components-ecl-date-block.d.ts.map +1 -1
  40. package/types/eui-ecl-components-ecl-divider.d.ts +0 -4
  41. package/types/eui-ecl-components-ecl-divider.d.ts.map +1 -1
  42. package/types/eui-ecl-components-ecl-file-upload.d.ts.map +1 -1
  43. package/types/eui-ecl-components-ecl-inpage-navigation.d.ts +25 -0
  44. package/types/eui-ecl-components-ecl-inpage-navigation.d.ts.map +1 -1
  45. package/types/eui-ecl-components-ecl-menu.d.ts +12 -1
  46. package/types/eui-ecl-components-ecl-menu.d.ts.map +1 -1
  47. package/types/eui-ecl-components-ecl-site-header.d.ts +240 -216
  48. package/types/eui-ecl-components-ecl-site-header.d.ts.map +1 -1
  49. package/types/eui-ecl-components-ecl-social-media-follow.d.ts +4 -2
  50. package/types/eui-ecl-components-ecl-social-media-follow.d.ts.map +1 -1
@@ -5407,13 +5407,13 @@
5407
5407
  },
5408
5408
  {
5409
5409
  "name": "EclInpageNavigationSectionEnterEvent",
5410
- "id": "class-EclInpageNavigationSectionEnterEvent-218decdcd6a7c68437e5d7e1d602b3cd8612271e9c1069d063d5d1f05e7f6c61f23a6fb4404b9d14cd21d0f249849eacc4c32a956fb3054803a25ed4469f0623",
5410
+ "id": "class-EclInpageNavigationSectionEnterEvent-5daafc90fdb4dbac03101fb1ec926edaec22dde8c7ba4699dcece0f2c2d48f01b9c51ed69bb59e72fd63be3a46eae2803257a7e8309d6a6dc7f5932d3148a469",
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 { CdkScrollable, ScrollDispatcher, ViewportRuler } from '@angular/cdk/scrolling';\nimport { AfterViewInit, ChangeDetectorRef, Component, DOCUMENT, DoCheck, ElementRef, IterableDiffer, IterableDiffers, NgZone, OnDestroy, OnInit, PLATFORM_ID, afterNextRender, inject, numberAttribute, output, input, viewChild, contentChildren, contentChild } 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';\nimport { isPlatformBrowser } from '@angular/common';\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 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.isButtonExpanded = !this.isButtonExpanded;\n this.eclInpageNavigationService.eclInpageNavigationToggle(this.isButtonExpanded);\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.isButtonExpanded = 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 item.sectionElement.scrollIntoView();\n item.sectionElement.focus();\n }\n this.isButtonExpanded = false;\n });\n }\n\n private onItemEnter(item: EclInpageNavigationItemComponent): void {\n this.selectNavigationItem(item.sectionElement);\n if (item.sectionElement) {\n item.sectionElement.scrollIntoView();\n if (item.sectionElement.tabIndex === -1) {\n item.sectionElement.tabIndex = 0;\n item.sectionElement.focus();\n item.sectionElement.tabIndex = -1;\n }\n }\n this.isButtonExpanded = false;\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.isButtonExpanded = 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 const offset = 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. 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",
5417
5417
  "displayName": "EclInpageNavigationSectionEnterEvent",
5418
5418
  "constructorObj": {
5419
5419
  "name": "constructor",
@@ -8457,13 +8457,13 @@
8457
8457
  },
8458
8458
  {
8459
8459
  "name": "EclSocialMediaFollowItemClickEvent",
8460
- "id": "class-EclSocialMediaFollowItemClickEvent-ed2164f85b7d64f8d8fac99dbd85b9daf46f2c0f6adb24b7cdeb865f195926ad0eee3b826c46f06ca87a06f0c0c5b7d1a996ce2d1ed4d4882aec79e8595572d9",
8460
+ "id": "class-EclSocialMediaFollowItemClickEvent-a5a386ce91d38e0d4ebb07c2085b8c669354f1a816b2677b7dde9628c9a14908687d7a7d0f9f6e66e8172233d257ac2a1145254275a03f9216caa201b32c6018",
8461
8461
  "file": "packages/ecl/components/ecl-social-media-follow/ecl-social-media-follow-item.component.ts",
8462
8462
  "coverageIgnore": false,
8463
8463
  "deprecated": false,
8464
8464
  "deprecationMessage": "",
8465
8465
  "type": "class",
8466
- "sourceCode": "import { booleanAttribute, Component, HostBinding, input, output } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EclBaseEvent } from '@eui/ecl/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\nimport { RouterLink, RouterLinkWithHref } from '@angular/router';\n\nexport class EclSocialMediaFollowItemClickEvent extends EclBaseEvent {}\n\n@Component({\n selector: 'ecl-social-media-follow-item',\n templateUrl: './ecl-social-media-follow-item.component.html',\n imports: [...EUI_ECL_ICON, ...EUI_ECL_LINK, NgTemplateOutlet, RouterLink, RouterLinkWithHref],\n})\nexport class EclSocialMediaFollowItemComponent extends ECLBaseDirective {\n readonly isInverted = input<false, unknown>(undefined, { transform: (booleanAttribute) as any });\n @HostBinding('attr.role') role = 'listitem';\n icon = input<string>();\n iconSet = input<string>('social-media');\n readonly href = input('');\n readonly routerLink = input('');\n readonly target = input<string>(undefined);\n readonly size = input('m');\n readonly extraAttributes = input<{\n name: string;\n value?: string | null;\n }[]>(undefined);\n\n @HostBinding('class')\n get cssClasses(): string {\n return [super.getCssClasses('ecl-social-media-follow__item')].join(' ').trim();\n }\n\n readonly itemClick = output<EclSocialMediaFollowItemClickEvent>();\n\n onItemClick(evt): void {\n this.itemClick.emit(new EclSocialMediaFollowItemClickEvent());\n if (!this.href() && !this.routerLink()) {\n evt.preventDefault();\n }\n }\n}\n",
8466
+ "sourceCode": "import { booleanAttribute, Component, inject, input, output } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EclBaseEvent } from '@eui/ecl/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\nimport { RouterLink, RouterLinkWithHref } from '@angular/router';\nimport { EclSocialMediaFollowComponent } from './ecl-social-media-follow.component';\n\nexport class EclSocialMediaFollowItemClickEvent extends EclBaseEvent {}\n\n@Component({\n selector: 'ecl-social-media-follow-item',\n templateUrl: './ecl-social-media-follow-item.component.html',\n imports: [...EUI_ECL_ICON, ...EUI_ECL_LINK, NgTemplateOutlet, RouterLink, RouterLinkWithHref],\n host: {\n 'role': 'listitem',\n '[class]': 'cssClasses',\n },\n})\nexport class EclSocialMediaFollowItemComponent extends ECLBaseDirective {\n readonly isInverted = input<false, unknown>(undefined, { transform: (booleanAttribute) as any });\n icon = input<string>();\n iconSet = input<string>('social-media');\n readonly href = input('');\n readonly routerLink = input('');\n readonly target = input<string>(undefined);\n readonly size = input('m');\n readonly extraAttributes = input<{\n name: string;\n value?: string | null;\n }[]>(undefined);\n\n private parent = inject(EclSocialMediaFollowComponent);\n\n get isIconOnly(): boolean {\n return this.parent?.isIconOnly() ?? false;\n }\n\n get cssClasses(): string {\n return [super.getCssClasses('ecl-social-media-follow__item')].join(' ').trim();\n }\n\n readonly itemClick = output<EclSocialMediaFollowItemClickEvent>();\n\n onItemClick(evt): void {\n this.itemClick.emit(new EclSocialMediaFollowItemClickEvent());\n if (!this.href() && !this.routerLink()) {\n evt.preventDefault();\n }\n }\n}\n",
8467
8467
  "displayName": "EclSocialMediaFollowItemClickEvent",
8468
8468
  "inputsClass": [],
8469
8469
  "outputsClass": [],
@@ -13303,6 +13303,11 @@
13303
13303
  "name": "EclSiteHeaderLoginComponent",
13304
13304
  "type": "component",
13305
13305
  "description": "Component for login/logout as part of the harmonised site header. Emits events when user logs in and when user opens the login dropdown."
13306
+ },
13307
+ {
13308
+ "name": "EclSiteHeaderSearchComponent",
13309
+ "type": "component",
13310
+ "description": "This component builds the search box in the ecl-site-header component. Adds specific style and functionality, emits events on search and..."
13306
13311
  }
13307
13312
  ],
13308
13313
  "outgoing": [
@@ -18033,12 +18038,12 @@
18033
18038
  },
18034
18039
  {
18035
18040
  "name": "EclDividerDirective",
18036
- "id": "directive-EclDividerDirective-c778b06e120fcce619744cfa04f716e96292edd208d2f30586c08dd8bb0fd21977eb58df39a4cb143ed317c9f950661ac4df476d3edef5ba48c7eb61b03e8306",
18041
+ "id": "directive-EclDividerDirective-8335ebb38f5612ec5a4bdd37aaf55f0c013e9f290749f7439a0096a4f3937f6a4c099fbcce510063095dd7b3e20f60dd44158063f777adace5876c68fd0d79a2",
18037
18042
  "file": "packages/ecl/components/ecl-divider/ecl-divider.directive.ts",
18038
18043
  "type": "directive",
18039
18044
  "description": "<p>Directive that applies ECL styling for horizontal separators (<code>&lt;hr&gt;</code> elements).\nAdds the <code>ecl-separator</code> CSS class to the host element.</p>\n",
18040
18045
  "rawdescription": "\n\nDirective that applies ECL styling for horizontal separators (`<hr>` elements).\nAdds the `ecl-separator` CSS class to the host element.\n",
18041
- "sourceCode": "import { Directive, HostBinding } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that applies ECL styling for horizontal separators (`<hr>` elements).\n * Adds the `ecl-separator` CSS class to the host element.\n */\n@Directive({\n selector: 'hr[eclDivider]',\n})\nexport class EclDividerDirective extends ECLBaseDirective {\n /**\n * Binds the `ecl-separator` CSS class to the host `<hr>` element.\n */\n @HostBinding('class.ecl-separator') hasClass = true;\n}\n",
18046
+ "sourceCode": "import { Directive } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Directive that applies ECL styling for horizontal separators (`<hr>` elements).\n * Adds the `ecl-separator` CSS class to the host element.\n */\n@Directive({\n selector: 'hr[eclDivider]',\n host: {\n 'class': 'ecl-separator',\n },\n})\nexport class EclDividerDirective extends ECLBaseDirective {}\n",
18042
18047
  "selector": "hr[eclDivider]",
18043
18048
  "providers": [],
18044
18049
  "hostDirectives": [],
@@ -18091,46 +18096,9 @@
18091
18096
  "outputsClass": [],
18092
18097
  "deprecated": false,
18093
18098
  "deprecationMessage": "",
18094
- "hostBindings": [
18095
- {
18096
- "coverageIgnore": false,
18097
- "name": "class.ecl-separator",
18098
- "actualName": "hasClass",
18099
- "defaultValue": "true",
18100
- "deprecated": false,
18101
- "deprecationMessage": "",
18102
- "rawdescription": "\n\nBinds the `ecl-separator` CSS class to the host `<hr>` element.\n",
18103
- "description": "<p>Binds the <code>ecl-separator</code> CSS class to the host <code>&lt;hr&gt;</code> element.</p>\n",
18104
- "line": 15,
18105
- "type": "boolean",
18106
- "decorators": []
18107
- }
18108
- ],
18099
+ "hostBindings": [],
18109
18100
  "hostListeners": [],
18110
- "propertiesClass": [
18111
- {
18112
- "name": "hasClass",
18113
- "coverageIgnore": false,
18114
- "defaultValue": "true",
18115
- "deprecated": false,
18116
- "deprecationMessage": "",
18117
- "type": "unknown",
18118
- "indexKey": "",
18119
- "optional": false,
18120
- "description": "<p>Binds the <code>ecl-separator</code> CSS class to the host <code>&lt;hr&gt;</code> element.</p>\n",
18121
- "line": 15,
18122
- "rawdescription": "\n\nBinds the `ecl-separator` CSS class to the host `<hr>` element.\n",
18123
- "decorators": [
18124
- {
18125
- "name": "HostBinding",
18126
- "stringifiedArguments": "'class.ecl-separator'"
18127
- }
18128
- ],
18129
- "modifierKind": [
18130
- 171
18131
- ]
18132
- }
18133
- ],
18101
+ "propertiesClass": [],
18134
18102
  "methodsClass": [
18135
18103
  {
18136
18104
  "name": "getCssClasses",
@@ -18174,8 +18142,8 @@
18174
18142
  "coverageIgnore": false,
18175
18143
  "jsdoctags": [
18176
18144
  {
18177
- "pos": 107,
18178
- "end": 256,
18145
+ "pos": 94,
18146
+ "end": 243,
18179
18147
  "kind": 321,
18180
18148
  "id": 0,
18181
18149
  "flags": 16777216,
@@ -20015,12 +19983,12 @@
20015
19983
  },
20016
19984
  {
20017
19985
  "name": "EclFileUploadDirective",
20018
- "id": "directive-EclFileUploadDirective-ab4f4f00663d81a0de751fab623c1532e0975d0a2c42ab3bb154b1263b7768a309b6952ed30ffc3738d459cd9b8a9ff9c03116db9478028a973efb08ca561e3b",
19986
+ "id": "directive-EclFileUploadDirective-e28d4f19a66fd44eef8fcedc12262c782b173d90e27797eeea41f8f899542b6533c65168a06323331cadeddfdb9014b71d049cb7081b707006db8e611359d24a",
20019
19987
  "file": "packages/ecl/components/ecl-file-upload/ecl-file-upload.directive.ts",
20020
19988
  "type": "directive",
20021
19989
  "description": "<p>Directive that enhances a native input[type=file] with ECL-compliant styling and behavior.\nSupports multiple file selection, dynamic file list rendering, translations and validation state.</p>\n",
20022
19990
  "rawdescription": "\n\nDirective that enhances a native input[type=file] with ECL-compliant styling and behavior.\nSupports multiple file selection, dynamic file list rendering, translations and validation state.\n",
20023
- "sourceCode": "import { isPlatformBrowser } from '@angular/common';\nimport {\n Directive,\n DoCheck,\n ElementRef,\n HostBinding,\n HostListener,\n inject,\n OnDestroy,\n OnInit,\n PLATFORM_ID,\n Renderer2,\n booleanAttribute,\n output,\n input,\n} from '@angular/core';\nimport { NgControl } from '@angular/forms';\nimport { TranslateService } from '@ngx-translate/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EclFileUpload } from './models/ecl-file-upload.model';\nimport { EclFileUploadFileSelectedEvent } from './events/ecl-file-upload-file-selected.event';\n\n/**\n * Directive that enhances a native input[type=file] with ECL-compliant styling and behavior.\n * Supports multiple file selection, dynamic file list rendering, translations and validation state.\n */\n@Directive({\n selector: '[eclFileUpload]',\n})\nexport class EclFileUploadDirective extends ECLBaseDirective implements OnInit, OnDestroy, DoCheck {\n protected ngControl = inject(NgControl, { optional: true, self: true });\n\n /**\n * Variant of the component's appearance. Currently unused. Default: `'default'`.\n */\n readonly variant = input('default');\n\n /**\n * Marks the component as invalid (if not using Angular form validation).\n */\n readonly isInvalid = input(false, { transform: booleanAttribute });\n\n /**\n * ID attribute applied to the native file input.\n */\n @HostBinding('attr.id')\n readonly id = input<string>(undefined);\n\n /**\n * Whether the component is disabled.\n */\n @HostBinding('attr.disabled')\n readonly disabled = input<boolean, unknown>(undefined, { transform: booleanAttribute });\n\n /**\n * Allows selecting multiple files.\n */\n @HostBinding('attr.multiple')\n readonly multiple = input<boolean, unknown>(undefined, { transform: booleanAttribute });\n\n /**\n * Event emitted when files are selected.\n */\n readonly filesSelected = output<EclFileUploadFileSelectedEvent>();\n\n /**\n * Host binding to define input type as 'file'.\n */\n @HostBinding('attr.type') type = 'file';\n\n private fileListEl: HTMLElement;\n\n private files: EclFileUpload[] = [];\n private buttonEl: HTMLElement;\n private labelEl: HTMLElement;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private readonly SPAN_BUTTON_CONVERSION_CLASSES = ['ecl-button', 'ecl-button--primary', 'ecl-file-upload__button'];\n private el = inject(ElementRef);\n private translate = inject(TranslateService);\n private renderer = inject(Renderer2);\n private platformId = inject(PLATFORM_ID);\n\n /**\n * Applies the base `ecl-file-upload` class to the host element.\n */\n @HostBinding('class')\n get cssClasses(): string {\n return [super.getCssClasses('ecl-file-upload')].join(' ').trim();\n }\n\n /**\n * Returns `true` if component should be displayed as invalid.\n * Prioritizes Angular form control status over `isInvalid` input.\n */\n @HostBinding('class.ecl-file-upload--invalid')\n get invalidState(): boolean {\n if (this.ngControl) {\n return this.ngControl.status === 'INVALID' && this.ngControl.touched;\n } else {\n return this.isInvalid();\n }\n }\n\n /**\n * Initializes component structure and translation subscription (browser-only).\n */\n ngOnInit(): void {\n if (isPlatformBrowser(this.platformId)) {\n this.createDOMStructure();\n this.handleTranslations();\n }\n }\n\n /**\n * Clean up resources and RxJS subscriptions.\n */\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * Checks component state during change detection to toggle the disabled state of internal elements.\n */\n ngDoCheck(): void {\n if (this.disabled()) {\n this.renderer.setAttribute(this.buttonEl, 'disabled', 'true');\n } else {\n this.renderer.removeAttribute(this.buttonEl, 'disabled');\n }\n }\n\n /**\n * Prevents file dialog from opening when component is disabled.\n * @param evt Click event on the input element.\n */\n @HostListener('click', ['$event']) onClick(evt: Event): void {\n if (this.disabled()) {\n evt.preventDefault();\n }\n }\n\n /**\n * Handles file selection and emits a structured file selection event.\n * @param evt Change event from input.\n */\n @HostListener('change', ['$event']) onFilesSelected(evt: Event): void {\n const inputElement: HTMLInputElement = evt.target as HTMLInputElement;\n const fileList: FileList = inputElement.files;\n this.files = this.getFileModels(fileList);\n\n const fileEvent = new EclFileUploadFileSelectedEvent(this.files);\n this.filesSelected.emit(fileEvent);\n\n if (!fileEvent.defaultPrevented) {\n this.handleTranslations();\n this.updateListItemsDOM(this.files);\n }\n }\n\n private handleTranslations(): void {\n const uploadButtonLabelKey = this.geti18nUploadButtonLabelKey();\n\n this.translate\n .stream(uploadButtonLabelKey)\n .pipe(takeUntil(this.destroy$))\n .subscribe((translation: string) => {\n if (this.buttonEl) {\n this.renderer.setProperty(this.buttonEl, 'textContent', translation);\n }\n });\n }\n\n private geti18nUploadButtonLabelKey(): string {\n let key = '';\n\n if (this.files && this.files.length !== 0) {\n if (this.multiple()) {\n key = 'ecl.file-upload.REPLACE-FILES';\n } else {\n key = 'ecl.file-upload.REPLACE-FILE';\n }\n } else {\n if (this.multiple()) {\n key = 'ecl.file-upload.CHOOSE-FILES';\n } else {\n key = 'ecl.file-upload.CHOOSE-FILE';\n }\n }\n\n return key;\n }\n\n private updateListItemsDOM(files: EclFileUpload[]): void {\n this.renderer.setProperty(this.fileListEl, 'textContent', '');\n files.forEach((file) => {\n const item = this.createFileListItemDOMElement(file);\n this.renderer.appendChild(this.fileListEl, item);\n });\n }\n\n private createDOMStructure(): void {\n const labelEl = this.createLabelDOMElement();\n const hostEl = this.getHostDOMElement();\n const fileListEl = this.createFileListDOMElement();\n\n hostEl.insertAdjacentElement('afterend', fileListEl);\n hostEl.insertAdjacentElement('afterend', labelEl);\n\n this.fileListEl = fileListEl;\n }\n\n private getHostDOMElement(): HTMLInputElement {\n return this.el.nativeElement;\n }\n\n private createLabelDOMElement(): HTMLElement {\n this.buttonEl = this.renderer.createElement('span');\n this.addClasses(this.buttonEl, this.SPAN_BUTTON_CONVERSION_CLASSES);\n\n this.labelEl = this.renderer.createElement('label');\n this.renderer.setAttribute(this.labelEl, 'for', this.id());\n this.renderer.addClass(this.labelEl, 'ecl-file-upload__button-container');\n\n this.renderer.appendChild(this.labelEl, this.buttonEl);\n\n return this.labelEl;\n }\n\n private addClasses(element: HTMLElement, classes: string[] ): void {\n classes.forEach(className=> this.renderer.addClass(element, className) )\n }\n\n private createFileListDOMElement(): HTMLElement {\n const element = this.renderer.createElement('ul');\n this.renderer.addClass(element,'ecl-file-upload__list');\n this.renderer.setAttribute(element,'aria-live','polite');\n\n return element;\n }\n\n private createFileListItemDOMElement(fileUpload: EclFileUpload): HTMLElement {\n const liElement = this.renderer.createElement('li');\n this.renderer.addClass(liElement,'ecl-file-upload__item');\n\n const fileNameElement = this.renderer.createElement('span');\n const fileName = this.renderer.createText(fileUpload.name);\n this.renderer.appendChild(fileNameElement, fileName);\n\n this.renderer.addClass( fileNameElement,'ecl-file-upload__item-name' );\n\n const fileMetaElement = this.renderer.createElement('span');\n\n const fileMetaElementText = this.renderer.createText(`(${fileUpload.size} - ${fileUpload.extension})`);\n this.renderer.appendChild(fileMetaElement, fileMetaElementText);\n this.renderer.addClass(fileMetaElement, 'ecl-file-upload__item-meta');\n\n this.renderer.appendChild(liElement, fileNameElement);\n this.renderer.appendChild(liElement, fileMetaElement);\n\n return liElement;\n }\n\n private getFileModels(fileList: FileList): EclFileUpload[] {\n return Array.from(fileList).map((f) => ({\n name: f.name,\n extension: this.getFilenameExtension(f.name),\n size: this.formatBytes(f.size),\n }));\n }\n\n private getFilenameExtension(filename: string): string {\n return filename.split('.').pop();\n }\n\n private formatBytes(bytes, decimals = 2): string {\n if (bytes === 0) {\n return '0 Bytes';\n }\n\n const k = 1024;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes = ['Bytes', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];\n\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;\n }\n}\n",
19991
+ "sourceCode": "import { isPlatformBrowser } from '@angular/common';\nimport {\n Directive,\n DoCheck,\n ElementRef,\n inject,\n OnDestroy,\n OnInit,\n PLATFORM_ID,\n Renderer2,\n booleanAttribute,\n output,\n input,\n} from '@angular/core';\nimport { NgControl } from '@angular/forms';\nimport { TranslateService } from '@ngx-translate/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EclFileUpload } from './models/ecl-file-upload.model';\nimport { EclFileUploadFileSelectedEvent } from './events/ecl-file-upload-file-selected.event';\n\n/**\n * Directive that enhances a native input[type=file] with ECL-compliant styling and behavior.\n * Supports multiple file selection, dynamic file list rendering, translations and validation state.\n */\n@Directive({\n selector: '[eclFileUpload]',\n host: {\n '[attr.type]': 'type',\n '[attr.id]': 'id()',\n '[attr.disabled]': 'disabled() ? \"\" : null',\n '[attr.multiple]': 'multiple() ? \"\" : null',\n '[class]': 'cssClasses',\n '[class.ecl-file-upload--invalid]': 'invalidState',\n '(click)': 'onClick($event)',\n '(change)': 'onFilesSelected($event)',\n },\n})\nexport class EclFileUploadDirective extends ECLBaseDirective implements OnInit, OnDestroy, DoCheck {\n protected ngControl = inject(NgControl, { optional: true, self: true });\n\n /**\n * Variant of the component's appearance. Currently unused. Default: `'default'`.\n */\n readonly variant = input('default');\n\n /**\n * Marks the component as invalid (if not using Angular form validation).\n */\n readonly isInvalid = input(false, { transform: booleanAttribute });\n\n /**\n * ID attribute applied to the native file input.\n */\n readonly id = input<string>(undefined);\n\n /**\n * Whether the component is disabled.\n */\n readonly disabled = input<boolean, unknown>(undefined, { transform: booleanAttribute });\n\n /**\n * Allows selecting multiple files.\n */\n readonly multiple = input<boolean, unknown>(undefined, { transform: booleanAttribute });\n\n /**\n * Event emitted when files are selected.\n */\n readonly filesSelected = output<EclFileUploadFileSelectedEvent>();\n\n /**\n * Host binding to define input type as 'file'.\n */\n type = 'file';\n\n private fileListEl: HTMLElement;\n\n private files: EclFileUpload[] = [];\n private buttonEl: HTMLElement;\n private labelEl: HTMLElement;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private readonly SPAN_BUTTON_CONVERSION_CLASSES = ['ecl-button', 'ecl-button--primary', 'ecl-file-upload__button'];\n private el = inject(ElementRef);\n private translate = inject(TranslateService);\n private renderer = inject(Renderer2);\n private platformId = inject(PLATFORM_ID);\n\n /**\n * Applies the base `ecl-file-upload` class to the host element.\n */\n get cssClasses(): string {\n return [super.getCssClasses('ecl-file-upload')].join(' ').trim();\n }\n\n /**\n * Returns `true` if component should be displayed as invalid.\n * Prioritizes Angular form control status over `isInvalid` input.\n */\n get invalidState(): boolean {\n if (this.ngControl) {\n return this.ngControl.status === 'INVALID' && this.ngControl.touched;\n } else {\n return this.isInvalid();\n }\n }\n\n /**\n * Initializes component structure and translation subscription (browser-only).\n */\n ngOnInit(): void {\n if (isPlatformBrowser(this.platformId)) {\n this.createDOMStructure();\n this.handleTranslations();\n }\n }\n\n /**\n * Clean up resources and RxJS subscriptions.\n */\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * Checks component state during change detection to toggle the disabled state of internal elements.\n */\n ngDoCheck(): void {\n if (this.disabled()) {\n this.renderer.setAttribute(this.buttonEl, 'disabled', 'true');\n } else {\n this.renderer.removeAttribute(this.buttonEl, 'disabled');\n }\n }\n\n /**\n * Prevents file dialog from opening when component is disabled.\n * @param evt Click event on the input element.\n */\n onClick(evt: Event): void {\n if (this.disabled()) {\n evt.preventDefault();\n }\n }\n\n /**\n * Handles file selection and emits a structured file selection event.\n * @param evt Change event from input.\n */\n onFilesSelected(evt: Event): void {\n const inputElement: HTMLInputElement = evt.target as HTMLInputElement;\n const fileList: FileList = inputElement.files;\n this.files = this.getFileModels(fileList);\n\n const fileEvent = new EclFileUploadFileSelectedEvent(this.files);\n this.filesSelected.emit(fileEvent);\n\n if (!fileEvent.defaultPrevented) {\n this.handleTranslations();\n this.updateListItemsDOM(this.files);\n }\n }\n\n private handleTranslations(): void {\n const uploadButtonLabelKey = this.geti18nUploadButtonLabelKey();\n\n this.translate\n .stream(uploadButtonLabelKey)\n .pipe(takeUntil(this.destroy$))\n .subscribe((translation: string) => {\n if (this.buttonEl) {\n this.renderer.setProperty(this.buttonEl, 'textContent', translation);\n }\n });\n }\n\n private geti18nUploadButtonLabelKey(): string {\n let key = '';\n\n if (this.files && this.files.length !== 0) {\n if (this.multiple()) {\n key = 'ecl.file-upload.REPLACE-FILES';\n } else {\n key = 'ecl.file-upload.REPLACE-FILE';\n }\n } else {\n if (this.multiple()) {\n key = 'ecl.file-upload.CHOOSE-FILES';\n } else {\n key = 'ecl.file-upload.CHOOSE-FILE';\n }\n }\n\n return key;\n }\n\n private updateListItemsDOM(files: EclFileUpload[]): void {\n this.renderer.setProperty(this.fileListEl, 'textContent', '');\n files.forEach((file) => {\n const item = this.createFileListItemDOMElement(file);\n this.renderer.appendChild(this.fileListEl, item);\n });\n }\n\n private createDOMStructure(): void {\n const labelEl = this.createLabelDOMElement();\n const hostEl = this.getHostDOMElement();\n const fileListEl = this.createFileListDOMElement();\n\n hostEl.insertAdjacentElement('afterend', fileListEl);\n hostEl.insertAdjacentElement('afterend', labelEl);\n\n this.fileListEl = fileListEl;\n }\n\n private getHostDOMElement(): HTMLInputElement {\n return this.el.nativeElement;\n }\n\n private createLabelDOMElement(): HTMLElement {\n this.buttonEl = this.renderer.createElement('span');\n this.addClasses(this.buttonEl, this.SPAN_BUTTON_CONVERSION_CLASSES);\n\n this.labelEl = this.renderer.createElement('label');\n this.renderer.setAttribute(this.labelEl, 'for', this.id());\n this.renderer.addClass(this.labelEl, 'ecl-file-upload__button-container');\n\n this.renderer.appendChild(this.labelEl, this.buttonEl);\n\n return this.labelEl;\n }\n\n private addClasses(element: HTMLElement, classes: string[] ): void {\n classes.forEach(className=> this.renderer.addClass(element, className) )\n }\n\n private createFileListDOMElement(): HTMLElement {\n const element = this.renderer.createElement('ul');\n this.renderer.addClass(element,'ecl-file-upload__list');\n this.renderer.setAttribute(element,'aria-live','polite');\n\n return element;\n }\n\n private createFileListItemDOMElement(fileUpload: EclFileUpload): HTMLElement {\n const liElement = this.renderer.createElement('li');\n this.renderer.addClass(liElement,'ecl-file-upload__item');\n\n const fileNameElement = this.renderer.createElement('span');\n const fileName = this.renderer.createText(fileUpload.name);\n this.renderer.appendChild(fileNameElement, fileName);\n\n this.renderer.addClass( fileNameElement,'ecl-file-upload__item-name' );\n\n const fileMetaElement = this.renderer.createElement('span');\n\n const fileMetaElementText = this.renderer.createText(`(${fileUpload.size} - ${fileUpload.extension})`);\n this.renderer.appendChild(fileMetaElement, fileMetaElementText);\n this.renderer.addClass(fileMetaElement, 'ecl-file-upload__item-meta');\n\n this.renderer.appendChild(liElement, fileNameElement);\n this.renderer.appendChild(liElement, fileMetaElement);\n\n return liElement;\n }\n\n private getFileModels(fileList: FileList): EclFileUpload[] {\n return Array.from(fileList).map((f) => ({\n name: f.name,\n extension: this.getFilenameExtension(f.name),\n size: this.formatBytes(f.size),\n }));\n }\n\n private getFilenameExtension(filename: string): string {\n return filename.split('.').pop();\n }\n\n private formatBytes(bytes, decimals = 2): string {\n if (bytes === 0) {\n return '0 Bytes';\n }\n\n const k = 1024;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes = ['Bytes', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];\n\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;\n }\n}\n",
20024
19992
  "selector": "[eclFileUpload]",
20025
19993
  "providers": [],
20026
19994
  "hostDirectives": [],
@@ -20036,16 +20004,9 @@
20036
20004
  "indexKey": "",
20037
20005
  "optional": false,
20038
20006
  "description": "<p>Whether the component is disabled.</p>\n",
20039
- "line": 55,
20007
+ "line": 61,
20040
20008
  "rawdescription": "\n\nWhether the component is disabled.\n",
20041
- "decorators": [
20042
- {
20043
- "name": "HostBinding",
20044
- "stringifiedArguments": "'attr.disabled'"
20045
- }
20046
- ],
20047
20009
  "modifierKind": [
20048
- 171,
20049
20010
  148
20050
20011
  ],
20051
20012
  "required": false
@@ -20060,16 +20021,9 @@
20060
20021
  "indexKey": "",
20061
20022
  "optional": false,
20062
20023
  "description": "<p>ID attribute applied to the native file input.</p>\n",
20063
- "line": 49,
20024
+ "line": 56,
20064
20025
  "rawdescription": "\n\nID attribute applied to the native file input.\n",
20065
- "decorators": [
20066
- {
20067
- "name": "HostBinding",
20068
- "stringifiedArguments": "'attr.id'"
20069
- }
20070
- ],
20071
20026
  "modifierKind": [
20072
- 171,
20073
20027
  148
20074
20028
  ],
20075
20029
  "required": false
@@ -20084,7 +20038,7 @@
20084
20038
  "indexKey": "",
20085
20039
  "optional": false,
20086
20040
  "description": "<p>Marks the component as invalid (if not using Angular form validation).</p>\n",
20087
- "line": 43,
20041
+ "line": 51,
20088
20042
  "rawdescription": "\n\nMarks the component as invalid (if not using Angular form validation).\n",
20089
20043
  "modifierKind": [
20090
20044
  148
@@ -20101,16 +20055,9 @@
20101
20055
  "indexKey": "",
20102
20056
  "optional": false,
20103
20057
  "description": "<p>Allows selecting multiple files.</p>\n",
20104
- "line": 61,
20058
+ "line": 66,
20105
20059
  "rawdescription": "\n\nAllows selecting multiple files.\n",
20106
- "decorators": [
20107
- {
20108
- "name": "HostBinding",
20109
- "stringifiedArguments": "'attr.multiple'"
20110
- }
20111
- ],
20112
20060
  "modifierKind": [
20113
- 171,
20114
20061
  148
20115
20062
  ],
20116
20063
  "required": false
@@ -20125,7 +20072,7 @@
20125
20072
  "indexKey": "",
20126
20073
  "optional": false,
20127
20074
  "description": "<p>Variant of the component&#39;s appearance. Currently unused. Default: <code>&#39;default&#39;</code>.</p>\n",
20128
- "line": 38,
20075
+ "line": 46,
20129
20076
  "rawdescription": "\n\nVariant of the component's appearance. Currently unused. Default: `'default'`.\n",
20130
20077
  "modifierKind": [
20131
20078
  148
@@ -20186,7 +20133,7 @@
20186
20133
  "indexKey": "",
20187
20134
  "optional": false,
20188
20135
  "description": "<p>Event emitted when files are selected.</p>\n",
20189
- "line": 66,
20136
+ "line": 71,
20190
20137
  "rawdescription": "\n\nEvent emitted when files are selected.\n",
20191
20138
  "modifierKind": [
20192
20139
  148
@@ -20196,194 +20143,8 @@
20196
20143
  ],
20197
20144
  "deprecated": false,
20198
20145
  "deprecationMessage": "",
20199
- "hostBindings": [
20200
- {
20201
- "coverageIgnore": false,
20202
- "name": "attr.disabled",
20203
- "actualName": "disabled",
20204
- "defaultValue": "input<boolean, unknown>(undefined, { transform: booleanAttribute })",
20205
- "deprecated": false,
20206
- "deprecationMessage": "",
20207
- "rawdescription": "\n\nWhether the component is disabled.\n",
20208
- "description": "<p>Whether the component is disabled.</p>\n",
20209
- "line": 55,
20210
- "type": "any",
20211
- "decorators": []
20212
- },
20213
- {
20214
- "coverageIgnore": false,
20215
- "name": "attr.id",
20216
- "actualName": "id",
20217
- "defaultValue": "input<string>(undefined)",
20218
- "deprecated": false,
20219
- "deprecationMessage": "",
20220
- "rawdescription": "\n\nID attribute applied to the native file input.\n",
20221
- "description": "<p>ID attribute applied to the native file input.</p>\n",
20222
- "line": 49,
20223
- "type": "any",
20224
- "decorators": []
20225
- },
20226
- {
20227
- "coverageIgnore": false,
20228
- "name": "attr.multiple",
20229
- "actualName": "multiple",
20230
- "defaultValue": "input<boolean, unknown>(undefined, { transform: booleanAttribute })",
20231
- "deprecated": false,
20232
- "deprecationMessage": "",
20233
- "rawdescription": "\n\nAllows selecting multiple files.\n",
20234
- "description": "<p>Allows selecting multiple files.</p>\n",
20235
- "line": 61,
20236
- "type": "any",
20237
- "decorators": []
20238
- },
20239
- {
20240
- "coverageIgnore": false,
20241
- "name": "attr.type",
20242
- "actualName": "type",
20243
- "defaultValue": "'file'",
20244
- "deprecated": false,
20245
- "deprecationMessage": "",
20246
- "rawdescription": "\n\nHost binding to define input type as 'file'.\n",
20247
- "description": "<p>Host binding to define input type as &#39;file&#39;.</p>\n",
20248
- "line": 71,
20249
- "type": "string",
20250
- "decorators": []
20251
- },
20252
- {
20253
- "coverageIgnore": false,
20254
- "name": "class",
20255
- "actualName": "cssClasses",
20256
- "deprecated": false,
20257
- "deprecationMessage": "",
20258
- "rawdescription": "\n\nApplies the base `ecl-file-upload` class to the host element.\n",
20259
- "description": "<p>Applies the base <code>ecl-file-upload</code> class to the host element.</p>\n",
20260
- "line": 89,
20261
- "type": "string",
20262
- "decorators": []
20263
- },
20264
- {
20265
- "coverageIgnore": false,
20266
- "name": "class.ecl-file-upload--invalid",
20267
- "actualName": "invalidState",
20268
- "deprecated": false,
20269
- "deprecationMessage": "",
20270
- "rawdescription": "\n\nReturns `true` if component should be displayed as invalid.\nPrioritizes Angular form control status over `isInvalid` input.\n",
20271
- "description": "<p>Returns <code>true</code> if component should be displayed as invalid.\nPrioritizes Angular form control status over <code>isInvalid</code> input.</p>\n",
20272
- "line": 98,
20273
- "type": "boolean",
20274
- "decorators": []
20275
- }
20276
- ],
20277
- "hostListeners": [
20278
- {
20279
- "coverageIgnore": false,
20280
- "name": "change",
20281
- "args": [
20282
- {
20283
- "name": "evt",
20284
- "type": "Event",
20285
- "optional": false,
20286
- "dotDotDotToken": false,
20287
- "deprecated": false,
20288
- "deprecationMessage": ""
20289
- }
20290
- ],
20291
- "argsDecorator": [
20292
- "$event"
20293
- ],
20294
- "deprecated": false,
20295
- "deprecationMessage": "",
20296
- "rawdescription": "\n\nHandles file selection and emits a structured file selection event.\n",
20297
- "description": "<p>Handles file selection and emits a structured file selection event.</p>\n",
20298
- "jsdoctags": [
20299
- {
20300
- "pos": 4493,
20301
- "end": 4534,
20302
- "kind": 342,
20303
- "id": 0,
20304
- "flags": 16842752,
20305
- "modifierFlagsCache": 0,
20306
- "transformFlags": 0,
20307
- "tagName": {
20308
- "pos": 4494,
20309
- "end": 4499,
20310
- "kind": 80,
20311
- "id": 0,
20312
- "flags": 16842752,
20313
- "transformFlags": 0,
20314
- "escapedText": "param"
20315
- },
20316
- "comment": "<p>Change event from input.</p>\n",
20317
- "name": {
20318
- "pos": 4500,
20319
- "end": 4503,
20320
- "kind": 80,
20321
- "id": 0,
20322
- "flags": 16842752,
20323
- "transformFlags": 0,
20324
- "escapedText": "evt"
20325
- },
20326
- "isNameFirst": true,
20327
- "isBracketed": false
20328
- }
20329
- ],
20330
- "line": 149
20331
- },
20332
- {
20333
- "coverageIgnore": false,
20334
- "name": "click",
20335
- "args": [
20336
- {
20337
- "name": "evt",
20338
- "type": "Event",
20339
- "optional": false,
20340
- "dotDotDotToken": false,
20341
- "deprecated": false,
20342
- "deprecationMessage": ""
20343
- }
20344
- ],
20345
- "argsDecorator": [
20346
- "$event"
20347
- ],
20348
- "deprecated": false,
20349
- "deprecationMessage": "",
20350
- "rawdescription": "\n\nPrevents file dialog from opening when component is disabled.\n",
20351
- "description": "<p>Prevents file dialog from opening when component is disabled.</p>\n",
20352
- "jsdoctags": [
20353
- {
20354
- "pos": 4201,
20355
- "end": 4251,
20356
- "kind": 342,
20357
- "id": 0,
20358
- "flags": 16842752,
20359
- "modifierFlagsCache": 0,
20360
- "transformFlags": 0,
20361
- "tagName": {
20362
- "pos": 4202,
20363
- "end": 4207,
20364
- "kind": 80,
20365
- "id": 0,
20366
- "flags": 16842752,
20367
- "transformFlags": 0,
20368
- "escapedText": "param"
20369
- },
20370
- "comment": "<p>Click event on the input element.</p>\n",
20371
- "name": {
20372
- "pos": 4208,
20373
- "end": 4211,
20374
- "kind": 80,
20375
- "id": 0,
20376
- "flags": 16842752,
20377
- "transformFlags": 0,
20378
- "escapedText": "evt"
20379
- },
20380
- "isNameFirst": true,
20381
- "isBracketed": false
20382
- }
20383
- ],
20384
- "line": 139
20385
- }
20386
- ],
20146
+ "hostBindings": [],
20147
+ "hostListeners": [],
20387
20148
  "propertiesClass": [
20388
20149
  {
20389
20150
  "name": "ngControl",
@@ -20395,7 +20156,7 @@
20395
20156
  "indexKey": "",
20396
20157
  "optional": false,
20397
20158
  "description": "",
20398
- "line": 33,
20159
+ "line": 41,
20399
20160
  "rawdescription": "\n",
20400
20161
  "modifierKind": [
20401
20162
  124
@@ -20411,17 +20172,8 @@
20411
20172
  "indexKey": "",
20412
20173
  "optional": false,
20413
20174
  "description": "<p>Host binding to define input type as &#39;file&#39;.</p>\n",
20414
- "line": 71,
20415
- "rawdescription": "\n\nHost binding to define input type as 'file'.\n",
20416
- "decorators": [
20417
- {
20418
- "name": "HostBinding",
20419
- "stringifiedArguments": "'attr.type'"
20420
- }
20421
- ],
20422
- "modifierKind": [
20423
- 171
20424
- ]
20175
+ "line": 76,
20176
+ "rawdescription": "\n\nHost binding to define input type as 'file'.\n"
20425
20177
  }
20426
20178
  ],
20427
20179
  "methodsClass": [
@@ -20432,7 +20184,7 @@
20432
20184
  "optional": false,
20433
20185
  "returnType": "void",
20434
20186
  "typeParameters": [],
20435
- "line": 127,
20187
+ "line": 130,
20436
20188
  "deprecated": false,
20437
20189
  "deprecationMessage": "",
20438
20190
  "rawdescription": "\n\nChecks component state during change detection to toggle the disabled state of internal elements.\n",
@@ -20445,7 +20197,7 @@
20445
20197
  "optional": false,
20446
20198
  "returnType": "void",
20447
20199
  "typeParameters": [],
20448
- "line": 119,
20200
+ "line": 122,
20449
20201
  "deprecated": false,
20450
20202
  "deprecationMessage": "",
20451
20203
  "rawdescription": "\n\nClean up resources and RxJS subscriptions.\n",
@@ -20458,7 +20210,7 @@
20458
20210
  "optional": false,
20459
20211
  "returnType": "void",
20460
20212
  "typeParameters": [],
20461
- "line": 109,
20213
+ "line": 112,
20462
20214
  "deprecated": false,
20463
20215
  "deprecationMessage": "",
20464
20216
  "rawdescription": "\n\nInitializes component structure and translation subscription (browser-only).\n",
@@ -20480,25 +20232,16 @@
20480
20232
  "optional": false,
20481
20233
  "returnType": "void",
20482
20234
  "typeParameters": [],
20483
- "line": 139,
20235
+ "line": 142,
20484
20236
  "deprecated": false,
20485
20237
  "deprecationMessage": "",
20486
20238
  "rawdescription": "\n\nPrevents file dialog from opening when component is disabled.\n",
20487
20239
  "description": "<p>Prevents file dialog from opening when component is disabled.</p>\n",
20488
- "decorators": [
20489
- {
20490
- "name": "HostListener",
20491
- "stringifiedArguments": "'click', ['$event']"
20492
- }
20493
- ],
20494
- "modifierKind": [
20495
- 171
20496
- ],
20497
20240
  "jsdoctags": [
20498
20241
  {
20499
20242
  "name": {
20500
- "pos": 4208,
20501
- "end": 4211,
20243
+ "pos": 4337,
20244
+ "end": 4340,
20502
20245
  "kind": 80,
20503
20246
  "id": 0,
20504
20247
  "flags": 16842752,
@@ -20511,8 +20254,8 @@
20511
20254
  "deprecated": false,
20512
20255
  "deprecationMessage": "",
20513
20256
  "tagName": {
20514
- "pos": 4202,
20515
- "end": 4207,
20257
+ "pos": 4331,
20258
+ "end": 4336,
20516
20259
  "kind": 80,
20517
20260
  "id": 0,
20518
20261
  "flags": 16842752,
@@ -20539,25 +20282,16 @@
20539
20282
  "optional": false,
20540
20283
  "returnType": "void",
20541
20284
  "typeParameters": [],
20542
- "line": 149,
20285
+ "line": 152,
20543
20286
  "deprecated": false,
20544
20287
  "deprecationMessage": "",
20545
20288
  "rawdescription": "\n\nHandles file selection and emits a structured file selection event.\n",
20546
20289
  "description": "<p>Handles file selection and emits a structured file selection event.</p>\n",
20547
- "decorators": [
20548
- {
20549
- "name": "HostListener",
20550
- "stringifiedArguments": "'change', ['$event']"
20551
- }
20552
- ],
20553
- "modifierKind": [
20554
- 171
20555
- ],
20556
20290
  "jsdoctags": [
20557
20291
  {
20558
20292
  "name": {
20559
- "pos": 4500,
20560
- "end": 4503,
20293
+ "pos": 4594,
20294
+ "end": 4597,
20561
20295
  "kind": 80,
20562
20296
  "id": 0,
20563
20297
  "flags": 16842752,
@@ -20570,8 +20304,8 @@
20570
20304
  "deprecated": false,
20571
20305
  "deprecationMessage": "",
20572
20306
  "tagName": {
20573
- "pos": 4494,
20574
- "end": 4499,
20307
+ "pos": 4588,
20308
+ "end": 4593,
20575
20309
  "kind": 80,
20576
20310
  "id": 0,
20577
20311
  "flags": 16842752,
@@ -20624,8 +20358,8 @@
20624
20358
  "coverageIgnore": false,
20625
20359
  "jsdoctags": [
20626
20360
  {
20627
- "pos": 667,
20628
- "end": 869,
20361
+ "pos": 632,
20362
+ "end": 834,
20629
20363
  "kind": 321,
20630
20364
  "id": 0,
20631
20365
  "flags": 16777216,
@@ -20649,7 +20383,7 @@
20649
20383
  "name": "cssClasses",
20650
20384
  "type": "string",
20651
20385
  "returnType": "string",
20652
- "line": 89,
20386
+ "line": 93,
20653
20387
  "rawdescription": "\n\nApplies the base `ecl-file-upload` class to the host element.\n",
20654
20388
  "description": "<p>Applies the base <code>ecl-file-upload</code> class to the host element.</p>\n"
20655
20389
  }
@@ -20660,7 +20394,7 @@
20660
20394
  "name": "invalidState",
20661
20395
  "type": "boolean",
20662
20396
  "returnType": "boolean",
20663
- "line": 98,
20397
+ "line": 101,
20664
20398
  "rawdescription": "\n\nReturns `true` if component should be displayed as invalid.\nPrioritizes Angular form control status over `isInvalid` input.\n",
20665
20399
  "description": "<p>Returns <code>true</code> if component should be displayed as invalid.\nPrioritizes Angular form control status over <code>isInvalid</code> input.</p>\n"
20666
20400
  }
@@ -50424,18 +50158,13 @@
50424
50158
  },
50425
50159
  {
50426
50160
  "name": "EclDateBlockComponent",
50427
- "id": "component-EclDateBlockComponent-13399b80b6dc7dce105216bc6198f95c2ee58313355907e1dd1bdb2a242a641c3894694a0ffc909e261c64973fc4a3074e8f8a5d360a66b12886ccd650e223d1",
50161
+ "id": "component-EclDateBlockComponent-d9d6a513627794cc2674cf854797813269cbdd31b9d32310cd714ec65c83a83fe2760430a07643b40187cdf4c8207b7f85999cb06622b72758552cb5f56dfbd7",
50428
50162
  "file": "packages/ecl/components/ecl-date-block/ecl-date-block.component.ts",
50429
50163
  "encapsulation": [],
50430
50164
  "entryComponents": [],
50431
50165
  "inputs": [],
50432
50166
  "outputs": [],
50433
- "providers": [
50434
- {
50435
- "name": "TranslateService",
50436
- "type": "injectable"
50437
- }
50438
- ],
50167
+ "providers": [],
50439
50168
  "selector": "time[eclDateBlock]",
50440
50169
  "styleUrls": [],
50441
50170
  "styles": [],
@@ -50453,7 +50182,7 @@
50453
50182
  "deprecationMessage": "",
50454
50183
  "rawdescription": "\n\nSets the `datetime` attribute of the `<time>` element.\nIf not provided, it is derived from `date` and `dateFormat`.\n",
50455
50184
  "description": "<p>Sets the <code>datetime</code> attribute of the <code>&lt;time&gt;</code> element.\nIf not provided, it is derived from <code>date</code> and <code>dateFormat</code>.</p>\n",
50456
- "line": 97,
50185
+ "line": 96,
50457
50186
  "type": "string",
50458
50187
  "decorators": []
50459
50188
  },
@@ -50467,7 +50196,7 @@
50467
50196
  "indexKey": "",
50468
50197
  "optional": false,
50469
50198
  "description": "<p>The date to be displayed. If not null, it&#39;s used to generate the <code>datetime</code> attribute and visual output.</p>\n",
50470
- "line": 45,
50199
+ "line": 44,
50471
50200
  "rawdescription": "\n\nThe date to be displayed. If not null, it's used to generate the `datetime` attribute and visual output.\n",
50472
50201
  "modifierKind": [
50473
50202
  148
@@ -50484,7 +50213,7 @@
50484
50213
  "indexKey": "",
50485
50214
  "optional": false,
50486
50215
  "description": "<p>The format to be used when rendering the date string (Angular DatePipe format).\nDefault is <code>&#39;dd/M/yyyy&#39;</code>.</p>\n",
50487
- "line": 51,
50216
+ "line": 50,
50488
50217
  "rawdescription": "\n\nThe format to be used when rendering the date string (Angular DatePipe format).\nDefault is `'dd/M/yyyy'`.\n",
50489
50218
  "modifierKind": [
50490
50219
  148
@@ -50501,7 +50230,7 @@
50501
50230
  "indexKey": "",
50502
50231
  "optional": false,
50503
50232
  "description": "<p>Explicit string for day part of the date (optional).\nUsed when date is not set or overridden manually.</p>\n",
50504
- "line": 65,
50233
+ "line": 64,
50505
50234
  "rawdescription": "\n\nExplicit string for day part of the date (optional).\nUsed when date is not set or overridden manually.\n",
50506
50235
  "modifierKind": [
50507
50236
  148
@@ -50518,7 +50247,7 @@
50518
50247
  "indexKey": "",
50519
50248
  "optional": false,
50520
50249
  "description": "<p>Explicit string for month part of the date (optional).\nUsed when date is not set or overridden manually.</p>\n",
50521
- "line": 71,
50250
+ "line": 70,
50522
50251
  "rawdescription": "\n\nExplicit string for month part of the date (optional).\nUsed when date is not set or overridden manually.\n",
50523
50252
  "modifierKind": [
50524
50253
  148
@@ -50535,7 +50264,7 @@
50535
50264
  "indexKey": "",
50536
50265
  "optional": false,
50537
50266
  "description": "<p>Explicit string used as an accessible or verbose label for the month (optional).</p>\n",
50538
- "line": 76,
50267
+ "line": 75,
50539
50268
  "rawdescription": "\n\nExplicit string used as an accessible or verbose label for the month (optional).\n",
50540
50269
  "modifierKind": [
50541
50270
  148
@@ -50552,7 +50281,7 @@
50552
50281
  "indexKey": "",
50553
50282
  "optional": false,
50554
50283
  "description": "<p>Optional visual variant of the date block. Can be:</p>\n<ul>\n<li><code>&#39;ongoing&#39;</code>: for ongoing events</li>\n<li><code>&#39;past&#39;</code>: for past events\nThis changes styling only.</li>\n</ul>\n",
50555
- "line": 59,
50284
+ "line": 58,
50556
50285
  "rawdescription": "\n\nOptional visual variant of the date block. Can be:\n- `'ongoing'`: for ongoing events\n- `'past'`: for past events\nThis changes styling only.\n",
50557
50286
  "modifierKind": [
50558
50287
  148
@@ -50569,7 +50298,7 @@
50569
50298
  "indexKey": "",
50570
50299
  "optional": false,
50571
50300
  "description": "<p>Explicit string for year part of the date (optional).\nUsed when date is not set or overridden manually.</p>\n",
50572
- "line": 82,
50301
+ "line": 81,
50573
50302
  "rawdescription": "\n\nExplicit string for year part of the date (optional).\nUsed when date is not set or overridden manually.\n",
50574
50303
  "modifierKind": [
50575
50304
  148
@@ -50632,7 +50361,7 @@
50632
50361
  "indexKey": "",
50633
50362
  "optional": false,
50634
50363
  "description": "",
50635
- "line": 84,
50364
+ "line": 83,
50636
50365
  "rawdescription": "\n"
50637
50366
  }
50638
50367
  ],
@@ -50688,7 +50417,7 @@
50688
50417
  "deprecationMessage": "",
50689
50418
  "rawdescription": "\n",
50690
50419
  "description": "",
50691
- "line": 86,
50420
+ "line": 85,
50692
50421
  "type": "string",
50693
50422
  "decorators": []
50694
50423
  }
@@ -50704,7 +50433,7 @@
50704
50433
  "description": "<p>Component used to display a formatted date in a styled time element.\nDesigned for use within content components such as content blocks or items.</p>\n",
50705
50434
  "rawdescription": "\n\nComponent used to display a formatted date in a styled time element.\nDesigned for use within content components such as content blocks or items.\n",
50706
50435
  "type": "component",
50707
- "sourceCode": "import { formatDate, DatePipe } from '@angular/common';\nimport { Component, Input, HostBinding, inject, input } from '@angular/core';\nimport '@angular/common/locales/global/bg';\nimport '@angular/common/locales/global/da';\nimport '@angular/common/locales/global/en';\nimport '@angular/common/locales/global/et';\nimport '@angular/common/locales/global/fr';\nimport '@angular/common/locales/global/hr';\nimport '@angular/common/locales/global/lv';\nimport '@angular/common/locales/global/hu';\nimport '@angular/common/locales/global/nl';\nimport '@angular/common/locales/global/pt';\nimport '@angular/common/locales/global/sk';\nimport '@angular/common/locales/global/fi';\nimport '@angular/common/locales/global/cs';\nimport '@angular/common/locales/global/de';\nimport '@angular/common/locales/global/el';\nimport '@angular/common/locales/global/es';\nimport '@angular/common/locales/global/ga';\nimport '@angular/common/locales/global/it';\nimport '@angular/common/locales/global/lt';\nimport '@angular/common/locales/global/mt';\nimport '@angular/common/locales/global/pl';\nimport '@angular/common/locales/global/ro';\nimport '@angular/common/locales/global/sl';\nimport '@angular/common/locales/global/sv';\nimport { TranslateService } from '@ngx-translate/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Component used to display a formatted date in a styled time element.\n * Designed for use within content components such as content blocks or items.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'time[eclDateBlock]',\n templateUrl: './ecl-date-block.component.html',\n imports: [DatePipe],\n providers: [TranslateService],\n})\nexport class EclDateBlockComponent extends ECLBaseDirective {\n /**\n * The date to be displayed. If not null, it's used to generate the `datetime` attribute and visual output.\n */\n readonly date = input<Date>(undefined);\n\n /**\n * The format to be used when rendering the date string (Angular DatePipe format).\n * Default is `'dd/M/yyyy'`.\n */\n readonly dateFormat = input('dd/M/yyyy');\n\n /**\n * Optional visual variant of the date block. Can be:\n * - `'ongoing'`: for ongoing events\n * - `'past'`: for past events\n * This changes styling only.\n */\n readonly variant = input<'ongoing' | 'past'>(null);\n\n /**\n * Explicit string for day part of the date (optional).\n * Used when date is not set or overridden manually.\n */\n readonly day = input<string>(undefined);\n\n /**\n * Explicit string for month part of the date (optional).\n * Used when date is not set or overridden manually.\n */\n readonly month = input<string>(undefined);\n\n /**\n * Explicit string used as an accessible or verbose label for the month (optional).\n */\n readonly monthTitle = input<string>(undefined);\n\n /**\n * Explicit string for year part of the date (optional).\n * Used when date is not set or overridden manually.\n */\n readonly year = input<string>(undefined);\n\n locale = 'en';\n @HostBinding('class')\n get cssClasses(): string {\n const variant = this.variant();\n return [super.getCssClasses('ecl-date-block'), variant ? `ecl-date-block--${variant}` : ''].join(' ').trim();\n }\n\n /**\n * Sets the `datetime` attribute of the `<time>` element.\n * If not provided, it is derived from `date` and `dateFormat`.\n */\n @Input()\n @HostBinding('attr.datetime')\n get datetime(): string {\n return this.getDatetime();\n }\n set datetime(value) {\n this._datetime = value;\n }\n private _datetime: string = null;\n private translateService = inject(TranslateService);\n\n constructor() {\n super();\n const translateService = this.translateService;\n\n this.locale = translateService.currentLang();\n }\n\n private getDatetime(): string {\n return this._datetime || this.getFormattedDate(this.date(), this.dateFormat());\n }\n\n private getFormattedDate(date: Date, dateFormat: string): string {\n if (date) {\n return formatDate(date, dateFormat, this.translateService.currentLang());\n } else {\n return null;\n }\n }\n}\n",
50436
+ "sourceCode": "import { formatDate, DatePipe } from '@angular/common';\nimport { Component, Input, HostBinding, inject, input } from '@angular/core';\nimport '@angular/common/locales/global/bg';\nimport '@angular/common/locales/global/da';\nimport '@angular/common/locales/global/en';\nimport '@angular/common/locales/global/et';\nimport '@angular/common/locales/global/fr';\nimport '@angular/common/locales/global/hr';\nimport '@angular/common/locales/global/lv';\nimport '@angular/common/locales/global/hu';\nimport '@angular/common/locales/global/nl';\nimport '@angular/common/locales/global/pt';\nimport '@angular/common/locales/global/sk';\nimport '@angular/common/locales/global/fi';\nimport '@angular/common/locales/global/cs';\nimport '@angular/common/locales/global/de';\nimport '@angular/common/locales/global/el';\nimport '@angular/common/locales/global/es';\nimport '@angular/common/locales/global/ga';\nimport '@angular/common/locales/global/it';\nimport '@angular/common/locales/global/lt';\nimport '@angular/common/locales/global/mt';\nimport '@angular/common/locales/global/pl';\nimport '@angular/common/locales/global/ro';\nimport '@angular/common/locales/global/sl';\nimport '@angular/common/locales/global/sv';\nimport { TranslateService } from '@ngx-translate/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n/**\n * Component used to display a formatted date in a styled time element.\n * Designed for use within content components such as content blocks or items.\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'time[eclDateBlock]',\n templateUrl: './ecl-date-block.component.html',\n imports: [DatePipe],\n})\nexport class EclDateBlockComponent extends ECLBaseDirective {\n /**\n * The date to be displayed. If not null, it's used to generate the `datetime` attribute and visual output.\n */\n readonly date = input<Date>(undefined);\n\n /**\n * The format to be used when rendering the date string (Angular DatePipe format).\n * Default is `'dd/M/yyyy'`.\n */\n readonly dateFormat = input('dd/M/yyyy');\n\n /**\n * Optional visual variant of the date block. Can be:\n * - `'ongoing'`: for ongoing events\n * - `'past'`: for past events\n * This changes styling only.\n */\n readonly variant = input<'ongoing' | 'past'>(null);\n\n /**\n * Explicit string for day part of the date (optional).\n * Used when date is not set or overridden manually.\n */\n readonly day = input<string>(undefined);\n\n /**\n * Explicit string for month part of the date (optional).\n * Used when date is not set or overridden manually.\n */\n readonly month = input<string>(undefined);\n\n /**\n * Explicit string used as an accessible or verbose label for the month (optional).\n */\n readonly monthTitle = input<string>(undefined);\n\n /**\n * Explicit string for year part of the date (optional).\n * Used when date is not set or overridden manually.\n */\n readonly year = input<string>(undefined);\n\n locale = 'en';\n @HostBinding('class')\n get cssClasses(): string {\n const variant = this.variant();\n return [super.getCssClasses('ecl-date-block'), variant ? `ecl-date-block--${variant}` : ''].join(' ').trim();\n }\n\n /**\n * Sets the `datetime` attribute of the `<time>` element.\n * If not provided, it is derived from `date` and `dateFormat`.\n */\n @Input()\n @HostBinding('attr.datetime')\n get datetime(): string {\n return this.getDatetime();\n }\n set datetime(value) {\n this._datetime = value;\n }\n private _datetime: string = null;\n private translateService = inject(TranslateService);\n\n constructor() {\n super();\n const translateService = this.translateService;\n\n this.locale = translateService.currentLang();\n }\n\n private getDatetime(): string {\n return this._datetime || this.getFormattedDate(this.date(), this.dateFormat());\n }\n\n private getFormattedDate(date: Date, dateFormat: string): string {\n if (date) {\n return formatDate(date, dateFormat, this.translateService.currentLang());\n } else {\n return null;\n }\n }\n}\n",
50708
50437
  "assetsDirs": [],
50709
50438
  "styleUrlsData": "",
50710
50439
  "stylesData": "",
@@ -50726,7 +50455,7 @@
50726
50455
  "deprecated": false,
50727
50456
  "deprecationMessage": "",
50728
50457
  "args": [],
50729
- "line": 104,
50458
+ "line": 103,
50730
50459
  "rawdescription": "\n"
50731
50460
  },
50732
50461
  "extends": [
@@ -50739,7 +50468,7 @@
50739
50468
  "name": "cssClasses",
50740
50469
  "type": "string",
50741
50470
  "returnType": "string",
50742
- "line": 86,
50471
+ "line": 85,
50743
50472
  "rawdescription": "\n",
50744
50473
  "description": ""
50745
50474
  }
@@ -50762,7 +50491,7 @@
50762
50491
  }
50763
50492
  ],
50764
50493
  "returnType": "void",
50765
- "line": 100,
50494
+ "line": 99,
50766
50495
  "rawdescription": "\n",
50767
50496
  "description": "",
50768
50497
  "jsdoctags": [
@@ -50783,7 +50512,7 @@
50783
50512
  "name": "datetime",
50784
50513
  "type": "string",
50785
50514
  "returnType": "string",
50786
- "line": 97,
50515
+ "line": 96,
50787
50516
  "rawdescription": "\n\nSets the `datetime` attribute of the `<time>` element.\nIf not provided, it is derived from `date` and `dateFormat`.\n",
50788
50517
  "description": "<p>Sets the <code>datetime</code> attribute of the <code>&lt;time&gt;</code> element.\nIf not provided, it is derived from <code>date</code> and <code>dateFormat</code>.</p>\n"
50789
50518
  }
@@ -50796,10 +50525,6 @@
50796
50525
  "name": "DatePipe",
50797
50526
  "type": "pipe"
50798
50527
  },
50799
- {
50800
- "name": "TranslateService",
50801
- "type": "injectable"
50802
- },
50803
50528
  {
50804
50529
  "name": "ECLBaseDirective",
50805
50530
  "type": "directive"
@@ -58188,7 +57913,7 @@
58188
57913
  },
58189
57914
  {
58190
57915
  "name": "EclInpageNavigationComponent",
58191
- "id": "component-EclInpageNavigationComponent-218decdcd6a7c68437e5d7e1d602b3cd8612271e9c1069d063d5d1f05e7f6c61f23a6fb4404b9d14cd21d0f249849eacc4c32a956fb3054803a25ed4469f0623",
57916
+ "id": "component-EclInpageNavigationComponent-5daafc90fdb4dbac03101fb1ec926edaec22dde8c7ba4699dcece0f2c2d48f01b9c51ed69bb59e72fd63be3a46eae2803257a7e8309d6a6dc7f5932d3148a469",
58192
57917
  "file": "packages/ecl/components/ecl-inpage-navigation/ecl-inpage-navigation.component.ts",
58193
57918
  "encapsulation": [],
58194
57919
  "entryComponents": [],
@@ -58497,7 +58222,7 @@
58497
58222
  "optional": false,
58498
58223
  "returnType": "void",
58499
58224
  "typeParameters": [],
58500
- "line": 105,
58225
+ "line": 111,
58501
58226
  "deprecated": false,
58502
58227
  "deprecationMessage": "",
58503
58228
  "rawdescription": "\n",
@@ -58510,7 +58235,7 @@
58510
58235
  "optional": false,
58511
58236
  "returnType": "void",
58512
58237
  "typeParameters": [],
58513
- "line": 144,
58238
+ "line": 150,
58514
58239
  "deprecated": false,
58515
58240
  "deprecationMessage": "",
58516
58241
  "rawdescription": "\n",
@@ -58523,7 +58248,7 @@
58523
58248
  "optional": false,
58524
58249
  "returnType": "void",
58525
58250
  "typeParameters": [],
58526
- "line": 153,
58251
+ "line": 159,
58527
58252
  "deprecated": false,
58528
58253
  "deprecationMessage": "",
58529
58254
  "rawdescription": "\n",
@@ -58536,7 +58261,7 @@
58536
58261
  "optional": false,
58537
58262
  "returnType": "void",
58538
58263
  "typeParameters": [],
58539
- "line": 101,
58264
+ "line": 107,
58540
58265
  "deprecated": false,
58541
58266
  "deprecationMessage": "",
58542
58267
  "rawdescription": "\n",
@@ -58549,7 +58274,7 @@
58549
58274
  "optional": false,
58550
58275
  "returnType": "void",
58551
58276
  "typeParameters": [],
58552
- "line": 166,
58277
+ "line": 172,
58553
58278
  "deprecated": false,
58554
58279
  "deprecationMessage": "",
58555
58280
  "rawdescription": "\n\nOn mobile view - handle the dropdown toggle.\n",
@@ -58571,7 +58296,7 @@
58571
58296
  "optional": false,
58572
58297
  "returnType": "void",
58573
58298
  "typeParameters": [],
58574
- "line": 175,
58299
+ "line": 189,
58575
58300
  "deprecated": false,
58576
58301
  "deprecationMessage": "",
58577
58302
  "rawdescription": "\n\nDropdown keyboard navigation on mobile view.\n",
@@ -58579,8 +58304,8 @@
58579
58304
  "jsdoctags": [
58580
58305
  {
58581
58306
  "name": {
58582
- "pos": 7260,
58583
- "end": 7263,
58307
+ "pos": 7926,
58308
+ "end": 7929,
58584
58309
  "kind": 80,
58585
58310
  "id": 0,
58586
58311
  "flags": 16842752,
@@ -58593,8 +58318,8 @@
58593
58318
  "deprecated": false,
58594
58319
  "deprecationMessage": "",
58595
58320
  "tagName": {
58596
- "pos": 7254,
58597
- "end": 7259,
58321
+ "pos": 7920,
58322
+ "end": 7925,
58598
58323
  "kind": 80,
58599
58324
  "id": 0,
58600
58325
  "flags": 16842752,
@@ -58665,14 +58390,14 @@
58665
58390
  "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",
58666
58391
  "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",
58667
58392
  "type": "component",
58668
- "sourceCode": "import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';\nimport { CdkScrollable, ScrollDispatcher, ViewportRuler } from '@angular/cdk/scrolling';\nimport { AfterViewInit, ChangeDetectorRef, Component, DOCUMENT, DoCheck, ElementRef, IterableDiffer, IterableDiffers, NgZone, OnDestroy, OnInit, PLATFORM_ID, afterNextRender, inject, numberAttribute, output, input, viewChild, contentChildren, contentChild } 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';\nimport { isPlatformBrowser } from '@angular/common';\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 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.isButtonExpanded = !this.isButtonExpanded;\n this.eclInpageNavigationService.eclInpageNavigationToggle(this.isButtonExpanded);\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.isButtonExpanded = 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 item.sectionElement.scrollIntoView();\n item.sectionElement.focus();\n }\n this.isButtonExpanded = false;\n });\n }\n\n private onItemEnter(item: EclInpageNavigationItemComponent): void {\n this.selectNavigationItem(item.sectionElement);\n if (item.sectionElement) {\n item.sectionElement.scrollIntoView();\n if (item.sectionElement.tabIndex === -1) {\n item.sectionElement.tabIndex = 0;\n item.sectionElement.focus();\n item.sectionElement.tabIndex = -1;\n }\n }\n this.isButtonExpanded = false;\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.isButtonExpanded = 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 const offset = 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",
58393
+ "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",
58669
58394
  "assetsDirs": [],
58670
58395
  "styleUrlsData": "",
58671
58396
  "stylesData": "\n @media (min-width: 996px) {\n .ecl-inpage-navigation__list {\n display: block !important;\n }\n }\n \n",
58672
58397
  "jsdoctags": [
58673
58398
  {
58674
- "pos": 1277,
58675
- "end": 1754,
58399
+ "pos": 1262,
58400
+ "end": 1739,
58676
58401
  "kind": 321,
58677
58402
  "id": 0,
58678
58403
  "flags": 16777216,
@@ -58687,7 +58412,7 @@
58687
58412
  "deprecated": false,
58688
58413
  "deprecationMessage": "",
58689
58414
  "args": [],
58690
- "line": 91,
58415
+ "line": 97,
58691
58416
  "rawdescription": "\n"
58692
58417
  },
58693
58418
  "extends": [
@@ -58706,7 +58431,7 @@
58706
58431
  "name": "hasNavigationList",
58707
58432
  "type": "boolean",
58708
58433
  "returnType": "boolean",
58709
- "line": 121,
58434
+ "line": 127,
58710
58435
  "rawdescription": "\n",
58711
58436
  "description": ""
58712
58437
  }
@@ -58717,7 +58442,7 @@
58717
58442
  "name": "currentNavigationLinkItem",
58718
58443
  "type": "unknown",
58719
58444
  "returnType": "EclInpageNavigationItemComponent",
58720
- "line": 125,
58445
+ "line": 131,
58721
58446
  "rawdescription": "\n",
58722
58447
  "description": ""
58723
58448
  }
@@ -58728,7 +58453,7 @@
58728
58453
  "name": "sizeIcon",
58729
58454
  "type": "string",
58730
58455
  "returnType": "string",
58731
- "line": 132,
58456
+ "line": 138,
58732
58457
  "rawdescription": "\n\nthe size of the arrow-down icon, used in mobile view. There are different sizes for EC and EU themes.\n",
58733
58458
  "description": "<p>the size of the arrow-down icon, used in mobile view. There are different sizes for EC and EU themes.</p>\n"
58734
58459
  }
@@ -58739,7 +58464,7 @@
58739
58464
  "name": "hasActiveSection",
58740
58465
  "type": "boolean",
58741
58466
  "returnType": "boolean",
58742
- "line": 140,
58467
+ "line": 146,
58743
58468
  "rawdescription": "\n",
58744
58469
  "description": ""
58745
58470
  }
@@ -64991,7 +64716,7 @@
64991
64716
  },
64992
64717
  {
64993
64718
  "name": "EclMenuItemComponent",
64994
- "id": "component-EclMenuItemComponent-faf8f48747e3fb73e8ffeeb94f71ae8c4d5a06d40a4f45ded7bef8ccc35eb12e3969e37df8239bb1e7d53fb4be6b57c09f5203d1bb1ea35777405a1b268c9690",
64719
+ "id": "component-EclMenuItemComponent-34f452bf97feb65169901e0c06a1fb0de14d012edd6ec1567c23c2a3ff5f8da70e3e579ec2af4034ca2d8cca1fa411c32b4c899c2b8dfc1e89d67142e51d0cb8",
64995
64720
  "file": "packages/ecl/components/ecl-menu/ecl-menu/ecl-menu-item.component.ts",
64996
64721
  "encapsulation": [
64997
64722
  "ViewEncapsulation.None"
@@ -65019,7 +64744,7 @@
65019
64744
  "deprecationMessage": "",
65020
64745
  "rawdescription": "\n",
65021
64746
  "description": "",
65022
- "line": 77,
64747
+ "line": 78,
65023
64748
  "type": "string",
65024
64749
  "decorators": []
65025
64750
  },
@@ -65030,19 +64755,20 @@
65030
64755
  "deprecationMessage": "",
65031
64756
  "rawdescription": "\n",
65032
64757
  "description": "",
65033
- "line": 67,
64758
+ "line": 68,
65034
64759
  "type": "string",
65035
64760
  "decorators": []
65036
64761
  },
65037
64762
  {
65038
64763
  "coverageIgnore": false,
64764
+ "required": false,
65039
64765
  "name": "isCurrent",
65040
64766
  "defaultValue": "false",
65041
64767
  "deprecated": false,
65042
64768
  "deprecationMessage": "",
65043
64769
  "rawdescription": "\n",
65044
64770
  "description": "",
65045
- "line": 79,
64771
+ "line": 80,
65046
64772
  "type": "boolean",
65047
64773
  "decorators": []
65048
64774
  },
@@ -65053,7 +64779,7 @@
65053
64779
  "deprecationMessage": "",
65054
64780
  "rawdescription": "\n",
65055
64781
  "description": "",
65056
- "line": 68,
64782
+ "line": 69,
65057
64783
  "type": "string",
65058
64784
  "decorators": []
65059
64785
  },
@@ -65067,7 +64793,7 @@
65067
64793
  "indexKey": "",
65068
64794
  "optional": false,
65069
64795
  "description": "<p>Custom attributes, to be added to the <a> tag of the menu item.</p>\n",
65070
- "line": 83,
64796
+ "line": 84,
65071
64797
  "rawdescription": "\n\nCustom attributes, to be added to the <a> tag of the menu item.\n",
65072
64798
  "modifierKind": [
65073
64799
  148
@@ -65084,7 +64810,7 @@
65084
64810
  "indexKey": "",
65085
64811
  "optional": false,
65086
64812
  "description": "",
65087
- "line": 75,
64813
+ "line": 76,
65088
64814
  "rawdescription": "\n",
65089
64815
  "modifierKind": [
65090
64816
  148
@@ -65101,7 +64827,7 @@
65101
64827
  "indexKey": "",
65102
64828
  "optional": false,
65103
64829
  "description": "",
65104
- "line": 76,
64830
+ "line": 77,
65105
64831
  "rawdescription": "\n",
65106
64832
  "modifierKind": [
65107
64833
  148
@@ -65118,7 +64844,7 @@
65118
64844
  "indexKey": "",
65119
64845
  "optional": false,
65120
64846
  "description": "",
65121
- "line": 74,
64847
+ "line": 75,
65122
64848
  "rawdescription": "\n",
65123
64849
  "modifierKind": [
65124
64850
  148
@@ -65135,7 +64861,7 @@
65135
64861
  "indexKey": "",
65136
64862
  "optional": false,
65137
64863
  "description": "",
65138
- "line": 78,
64864
+ "line": 79,
65139
64865
  "rawdescription": "\n",
65140
64866
  "modifierKind": [
65141
64867
  148
@@ -65152,7 +64878,7 @@
65152
64878
  "indexKey": "",
65153
64879
  "optional": false,
65154
64880
  "description": "<p>When in mobile view, use this property to set aria-label for the toggle items button (to expand item&#39;s children).</p>\n",
65155
- "line": 72,
64881
+ "line": 73,
65156
64882
  "rawdescription": "\n\nWhen in mobile view, use this property to set aria-label for the toggle items button (to expand item's children).\n",
65157
64883
  "modifierKind": [
65158
64884
  148
@@ -65210,7 +64936,7 @@
65210
64936
  "defaultValue": "new EventEmitter<EclMenuItemCaretEvent>()",
65211
64937
  "deprecated": false,
65212
64938
  "deprecationMessage": "",
65213
- "line": 125,
64939
+ "line": 126,
65214
64940
  "type": "EventEmitter"
65215
64941
  },
65216
64942
  {
@@ -65219,7 +64945,7 @@
65219
64945
  "defaultValue": "new EventEmitter<EclMenuItemFocusEvent>()",
65220
64946
  "deprecated": false,
65221
64947
  "deprecationMessage": "",
65222
- "line": 132,
64948
+ "line": 133,
65223
64949
  "type": "EventEmitter"
65224
64950
  },
65225
64951
  {
@@ -65230,7 +64956,7 @@
65230
64956
  "deprecationMessage": "",
65231
64957
  "rawdescription": "\n\nEvent that is emited on clicking the caret button to expand item's children in mobile mode.\n",
65232
64958
  "description": "<p>Event that is emited on clicking the caret button to expand item&#39;s children in mobile mode.</p>\n",
65233
- "line": 129,
64959
+ "line": 130,
65234
64960
  "type": "EventEmitter"
65235
64961
  },
65236
64962
  {
@@ -65239,7 +64965,7 @@
65239
64965
  "defaultValue": "new EventEmitter<EclMenuItemHoverOutEvent>()",
65240
64966
  "deprecated": false,
65241
64967
  "deprecationMessage": "",
65242
- "line": 130,
64968
+ "line": 131,
65243
64969
  "type": "EventEmitter"
65244
64970
  },
65245
64971
  {
@@ -65248,7 +64974,7 @@
65248
64974
  "defaultValue": "new EventEmitter<EclMenuItemKeydownEvent>()",
65249
64975
  "deprecated": false,
65250
64976
  "deprecationMessage": "",
65251
- "line": 133,
64977
+ "line": 134,
65252
64978
  "type": "EventEmitter"
65253
64979
  },
65254
64980
  {
@@ -65257,7 +64983,7 @@
65257
64983
  "defaultValue": "new EventEmitter<EclMenuItemSelectEvent>()",
65258
64984
  "deprecated": false,
65259
64985
  "deprecationMessage": "",
65260
- "line": 124,
64986
+ "line": 125,
65261
64987
  "type": "EventEmitter"
65262
64988
  },
65263
64989
  {
@@ -65266,7 +64992,7 @@
65266
64992
  "defaultValue": "new EventEmitter<EclMenuItemSelectEvent>()",
65267
64993
  "deprecated": false,
65268
64994
  "deprecationMessage": "",
65269
- "line": 131,
64995
+ "line": 132,
65270
64996
  "type": "EventEmitter"
65271
64997
  },
65272
64998
  {
@@ -65277,7 +65003,7 @@
65277
65003
  "deprecationMessage": "",
65278
65004
  "rawdescription": "\n\nThis event is emited when the keyboard nav reaches the last item in mobile view.\nThen the next focused element should be the 'close' btn.\n",
65279
65005
  "description": "<p>This event is emited when the keyboard nav reaches the last item in mobile view.\nThen the next focused element should be the &#39;close&#39; btn.</p>\n",
65280
- "line": 138,
65006
+ "line": 139,
65281
65007
  "type": "EventEmitter"
65282
65008
  }
65283
65009
  ],
@@ -65292,7 +65018,7 @@
65292
65018
  "indexKey": "",
65293
65019
  "optional": false,
65294
65020
  "description": "",
65295
- "line": 65,
65021
+ "line": 66,
65296
65022
  "rawdescription": "\n"
65297
65023
  },
65298
65024
  {
@@ -65304,7 +65030,7 @@
65304
65030
  "indexKey": "",
65305
65031
  "optional": false,
65306
65032
  "description": "",
65307
- "line": 85,
65033
+ "line": 86,
65308
65034
  "rawdescription": "\n"
65309
65035
  },
65310
65036
  {
@@ -65317,7 +65043,7 @@
65317
65043
  "indexKey": "",
65318
65044
  "optional": false,
65319
65045
  "description": "<p>Set to &#39;true&#39;, when item has more than 13 chidren and the overlay needs to use the full available space.</p>\n",
65320
- "line": 89,
65046
+ "line": 90,
65321
65047
  "rawdescription": "\n\nSet to 'true', when item has more than 13 chidren and the overlay needs to use the full available space.\n"
65322
65048
  },
65323
65049
  {
@@ -65330,7 +65056,7 @@
65330
65056
  "indexKey": "",
65331
65057
  "optional": false,
65332
65058
  "description": "",
65333
- "line": 90,
65059
+ "line": 91,
65334
65060
  "rawdescription": "\n"
65335
65061
  },
65336
65062
  {
@@ -65343,7 +65069,7 @@
65343
65069
  "indexKey": "",
65344
65070
  "optional": false,
65345
65071
  "description": "",
65346
- "line": 91,
65072
+ "line": 92,
65347
65073
  "rawdescription": "\n"
65348
65074
  },
65349
65075
  {
@@ -65356,7 +65082,7 @@
65356
65082
  "indexKey": "",
65357
65083
  "optional": false,
65358
65084
  "description": "<p>Used when menu has overlay, to show if the item is currently displayed.</p>\n",
65359
- "line": 95,
65085
+ "line": 96,
65360
65086
  "rawdescription": "\n\nUsed when menu has overlay, to show if the item is currently displayed.\n"
65361
65087
  },
65362
65088
  {
@@ -65369,7 +65095,7 @@
65369
65095
  "indexKey": "",
65370
65096
  "optional": false,
65371
65097
  "description": "<p>The <button> element of the menu item, when item has children.</p>\n",
65372
- "line": 122,
65098
+ "line": 123,
65373
65099
  "rawdescription": "\n\nThe <button> element of the menu item, when item has children.\n",
65374
65100
  "modifierKind": [
65375
65101
  148
@@ -65385,7 +65111,7 @@
65385
65111
  "indexKey": "",
65386
65112
  "optional": false,
65387
65113
  "description": "<p>The <a> element of the menu item, when there are no children.</p>\n",
65388
- "line": 118,
65114
+ "line": 119,
65389
65115
  "rawdescription": "\n\nThe <a> element of the menu item, when there are no children.\n",
65390
65116
  "modifierKind": [
65391
65117
  148
@@ -65401,7 +65127,7 @@
65401
65127
  "indexKey": "",
65402
65128
  "optional": false,
65403
65129
  "description": "",
65404
- "line": 114,
65130
+ "line": 115,
65405
65131
  "rawdescription": "\n",
65406
65132
  "modifierKind": [
65407
65133
  148
@@ -65433,7 +65159,7 @@
65433
65159
  "optional": false,
65434
65160
  "returnType": "void",
65435
65161
  "typeParameters": [],
65436
- "line": 360,
65162
+ "line": 374,
65437
65163
  "deprecated": false,
65438
65164
  "deprecationMessage": "",
65439
65165
  "rawdescription": "\n\nThis method calculates height and width of an item, depending the maximum of lines(rows) allowed.\nDepends on the 'maxLines' property of the parent menu component.\n",
@@ -65441,8 +65167,8 @@
65441
65167
  "jsdoctags": [
65442
65168
  {
65443
65169
  "name": {
65444
- "pos": 12055,
65445
- "end": 12063,
65170
+ "pos": 12705,
65171
+ "end": 12713,
65446
65172
  "kind": 80,
65447
65173
  "id": 0,
65448
65174
  "flags": 16842752,
@@ -65455,8 +65181,8 @@
65455
65181
  "deprecated": false,
65456
65182
  "deprecationMessage": "",
65457
65183
  "tagName": {
65458
- "pos": 12049,
65459
- "end": 12054,
65184
+ "pos": 12699,
65185
+ "end": 12704,
65460
65186
  "kind": 80,
65461
65187
  "id": 0,
65462
65188
  "flags": 16842752,
@@ -65467,8 +65193,8 @@
65467
65193
  },
65468
65194
  {
65469
65195
  "name": {
65470
- "pos": 12142,
65471
- "end": 12160,
65196
+ "pos": 12792,
65197
+ "end": 12810,
65472
65198
  "kind": 80,
65473
65199
  "id": 0,
65474
65200
  "flags": 16842752,
@@ -65481,8 +65207,8 @@
65481
65207
  "deprecated": false,
65482
65208
  "deprecationMessage": "",
65483
65209
  "tagName": {
65484
- "pos": 12136,
65485
- "end": 12141,
65210
+ "pos": 12786,
65211
+ "end": 12791,
65486
65212
  "kind": 80,
65487
65213
  "id": 0,
65488
65214
  "flags": 16842752,
@@ -65493,8 +65219,8 @@
65493
65219
  },
65494
65220
  {
65495
65221
  "tagName": {
65496
- "pos": 12169,
65497
- "end": 12176,
65222
+ "pos": 12819,
65223
+ "end": 12826,
65498
65224
  "kind": 80,
65499
65225
  "id": 0,
65500
65226
  "flags": 16842752,
@@ -65512,7 +65238,7 @@
65512
65238
  "optional": false,
65513
65239
  "returnType": "void",
65514
65240
  "typeParameters": [],
65515
- "line": 182,
65241
+ "line": 196,
65516
65242
  "deprecated": false,
65517
65243
  "deprecationMessage": "",
65518
65244
  "rawdescription": "\n",
@@ -65525,7 +65251,7 @@
65525
65251
  "optional": false,
65526
65252
  "returnType": "void",
65527
65253
  "typeParameters": [],
65528
- "line": 208,
65254
+ "line": 222,
65529
65255
  "deprecated": false,
65530
65256
  "deprecationMessage": "",
65531
65257
  "rawdescription": "\n",
@@ -65547,7 +65273,7 @@
65547
65273
  "optional": false,
65548
65274
  "returnType": "void",
65549
65275
  "typeParameters": [],
65550
- "line": 266,
65276
+ "line": 280,
65551
65277
  "deprecated": false,
65552
65278
  "deprecationMessage": "",
65553
65279
  "rawdescription": "\n\nManages the keyboard navigation when the current element is the button of the menu item.\n",
@@ -65555,8 +65281,8 @@
65555
65281
  "jsdoctags": [
65556
65282
  {
65557
65283
  "name": {
65558
- "pos": 8936,
65559
- "end": 8939,
65284
+ "pos": 9586,
65285
+ "end": 9589,
65560
65286
  "kind": 80,
65561
65287
  "id": 0,
65562
65288
  "flags": 16842752,
@@ -65569,8 +65295,8 @@
65569
65295
  "deprecated": false,
65570
65296
  "deprecationMessage": "",
65571
65297
  "tagName": {
65572
- "pos": 8930,
65573
- "end": 8935,
65298
+ "pos": 9580,
65299
+ "end": 9585,
65574
65300
  "kind": 80,
65575
65301
  "id": 0,
65576
65302
  "flags": 16842752,
@@ -65588,7 +65314,7 @@
65588
65314
  "optional": false,
65589
65315
  "returnType": "void",
65590
65316
  "typeParameters": [],
65591
- "line": 246,
65317
+ "line": 260,
65592
65318
  "deprecated": false,
65593
65319
  "deprecationMessage": "",
65594
65320
  "rawdescription": "\n\nManages the state when the item is focused, when navigating with keyboard and the navigation is coming from\n the next root menu item.\n",
@@ -65601,7 +65327,7 @@
65601
65327
  "optional": false,
65602
65328
  "returnType": "void",
65603
65329
  "typeParameters": [],
65604
- "line": 258,
65330
+ "line": 272,
65605
65331
  "deprecated": false,
65606
65332
  "deprecationMessage": "",
65607
65333
  "rawdescription": "\n\nManages the state when the item is focused, when navigating with keyboard and the navigation is coming from\n the previous root menu item.\n",
@@ -65614,7 +65340,7 @@
65614
65340
  "optional": false,
65615
65341
  "returnType": "void",
65616
65342
  "typeParameters": [],
65617
- "line": 236,
65343
+ "line": 250,
65618
65344
  "deprecated": false,
65619
65345
  "deprecationMessage": "",
65620
65346
  "rawdescription": "\n\nManages the state when the item is focused, when navigating with keyboard and the navigation is coming from the submenu.\n",
@@ -65636,7 +65362,7 @@
65636
65362
  "optional": false,
65637
65363
  "returnType": "void",
65638
65364
  "typeParameters": [],
65639
- "line": 229,
65365
+ "line": 243,
65640
65366
  "deprecated": false,
65641
65367
  "deprecationMessage": "",
65642
65368
  "rawdescription": "\n\nWhen clicking the caret button, to expand item's children. Used in mobile view.\n",
@@ -65644,8 +65370,8 @@
65644
65370
  "jsdoctags": [
65645
65371
  {
65646
65372
  "name": {
65647
- "pos": 7843,
65648
- "end": 7846,
65373
+ "pos": 8493,
65374
+ "end": 8496,
65649
65375
  "kind": 80,
65650
65376
  "id": 0,
65651
65377
  "flags": 16842752,
@@ -65658,8 +65384,8 @@
65658
65384
  "deprecated": false,
65659
65385
  "deprecationMessage": "",
65660
65386
  "tagName": {
65661
- "pos": 7837,
65662
- "end": 7842,
65387
+ "pos": 8487,
65388
+ "end": 8492,
65663
65389
  "kind": 80,
65664
65390
  "id": 0,
65665
65391
  "flags": 16842752,
@@ -65686,7 +65412,7 @@
65686
65412
  "optional": false,
65687
65413
  "returnType": "void",
65688
65414
  "typeParameters": [],
65689
- "line": 217,
65415
+ "line": 231,
65690
65416
  "deprecated": false,
65691
65417
  "deprecationMessage": "",
65692
65418
  "rawdescription": "\n",
@@ -65721,7 +65447,7 @@
65721
65447
  "optional": false,
65722
65448
  "returnType": "void",
65723
65449
  "typeParameters": [],
65724
- "line": 213,
65450
+ "line": 227,
65725
65451
  "deprecated": false,
65726
65452
  "deprecationMessage": "",
65727
65453
  "rawdescription": "\n",
@@ -65756,7 +65482,7 @@
65756
65482
  "optional": false,
65757
65483
  "returnType": "void",
65758
65484
  "typeParameters": [],
65759
- "line": 172,
65485
+ "line": 186,
65760
65486
  "deprecated": false,
65761
65487
  "deprecationMessage": "",
65762
65488
  "rawdescription": "\n",
@@ -65791,7 +65517,7 @@
65791
65517
  "optional": false,
65792
65518
  "returnType": "void",
65793
65519
  "typeParameters": [],
65794
- "line": 177,
65520
+ "line": 191,
65795
65521
  "deprecated": false,
65796
65522
  "deprecationMessage": "",
65797
65523
  "rawdescription": "\n",
@@ -65826,7 +65552,7 @@
65826
65552
  "optional": false,
65827
65553
  "returnType": "void",
65828
65554
  "typeParameters": [],
65829
- "line": 316,
65555
+ "line": 330,
65830
65556
  "deprecated": false,
65831
65557
  "deprecationMessage": "",
65832
65558
  "rawdescription": "\n\nManages the keyboard navigation when the current element is the <a> tag of the menu item.\n",
@@ -65834,8 +65560,8 @@
65834
65560
  "jsdoctags": [
65835
65561
  {
65836
65562
  "name": {
65837
- "pos": 10682,
65838
- "end": 10685,
65563
+ "pos": 11332,
65564
+ "end": 11335,
65839
65565
  "kind": 80,
65840
65566
  "id": 0,
65841
65567
  "flags": 16842752,
@@ -65848,8 +65574,8 @@
65848
65574
  "deprecated": false,
65849
65575
  "deprecationMessage": "",
65850
65576
  "tagName": {
65851
- "pos": 10676,
65852
- "end": 10681,
65577
+ "pos": 11326,
65578
+ "end": 11331,
65853
65579
  "kind": 80,
65854
65580
  "id": 0,
65855
65581
  "flags": 16842752,
@@ -65928,14 +65654,14 @@
65928
65654
  "description": "<p>This component represents a root menu item. Adds styling and functionality to menu item.</p>\n",
65929
65655
  "rawdescription": "\n\nThis component represents a root menu item. Adds styling and functionality to menu item.\n",
65930
65656
  "type": "component",
65931
- "sourceCode": "import { NgTemplateOutlet } from '@angular/common';\nimport {\n AfterContentInit,\n afterNextRender,\n Component,\n ElementRef,\n EventEmitter,\n forwardRef,\n inject,\n Input,\n OnDestroy,\n Output,\n Renderer2,\n ViewEncapsulation,\n DOCUMENT,\n input,\n contentChild,\n viewChild,\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 { EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { Subject } from 'rxjs';\nimport { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';\nimport { EclMenuMegaComponent } from '../ecl-menu-mega';\nimport {\n EclMenuItemCaretEvent,\n EclMenuItemFocusEvent,\n EclMenuItemHoverEvent,\n EclMenuItemHoverOutEvent,\n EclMenuItemKeydownEvent,\n EclMenuItemParentFocusEvent,\n EclMenuItemSelectEvent,\n} from '../events';\nimport { EclMenuItem } from '../models/ecl-menu-item.model';\n\nconst enum ColTrigger {\n COL1_TRIGGER = 5,\n COL2_TRIGGER = 9,\n COL3_TRIGGER = 13,\n}\n\n/**\n * This component represents a root menu item. Adds styling and functionality to menu item.\n */\n@Component({\n selector: 'ecl-menu-item',\n templateUrl: './ecl-menu-item.component.html',\n imports: [NgTemplateOutlet, RouterLink, RouterLinkWithHref, ...EUI_ECL_BUTTON, ...EUI_ECL_ICON, ...EUI_ECL_LINK],\n encapsulation: ViewEncapsulation.None,\n host: {\n role: 'listitem',\n '[class]': 'cssClasses',\n '[class.ecl-menu__item--has-children]': 'hasEclChildrenDataAttribute',\n '[attr.aria-haspopup]': 'hasEclChildrenDataAttribute',\n '[attr.data-expanded]': 'isDataExpanded',\n '(mouseenter)': 'onItemMouseEnter($event)',\n '(mouseleave)': 'onItemMouseLeave($event)',\n },\n})\nexport class EclMenuItemComponent extends ECLBaseDirective implements EclMenuItem, AfterContentInit, OnDestroy {\n el = inject(ElementRef);\n\n @Input() id: string;\n @Input() label: string;\n /**\n * When in mobile view, use this property to set aria-label for the toggle items button (to expand item's children).\n */\n readonly toggleAriaLabel = 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 @Input() isCurrent = false;\n /**\n * Custom attributes, to be added to the <a> tag of the menu item.\n */\n readonly linkExtraAttributes = input<Record<string, string>>(undefined);\n\n isExpanded: boolean;\n /**\n * Set to 'true', when item has more than 13 chidren and the overlay needs to use the full available space.\n */\n isFull = false;\n isHovered = false;\n isMobileBreakpoint = false;\n /**\n * Used when menu has overlay, to show if the item is currently displayed.\n */\n isVisible = true;\n\n private readonly doc = inject(DOCUMENT);\n private readonly window = this.doc.defaultView; // Window | null\n\n /**\n * The default role of the item is 'listitem' and should not be changed.\n */\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-menu__item'),\n this.isCurrent ? 'ecl-menu__item--current' : '',\n this.isExpanded ? 'ecl-menu__item--expanded' : '',\n this.getClassDependingChildrenCnt(),\n ]\n .join(' ')\n .trim();\n }\n\n readonly submenu = contentChild(forwardRef(() => EclMenuMegaComponent));\n /**\n * The <a> element of the menu item, when there are no children.\n */\n readonly menuLink = viewChild<ElementRef<HTMLAnchorElement>>('menuLink');\n /**\n * The <button> element of the menu item, when item has children.\n */\n readonly menuButton = viewChild(EclButtonComponent);\n\n @Output() menuItemSelect = new EventEmitter<EclMenuItemSelectEvent>();\n @Output() menuItemCaret = new EventEmitter<EclMenuItemCaretEvent>();\n /**\n * Event that is emited on clicking the caret button to expand item's children in mobile mode.\n */\n @Output() menuItemHover = new EventEmitter<EclMenuItemHoverEvent>();\n @Output() menuItemHoverOut = new EventEmitter<EclMenuItemHoverOutEvent>();\n @Output() menuMegaItemSelect = new EventEmitter<EclMenuItemSelectEvent>();\n @Output() menuItemFocus = new EventEmitter<EclMenuItemFocusEvent>();\n @Output() menuItemKeydown = new EventEmitter<EclMenuItemKeydownEvent>();\n /**\n * This event is emited when the keyboard nav reaches the last item in mobile view.\n * Then the next focused element should be the 'close' btn.\n */\n @Output() menuMegaLastItemTab = new EventEmitter<void>();\n\n get hasEclChildrenDataAttribute(): boolean {\n return this.hasChildren || undefined;\n }\n\n get isDataExpanded(): boolean {\n return this.hasChildren ? this.isHovered : null;\n }\n\n get ariaCurrent(): boolean {\n return this.isCurrent ? true : null;\n }\n\n get hasChildren(): boolean {\n return !!this.submenu();\n }\n\n get children(): EclMenuItem[] {\n return this.hasChildren ? this.submenu().eclMenuMegaItems.toArray() : [];\n }\n\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private renderer = inject(Renderer2);\n private appShell = inject(EuiAppShellService);\n\n constructor() {\n super();\n afterNextRender(() => {\n this.observeBreakpointChanges();\n this.setExtraAttributesForLink(this.menuLink()?.nativeElement, this.linkExtraAttributes());\n });\n }\n\n onItemMouseEnter(evt: MouseEvent): void {\n if (this.isMobileBreakpoint) return;\n this.menuItemHover.next(new EclMenuItemHoverEvent(this, evt));\n }\n\n onItemMouseLeave(evt: MouseEvent): void {\n if (this.isMobileBreakpoint) return;\n this.menuItemHoverOut.next(new EclMenuItemHoverOutEvent(this, evt));\n }\n\n ngAfterContentInit(): void {\n // Subscibe to submenu component events.\n const submenu = this.submenu();\n if (submenu) {\n submenu.menuItemSelect.pipe(takeUntil(this.destroy$)).subscribe((it: EclMenuItemSelectEvent) => {\n this.menuMegaItemSelect.next(new EclMenuItemSelectEvent(it.menuItem, it.domEvent));\n });\n submenu.menuMegaItemParentFocus.pipe(takeUntil(this.destroy$)).subscribe((it: EclMenuItemParentFocusEvent) => {\n if (!this.isMobileBreakpoint) {\n this.onFocusFromSubmenu();\n }\n });\n submenu.menuMegaLastItemTab.pipe(takeUntil(this.destroy$)).subscribe(() => {\n if (this.isMobileBreakpoint) {\n this.menuMegaLastItemTab.next();\n }\n });\n\n if (this.hasSubmenuAnySelections()) {\n this.isCurrent = true;\n }\n }\n\n // this.tabindex = this.routerLink || this.href ? 0 : -1;\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n onItemFocus(evt: FocusEvent): void {\n this.menuItemFocus.next(new EclMenuItemFocusEvent(this, evt));\n }\n\n onItemClick(evt: Event): void {\n this.menuItemSelect.next(new EclMenuItemSelectEvent(this, evt));\n\n if (!this.href) {\n evt.stopPropagation();\n }\n }\n\n /**\n * When clicking the caret button, to expand item's children. Used in mobile view.\n * @param evt\n */\n onItemCaretClick(evt: MouseEvent): void {\n this.menuItemCaret.next(new EclMenuItemCaretEvent(this, evt));\n }\n\n /**\n * Manages the state when the item is focused, when navigating with keyboard and the navigation is coming from the submenu.\n */\n onFocusFromSubmenu(): void {\n this.onButtonFocus();\n this.isHovered = false;\n this.isExpanded = false;\n }\n\n /**\n * Manages the state when the item is focused, when navigating with keyboard and the navigation is coming from\n * the next root menu item.\n */\n onFocusFromNext(): void {\n if (this.menuButton()) {\n this.onButtonFocus();\n } else {\n this.onLinkFocus();\n }\n }\n\n /**\n * Manages the state when the item is focused, when navigating with keyboard and the navigation is coming from\n * the previous root menu item.\n */\n onFocusFromPrev(): void {\n this.onLinkFocus();\n }\n\n /**\n * Manages the keyboard navigation when the current element is the button of the menu item.\n * @param evt\n */\n onButtonKeydown(evt: Event): void {\n switch ((evt as KeyboardEvent).key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n if (this.isHovered) {\n this.selectFirstMegaMenuItem();\n } else {\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n }\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.onLinkFocus();\n break;\n }\n case KeyCode.ARROW_RIGHT: {\n evt.preventDefault();\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n case KeyCode.ARROW_LEFT: {\n evt.preventDefault();\n this.onLinkFocus();\n break;\n }\n case KeyCode.TAB: {\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n case KeyCode.ENTER: {\n evt.preventDefault();\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n case KeyCode.ESCAPE: {\n evt.preventDefault();\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n default: {\n break;\n }\n }\n }\n\n /**\n * Manages the keyboard navigation when the current element is the <a> tag of the menu item.\n * @param evt\n */\n onLinkKeydown(evt: Event): void {\n switch ((evt as KeyboardEvent).key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n this.onLinkNextFocus(evt);\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n case KeyCode.ARROW_RIGHT: {\n evt.preventDefault();\n this.onLinkNextFocus(evt);\n break;\n }\n case KeyCode.ARROW_LEFT: {\n evt.preventDefault();\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n case KeyCode.ENTER: {\n this.onItemClick(evt);\n break;\n }\n case KeyCode.ESCAPE: {\n evt.preventDefault();\n this.onLinkEscape(evt);\n break;\n }\n default: {\n break;\n }\n }\n }\n\n /**\n * This method calculates height and width of an item, depending the maximum of lines(rows) allowed.\n * Depends on the 'maxLines' property of the parent menu component.\n * @param maxLines - property that sets the maximum possible lines in a menu item.\n * @param isMobileBreakpoint\n * @returns\n */\n checkMenuItem(maxLines: number, isMobileBreakpoint: boolean): void {\n if (maxLines < 1) return;\n\n const currentItem = this.el.nativeElement;\n const currentLink = this.menuLink().nativeElement;\n if (isMobileBreakpoint) {\n this.renderer.setStyle(currentLink, 'width', '100%');\n return;\n }\n this.renderer.setStyle(currentItem, 'alignItems', 'flex-start');\n const linkStyle = this.window.getComputedStyle(currentLink);\n\n const maxHeight = this.getMenuItemLinkMaxHeight(linkStyle, maxLines);\n\n if (currentLink.offsetHeight > maxHeight) {\n this.changeMenuItemLinkWidth(currentLink, maxLines, linkStyle);\n }\n this.renderer.removeStyle(currentItem, 'alignItems');\n }\n\n private onLinkEscape(evt: Event): void {\n const menuButton = this.menuButton();\n if (menuButton) {\n menuButton.el.nativeElement.focus();\n evt.stopPropagation();\n } else {\n this.menuLink().nativeElement.blur();\n }\n }\n\n private selectFirstMegaMenuItem(): void {\n this.submenu().selectFirstSubItem();\n }\n\n private onLinkFocus(): void {\n this.menuLink().nativeElement.focus();\n }\n\n private onLinkNextFocus(evt: Event): void {\n if (this.menuButton()) {\n this.onButtonFocus();\n } else {\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n }\n }\n\n private onButtonFocus(): void {\n this.menuButton().el.nativeElement.focus();\n }\n\n private getMenuItemLinkMaxHeight(linkStyle: CSSStyleDeclaration, maxLines: number): number {\n return parseInt(linkStyle.lineHeight, 10) * maxLines + parseInt(linkStyle.paddingTop, 10) + parseInt(linkStyle.paddingBottom, 10);\n }\n\n /**\n * Calculates width of a menu item, depending on maximum lines of text allowed.\n * @param currentLink\n * @param maxLines\n * @param linkStyle\n * @returns\n */\n private changeMenuItemLinkWidth(currentLink: HTMLAnchorElement, maxLines: number, linkStyle: CSSStyleDeclaration): void {\n this.renderer.setStyle(currentLink, 'white-space', 'nowrap');\n const linkWidth = currentLink.offsetWidth;\n if (maxLines === 1) {\n this.renderer.setStyle(currentLink, 'width', `${linkWidth + parseInt(linkStyle.paddingLeft, 10) + parseInt(linkStyle.paddingRight, 10)}px`);\n this.renderer.removeStyle(currentLink, 'white-space');\n return;\n }\n const textSize = currentLink.text.length;\n const letterWidth = Math.ceil(linkWidth / textSize);\n const wordsArray = currentLink.text.trim().split(' ');\n const goalWidth = Math.ceil(linkWidth / maxLines);\n const firstWord = wordsArray[0];\n let cnt = 1;\n let wordWidth = Math.ceil((firstWord.length + 1) * letterWidth);\n while (wordWidth < goalWidth) {\n wordWidth += Math.ceil((wordsArray[cnt].length + 1) * letterWidth);\n cnt++;\n }\n this.renderer.setStyle(currentLink, 'width', `${wordWidth + parseInt(linkStyle.paddingLeft, 10) + parseInt(linkStyle.paddingRight, 10)}px`);\n this.renderer.removeStyle(currentLink, 'white-space');\n }\n\n private getClassDependingChildrenCnt(): string {\n if (this.hasChildren) {\n if (this.submenu().eclMenuMegaItems.length < ColTrigger.COL1_TRIGGER) {\n return 'ecl-menu__item--col1';\n } else if (this.submenu().eclMenuMegaItems.length < ColTrigger.COL2_TRIGGER) {\n return 'ecl-menu__item--col2';\n } else if (this.submenu().eclMenuMegaItems.length < ColTrigger.COL3_TRIGGER) {\n return 'ecl-menu__item--col3';\n } else {\n this.isFull = true;\n return 'ecl-menu__item--full';\n }\n }\n return '';\n }\n\n private hasSubmenuAnySelections(): boolean {\n const submenu = this.submenu();\n return submenu && !!submenu.eclMenuMegaItems.find((it) => it.isCurrent);\n }\n\n private setExtraAttributesForLink(link: HTMLElement, linkExtraAttributes: Record<string, string>): void {\n if (linkExtraAttributes) {\n Object.keys(linkExtraAttributes).forEach((key) => {\n if (key !== 'href' && key !== 'routerLink') {\n this.renderer.setAttribute(link, key, linkExtraAttributes[key]);\n }\n });\n }\n }\n\n private observeBreakpointChanges(): void {\n this.appShell.getState<any>('breakpoints')\n .pipe(\n map(bp => !!(bp?.isMobile || bp?.isTablet || bp?.isLtLargeTablet)), // xs/sm/md/lg (< 1140px)\n distinctUntilChanged(),\n takeUntil(this.destroy$),\n )\n .subscribe((isMobile) => {\n this.isMobileBreakpoint = isMobile;\n });\n }\n}\n",
65657
+ "sourceCode": "import { NgTemplateOutlet } from '@angular/common';\nimport {\n AfterContentInit,\n afterNextRender,\n Component,\n ElementRef,\n EventEmitter,\n forwardRef,\n inject,\n Input,\n OnDestroy,\n Output,\n Renderer2,\n ViewEncapsulation,\n DOCUMENT,\n input,\n contentChild,\n viewChild,\n booleanAttribute,\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 { EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\nimport { ECLBaseDirective, KeyCode } from '@eui/ecl/core';\nimport { Subject } from 'rxjs';\nimport { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';\nimport { EclMenuMegaComponent } from '../ecl-menu-mega';\nimport {\n EclMenuItemCaretEvent,\n EclMenuItemFocusEvent,\n EclMenuItemHoverEvent,\n EclMenuItemHoverOutEvent,\n EclMenuItemKeydownEvent,\n EclMenuItemParentFocusEvent,\n EclMenuItemSelectEvent,\n} from '../events';\nimport { EclMenuItem } from '../models/ecl-menu-item.model';\n\nconst enum ColTrigger {\n COL1_TRIGGER = 5,\n COL2_TRIGGER = 9,\n COL3_TRIGGER = 13,\n}\n\n/**\n * This component represents a root menu item. Adds styling and functionality to menu item.\n */\n@Component({\n selector: 'ecl-menu-item',\n templateUrl: './ecl-menu-item.component.html',\n imports: [NgTemplateOutlet, RouterLink, RouterLinkWithHref, ...EUI_ECL_BUTTON, ...EUI_ECL_ICON, ...EUI_ECL_LINK],\n encapsulation: ViewEncapsulation.None,\n host: {\n role: 'listitem',\n '[class]': 'cssClasses',\n '[class.ecl-menu__item--has-children]': 'hasEclChildrenDataAttribute',\n '[attr.aria-haspopup]': 'hasEclChildrenDataAttribute',\n '[attr.data-expanded]': 'isDataExpanded',\n '(mouseenter)': 'onItemMouseEnter($event)',\n '(mouseleave)': 'onItemMouseLeave($event)',\n },\n})\nexport class EclMenuItemComponent extends ECLBaseDirective implements EclMenuItem, AfterContentInit, OnDestroy {\n el = inject(ElementRef);\n\n @Input() id: string;\n @Input() label: string;\n /**\n * When in mobile view, use this property to set aria-label for the toggle items button (to expand item's children).\n */\n readonly toggleAriaLabel = 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 @Input({ transform: booleanAttribute }) isCurrent = false;\n /**\n * Custom attributes, to be added to the <a> tag of the menu item.\n */\n readonly linkExtraAttributes = input<Record<string, string>>(undefined);\n\n isExpanded: boolean;\n /**\n * Set to 'true', when item has more than 13 chidren and the overlay needs to use the full available space.\n */\n isFull = false;\n isHovered = false;\n isMobileBreakpoint = false;\n /**\n * Used when menu has overlay, to show if the item is currently displayed.\n */\n isVisible = true;\n\n private readonly doc = inject(DOCUMENT);\n private readonly window = this.doc.defaultView; // Window | null\n\n /**\n * The default role of the item is 'listitem' and should not be changed.\n */\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-menu__item'),\n this.isCurrent ? 'ecl-menu__item--current' : '',\n this.isExpanded ? 'ecl-menu__item--expanded' : '',\n this.getClassDependingChildrenCnt(),\n ]\n .join(' ')\n .trim();\n }\n\n readonly submenu = contentChild(forwardRef(() => EclMenuMegaComponent));\n /**\n * The <a> element of the menu item, when there are no children.\n */\n readonly menuLink = viewChild<ElementRef<HTMLAnchorElement>>('menuLink');\n /**\n * The <button> element of the menu item, when item has children.\n */\n readonly menuButton = viewChild(EclButtonComponent);\n\n @Output() menuItemSelect = new EventEmitter<EclMenuItemSelectEvent>();\n @Output() menuItemCaret = new EventEmitter<EclMenuItemCaretEvent>();\n /**\n * Event that is emited on clicking the caret button to expand item's children in mobile mode.\n */\n @Output() menuItemHover = new EventEmitter<EclMenuItemHoverEvent>();\n @Output() menuItemHoverOut = new EventEmitter<EclMenuItemHoverOutEvent>();\n @Output() menuMegaItemSelect = new EventEmitter<EclMenuItemSelectEvent>();\n @Output() menuItemFocus = new EventEmitter<EclMenuItemFocusEvent>();\n @Output() menuItemKeydown = new EventEmitter<EclMenuItemKeydownEvent>();\n /**\n * This event is emited when the keyboard nav reaches the last item in mobile view.\n * Then the next focused element should be the 'close' btn.\n */\n @Output() menuMegaLastItemTab = new EventEmitter<void>();\n\n get hasEclChildrenDataAttribute(): boolean {\n return this.hasChildren || undefined;\n }\n\n get isDataExpanded(): boolean {\n return this.hasChildren ? this.isHovered : null;\n }\n\n /**\n * 'aria-current' is set to 'page' only when this item itself is the current page, and not when it is\n * marked current merely because one of its children is the active item (in that case the child link\n * carries 'aria-current=\"page\"'). Derived from live state so it stays correct whether 'isCurrent' is set\n * at render time or updated on selection.\n */\n get ariaCurrent(): string | null {\n return this.isCurrent && !this.hasCurrentChild ? 'page' : null;\n }\n\n /**\n * Whether any child (sub-item) is the current item.\n */\n get hasCurrentChild(): boolean {\n return this.children.some((child) => child.isCurrent);\n }\n\n get hasChildren(): boolean {\n return !!this.submenu();\n }\n\n get children(): EclMenuItem[] {\n return this.hasChildren ? this.submenu().eclMenuMegaItems.toArray() : [];\n }\n\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private renderer = inject(Renderer2);\n private appShell = inject(EuiAppShellService);\n\n constructor() {\n super();\n afterNextRender(() => {\n this.observeBreakpointChanges();\n this.setExtraAttributesForLink(this.menuLink()?.nativeElement, this.linkExtraAttributes());\n });\n }\n\n onItemMouseEnter(evt: MouseEvent): void {\n if (this.isMobileBreakpoint) return;\n this.menuItemHover.next(new EclMenuItemHoverEvent(this, evt));\n }\n\n onItemMouseLeave(evt: MouseEvent): void {\n if (this.isMobileBreakpoint) return;\n this.menuItemHoverOut.next(new EclMenuItemHoverOutEvent(this, evt));\n }\n\n ngAfterContentInit(): void {\n // Subscibe to submenu component events.\n const submenu = this.submenu();\n if (submenu) {\n submenu.menuItemSelect.pipe(takeUntil(this.destroy$)).subscribe((it: EclMenuItemSelectEvent) => {\n this.menuMegaItemSelect.next(new EclMenuItemSelectEvent(it.menuItem, it.domEvent));\n });\n submenu.menuMegaItemParentFocus.pipe(takeUntil(this.destroy$)).subscribe((it: EclMenuItemParentFocusEvent) => {\n if (!this.isMobileBreakpoint) {\n this.onFocusFromSubmenu();\n }\n });\n submenu.menuMegaLastItemTab.pipe(takeUntil(this.destroy$)).subscribe(() => {\n if (this.isMobileBreakpoint) {\n this.menuMegaLastItemTab.next();\n }\n });\n\n if (this.hasSubmenuAnySelections()) {\n this.isCurrent = true;\n }\n }\n\n // this.tabindex = this.routerLink || this.href ? 0 : -1;\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n onItemFocus(evt: FocusEvent): void {\n this.menuItemFocus.next(new EclMenuItemFocusEvent(this, evt));\n }\n\n onItemClick(evt: Event): void {\n this.menuItemSelect.next(new EclMenuItemSelectEvent(this, evt));\n\n if (!this.href) {\n evt.stopPropagation();\n }\n }\n\n /**\n * When clicking the caret button, to expand item's children. Used in mobile view.\n * @param evt\n */\n onItemCaretClick(evt: MouseEvent): void {\n this.menuItemCaret.next(new EclMenuItemCaretEvent(this, evt));\n }\n\n /**\n * Manages the state when the item is focused, when navigating with keyboard and the navigation is coming from the submenu.\n */\n onFocusFromSubmenu(): void {\n this.onButtonFocus();\n this.isHovered = false;\n this.isExpanded = false;\n }\n\n /**\n * Manages the state when the item is focused, when navigating with keyboard and the navigation is coming from\n * the next root menu item.\n */\n onFocusFromNext(): void {\n if (this.menuButton()) {\n this.onButtonFocus();\n } else {\n this.onLinkFocus();\n }\n }\n\n /**\n * Manages the state when the item is focused, when navigating with keyboard and the navigation is coming from\n * the previous root menu item.\n */\n onFocusFromPrev(): void {\n this.onLinkFocus();\n }\n\n /**\n * Manages the keyboard navigation when the current element is the button of the menu item.\n * @param evt\n */\n onButtonKeydown(evt: Event): void {\n switch ((evt as KeyboardEvent).key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n if (this.isHovered) {\n this.selectFirstMegaMenuItem();\n } else {\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n }\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.onLinkFocus();\n break;\n }\n case KeyCode.ARROW_RIGHT: {\n evt.preventDefault();\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n case KeyCode.ARROW_LEFT: {\n evt.preventDefault();\n this.onLinkFocus();\n break;\n }\n case KeyCode.TAB: {\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n case KeyCode.ENTER: {\n evt.preventDefault();\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n case KeyCode.ESCAPE: {\n evt.preventDefault();\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n default: {\n break;\n }\n }\n }\n\n /**\n * Manages the keyboard navigation when the current element is the <a> tag of the menu item.\n * @param evt\n */\n onLinkKeydown(evt: Event): void {\n switch ((evt as KeyboardEvent).key) {\n case KeyCode.ARROW_DOWN: {\n evt.preventDefault();\n this.onLinkNextFocus(evt);\n break;\n }\n case KeyCode.ARROW_UP: {\n evt.preventDefault();\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n case KeyCode.ARROW_RIGHT: {\n evt.preventDefault();\n this.onLinkNextFocus(evt);\n break;\n }\n case KeyCode.ARROW_LEFT: {\n evt.preventDefault();\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n break;\n }\n case KeyCode.ENTER: {\n this.onItemClick(evt);\n break;\n }\n case KeyCode.ESCAPE: {\n evt.preventDefault();\n this.onLinkEscape(evt);\n break;\n }\n default: {\n break;\n }\n }\n }\n\n /**\n * This method calculates height and width of an item, depending the maximum of lines(rows) allowed.\n * Depends on the 'maxLines' property of the parent menu component.\n * @param maxLines - property that sets the maximum possible lines in a menu item.\n * @param isMobileBreakpoint\n * @returns\n */\n checkMenuItem(maxLines: number, isMobileBreakpoint: boolean): void {\n if (maxLines < 1) return;\n\n const currentItem = this.el.nativeElement;\n const currentLink = this.menuLink().nativeElement;\n if (isMobileBreakpoint) {\n this.renderer.setStyle(currentLink, 'width', '100%');\n return;\n }\n this.renderer.setStyle(currentItem, 'alignItems', 'flex-start');\n const linkStyle = this.window.getComputedStyle(currentLink);\n\n const maxHeight = this.getMenuItemLinkMaxHeight(linkStyle, maxLines);\n\n if (currentLink.offsetHeight > maxHeight) {\n this.changeMenuItemLinkWidth(currentLink, maxLines, linkStyle);\n }\n this.renderer.removeStyle(currentItem, 'alignItems');\n }\n\n private onLinkEscape(evt: Event): void {\n const menuButton = this.menuButton();\n if (menuButton) {\n menuButton.el.nativeElement.focus();\n evt.stopPropagation();\n } else {\n this.menuLink().nativeElement.blur();\n }\n }\n\n private selectFirstMegaMenuItem(): void {\n this.submenu().selectFirstSubItem();\n }\n\n private onLinkFocus(): void {\n this.menuLink().nativeElement.focus();\n }\n\n private onLinkNextFocus(evt: Event): void {\n if (this.menuButton()) {\n this.onButtonFocus();\n } else {\n this.menuItemKeydown.next(new EclMenuItemKeydownEvent(this, evt as KeyboardEvent));\n }\n }\n\n private onButtonFocus(): void {\n this.menuButton().el.nativeElement.focus();\n }\n\n private getMenuItemLinkMaxHeight(linkStyle: CSSStyleDeclaration, maxLines: number): number {\n return parseInt(linkStyle.lineHeight, 10) * maxLines + parseInt(linkStyle.paddingTop, 10) + parseInt(linkStyle.paddingBottom, 10);\n }\n\n /**\n * Calculates width of a menu item, depending on maximum lines of text allowed.\n * @param currentLink\n * @param maxLines\n * @param linkStyle\n * @returns\n */\n private changeMenuItemLinkWidth(currentLink: HTMLAnchorElement, maxLines: number, linkStyle: CSSStyleDeclaration): void {\n this.renderer.setStyle(currentLink, 'white-space', 'nowrap');\n const linkWidth = currentLink.offsetWidth;\n if (maxLines === 1) {\n this.renderer.setStyle(currentLink, 'width', `${linkWidth + parseInt(linkStyle.paddingLeft, 10) + parseInt(linkStyle.paddingRight, 10)}px`);\n this.renderer.removeStyle(currentLink, 'white-space');\n return;\n }\n const textSize = currentLink.text.length;\n const letterWidth = Math.ceil(linkWidth / textSize);\n const wordsArray = currentLink.text.trim().split(' ');\n const goalWidth = Math.ceil(linkWidth / maxLines);\n const firstWord = wordsArray[0];\n let cnt = 1;\n let wordWidth = Math.ceil((firstWord.length + 1) * letterWidth);\n while (wordWidth < goalWidth) {\n wordWidth += Math.ceil((wordsArray[cnt].length + 1) * letterWidth);\n cnt++;\n }\n this.renderer.setStyle(currentLink, 'width', `${wordWidth + parseInt(linkStyle.paddingLeft, 10) + parseInt(linkStyle.paddingRight, 10)}px`);\n this.renderer.removeStyle(currentLink, 'white-space');\n }\n\n private getClassDependingChildrenCnt(): string {\n if (this.hasChildren) {\n if (this.submenu().eclMenuMegaItems.length < ColTrigger.COL1_TRIGGER) {\n return 'ecl-menu__item--col1';\n } else if (this.submenu().eclMenuMegaItems.length < ColTrigger.COL2_TRIGGER) {\n return 'ecl-menu__item--col2';\n } else if (this.submenu().eclMenuMegaItems.length < ColTrigger.COL3_TRIGGER) {\n return 'ecl-menu__item--col3';\n } else {\n this.isFull = true;\n return 'ecl-menu__item--full';\n }\n }\n return '';\n }\n\n private hasSubmenuAnySelections(): boolean {\n const submenu = this.submenu();\n return submenu && !!submenu.eclMenuMegaItems.find((it) => it.isCurrent);\n }\n\n private setExtraAttributesForLink(link: HTMLElement, linkExtraAttributes: Record<string, string>): void {\n if (linkExtraAttributes) {\n Object.keys(linkExtraAttributes).forEach((key) => {\n if (key !== 'href' && key !== 'routerLink') {\n this.renderer.setAttribute(link, key, linkExtraAttributes[key]);\n }\n });\n }\n }\n\n private observeBreakpointChanges(): void {\n this.appShell.getState<any>('breakpoints')\n .pipe(\n map(bp => !!(bp?.isMobile || bp?.isTablet || bp?.isLtLargeTablet)), // xs/sm/md/lg (< 1140px)\n distinctUntilChanged(),\n takeUntil(this.destroy$),\n )\n .subscribe((isMobile) => {\n this.isMobileBreakpoint = isMobile;\n });\n }\n}\n",
65932
65658
  "assetsDirs": [],
65933
65659
  "styleUrlsData": "",
65934
65660
  "stylesData": "",
65935
65661
  "jsdoctags": [
65936
65662
  {
65937
- "pos": 1294,
65938
- "end": 1393,
65663
+ "pos": 1316,
65664
+ "end": 1415,
65939
65665
  "kind": 321,
65940
65666
  "id": 0,
65941
65667
  "flags": 16777216,
@@ -65950,7 +65676,7 @@
65950
65676
  "deprecated": false,
65951
65677
  "deprecationMessage": "",
65952
65678
  "args": [],
65953
- "line": 162,
65679
+ "line": 176,
65954
65680
  "rawdescription": "\n"
65955
65681
  },
65956
65682
  "extends": [
@@ -65968,7 +65694,7 @@
65968
65694
  "name": "cssClasses",
65969
65695
  "type": "string",
65970
65696
  "returnType": "string",
65971
- "line": 103,
65697
+ "line": 104,
65972
65698
  "rawdescription": "\n\nThe default role of the item is 'listitem' and should not be changed.\n",
65973
65699
  "description": "<p>The default role of the item is &#39;listitem&#39; and should not be changed.</p>\n"
65974
65700
  }
@@ -65979,7 +65705,7 @@
65979
65705
  "name": "hasEclChildrenDataAttribute",
65980
65706
  "type": "boolean",
65981
65707
  "returnType": "boolean",
65982
- "line": 140,
65708
+ "line": 141,
65983
65709
  "rawdescription": "\n",
65984
65710
  "description": ""
65985
65711
  }
@@ -65990,7 +65716,7 @@
65990
65716
  "name": "isDataExpanded",
65991
65717
  "type": "boolean",
65992
65718
  "returnType": "boolean",
65993
- "line": 144,
65719
+ "line": 145,
65994
65720
  "rawdescription": "\n",
65995
65721
  "description": ""
65996
65722
  }
@@ -65999,11 +65725,22 @@
65999
65725
  "name": "ariaCurrent",
66000
65726
  "getSignature": {
66001
65727
  "name": "ariaCurrent",
65728
+ "type": "unknown",
65729
+ "returnType": "string | null",
65730
+ "line": 155,
65731
+ "rawdescription": "\n\n'aria-current' is set to 'page' only when this item itself is the current page, and not when it is\nmarked current merely because one of its children is the active item (in that case the child link\ncarries 'aria-current=\"page\"'). Derived from live state so it stays correct whether 'isCurrent' is set\nat render time or updated on selection.\n",
65732
+ "description": "<p>&#39;aria-current&#39; is set to &#39;page&#39; only when this item itself is the current page, and not when it is\nmarked current merely because one of its children is the active item (in that case the child link\ncarries &#39;aria-current=&quot;page&quot;&#39;). Derived from live state so it stays correct whether &#39;isCurrent&#39; is set\nat render time or updated on selection.</p>\n"
65733
+ }
65734
+ },
65735
+ "hasCurrentChild": {
65736
+ "name": "hasCurrentChild",
65737
+ "getSignature": {
65738
+ "name": "hasCurrentChild",
66002
65739
  "type": "boolean",
66003
65740
  "returnType": "boolean",
66004
- "line": 148,
66005
- "rawdescription": "\n",
66006
- "description": ""
65741
+ "line": 162,
65742
+ "rawdescription": "\n\nWhether any child (sub-item) is the current item.\n",
65743
+ "description": "<p>Whether any child (sub-item) is the current item.</p>\n"
66007
65744
  }
66008
65745
  },
66009
65746
  "hasChildren": {
@@ -66012,7 +65749,7 @@
66012
65749
  "name": "hasChildren",
66013
65750
  "type": "boolean",
66014
65751
  "returnType": "boolean",
66015
- "line": 152,
65752
+ "line": 166,
66016
65753
  "rawdescription": "\n",
66017
65754
  "description": ""
66018
65755
  }
@@ -66023,7 +65760,7 @@
66023
65760
  "name": "children",
66024
65761
  "type": "[]",
66025
65762
  "returnType": "EclMenuItem[]",
66026
- "line": 156,
65763
+ "line": 170,
66027
65764
  "rawdescription": "\n",
66028
65765
  "description": ""
66029
65766
  }
@@ -82815,7 +82552,7 @@
82815
82552
  }
82816
82553
  ]
82817
82554
  },
82818
- "templateData": "<div class=\"ecl-site-footer__section ecl-site-footer__section--common\">\n @if (!isCore()) {\n <a href=\"https://commission.europa.eu/index_{{languageCode()}}\"\n class=\"ecl-link ecl-link--standalone ecl-link--inverted ecl-site-footer__logo-link\">\n <picture class=\"ecl-picture ecl-site-footer__picture\"><img class=\"ecl-site-footer__logo-image\"\n src=\"assets/images/ecl/logo/ec/negative/logo-ec--{{logoLanguageCode}}.svg\" alt=\"European Commission\">\n </picture>\n </a>\n <div class=\"ecl-site-footer__extra-links-container\">\n <ecl-social-media-follow description=\"{{'ecl.footer.FOLLOW-EUROPEAN-COMMISSION' | translate}}\"\n class=\"ecl-social-media-follow--description_inline ecl-site-footer__social-media\">\n <ecl-social-media-follow-item icon=\"mastodon\" href=\"https://ec.social-network.europa.eu/@EUCommission\"\n isInverted></ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"linkedin\" href=\"https://www.linkedin.com/company/european-commission\"\n isInverted></ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"bluesky\" href=\"https://bsky.app/profile/ec.europa.eu\"\n isInverted></ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"facebook\" href=\"https://www.facebook.com/EuropeanCommission\"\n isInverted></ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"youtube\" href=\"https://www.youtube.com/user/eutube\"\n isInverted></ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"chain\"\n href=\"https://european-union.europa.eu/contact-eu/social-media-channels_{{languageCode()}}\"\n isInverted></ecl-social-media-follow-item>\n </ecl-social-media-follow>\n <ul eclSiteFooterList isInline>\n <li eclSiteFooterListItem><a\n href=\"https://commission.europa.eu/about-european-commission/contact_{{languageCode()}}\"\n class=\"ecl-link ecl-link--standalone ecl-link--inverted ecl-site-footer__link\">{{ 'ecl.footer.CONTACT' | translate }}</a></li>\n </ul>\n </div>\n } @else {\n <ecl-social-media-follow description=\"{{'ecl.footer.FOLLOW-US' | translate}}\"\n class=\"ecl-social-media-follow--description_inline ecl-site-footer__social-media\">\n <ecl-social-media-follow-item icon=\"mastodon\" href=\"https://ec.social-network.europa.eu/@EUCommission\"\n isInverted></ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"linkedin\" href=\"https://www.linkedin.com/company/european-commission\"\n isInverted></ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"bluesky\" href=\"https://bsky.app/profile/ec.europa.eu\"\n isInverted></ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"facebook\" href=\"https://www.facebook.com/EuropeanCommission\"\n isInverted></ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"youtube\" href=\"https://www.youtube.com/user/eutube\"\n isInverted></ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"chain\"\n href=\"https://european-union.europa.eu/contact-eu/social-media-channels_{{languageCode()}}\"\n isInverted></ecl-social-media-follow-item>\n </ecl-social-media-follow>\n }\n <ul eclSiteFooterList isInline>\n <li eclSiteFooterListItem><a\n href=\"https://commission.europa.eu/legal-notice/vulnerability-disclosure-policy_{{languageCode()}}\"\n eclLink isInverted variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.REPORT-IT-VULNERABILITY' | translate }}</a></li>\n <li eclSiteFooterListItem><a href=\"https://commission.europa.eu/languages-our-websites_{{languageCode()}}\" eclLink\n isInverted variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.LANGUAGES' | translate }}</a></li>\n <li eclSiteFooterListItem><a href=\"https://commission.europa.eu/cookies_{{languageCode()}}\" eclLink isInverted\n variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.COOKIES' | translate }}</a></li>\n <li eclSiteFooterListItem><a href=\"https://commission.europa.eu/privacy-policy_{{languageCode()}}\" eclLink\n isInverted variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.PRIVACY-POLICY' | translate }}</a></li>\n <li eclSiteFooterListItem><a href=\"https://commission.europa.eu/legal-notice_{{languageCode()}}\" eclLink\n isInverted variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.LEGAL-NOTICE' | translate }}</a></li>\n <li eclSiteFooterListItem><a href=\"{{ a11yStatementRef() }}\"\n eclLink isInverted variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.ACCESSIBILITY' | translate }}</a></li>\n </ul>\n</div>"
82555
+ "templateData": "<div class=\"ecl-site-footer__section ecl-site-footer__section--common\">\n @if (!isCore()) {\n <a href=\"https://commission.europa.eu/index_{{languageCode()}}\"\n class=\"ecl-link ecl-link--standalone ecl-link--inverted ecl-site-footer__logo-link\">\n <picture class=\"ecl-picture ecl-site-footer__picture\"><img class=\"ecl-site-footer__logo-image\"\n src=\"assets/images/ecl/logo/ec/negative/logo-ec--{{logoLanguageCode}}.svg\" alt=\"European Commission\">\n </picture>\n </a>\n <div class=\"ecl-site-footer__extra-links-container\">\n <ecl-social-media-follow isIconOnly description=\"{{'ecl.footer.FOLLOW-EUROPEAN-COMMISSION' | translate}}\"\n class=\"ecl-social-media-follow--description_inline ecl-site-footer__social-media\">\n <ecl-social-media-follow-item icon=\"mastodon\" href=\"https://ec.social-network.europa.eu/@EUCommission\"\n isInverted>Mastodon</ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"linkedin\" href=\"https://www.linkedin.com/company/european-commission\"\n isInverted>LinkedIn</ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"bluesky\" href=\"https://bsky.app/profile/ec.europa.eu\"\n isInverted>Bluesky</ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"facebook\" href=\"https://www.facebook.com/EuropeanCommission\"\n isInverted>Facebook</ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"youtube\" href=\"https://www.youtube.com/user/eutube\"\n isInverted>YouTube</ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"chain\"\n href=\"https://european-union.europa.eu/contact-eu/social-media-channels_{{languageCode()}}\"\n isInverted>Other</ecl-social-media-follow-item>\n </ecl-social-media-follow>\n <ul eclSiteFooterList isInline>\n <li eclSiteFooterListItem><a\n href=\"https://commission.europa.eu/about-european-commission/contact_{{languageCode()}}\"\n class=\"ecl-link ecl-link--standalone ecl-link--inverted ecl-site-footer__link\">{{ 'ecl.footer.CONTACT' | translate }}</a></li>\n </ul>\n </div>\n } @else {\n <ecl-social-media-follow isIconOnly description=\"{{'ecl.footer.FOLLOW-US' | translate}}\"\n class=\"ecl-social-media-follow--description_inline ecl-site-footer__social-media\">\n <ecl-social-media-follow-item icon=\"mastodon\" href=\"https://ec.social-network.europa.eu/@EUCommission\"\n isInverted>Mastodon</ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"linkedin\" href=\"https://www.linkedin.com/company/european-commission\"\n isInverted>LinkedIn</ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"bluesky\" href=\"https://bsky.app/profile/ec.europa.eu\"\n isInverted>Bluesky</ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"facebook\" href=\"https://www.facebook.com/EuropeanCommission\"\n isInverted>Facebook</ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"youtube\" href=\"https://www.youtube.com/user/eutube\"\n isInverted>YouTube</ecl-social-media-follow-item>\n <ecl-social-media-follow-item icon=\"chain\"\n href=\"https://european-union.europa.eu/contact-eu/social-media-channels_{{languageCode()}}\"\n isInverted>Other</ecl-social-media-follow-item>\n </ecl-social-media-follow>\n }\n <ul eclSiteFooterList isInline>\n <li eclSiteFooterListItem><a\n href=\"https://commission.europa.eu/legal-notice/vulnerability-disclosure-policy_{{languageCode()}}\"\n eclLink isInverted variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.REPORT-IT-VULNERABILITY' | translate }}</a></li>\n <li eclSiteFooterListItem><a href=\"https://commission.europa.eu/languages-our-websites_{{languageCode()}}\" eclLink\n isInverted variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.LANGUAGES' | translate }}</a></li>\n <li eclSiteFooterListItem><a href=\"https://commission.europa.eu/cookies_{{languageCode()}}\" eclLink isInverted\n variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.COOKIES' | translate }}</a></li>\n <li eclSiteFooterListItem><a href=\"https://commission.europa.eu/privacy-policy_{{languageCode()}}\" eclLink\n isInverted variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.PRIVACY-POLICY' | translate }}</a></li>\n <li eclSiteFooterListItem><a href=\"https://commission.europa.eu/legal-notice_{{languageCode()}}\" eclLink\n isInverted variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.LEGAL-NOTICE' | translate }}</a></li>\n <li eclSiteFooterListItem><a href=\"{{ a11yStatementRef() }}\"\n eclLink isInverted variant=\"standalone\" eclSiteFooterLink>{{ 'ecl.footer.ACCESSIBILITY' | translate }}</a></li>\n </ul>\n</div>"
82819
82556
  },
82820
82557
  {
82821
82558
  "name": "EclSiteHeaderActionComponent",
@@ -84430,10 +84167,11 @@
84430
84167
  },
84431
84168
  {
84432
84169
  "name": "EclSiteHeaderLanguageComponent",
84433
- "id": "component-EclSiteHeaderLanguageComponent-8d83b2bdcc74673ec7fc4585b1fc9cc96c013ee64a0e713025217ce9bd2f79ccfa1c6406ce41e1e79d0040a209bc785f0be27cca0ade433c9ea4e55fbba6df2c",
84170
+ "id": "component-EclSiteHeaderLanguageComponent-6d5a8dabfc452efabf51524b958206330b0e8d969c92a72ff623dbe1b45bee987ed4a81174ab72b108458c5b8639f088adba2c57c6cb65b7ccf06266d617d7e0",
84434
84171
  "file": "packages/ecl/components/ecl-site-header/language/ecl-site-header-language.component.ts",
84435
84172
  "encapsulation": [],
84436
84173
  "entryComponents": [],
84174
+ "host": {},
84437
84175
  "inputs": [],
84438
84176
  "outputs": [],
84439
84177
  "providers": [],
@@ -84510,7 +84248,7 @@
84510
84248
  "deprecationMessage": "",
84511
84249
  "rawdescription": "\n\nThie event is emited, when language link, showing the current language is clicked.\n",
84512
84250
  "description": "<p>Thie event is emited, when language link, showing the current language is clicked.</p>\n",
84513
- "line": 66,
84251
+ "line": 62,
84514
84252
  "type": "EventEmitter"
84515
84253
  },
84516
84254
  {
@@ -84521,7 +84259,7 @@
84521
84259
  "deprecationMessage": "",
84522
84260
  "rawdescription": "\n\nThie event is emited, when user selects a new language from the dropdown.\n",
84523
84261
  "description": "<p>Thie event is emited, when user selects a new language from the dropdown.</p>\n",
84524
- "line": 70,
84262
+ "line": 66,
84525
84263
  "type": "EventEmitter"
84526
84264
  }
84527
84265
  ],
@@ -84536,7 +84274,7 @@
84536
84274
  "indexKey": "",
84537
84275
  "optional": false,
84538
84276
  "description": "",
84539
- "line": 51,
84277
+ "line": 56,
84540
84278
  "rawdescription": "\n",
84541
84279
  "modifierKind": [
84542
84280
  124
@@ -84552,7 +84290,7 @@
84552
84290
  "indexKey": "",
84553
84291
  "optional": false,
84554
84292
  "description": "",
84555
- "line": 50,
84293
+ "line": 55,
84556
84294
  "rawdescription": "\n",
84557
84295
  "modifierKind": [
84558
84296
  124
@@ -84568,7 +84306,7 @@
84568
84306
  "indexKey": "",
84569
84307
  "optional": false,
84570
84308
  "description": "",
84571
- "line": 106,
84309
+ "line": 100,
84572
84310
  "rawdescription": "\n"
84573
84311
  },
84574
84312
  {
@@ -84581,7 +84319,7 @@
84581
84319
  "indexKey": "",
84582
84320
  "optional": false,
84583
84321
  "description": "<p>Array of EU languages, that can be selected for the current site.</p>\n",
84584
- "line": 101,
84322
+ "line": 95,
84585
84323
  "rawdescription": "\n\nArray of EU languages, that can be selected for the current site.\n"
84586
84324
  },
84587
84325
  {
@@ -84594,7 +84332,7 @@
84594
84332
  "indexKey": "",
84595
84333
  "optional": false,
84596
84334
  "description": "",
84597
- "line": 52,
84335
+ "line": 57,
84598
84336
  "rawdescription": "\n",
84599
84337
  "modifierKind": [
84600
84338
  124
@@ -84609,7 +84347,7 @@
84609
84347
  "indexKey": "",
84610
84348
  "optional": false,
84611
84349
  "description": "<p>This property is used for dropdown positioning on the screen.</p>\n",
84612
- "line": 90,
84350
+ "line": 84,
84613
84351
  "rawdescription": "\n\nThis property is used for dropdown positioning on the screen.\n"
84614
84352
  },
84615
84353
  {
@@ -84622,7 +84360,7 @@
84622
84360
  "indexKey": "",
84623
84361
  "optional": false,
84624
84362
  "description": "",
84625
- "line": 74,
84363
+ "line": 68,
84626
84364
  "rawdescription": "\n"
84627
84365
  },
84628
84366
  {
@@ -84634,7 +84372,7 @@
84634
84372
  "indexKey": "",
84635
84373
  "optional": false,
84636
84374
  "description": "<p>This property is used for dropdown positioning on the screen.</p>\n",
84637
- "line": 82,
84375
+ "line": 76,
84638
84376
  "rawdescription": "\n\nThis property is used for dropdown positioning on the screen.\n"
84639
84377
  },
84640
84378
  {
@@ -84646,7 +84384,7 @@
84646
84384
  "indexKey": "",
84647
84385
  "optional": false,
84648
84386
  "description": "<p>This property is used for dropdown positioning on the screen.</p>\n",
84649
- "line": 78,
84387
+ "line": 72,
84650
84388
  "rawdescription": "\n\nThis property is used for dropdown positioning on the screen.\n"
84651
84389
  },
84652
84390
  {
@@ -84658,25 +84396,9 @@
84658
84396
  "indexKey": "",
84659
84397
  "optional": false,
84660
84398
  "description": "<p>This property is used for dropdown positioning on the screen.</p>\n",
84661
- "line": 86,
84399
+ "line": 80,
84662
84400
  "rawdescription": "\n\nThis property is used for dropdown positioning on the screen.\n"
84663
84401
  },
84664
- {
84665
- "name": "LANGUAGE_MAX_COLUMNS",
84666
- "coverageIgnore": false,
84667
- "defaultValue": "8",
84668
- "deprecated": false,
84669
- "deprecationMessage": "",
84670
- "type": "number",
84671
- "indexKey": "",
84672
- "optional": false,
84673
- "description": "",
84674
- "line": 73,
84675
- "rawdescription": "\n",
84676
- "modifierKind": [
84677
- 148
84678
- ]
84679
- },
84680
84402
  {
84681
84403
  "name": "languageArrowPosition",
84682
84404
  "coverageIgnore": false,
@@ -84686,7 +84408,7 @@
84686
84408
  "indexKey": "",
84687
84409
  "optional": false,
84688
84410
  "description": "<p>This property is used for dropdown positioning on the screen.</p>\n",
84689
- "line": 94,
84411
+ "line": 88,
84690
84412
  "rawdescription": "\n\nThis property is used for dropdown positioning on the screen.\n"
84691
84413
  },
84692
84414
  {
@@ -84699,41 +84421,9 @@
84699
84421
  "indexKey": "",
84700
84422
  "optional": false,
84701
84423
  "description": "",
84702
- "line": 95,
84424
+ "line": 89,
84703
84425
  "rawdescription": "\n"
84704
84426
  },
84705
- {
84706
- "name": "languageLinkElement",
84707
- "coverageIgnore": false,
84708
- "defaultValue": "viewChild('languageLink', { read: ElementRef })",
84709
- "deprecated": false,
84710
- "deprecationMessage": "",
84711
- "type": "unknown",
84712
- "indexKey": "",
84713
- "optional": false,
84714
- "description": "<p>The link to open the popover dialog.</p>\n",
84715
- "line": 61,
84716
- "rawdescription": "\n\nThe link to open the popover dialog.\n",
84717
- "modifierKind": [
84718
- 148
84719
- ]
84720
- },
84721
- {
84722
- "name": "languagePopover",
84723
- "coverageIgnore": false,
84724
- "defaultValue": "viewChild(EclSiteHeaderLanguagePopoverComponent)",
84725
- "deprecated": false,
84726
- "deprecationMessage": "",
84727
- "type": "unknown",
84728
- "indexKey": "",
84729
- "optional": false,
84730
- "description": "<p>The language popover, that shows all available languages (configured in the config file of the current site).</p>\n",
84731
- "line": 57,
84732
- "rawdescription": "\n\nThe language popover, that shows all available languages (configured in the config file of the current site).\n",
84733
- "modifierKind": [
84734
- 148
84735
- ]
84736
- },
84737
84427
  {
84738
84428
  "name": "leftPosition",
84739
84429
  "coverageIgnore": false,
@@ -84743,25 +84433,9 @@
84743
84433
  "indexKey": "",
84744
84434
  "optional": false,
84745
84435
  "description": "",
84746
- "line": 97,
84436
+ "line": 91,
84747
84437
  "rawdescription": "\n"
84748
84438
  },
84749
- {
84750
- "name": "MOBILE_BREAKPOINT",
84751
- "coverageIgnore": false,
84752
- "defaultValue": "768",
84753
- "deprecated": false,
84754
- "deprecationMessage": "",
84755
- "type": "number",
84756
- "indexKey": "",
84757
- "optional": false,
84758
- "description": "",
84759
- "line": 72,
84760
- "rawdescription": "\n",
84761
- "modifierKind": [
84762
- 148
84763
- ]
84764
- },
84765
84439
  {
84766
84440
  "name": "nonEuColumnsCount",
84767
84441
  "coverageIgnore": false,
@@ -84772,7 +84446,7 @@
84772
84446
  "indexKey": "",
84773
84447
  "optional": false,
84774
84448
  "description": "",
84775
- "line": 107,
84449
+ "line": 101,
84776
84450
  "rawdescription": "\n"
84777
84451
  },
84778
84452
  {
@@ -84785,7 +84459,7 @@
84785
84459
  "indexKey": "",
84786
84460
  "optional": false,
84787
84461
  "description": "<p>Array of non-EU languages, that can be selected for the current site.</p>\n",
84788
- "line": 105,
84462
+ "line": 99,
84789
84463
  "rawdescription": "\n\nArray of non-EU languages, that can be selected for the current site.\n"
84790
84464
  },
84791
84465
  {
@@ -84797,7 +84471,7 @@
84797
84471
  "indexKey": "",
84798
84472
  "optional": false,
84799
84473
  "description": "",
84800
- "line": 96,
84474
+ "line": 90,
84801
84475
  "rawdescription": "\n"
84802
84476
  }
84803
84477
  ],
@@ -84809,11 +84483,14 @@
84809
84483
  "optional": false,
84810
84484
  "returnType": "string",
84811
84485
  "typeParameters": [],
84812
- "line": 143,
84486
+ "line": 145,
84813
84487
  "deprecated": false,
84814
84488
  "deprecationMessage": "",
84815
84489
  "rawdescription": "\n",
84816
- "description": ""
84490
+ "description": "",
84491
+ "modifierKind": [
84492
+ 124
84493
+ ]
84817
84494
  },
84818
84495
  {
84819
84496
  "name": "hasLanguageCodes",
@@ -84822,14 +84499,11 @@
84822
84499
  "optional": false,
84823
84500
  "returnType": "boolean",
84824
84501
  "typeParameters": [],
84825
- "line": 200,
84502
+ "line": 196,
84826
84503
  "deprecated": false,
84827
84504
  "deprecationMessage": "",
84828
84505
  "rawdescription": "\n",
84829
- "description": "",
84830
- "modifierKind": [
84831
- 125
84832
- ]
84506
+ "description": ""
84833
84507
  },
84834
84508
  {
84835
84509
  "name": "ngAfterViewInit",
@@ -84838,11 +84512,11 @@
84838
84512
  "optional": false,
84839
84513
  "returnType": "void",
84840
84514
  "typeParameters": [],
84841
- "line": 130,
84515
+ "line": 135,
84842
84516
  "deprecated": false,
84843
84517
  "deprecationMessage": "",
84844
- "rawdescription": "\n\nAfter view is initialized -> calculate popover position and initialize languages, that are configured in the config file\n of the current site.\n",
84845
- "description": "<p>After view is initialized -&gt; calculate popover position and initialize languages, that are configured in the config file\n of the current site.</p>\n"
84518
+ "rawdescription": "\n\nAfter view is initialized -> set up resize repositioning and initialize languages, that are configured in the config file\n of the current site.\n",
84519
+ "description": "<p>After view is initialized -&gt; set up resize repositioning and initialize languages, that are configured in the config file\n of the current site.</p>\n"
84846
84520
  },
84847
84521
  {
84848
84522
  "name": "ngOnDestroy",
@@ -84851,7 +84525,7 @@
84851
84525
  "optional": false,
84852
84526
  "returnType": "void",
84853
84527
  "typeParameters": [],
84854
- "line": 138,
84528
+ "line": 140,
84855
84529
  "deprecated": false,
84856
84530
  "deprecationMessage": "",
84857
84531
  "rawdescription": "\n",
@@ -84864,7 +84538,7 @@
84864
84538
  "optional": false,
84865
84539
  "returnType": "void",
84866
84540
  "typeParameters": [],
84867
- "line": 122,
84541
+ "line": 127,
84868
84542
  "deprecated": false,
84869
84543
  "deprecationMessage": "",
84870
84544
  "rawdescription": "\n",
@@ -84877,19 +84551,13 @@
84877
84551
  "optional": false,
84878
84552
  "returnType": "void",
84879
84553
  "typeParameters": [],
84880
- "line": 188,
84554
+ "line": 185,
84881
84555
  "deprecated": false,
84882
84556
  "deprecationMessage": "",
84883
84557
  "rawdescription": "\n\nClose the dropdown, when clicking outside of the component.\n",
84884
84558
  "description": "<p>Close the dropdown, when clicking outside of the component.</p>\n",
84885
- "decorators": [
84886
- {
84887
- "name": "HostListener",
84888
- "stringifiedArguments": "'eclClickOutside'"
84889
- }
84890
- ],
84891
84559
  "modifierKind": [
84892
- 171
84560
+ 124
84893
84561
  ]
84894
84562
  },
84895
84563
  {
@@ -84899,19 +84567,13 @@
84899
84567
  "optional": false,
84900
84568
  "returnType": "void",
84901
84569
  "typeParameters": [],
84902
- "line": 196,
84570
+ "line": 192,
84903
84571
  "deprecated": false,
84904
84572
  "deprecationMessage": "",
84905
84573
  "rawdescription": "\n\nClose the dropdown, when pressing ESC key.\n",
84906
84574
  "description": "<p>Close the dropdown, when pressing ESC key.</p>\n",
84907
- "decorators": [
84908
- {
84909
- "name": "HostListener",
84910
- "stringifiedArguments": "'document:keydown.escape'"
84911
- }
84912
- ],
84913
84575
  "modifierKind": [
84914
- 171
84576
+ 124
84915
84577
  ]
84916
84578
  },
84917
84579
  {
@@ -84930,16 +84592,19 @@
84930
84592
  "optional": false,
84931
84593
  "returnType": "void",
84932
84594
  "typeParameters": [],
84933
- "line": 151,
84595
+ "line": 153,
84934
84596
  "deprecated": false,
84935
84597
  "deprecationMessage": "",
84936
84598
  "rawdescription": "\n\nToggle the language dropdown when clicking the link, showing the current language.\n",
84937
84599
  "description": "<p>Toggle the language dropdown when clicking the link, showing the current language.</p>\n",
84600
+ "modifierKind": [
84601
+ 124
84602
+ ],
84938
84603
  "jsdoctags": [
84939
84604
  {
84940
84605
  "name": {
84941
- "pos": 5256,
84942
- "end": 5259,
84606
+ "pos": 5258,
84607
+ "end": 5261,
84943
84608
  "kind": 80,
84944
84609
  "id": 0,
84945
84610
  "flags": 16842752,
@@ -84952,8 +84617,8 @@
84952
84617
  "deprecated": false,
84953
84618
  "deprecationMessage": "",
84954
84619
  "tagName": {
84955
- "pos": 5250,
84956
- "end": 5255,
84620
+ "pos": 5252,
84621
+ "end": 5257,
84957
84622
  "kind": 80,
84958
84623
  "id": 0,
84959
84624
  "flags": 16842752,
@@ -84980,11 +84645,14 @@
84980
84645
  "optional": false,
84981
84646
  "returnType": "void",
84982
84647
  "typeParameters": [],
84983
- "line": 173,
84648
+ "line": 171,
84984
84649
  "deprecated": false,
84985
84650
  "deprecationMessage": "",
84986
84651
  "rawdescription": "\n",
84987
84652
  "description": "",
84653
+ "modifierKind": [
84654
+ 124
84655
+ ],
84988
84656
  "jsdoctags": [
84989
84657
  {
84990
84658
  "name": "evt",
@@ -85015,11 +84683,14 @@
85015
84683
  "optional": false,
85016
84684
  "returnType": "void",
85017
84685
  "typeParameters": [],
85018
- "line": 177,
84686
+ "line": 175,
85019
84687
  "deprecated": false,
85020
84688
  "deprecationMessage": "",
85021
84689
  "rawdescription": "\n",
85022
84690
  "description": "",
84691
+ "modifierKind": [
84692
+ 124
84693
+ ],
85023
84694
  "jsdoctags": [
85024
84695
  {
85025
84696
  "name": "evt",
@@ -85076,44 +84747,8 @@
85076
84747
  "coverageIgnore": false,
85077
84748
  "deprecated": false,
85078
84749
  "deprecationMessage": "",
85079
- "hostBindings": [
85080
- {
85081
- "coverageIgnore": false,
85082
- "name": "class",
85083
- "actualName": "cssClasses",
85084
- "deprecated": false,
85085
- "deprecationMessage": "",
85086
- "rawdescription": "\n",
85087
- "description": "",
85088
- "line": 118,
85089
- "type": "string",
85090
- "decorators": []
85091
- }
85092
- ],
85093
- "hostListeners": [
85094
- {
85095
- "coverageIgnore": false,
85096
- "name": "document:keydown.escape",
85097
- "args": [],
85098
- "argsDecorator": [],
85099
- "deprecated": false,
85100
- "deprecationMessage": "",
85101
- "rawdescription": "\n\nClose the dropdown, when pressing ESC key.\n",
85102
- "description": "<p>Close the dropdown, when pressing ESC key.</p>\n",
85103
- "line": 196
85104
- },
85105
- {
85106
- "coverageIgnore": false,
85107
- "name": "eclClickOutside",
85108
- "args": [],
85109
- "argsDecorator": [],
85110
- "deprecated": false,
85111
- "deprecationMessage": "",
85112
- "rawdescription": "\n\nClose the dropdown, when clicking outside of the component.\n",
85113
- "description": "<p>Close the dropdown, when clicking outside of the component.</p>\n",
85114
- "line": 188
85115
- }
85116
- ],
84750
+ "hostBindings": [],
84751
+ "hostListeners": [],
85117
84752
  "standalone": false,
85118
84753
  "imports": [
85119
84754
  {
@@ -85139,14 +84774,14 @@
85139
84774
  "description": "<p>This component is used to switch between the languages of the application. Shows the current language, when clicked,\n opens a language selector.</p>\n",
85140
84775
  "rawdescription": "\n\nThis component is used to switch between the languages of the application. Shows the current language, when clicked,\n opens a language selector.\n",
85141
84776
  "type": "component",
85142
- "sourceCode": "import {\n AfterViewInit,\n Component,\n DOCUMENT,\n ElementRef,\n EventEmitter,\n HostBinding,\n HostListener,\n inject,\n OnDestroy,\n OnInit,\n Output,\n viewChild,\n} from '@angular/core';\nimport { UpperCasePipe } from '@angular/common';\nimport { A11yModule } from '@angular/cdk/a11y';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { EuiEuLanguages, GLOBAL_CONFIG_TOKEN, GlobalConfig, I18nService } from '@eui/core';\nimport { EuiLanguage } from '@eui/base';\nimport { ECLBaseDirective, ECLClickOutsideDirective, EclRtlService, EclThemeService } from '@eui/ecl/core';\nimport { Subject, takeUntil } from 'rxjs';\nimport { EclSiteHeaderLanguageClickEvent, EclSiteHeaderLanguageCloseEvent, EclSiteHeaderLanguageSelectedEvent } from '../events';\nimport { EclSiteHeaderLanguagePopoverComponent } from './ecl-site-header-language-popover.component';\nimport { EclAreaDataService } from '../services/ecl-area-data.service';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\n\n/**\n * This component is used to switch between the languages of the application. Shows the current language, when clicked,\n * opens a language selector.\n */\n@Component({\n selector: 'ecl-site-header-language',\n templateUrl: './ecl-site-header-language.component.html',\n imports: [A11yModule, TranslatePipe, UpperCasePipe, ...EUI_ECL_ICON, EclSiteHeaderLanguagePopoverComponent],\n hostDirectives: [\n {\n directive: ECLClickOutsideDirective,\n outputs: ['eclClickOutside'],\n },\n ],\n styles: [\n `\n :host {\n display: block;\n }\n `,\n ],\n})\nexport class EclSiteHeaderLanguageComponent extends ECLBaseDirective implements OnInit, AfterViewInit, OnDestroy {\n protected eclThemeService = inject(EclThemeService);\n protected config = inject<GlobalConfig>(GLOBAL_CONFIG_TOKEN, { optional: true });\n protected i18nService = inject(I18nService);\n\n /**\n * The language popover, that shows all available languages (configured in the config file of the current site).\n */\n readonly languagePopover = viewChild(EclSiteHeaderLanguagePopoverComponent);\n /**\n * The link to open the popover dialog.\n */\n readonly languageLinkElement = viewChild('languageLink', { read: ElementRef });\n\n /**\n * Thie event is emited, when language link, showing the current language is clicked.\n */\n @Output() languageClick = new EventEmitter<EclSiteHeaderLanguageClickEvent>();\n /**\n * Thie event is emited, when user selects a new language from the dropdown.\n */\n @Output() languageSelected = new EventEmitter<EclSiteHeaderLanguageSelectedEvent>();\n\n readonly MOBILE_BREAKPOINT = 768;\n readonly LANGUAGE_MAX_COLUMNS = 8;\n isLanguagesDropdownVisible = false;\n /**\n * This property is used for dropdown positioning on the screen.\n */\n isPushRight: boolean;\n /**\n * This property is used for dropdown positioning on the screen.\n */\n isPushLeft: boolean;\n /**\n * This property is used for dropdown positioning on the screen.\n */\n isStack: boolean;\n /**\n * This property is used for dropdown positioning on the screen.\n */\n isFull: boolean;\n /**\n * This property is used for dropdown positioning on the screen.\n */\n languageArrowPosition: string;\n languageCode = 'en';\n rightPosition: number;\n leftPosition: number;\n /**\n * Array of EU languages, that can be selected for the current site.\n */\n euLanguages: EuiLanguage[] = [];\n /**\n * Array of non-EU languages, that can be selected for the current site.\n */\n nonEuLanguages: EuiLanguage[] = [];\n euColumnsCount = 1;\n nonEuColumnsCount = 1;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private _languages: EuiLanguage[] = [];\n private parentHeaderWidth: number;\n private isRtl = false;\n private eclAreaDataService = inject(EclAreaDataService);\n private eclRtlService = inject(EclRtlService);\n private readonly document = inject<Document>(DOCUMENT);\n private readonly window = this.document.defaultView; // Window | null\n\n @HostBinding('class')\n get cssClasses(): string {\n return [super.getCssClasses('ecl-site-header__language')].join(' ').trim();\n }\n\n ngOnInit(): void {\n this.handleRtlChangeState();\n }\n\n /**\n * After view is initialized -> calculate popover position and initialize languages, that are configured in the config file\n * of the current site.\n */\n ngAfterViewInit(): void {\n this.eclAreaDataService.dataSubject$.pipe(takeUntil(this.destroy$)).subscribe(\n parentHeaderRect => {\n this.calculatePopoverPosition(parentHeaderRect.right, parentHeaderRect.left);\n });\n this.handleInitialConfiguredLanguages();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.complete();\n }\n\n getLanguageLabel(): string {\n return `${EuiEuLanguages.getLanguageByCode(this.languageCode)?.label} - ${this.languageCode.toUpperCase()}`;\n }\n\n /**\n * Toggle the language dropdown when clicking the link, showing the current language.\n * @param evt\n */\n onLanguageClick(evt: Event): void {\n this.isLanguagesDropdownVisible = !this.isLanguagesDropdownVisible;\n if( !this.isLanguagesDropdownVisible ) {\n setTimeout(() => {\n this.isFull = false;\n this.isStack = false;\n this.isPushRight = false;\n this.rightPosition = undefined;\n this.leftPosition = undefined;\n this.languageArrowPosition = undefined;\n });\n }\n\n // If the dropdown is visible, we set the max-height of the dropdown, so that it can be scrolled.\n if (this.isLanguagesDropdownVisible) {\n setTimeout(() => this.languagePopover().setLanguageContentMaxHeight());\n }\n this.languageClick.next(new EclSiteHeaderLanguageClickEvent());\n\n evt.preventDefault();\n }\n\n onLanguageClosed(evt: EclSiteHeaderLanguageCloseEvent): void {\n this.isLanguagesDropdownVisible = false;\n }\n\n onLanguageSelected(evt: EclSiteHeaderLanguageSelectedEvent): void {\n this.languageCode = evt.language.code;\n this.updateCurrentLanguage(evt.language.code);\n this.isLanguagesDropdownVisible = false;\n this.languageSelected.next(new EclSiteHeaderLanguageSelectedEvent(evt.language));\n }\n\n /**\n * Close the dropdown, when clicking outside of the component.\n */\n @HostListener('eclClickOutside')\n onClickOutside(): void {\n this.isLanguagesDropdownVisible = false;\n }\n\n /**\n * Close the dropdown, when pressing ESC key.\n */\n @HostListener('document:keydown.escape')\n onEscapeKeydownHandler(): void {\n this.isLanguagesDropdownVisible = false;\n }\n\n public hasLanguageCodes(): boolean {\n return this._languages && this._languages.length > 0;\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 * Calculate the number of columns for EU and non-EU languages, depending on languages' count.\n */\n private updateLanguages(): void {\n\n this.euLanguages = this._languages.filter((item) => EuiEuLanguages.isEuLanguage(item.code));\n\n this.nonEuLanguages = this._languages.filter((item) => !EuiEuLanguages.isEuLanguage(item.code));\n\n this.euColumnsCount = Math.ceil(this.euLanguages.length / this.LANGUAGE_MAX_COLUMNS);\n\n this.nonEuColumnsCount = Math.ceil(this.nonEuLanguages.length / this.LANGUAGE_MAX_COLUMNS);\n }\n\n private calculatePopoverPosition( parentHeaderRight: number, parentHeaderLeft: number): void {\n setTimeout(() => {\n if (this.hasLanguageCodes()) {\n const arrowSize = '0.5rem';\n const linkRect = this.languageLinkElement().nativeElement.getBoundingClientRect();\n const popoverRect = this.languagePopover()?.el.nativeElement.getBoundingClientRect();\n const screenWidth = this.window.innerWidth;\n const vw = Math.max(document.documentElement.clientWidth || 0, this.window.innerWidth || 0);\n\n this.isFull = false;\n this.isStack = false;\n this.isPushRight = false;\n this.isPushLeft = false;\n this.rightPosition = undefined;\n this.leftPosition = undefined;\n this.languageArrowPosition = undefined;\n\n if (popoverRect?.width > this.parentHeaderWidth) {\n this.isStack = true;\n if (this.nonEuLanguages.length) {\n this.nonEuColumnsCount = Math.max(this.euColumnsCount, this.nonEuColumnsCount);\n }\n }\n if (this.isRtl && popoverRect?.left < 0) {\n const arrowPosition = linkRect.right - parentHeaderLeft - linkRect.width / 2;\n this.isPushLeft = true;\n this.leftPosition = -linkRect.left + parentHeaderLeft;\n this.languageArrowPosition = `${arrowPosition}px`;\n } else if (!this.isRtl && popoverRect?.right > screenWidth) {\n const arrowPosition = parentHeaderRight - linkRect.right + linkRect.width / 2;\n\n this.isPushRight = true;\n this.rightPosition = -parentHeaderRight + linkRect.right;\n this.languageArrowPosition = `calc(${arrowPosition}px - ${arrowSize})`;\n }\n\n if (vw < this.MOBILE_BREAKPOINT) {\n const arrowPosition = popoverRect?.right - linkRect.right + linkRect.width / 2;\n\n this.isFull = true;\n this.languageArrowPosition = `calc(${arrowPosition}px - ${arrowSize})`;\n }\n }\n });\n }\n\n private getConfiguredLanguages(): void {\n const languages: string[] = this.config?.i18n?.i18nService?.languages.map(lang => {\n return (typeof lang !== 'string') ? (lang as EuiLanguage).code : lang\n }) || [];\n this._languages = EuiEuLanguages.getAllLanguagesByCodes(languages);\n\n if (this.config?.i18n?.i18nService?.defaultLanguage) {\n this.languageCode = this.config?.i18n?.i18nService?.defaultLanguage;\n } else {\n if (this._languages && this._languages.length > 0) {\n this.languageCode = this._languages[0].code;\n }\n }\n }\n\n private updateCurrentLanguage(lang: string): void {\n this.i18nService.updateState({\n activeLang: lang,\n });\n }\n\n private handleInitialConfiguredLanguages(): void {\n setTimeout(() => {\n if (this._languages === undefined || this._languages.length === 0) {\n this.getConfiguredLanguages();\n }\n this.updateLanguages();\n });\n }\n}\n",
84777
+ "sourceCode": "import {\n AfterViewInit,\n Component,\n DOCUMENT,\n ElementRef,\n EventEmitter,\n inject,\n OnDestroy,\n OnInit,\n Output,\n viewChild,\n} from '@angular/core';\nimport { UpperCasePipe } from '@angular/common';\nimport { A11yModule } from '@angular/cdk/a11y';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { EuiEuLanguages, GLOBAL_CONFIG_TOKEN, GlobalConfig, I18nService } from '@eui/core';\nimport { EuiLanguage } from '@eui/base';\nimport { ECLBaseDirective, ECLClickOutsideDirective, EclRtlService, EclThemeService } from '@eui/ecl/core';\nimport { debounceTime, fromEvent, Subject, takeUntil } from 'rxjs';\nimport { EclSiteHeaderLanguageClickEvent, EclSiteHeaderLanguageCloseEvent, EclSiteHeaderLanguageSelectedEvent } from '../events';\nimport { EclSiteHeaderLanguagePopoverComponent } from './ecl-site-header-language-popover.component';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\n\n/** Half the arrow's own width, matching ECL's `arrowSize`. */\nconst ARROW_SIZE = '0.5rem';\n\n/**\n * This component is used to switch between the languages of the application. Shows the current language, when clicked,\n * opens a language selector.\n */\n@Component({\n selector: 'ecl-site-header-language',\n templateUrl: './ecl-site-header-language.component.html',\n imports: [A11yModule, TranslatePipe, UpperCasePipe, ...EUI_ECL_ICON, EclSiteHeaderLanguagePopoverComponent],\n hostDirectives: [\n {\n directive: ECLClickOutsideDirective,\n outputs: ['eclClickOutside'],\n },\n ],\n styles: [\n `\n :host {\n display: block;\n }\n `,\n ],\n host: {\n '[class]': 'cssClasses',\n '(eclClickOutside)': 'onClickOutside()',\n '(document:keydown.escape)': 'onEscapeKeydownHandler()',\n },\n})\nexport class EclSiteHeaderLanguageComponent extends ECLBaseDirective implements OnInit, AfterViewInit, OnDestroy {\n protected eclThemeService = inject(EclThemeService);\n protected config = inject<GlobalConfig>(GLOBAL_CONFIG_TOKEN, { optional: true });\n protected i18nService = inject(I18nService);\n\n /**\n * Thie event is emited, when language link, showing the current language is clicked.\n */\n @Output() languageClick = new EventEmitter<EclSiteHeaderLanguageClickEvent>();\n /**\n * Thie event is emited, when user selects a new language from the dropdown.\n */\n @Output() languageSelected = new EventEmitter<EclSiteHeaderLanguageSelectedEvent>();\n\n isLanguagesDropdownVisible = false;\n /**\n * This property is used for dropdown positioning on the screen.\n */\n isPushRight: boolean;\n /**\n * This property is used for dropdown positioning on the screen.\n */\n isPushLeft: boolean;\n /**\n * This property is used for dropdown positioning on the screen.\n */\n isStack: boolean;\n /**\n * This property is used for dropdown positioning on the screen.\n */\n isFull: boolean;\n /**\n * This property is used for dropdown positioning on the screen.\n */\n languageArrowPosition: string;\n languageCode = 'en';\n rightPosition: number;\n leftPosition: number;\n /**\n * Array of EU languages, that can be selected for the current site.\n */\n euLanguages: EuiLanguage[] = [];\n /**\n * Array of non-EU languages, that can be selected for the current site.\n */\n nonEuLanguages: EuiLanguage[] = [];\n euColumnsCount = 1;\n nonEuColumnsCount = 1;\n\n /**\n * The language popover, that shows all available languages (configured in the config file of the current site).\n */\n private readonly languagePopover = viewChild(EclSiteHeaderLanguagePopoverComponent);\n /**\n * The link to open the popover dialog.\n */\n private readonly languageLinkElement = viewChild('languageLink', { read: ElementRef });\n\n private readonly MOBILE_BREAKPOINT = 768;\n private readonly LANGUAGE_MAX_COLUMNS = 8;\n private readonly RESIZE_DEBOUNCE = 200;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private _languages: EuiLanguage[] = [];\n private isRtl = false;\n private readonly eclRtlService = inject(EclRtlService);\n private readonly el = inject(ElementRef);\n private readonly document = inject<Document>(DOCUMENT);\n private readonly window = this.document.defaultView; // Window | null\n\n protected get cssClasses(): string {\n return [super.getCssClasses('ecl-site-header__language')].join(' ').trim();\n }\n\n ngOnInit(): void {\n this.handleRtlChangeState();\n }\n\n /**\n * After view is initialized -> set up resize repositioning and initialize languages, that are configured in the config file\n * of the current site.\n */\n ngAfterViewInit(): void {\n this.handleResize();\n this.handleInitialConfiguredLanguages();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.complete();\n }\n\n protected getLanguageLabel(): string {\n return `${EuiEuLanguages.getLanguageByCode(this.languageCode)?.label} - ${this.languageCode.toUpperCase()}`;\n }\n\n /**\n * Toggle the language dropdown when clicking the link, showing the current language.\n * @param evt\n */\n protected onLanguageClick(evt: Event): void {\n this.isLanguagesDropdownVisible = !this.isLanguagesDropdownVisible;\n if (!this.isLanguagesDropdownVisible) {\n setTimeout(() => this.resetPositioning());\n }\n\n // If the dropdown is visible, we set the max-height of the dropdown, so that it can be scrolled.\n if (this.isLanguagesDropdownVisible) {\n setTimeout(() => this.languagePopover().setLanguageContentMaxHeight());\n // Position the popover and its arrow after the popover is rendered and reflowed.\n // Matches ECL's updateOverlayPosition call in toggleOverlay.\n requestAnimationFrame(() => this.calculatePopoverPosition());\n }\n this.languageClick.next(new EclSiteHeaderLanguageClickEvent());\n\n evt.preventDefault();\n }\n\n protected onLanguageClosed(evt: EclSiteHeaderLanguageCloseEvent): void {\n this.isLanguagesDropdownVisible = false;\n }\n\n protected onLanguageSelected(evt: EclSiteHeaderLanguageSelectedEvent): void {\n this.languageCode = evt.language.code;\n this.updateCurrentLanguage(evt.language.code);\n this.isLanguagesDropdownVisible = false;\n this.languageSelected.next(new EclSiteHeaderLanguageSelectedEvent(evt.language));\n }\n\n /**\n * Close the dropdown, when clicking outside of the component.\n */\n protected onClickOutside(): void {\n this.isLanguagesDropdownVisible = false;\n }\n\n /**\n * Close the dropdown, when pressing ESC key.\n */\n protected onEscapeKeydownHandler(): void {\n this.isLanguagesDropdownVisible = false;\n }\n\n hasLanguageCodes(): boolean {\n return this._languages && this._languages.length > 0;\n }\n\n private handleRtlChangeState(): void {\n this.eclRtlService.currentRtlState$.pipe(takeUntil(this.destroy$)).subscribe((rtlState) => {\n this.isRtl = rtlState;\n if (this.isLanguagesDropdownVisible) {\n this.calculatePopoverPosition();\n }\n });\n }\n\n /**\n * Calculate the number of columns for EU and non-EU languages, depending on languages' count.\n */\n private updateLanguages(): void {\n\n this.euLanguages = this._languages.filter((item) => EuiEuLanguages.isEuLanguage(item.code));\n\n this.nonEuLanguages = this._languages.filter((item) => !EuiEuLanguages.isEuLanguage(item.code));\n\n this.euColumnsCount = Math.ceil(this.euLanguages.length / this.LANGUAGE_MAX_COLUMNS);\n\n this.nonEuColumnsCount = Math.ceil(this.nonEuLanguages.length / this.LANGUAGE_MAX_COLUMNS);\n }\n\n /**\n * Clears every positioning flag/offset so a fresh calculation (or a close) starts from a known state.\n */\n private resetPositioning(): void {\n this.isFull = false;\n this.isStack = false;\n this.isPushRight = false;\n this.isPushLeft = false;\n this.rightPosition = undefined;\n this.leftPosition = undefined;\n this.languageArrowPosition = undefined;\n }\n\n /**\n * Positions the language popover and its arrow, matching ECL's updateOverlayPosition.\n * The container is the site-header top area (ECL's '[data-ecl-site-header-top]'), resolved from\n * the DOM rather than a shared service so the measurement is taken at the right time (on open/resize).\n */\n private calculatePopoverPosition(): void {\n if (!this.isLanguagesDropdownVisible || !this.hasLanguageCodes()) return;\n\n const container = this.el.nativeElement.closest('.ecl-site-header__top') as HTMLElement | null;\n const languagePopover = this.languagePopover();\n if (!container || !languagePopover) return;\n\n const toggleButtonRect = this.languageLinkElement().nativeElement.getBoundingClientRect();\n const popoverRect = languagePopover.el.nativeElement.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const screenWidth = this.window.innerWidth;\n const clientWidth = Math.max(this.document.documentElement.clientWidth || 0, this.window.innerWidth || 0);\n\n this.resetPositioning();\n\n // Stack the EU / non-EU lists when the popover is wider than the container.\n if (popoverRect.width > containerRect.width) {\n this.isStack = true;\n if (this.nonEuLanguages.length) {\n this.nonEuColumnsCount = Math.max(this.euColumnsCount, this.nonEuColumnsCount);\n }\n }\n\n // Mobile: the popover is full width. The arrow is anchored from the box's right edge,\n // so the offset is measured against popoverRect.right. Exclusive with push-right/left,\n // matching ECL's updateOverlayPosition (mobile branch returns early).\n if (clientWidth < this.MOBILE_BREAKPOINT) {\n const arrowOffset = popoverRect.right - toggleButtonRect.right + toggleButtonRect.width / 2;\n this.isFull = true;\n this.languageArrowPosition = `calc(${arrowOffset}px - ${ARROW_SIZE})`;\n return;\n }\n\n // RTL: popover overflows the left edge -> push it right against the container's left edge.\n if (this.isRtl && popoverRect.left < 0) {\n const arrowOffset = toggleButtonRect.right - containerRect.left - toggleButtonRect.width / 2;\n this.isPushLeft = true;\n this.leftPosition = -toggleButtonRect.left + containerRect.left;\n this.languageArrowPosition = `${arrowOffset}px`;\n } else if (!this.isRtl && popoverRect.right > screenWidth) {\n // LTR: popover overflows the right edge -> push it left against the container's right edge.\n const arrowOffset = containerRect.right - toggleButtonRect.right + toggleButtonRect.width / 2;\n this.isPushRight = true;\n this.rightPosition = -containerRect.right + toggleButtonRect.right;\n this.languageArrowPosition = `calc(${arrowOffset}px - ${ARROW_SIZE})`;\n }\n }\n\n /**\n * On window resize -> reposition the popover, but only while it is open.\n * Debounced for performance, matching ECL's handleResize.\n */\n private handleResize(): void {\n const win = this.window;\n if (!win) return;\n fromEvent(win, 'resize')\n .pipe(debounceTime(this.RESIZE_DEBOUNCE), takeUntil(this.destroy$))\n .subscribe(() => {\n if (this.isLanguagesDropdownVisible) {\n this.calculatePopoverPosition();\n }\n });\n }\n\n private getConfiguredLanguages(): void {\n const languages: string[] = this.config?.i18n?.i18nService?.languages.map(lang => {\n return (typeof lang !== 'string') ? (lang as EuiLanguage).code : lang\n }) || [];\n this._languages = EuiEuLanguages.getAllLanguagesByCodes(languages);\n\n if (this.config?.i18n?.i18nService?.defaultLanguage) {\n this.languageCode = this.config?.i18n?.i18nService?.defaultLanguage;\n } else {\n if (this._languages && this._languages.length > 0) {\n this.languageCode = this._languages[0].code;\n }\n }\n }\n\n private updateCurrentLanguage(lang: string): void {\n this.i18nService.updateState({\n activeLang: lang,\n });\n }\n\n private handleInitialConfiguredLanguages(): void {\n setTimeout(() => {\n if (this._languages === undefined || this._languages.length === 0) {\n this.getConfiguredLanguages();\n }\n this.updateLanguages();\n });\n }\n}\n",
85143
84778
  "assetsDirs": [],
85144
84779
  "styleUrlsData": "",
85145
84780
  "stylesData": "\n :host {\n display: block;\n }\n \n",
85146
84781
  "jsdoctags": [
85147
84782
  {
85148
- "pos": 1016,
85149
- "end": 1174,
84783
+ "pos": 1027,
84784
+ "end": 1185,
85150
84785
  "kind": 321,
85151
84786
  "id": 0,
85152
84787
  "flags": 16777216,
@@ -85170,7 +84805,7 @@
85170
84805
  "name": "cssClasses",
85171
84806
  "type": "string",
85172
84807
  "returnType": "string",
85173
- "line": 118,
84808
+ "line": 123,
85174
84809
  "rawdescription": "\n",
85175
84810
  "description": ""
85176
84811
  }
@@ -85226,10 +84861,11 @@
85226
84861
  },
85227
84862
  {
85228
84863
  "name": "EclSiteHeaderLanguagePopoverComponent",
85229
- "id": "component-EclSiteHeaderLanguagePopoverComponent-2cf806c3aaf3e3fcddc93cd58235381bd2e1e52280c90c3e70a35e692f77179e7aa3c79c39058a5f33e5faea66a7df1073498292a7c2004e7c862751e9d21667",
84864
+ "id": "component-EclSiteHeaderLanguagePopoverComponent-e1d84a0bf4a937ce3e593bdd02f17dca9b853cc426819d4e57f144f50f918762e5340d2d90f1a0428c1e121c76d983d3378cbb1b91a0dd7b4a991de29be1315b",
85230
84865
  "file": "packages/ecl/components/ecl-site-header/language/ecl-site-header-language-popover.component.ts",
85231
84866
  "encapsulation": [],
85232
84867
  "entryComponents": [],
84868
+ "host": {},
85233
84869
  "inputs": [],
85234
84870
  "outputs": [],
85235
84871
  "providers": [],
@@ -85244,85 +84880,34 @@
85244
84880
  "hostDirectives": [],
85245
84881
  "inputsClass": [
85246
84882
  {
84883
+ "name": "euColumnsCount",
85247
84884
  "coverageIgnore": false,
85248
- "name": "euLanguages",
85249
- "defaultValue": "[]",
85250
- "deprecated": false,
85251
- "deprecationMessage": "",
85252
- "rawdescription": "\n",
85253
- "description": "",
85254
- "line": 35,
85255
- "type": "EuiLanguage[]",
85256
- "decorators": []
85257
- },
85258
- {
85259
- "coverageIgnore": false,
85260
- "name": "languageArrowPosition",
85261
- "deprecated": false,
85262
- "deprecationMessage": "",
85263
- "rawdescription": "\n\nProperty to position the arrow of the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n",
85264
- "description": "<p>Property to position the arrow of the dialog correctly. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85265
- "line": 76,
85266
- "type": "string",
85267
- "decorators": []
85268
- },
85269
- {
85270
- "coverageIgnore": false,
85271
- "name": "languageCode",
85272
- "deprecated": false,
85273
- "deprecationMessage": "",
85274
- "rawdescription": "\n\nCurrent language\n",
85275
- "description": "<p>Current language</p>\n",
85276
- "line": 34,
85277
- "type": "string",
85278
- "decorators": []
85279
- },
85280
- {
85281
- "coverageIgnore": false,
85282
- "name": "leftPosition",
84885
+ "defaultValue": "undefined",
85283
84886
  "deprecated": false,
85284
84887
  "deprecationMessage": "",
85285
- "rawdescription": "\n\nProperty to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n",
85286
- "description": "<p>Property to position the dialog correctly. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85287
- "line": 72,
85288
84888
  "type": "number",
85289
- "decorators": []
84889
+ "indexKey": "",
84890
+ "optional": false,
84891
+ "description": "<p>Number of columns for eu languages. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
84892
+ "line": 52,
84893
+ "rawdescription": "\n\nNumber of columns for eu languages. Calculated by the parent component 'ecl-site-header-language'.\n",
84894
+ "modifierKind": [
84895
+ 148
84896
+ ],
84897
+ "required": false
85290
84898
  },
85291
84899
  {
84900
+ "name": "euLanguages",
85292
84901
  "coverageIgnore": false,
85293
- "name": "nonEuLanguages",
85294
84902
  "defaultValue": "[]",
85295
84903
  "deprecated": false,
85296
84904
  "deprecationMessage": "",
85297
- "rawdescription": "\n",
85298
- "description": "",
85299
- "line": 36,
85300
84905
  "type": "EuiLanguage[]",
85301
- "decorators": []
85302
- },
85303
- {
85304
- "coverageIgnore": false,
85305
- "name": "rightPosition",
85306
- "deprecated": false,
85307
- "deprecationMessage": "",
85308
- "rawdescription": "\n\nProperty to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n",
85309
- "description": "<p>Property to position the dialog correctly. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85310
- "line": 68,
85311
- "type": "number",
85312
- "decorators": []
85313
- },
85314
- {
85315
- "name": "euColumnsCount",
85316
- "coverageIgnore": false,
85317
- "defaultValue": "undefined",
85318
- "deprecated": false,
85319
- "deprecationMessage": "",
85320
- "type": "number",
85321
84906
  "indexKey": "",
85322
84907
  "optional": false,
85323
- "description": "<p>Number of columns for eu languages. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85324
- "line": 40,
85325
- "rawdescription": "\n\nNumber of columns for eu languages. Calculated by the parent component 'ecl-site-header-language'.\n",
84908
+ "description": "",
84909
+ "line": 47,
84910
+ "rawdescription": "\n",
85326
84911
  "modifierKind": [
85327
84912
  148
85328
84913
  ],
@@ -85338,7 +84923,7 @@
85338
84923
  "indexKey": "",
85339
84924
  "optional": false,
85340
84925
  "description": "<p>Property to position the dialog correctly. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85341
- "line": 64,
84926
+ "line": 76,
85342
84927
  "rawdescription": "\n\nProperty to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n",
85343
84928
  "modifierKind": [
85344
84929
  148
@@ -85355,7 +84940,7 @@
85355
84940
  "indexKey": "",
85356
84941
  "optional": false,
85357
84942
  "description": "<p>Property to show/hide the dialog.</p>\n",
85358
- "line": 48,
84943
+ "line": 60,
85359
84944
  "rawdescription": "\n\nProperty to show/hide the dialog.\n",
85360
84945
  "modifierKind": [
85361
84946
  148
@@ -85372,7 +84957,7 @@
85372
84957
  "indexKey": "",
85373
84958
  "optional": false,
85374
84959
  "description": "<p>Property to position the dialog correctly. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85375
- "line": 56,
84960
+ "line": 68,
85376
84961
  "rawdescription": "\n\nProperty to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n",
85377
84962
  "modifierKind": [
85378
84963
  148
@@ -85389,7 +84974,7 @@
85389
84974
  "indexKey": "",
85390
84975
  "optional": false,
85391
84976
  "description": "<p>Property to position the dialog correctly. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85392
- "line": 52,
84977
+ "line": 64,
85393
84978
  "rawdescription": "\n\nProperty to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n",
85394
84979
  "modifierKind": [
85395
84980
  148
@@ -85406,7 +84991,58 @@
85406
84991
  "indexKey": "",
85407
84992
  "optional": false,
85408
84993
  "description": "<p>Property to position the dialog correctly. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85409
- "line": 60,
84994
+ "line": 72,
84995
+ "rawdescription": "\n\nProperty to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n",
84996
+ "modifierKind": [
84997
+ 148
84998
+ ],
84999
+ "required": false
85000
+ },
85001
+ {
85002
+ "name": "languageArrowPosition",
85003
+ "coverageIgnore": false,
85004
+ "defaultValue": "undefined",
85005
+ "deprecated": false,
85006
+ "deprecationMessage": "",
85007
+ "type": "string",
85008
+ "indexKey": "",
85009
+ "optional": false,
85010
+ "description": "<p>Property to position the arrow of the dialog correctly. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85011
+ "line": 88,
85012
+ "rawdescription": "\n\nProperty to position the arrow of the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n",
85013
+ "modifierKind": [
85014
+ 148
85015
+ ],
85016
+ "required": false
85017
+ },
85018
+ {
85019
+ "name": "languageCode",
85020
+ "coverageIgnore": false,
85021
+ "defaultValue": "undefined",
85022
+ "deprecated": false,
85023
+ "deprecationMessage": "",
85024
+ "type": "string",
85025
+ "indexKey": "",
85026
+ "optional": false,
85027
+ "description": "<p>Current language</p>\n",
85028
+ "line": 46,
85029
+ "rawdescription": "\n\nCurrent language\n",
85030
+ "modifierKind": [
85031
+ 148
85032
+ ],
85033
+ "required": false
85034
+ },
85035
+ {
85036
+ "name": "leftPosition",
85037
+ "coverageIgnore": false,
85038
+ "defaultValue": "undefined",
85039
+ "deprecated": false,
85040
+ "deprecationMessage": "",
85041
+ "type": "number",
85042
+ "indexKey": "",
85043
+ "optional": false,
85044
+ "description": "<p>Property to position the dialog correctly. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85045
+ "line": 84,
85410
85046
  "rawdescription": "\n\nProperty to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n",
85411
85047
  "modifierKind": [
85412
85048
  148
@@ -85423,13 +85059,47 @@
85423
85059
  "indexKey": "",
85424
85060
  "optional": false,
85425
85061
  "description": "<p>Number of columns for non-eu languages. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85426
- "line": 44,
85062
+ "line": 56,
85427
85063
  "rawdescription": "\n\nNumber of columns for non-eu languages. Calculated by the parent component 'ecl-site-header-language'.\n",
85428
85064
  "modifierKind": [
85429
85065
  148
85430
85066
  ],
85431
85067
  "required": false
85432
85068
  },
85069
+ {
85070
+ "name": "nonEuLanguages",
85071
+ "coverageIgnore": false,
85072
+ "defaultValue": "[]",
85073
+ "deprecated": false,
85074
+ "deprecationMessage": "",
85075
+ "type": "EuiLanguage[]",
85076
+ "indexKey": "",
85077
+ "optional": false,
85078
+ "description": "",
85079
+ "line": 48,
85080
+ "rawdescription": "\n",
85081
+ "modifierKind": [
85082
+ 148
85083
+ ],
85084
+ "required": false
85085
+ },
85086
+ {
85087
+ "name": "rightPosition",
85088
+ "coverageIgnore": false,
85089
+ "defaultValue": "undefined",
85090
+ "deprecated": false,
85091
+ "deprecationMessage": "",
85092
+ "type": "number",
85093
+ "indexKey": "",
85094
+ "optional": false,
85095
+ "description": "<p>Property to position the dialog correctly. Calculated by the parent component &#39;ecl-site-header-language&#39;.</p>\n",
85096
+ "line": 80,
85097
+ "rawdescription": "\n\nProperty to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n",
85098
+ "modifierKind": [
85099
+ 148
85100
+ ],
85101
+ "required": false
85102
+ },
85433
85103
  {
85434
85104
  "coverageIgnore": false,
85435
85105
  "name": "class",
@@ -85484,7 +85154,7 @@
85484
85154
  "indexKey": "",
85485
85155
  "optional": false,
85486
85156
  "description": "",
85487
- "line": 78,
85157
+ "line": 90,
85488
85158
  "rawdescription": "\n",
85489
85159
  "modifierKind": [
85490
85160
  148
@@ -85500,7 +85170,7 @@
85500
85170
  "indexKey": "",
85501
85171
  "optional": false,
85502
85172
  "description": "",
85503
- "line": 79,
85173
+ "line": 91,
85504
85174
  "rawdescription": "\n",
85505
85175
  "modifierKind": [
85506
85176
  148
@@ -85519,7 +85189,7 @@
85519
85189
  "indexKey": "",
85520
85190
  "optional": false,
85521
85191
  "description": "",
85522
- "line": 25,
85192
+ "line": 37,
85523
85193
  "rawdescription": "\n",
85524
85194
  "modifierKind": [
85525
85195
  124
@@ -85535,31 +85205,9 @@
85535
85205
  "indexKey": "",
85536
85206
  "optional": false,
85537
85207
  "description": "",
85538
- "line": 24,
85208
+ "line": 36,
85539
85209
  "rawdescription": "\n"
85540
85210
  },
85541
- {
85542
- "name": "labelledBy",
85543
- "coverageIgnore": false,
85544
- "defaultValue": "'ecl-site-header__language-title'",
85545
- "deprecated": false,
85546
- "deprecationMessage": "",
85547
- "type": "string",
85548
- "indexKey": "",
85549
- "optional": false,
85550
- "description": "",
85551
- "line": 85,
85552
- "rawdescription": "\n",
85553
- "decorators": [
85554
- {
85555
- "name": "HostBinding",
85556
- "stringifiedArguments": "'attr.aria-labelledby'"
85557
- }
85558
- ],
85559
- "modifierKind": [
85560
- 171
85561
- ]
85562
- },
85563
85211
  {
85564
85212
  "name": "languageContent",
85565
85213
  "coverageIgnore": false,
@@ -85570,7 +85218,7 @@
85570
85218
  "indexKey": "",
85571
85219
  "optional": false,
85572
85220
  "description": "<p>The div, that wraps all the languages.</p>\n",
85573
- "line": 30,
85221
+ "line": 42,
85574
85222
  "rawdescription": "\n\nThe div, that wraps all the languages.\n",
85575
85223
  "modifierKind": [
85576
85224
  148
@@ -85585,30 +85233,8 @@
85585
85233
  "indexKey": "",
85586
85234
  "optional": false,
85587
85235
  "description": "",
85588
- "line": 91,
85236
+ "line": 93,
85589
85237
  "rawdescription": "\n"
85590
- },
85591
- {
85592
- "name": "role",
85593
- "coverageIgnore": false,
85594
- "defaultValue": "'dialog'",
85595
- "deprecated": false,
85596
- "deprecationMessage": "",
85597
- "type": "string",
85598
- "indexKey": "",
85599
- "optional": false,
85600
- "description": "<p>The role of the dialog is &#39;dialog&#39;. Should not be changed.</p>\n",
85601
- "line": 84,
85602
- "rawdescription": "\n\nThe role of the dialog is 'dialog'. Should not be changed.\n",
85603
- "decorators": [
85604
- {
85605
- "name": "HostBinding",
85606
- "stringifiedArguments": "'attr.role'"
85607
- }
85608
- ],
85609
- "modifierKind": [
85610
- 171
85611
- ]
85612
85238
  }
85613
85239
  ],
85614
85240
  "methodsClass": [
@@ -85619,7 +85245,7 @@
85619
85245
  "optional": false,
85620
85246
  "returnType": "void",
85621
85247
  "typeParameters": [],
85622
- "line": 133,
85248
+ "line": 136,
85623
85249
  "deprecated": false,
85624
85250
  "deprecationMessage": "",
85625
85251
  "rawdescription": "\n",
@@ -85632,7 +85258,7 @@
85632
85258
  "optional": false,
85633
85259
  "returnType": "void",
85634
85260
  "typeParameters": [],
85635
- "line": 138,
85261
+ "line": 141,
85636
85262
  "deprecated": false,
85637
85263
  "deprecationMessage": "",
85638
85264
  "rawdescription": "\n",
@@ -85662,7 +85288,7 @@
85662
85288
  "optional": false,
85663
85289
  "returnType": "void",
85664
85290
  "typeParameters": [],
85665
- "line": 142,
85291
+ "line": 145,
85666
85292
  "deprecated": false,
85667
85293
  "deprecationMessage": "",
85668
85294
  "rawdescription": "\n",
@@ -85699,7 +85325,7 @@
85699
85325
  "optional": false,
85700
85326
  "returnType": "void",
85701
85327
  "typeParameters": [],
85702
- "line": 152,
85328
+ "line": 154,
85703
85329
  "deprecated": false,
85704
85330
  "deprecationMessage": "",
85705
85331
  "rawdescription": "\n\nSet the max-height property of the component. It is calculated depending on the viewport.\n",
@@ -85747,82 +85373,7 @@
85747
85373
  "coverageIgnore": false,
85748
85374
  "deprecated": false,
85749
85375
  "deprecationMessage": "",
85750
- "hostBindings": [
85751
- {
85752
- "coverageIgnore": false,
85753
- "name": "attr.aria-labelledby",
85754
- "actualName": "labelledBy",
85755
- "defaultValue": "'ecl-site-header__language-title'",
85756
- "deprecated": false,
85757
- "deprecationMessage": "",
85758
- "rawdescription": "\n",
85759
- "description": "",
85760
- "line": 85,
85761
- "type": "string",
85762
- "decorators": []
85763
- },
85764
- {
85765
- "coverageIgnore": false,
85766
- "name": "attr.aria-modal",
85767
- "actualName": "isModal",
85768
- "deprecated": false,
85769
- "deprecationMessage": "",
85770
- "rawdescription": "\n",
85771
- "description": "",
85772
- "line": 124,
85773
- "type": "boolean | undefined",
85774
- "decorators": []
85775
- },
85776
- {
85777
- "coverageIgnore": false,
85778
- "name": "attr.hidden",
85779
- "actualName": "isDropdownHidden",
85780
- "deprecated": false,
85781
- "deprecationMessage": "",
85782
- "rawdescription": "\n",
85783
- "description": "",
85784
- "line": 129,
85785
- "type": "boolean | undefined",
85786
- "decorators": []
85787
- },
85788
- {
85789
- "coverageIgnore": false,
85790
- "name": "attr.role",
85791
- "actualName": "role",
85792
- "defaultValue": "'dialog'",
85793
- "deprecated": false,
85794
- "deprecationMessage": "",
85795
- "rawdescription": "\n\nThe role of the dialog is 'dialog'. Should not be changed.\n",
85796
- "description": "<p>The role of the dialog is &#39;dialog&#39;. Should not be changed.</p>\n",
85797
- "line": 84,
85798
- "type": "string",
85799
- "decorators": []
85800
- },
85801
- {
85802
- "coverageIgnore": false,
85803
- "name": "class",
85804
- "actualName": "cssClasses",
85805
- "deprecated": false,
85806
- "deprecationMessage": "",
85807
- "rawdescription": "\n",
85808
- "description": "",
85809
- "line": 112,
85810
- "type": "string",
85811
- "decorators": []
85812
- },
85813
- {
85814
- "coverageIgnore": false,
85815
- "name": "style.display",
85816
- "actualName": "display",
85817
- "deprecated": false,
85818
- "deprecationMessage": "",
85819
- "rawdescription": "\n",
85820
- "description": "",
85821
- "line": 87,
85822
- "type": "string",
85823
- "decorators": []
85824
- }
85825
- ],
85376
+ "hostBindings": [],
85826
85377
  "hostListeners": [],
85827
85378
  "standalone": false,
85828
85379
  "imports": [
@@ -85843,14 +85394,14 @@
85843
85394
  "description": "<p>This component is a popover, that appears after the user clicks on language link. It contains all the available languages,\n configured for the current site. Adds styling and functionality for the dialog.\nEmits events when language is selected and when dialog is closed.</p>\n",
85844
85395
  "rawdescription": "\n\nThis component is a popover, that appears after the user clicks on language link. It contains all the available languages,\n configured for the current site. Adds styling and functionality for the dialog.\nEmits events when language is selected and when dialog is closed.\n",
85845
85396
  "type": "component",
85846
- "sourceCode": "import { ScrollDispatcher } from '@angular/cdk/scrolling';\nimport { Component, DOCUMENT, ElementRef, HostBinding, HostListener, Input, NgZone, OnDestroy, afterNextRender, booleanAttribute, inject, output, input, viewChild } from '@angular/core';\nimport { auditTime, fromEvent, Subject, takeUntil } from 'rxjs';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { EuiLanguage } from '@eui/base';\nimport { EclThemeService } from '@eui/ecl/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EclSiteHeaderLanguageCloseEvent, EclSiteHeaderLanguageSelectedEvent } from '../events';\nimport { EUI_ECL_BUTTON } from '@eui/ecl/components/ecl-button';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\n\n/**\n * This component is a popover, that appears after the user clicks on language link. It contains all the available languages,\n * configured for the current site. Adds styling and functionality for the dialog.\n * Emits events when language is selected and when dialog is closed.\n */\n@Component({\n selector: 'ecl-site-header-language-popover',\n templateUrl: './ecl-site-header-language-popover.component.html',\n imports: [TranslatePipe, ...EUI_ECL_BUTTON, ...EUI_ECL_ICON, ...EUI_ECL_LINK],\n})\nexport class EclSiteHeaderLanguagePopoverComponent extends ECLBaseDirective implements OnDestroy {\n el = inject(ElementRef);\n protected eclThemeService = inject(EclThemeService);\n\n /**\n * The div, that wraps all the languages.\n */\n readonly languageContent = viewChild<ElementRef>('languageContent');\n /**\n * Current language\n */\n @Input() languageCode: string;\n @Input() euLanguages: EuiLanguage[] = [];\n @Input() nonEuLanguages: EuiLanguage[] = [];\n /**\n * Number of columns for eu languages. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly euColumnsCount = input<number>(undefined);\n /**\n * Number of columns for non-eu languages. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly nonEuColumnsCount = input<number>(undefined);\n /**\n * Property to show/hide the dialog.\n */\n readonly isHidden = input(false, { transform: booleanAttribute });\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly isPushRight = input(false, { transform: booleanAttribute });\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly isPushLeft = input(false, { transform: booleanAttribute });\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly isStack = input(false, { transform: booleanAttribute });\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly isFull = input(false, { transform: booleanAttribute });\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n @Input() @HostBinding('style.right.px') rightPosition: number;\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n @Input() @HostBinding('style.left.px') leftPosition: number;\n /**\n * Property to position the arrow of the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n @Input() @HostBinding('style.--ecl-language-arrow-position') languageArrowPosition: string;\n\n readonly languageClosed = output<EclSiteHeaderLanguageCloseEvent>();\n readonly languageSelected = output<EclSiteHeaderLanguageSelectedEvent>();\n\n /**\n * The role of the dialog is 'dialog'. Should not be changed.\n */\n @HostBinding('attr.role') role = 'dialog';\n @HostBinding('attr.aria-labelledby') labelledBy = 'ecl-site-header__language-title';\n @HostBinding('style.display')\n get display():string {\n return this.isHidden() ? 'none' : 'block';\n }\n\n languageContentMaxHeight: number;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private scrollDispatcher = inject(ScrollDispatcher);\n private zone = inject(NgZone);\n private readonly document = inject<Document>(DOCUMENT);\n private readonly window = this.document.defaultView; // Window | null\n\n constructor() {\n super();\n afterNextRender(() => {\n this.subscribeToCDKScrollEvent();\n fromEvent(this.window, 'resize').pipe(\n auditTime(50),\n takeUntil(this.destroy$)).subscribe(() => {\n // Calculate the height after resize. If the window is too small -> scroll should appear.\n setTimeout(() => this.setLanguageContentMaxHeight());\n });\n });\n }\n\n @HostBinding('class')\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-site-header__language-container'),\n this.isPushRight() ? 'ecl-site-header__language-container--push-right' : '',\n this.isPushLeft() ? 'ecl-site-header__language-container--push-left' : '',\n this.isFull() ? 'ecl-site-header__language-container--full' : '',\n ]\n .join(' ')\n .trim();\n }\n\n @HostBinding('attr.aria-modal')\n get isModal(): boolean | undefined {\n return !this.isHidden() || undefined;\n }\n\n @HostBinding('attr.hidden')\n get isDropdownHidden(): boolean | undefined {\n return this.isHidden() || undefined;\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n onCloseClick(): void {\n this.languageClosed.emit(new EclSiteHeaderLanguageCloseEvent());\n }\n\n onLanguageClick(language: EuiLanguage, evt: MouseEvent): void {\n this.languageCode = language.code;\n this.languageSelected.emit(new EclSiteHeaderLanguageSelectedEvent(language));\n\n evt.preventDefault();\n }\n\n /**\n * Set the max-height property of the component. It is calculated depending on the viewport.\n */\n setLanguageContentMaxHeight(): void {\n const viewportHeight = this.window.innerHeight;\n const languageContent = this.languageContent();\n if (languageContent) {\n const listTop = languageContent.nativeElement.getBoundingClientRect().top;\n const availableSpace = viewportHeight - listTop;\n if (availableSpace > 0) {\n this.languageContentMaxHeight = availableSpace;\n }\n }\n }\n\n private subscribeToCDKScrollEvent(): void {\n this.scrollDispatcher.scrolled().pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.zone.run(() => {\n this.setLanguageContentMaxHeight();\n });\n });\n }\n}\n",
85397
+ "sourceCode": "import { ScrollDispatcher } from '@angular/cdk/scrolling';\nimport { Component, DOCUMENT, ElementRef, NgZone, OnDestroy, afterNextRender, booleanAttribute, inject, output, input, viewChild } from '@angular/core';\nimport { auditTime, fromEvent, Subject, takeUntil } from 'rxjs';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { EuiLanguage } from '@eui/base';\nimport { EclThemeService } from '@eui/ecl/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EclSiteHeaderLanguageCloseEvent, EclSiteHeaderLanguageSelectedEvent } from '../events';\nimport { EUI_ECL_BUTTON } from '@eui/ecl/components/ecl-button';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\n\n/**\n * This component is a popover, that appears after the user clicks on language link. It contains all the available languages,\n * configured for the current site. Adds styling and functionality for the dialog.\n * Emits events when language is selected and when dialog is closed.\n */\n@Component({\n selector: 'ecl-site-header-language-popover',\n templateUrl: './ecl-site-header-language-popover.component.html',\n imports: [TranslatePipe, ...EUI_ECL_BUTTON, ...EUI_ECL_ICON, ...EUI_ECL_LINK],\n host: {\n // The role of the dialog is 'dialog'. Should not be changed.\n role: 'dialog',\n 'aria-labelledby': 'ecl-site-header__language-title',\n '[class]': 'cssClasses',\n '[style.display]': 'display',\n '[style.right.px]': 'rightPosition()',\n '[style.left.px]': 'leftPosition()',\n '[style.--ecl-overlay-arrow-position]': 'languageArrowPosition()',\n '[attr.aria-modal]': 'isModal',\n '[attr.hidden]': 'isDropdownHidden',\n },\n})\nexport class EclSiteHeaderLanguagePopoverComponent extends ECLBaseDirective implements OnDestroy {\n el = inject(ElementRef);\n protected eclThemeService = inject(EclThemeService);\n\n /**\n * The div, that wraps all the languages.\n */\n readonly languageContent = viewChild<ElementRef>('languageContent');\n /**\n * Current language\n */\n readonly languageCode = input<string>(undefined);\n readonly euLanguages = input<EuiLanguage[]>([]);\n readonly nonEuLanguages = input<EuiLanguage[]>([]);\n /**\n * Number of columns for eu languages. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly euColumnsCount = input<number>(undefined);\n /**\n * Number of columns for non-eu languages. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly nonEuColumnsCount = input<number>(undefined);\n /**\n * Property to show/hide the dialog.\n */\n readonly isHidden = input(false, { transform: booleanAttribute });\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly isPushRight = input(false, { transform: booleanAttribute });\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly isPushLeft = input(false, { transform: booleanAttribute });\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly isStack = input(false, { transform: booleanAttribute });\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly isFull = input(false, { transform: booleanAttribute });\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly rightPosition = input<number>(undefined);\n /**\n * Property to position the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly leftPosition = input<number>(undefined);\n /**\n * Property to position the arrow of the dialog correctly. Calculated by the parent component 'ecl-site-header-language'.\n */\n readonly languageArrowPosition = input<string>(undefined);\n\n readonly languageClosed = output<EclSiteHeaderLanguageCloseEvent>();\n readonly languageSelected = output<EclSiteHeaderLanguageSelectedEvent>();\n\n languageContentMaxHeight: number;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private scrollDispatcher = inject(ScrollDispatcher);\n private zone = inject(NgZone);\n private readonly document = inject<Document>(DOCUMENT);\n private readonly window = this.document.defaultView; // Window | null\n\n constructor() {\n super();\n afterNextRender(() => {\n this.subscribeToCDKScrollEvent();\n fromEvent(this.window, 'resize').pipe(\n auditTime(50),\n takeUntil(this.destroy$)).subscribe(() => {\n // Calculate the height after resize. If the window is too small -> scroll should appear.\n setTimeout(() => this.setLanguageContentMaxHeight());\n });\n });\n }\n\n protected get cssClasses(): string {\n return [\n super.getCssClasses('ecl-site-header__language-container'),\n this.isPushRight() ? 'ecl-site-header__language-container--push-right' : '',\n this.isPushLeft() ? 'ecl-site-header__language-container--push-left' : '',\n this.isFull() ? 'ecl-site-header__language-container--full' : '',\n ]\n .join(' ')\n .trim();\n }\n\n protected get display(): string {\n return this.isHidden() ? 'none' : 'block';\n }\n\n protected get isModal(): boolean | undefined {\n return !this.isHidden() || undefined;\n }\n\n protected get isDropdownHidden(): boolean | undefined {\n return this.isHidden() || undefined;\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n onCloseClick(): void {\n this.languageClosed.emit(new EclSiteHeaderLanguageCloseEvent());\n }\n\n onLanguageClick(language: EuiLanguage, evt: MouseEvent): void {\n this.languageSelected.emit(new EclSiteHeaderLanguageSelectedEvent(language));\n\n evt.preventDefault();\n }\n\n /**\n * Set the max-height property of the component. It is calculated depending on the viewport.\n */\n setLanguageContentMaxHeight(): void {\n const viewportHeight = this.window.innerHeight;\n const languageContent = this.languageContent();\n if (languageContent) {\n const listTop = languageContent.nativeElement.getBoundingClientRect().top;\n const availableSpace = viewportHeight - listTop;\n if (availableSpace > 0) {\n this.languageContentMaxHeight = availableSpace;\n }\n }\n }\n\n private subscribeToCDKScrollEvent(): void {\n this.scrollDispatcher.scrolled().pipe(takeUntil(this.destroy$)).subscribe(() => {\n this.zone.run(() => {\n this.setLanguageContentMaxHeight();\n });\n });\n }\n}\n",
85847
85398
  "assetsDirs": [],
85848
85399
  "styleUrlsData": "",
85849
85400
  "stylesData": "",
85850
85401
  "jsdoctags": [
85851
85402
  {
85852
- "pos": 789,
85853
- "end": 1075,
85403
+ "pos": 755,
85404
+ "end": 1041,
85854
85405
  "kind": 321,
85855
85406
  "id": 0,
85856
85407
  "flags": 16777216,
@@ -85865,7 +85416,7 @@
85865
85416
  "deprecated": false,
85866
85417
  "deprecationMessage": "",
85867
85418
  "args": [],
85868
- "line": 96,
85419
+ "line": 98,
85869
85420
  "rawdescription": "\n"
85870
85421
  },
85871
85422
  "extends": [
@@ -85875,24 +85426,24 @@
85875
85426
  "OnDestroy"
85876
85427
  ],
85877
85428
  "accessors": {
85878
- "display": {
85879
- "name": "display",
85429
+ "cssClasses": {
85430
+ "name": "cssClasses",
85880
85431
  "getSignature": {
85881
- "name": "display",
85432
+ "name": "cssClasses",
85882
85433
  "type": "string",
85883
85434
  "returnType": "string",
85884
- "line": 87,
85435
+ "line": 113,
85885
85436
  "rawdescription": "\n",
85886
85437
  "description": ""
85887
85438
  }
85888
85439
  },
85889
- "cssClasses": {
85890
- "name": "cssClasses",
85440
+ "display": {
85441
+ "name": "display",
85891
85442
  "getSignature": {
85892
- "name": "cssClasses",
85443
+ "name": "display",
85893
85444
  "type": "string",
85894
85445
  "returnType": "string",
85895
- "line": 112,
85446
+ "line": 124,
85896
85447
  "rawdescription": "\n",
85897
85448
  "description": ""
85898
85449
  }
@@ -85903,7 +85454,7 @@
85903
85454
  "name": "isModal",
85904
85455
  "type": "unknown",
85905
85456
  "returnType": "boolean | undefined",
85906
- "line": 124,
85457
+ "line": 128,
85907
85458
  "rawdescription": "\n",
85908
85459
  "description": ""
85909
85460
  }
@@ -85914,7 +85465,7 @@
85914
85465
  "name": "isDropdownHidden",
85915
85466
  "type": "unknown",
85916
85467
  "returnType": "boolean | undefined",
85917
- "line": 129,
85468
+ "line": 132,
85918
85469
  "rawdescription": "\n",
85919
85470
  "description": ""
85920
85471
  }
@@ -85955,14 +85506,15 @@
85955
85506
  }
85956
85507
  ]
85957
85508
  },
85958
- "templateData": "<div class=\"ecl-site-header__language-header\">\n <div class=\"ecl-site-header__language-title\">\n {{ 'ecl.language-list.SELECT-LANGUAGE' | translate }}\n </div>\n <button eclButton variant=\"tertiary\" eclStyle=\"neutral\" isIconOnly class=\"ecl-site-header__language-close\" (click)=\"onCloseClick()\">\n <span class=\"ecl-button__container\">\n <span class=\"ecl-button__label\">\n {{ 'ecl.common.CLOSE' | translate }}\n </span>\n <ecl-icon icon=\"close\" size=\"m\"></ecl-icon>\n </span>\n </button>\n</div>\n\n<div #languageContent class=\"ecl-site-header__language-content\" [style.max-height.px]=\"languageContentMaxHeight\"\n [class.ecl-site-header__language-content--stack]=\"isStack()\">\n @if (euLanguages.length) {\n <div class=\"ecl-site-header__language-category ecl-site-header__language-category--{{ euColumnsCount() }}-col\">\n <div class=\"ecl-site-header__language-category-title\">\n {{ 'ecl.language-list.EU-LANGUAGES' | translate }}\n </div>\n <ul class=\"ecl-site-header__language-list\" [attr.translate]=\"'no'\">\n @for (item of euLanguages; track item.code) {\n <li class=\"ecl-site-header__language-item\">\n <a\n eclLink\n href=\"#\"\n variant=\"standalone\"\n [lang]=\"item.code\"\n [hreflang]=\"item.code\"\n class=\"ecl-site-header__language-link\"\n [class.ecl-site-header__language-link--active]=\"item.code === languageCode\"\n (click)=\"onLanguageClick(item, $event)\">\n <span class=\"ecl-site-header__language-link-code\">{{ item.code }}</span>\n <span class=\"ecl-site-header__language-link-label\">{{ item.label }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n }\n @if (nonEuLanguages.length) {\n <div class=\"ecl-site-header__language-category ecl-site-header__language-category--{{ nonEuColumnsCount() }}-col\">\n <div class=\"ecl-site-header__language-category-title\">\n {{ 'ecl.language-list.NON-EU-LANGUAGES' | translate }}\n </div>\n <ul class=\"ecl-site-header__language-list\" [attr.translate]=\"'no'\">\n @for (item of nonEuLanguages; track item.code) {\n <li class=\"ecl-site-header__language-item\">\n <a\n eclLink\n href=\"#\"\n [lang]=\"item.code\"\n [hreflang]=\"item.code\"\n variant=\"standalone\"\n class=\"ecl-site-header__language-link\"\n [class.ecl-site-header__language-link--active]=\"item.code === languageCode\"\n (click)=\"onLanguageClick(item, $event)\">\n <span class=\"ecl-site-header__language-link-code\">{{ item.code }}</span>\n <span class=\"ecl-site-header__language-link-label\">{{ item.label }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n }\n</div>\n"
85509
+ "templateData": "<div class=\"ecl-site-header__language-header\">\n <div class=\"ecl-site-header__language-title\">\n {{ 'ecl.language-list.SELECT-LANGUAGE' | translate }}\n </div>\n <button eclButton variant=\"tertiary\" eclStyle=\"neutral\" isIconOnly class=\"ecl-site-header__language-close\" (click)=\"onCloseClick()\">\n <span class=\"ecl-button__container\">\n <span class=\"ecl-button__label\">\n {{ 'ecl.common.CLOSE' | translate }}\n </span>\n <ecl-icon icon=\"close\" size=\"m\"></ecl-icon>\n </span>\n </button>\n</div>\n\n<div #languageContent class=\"ecl-site-header__language-content\" [style.max-height.px]=\"languageContentMaxHeight\"\n [class.ecl-site-header__language-content--stack]=\"isStack()\">\n @if (euLanguages().length) {\n <div class=\"ecl-site-header__language-category ecl-site-header__language-category--{{ euColumnsCount() }}-col\">\n <div class=\"ecl-site-header__language-category-title\">\n {{ 'ecl.language-list.EU-LANGUAGES' | translate }}\n </div>\n <ul class=\"ecl-site-header__language-list\" [attr.translate]=\"'no'\">\n @for (item of euLanguages(); track item.code) {\n <li class=\"ecl-site-header__language-item\">\n <a\n eclLink\n href=\"#\"\n variant=\"standalone\"\n [lang]=\"item.code\"\n [hreflang]=\"item.code\"\n class=\"ecl-site-header__language-link\"\n [class.ecl-site-header__language-link--active]=\"item.code === languageCode()\"\n (click)=\"onLanguageClick(item, $event)\">\n <span class=\"ecl-site-header__language-link-code\">{{ item.code }}</span>\n <span class=\"ecl-site-header__language-link-label\">{{ item.label }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n }\n @if (nonEuLanguages().length) {\n <div class=\"ecl-site-header__language-category ecl-site-header__language-category--{{ nonEuColumnsCount() }}-col\">\n <div class=\"ecl-site-header__language-category-title\">\n {{ 'ecl.language-list.NON-EU-LANGUAGES' | translate }}\n </div>\n <ul class=\"ecl-site-header__language-list\" [attr.translate]=\"'no'\">\n @for (item of nonEuLanguages(); track item.code) {\n <li class=\"ecl-site-header__language-item\">\n <a\n eclLink\n href=\"#\"\n [lang]=\"item.code\"\n [hreflang]=\"item.code\"\n variant=\"standalone\"\n class=\"ecl-site-header__language-link\"\n [class.ecl-site-header__language-link--active]=\"item.code === languageCode()\"\n (click)=\"onLanguageClick(item, $event)\">\n <span class=\"ecl-site-header__language-link-code\">{{ item.code }}</span>\n <span class=\"ecl-site-header__language-link-label\">{{ item.label }}</span>\n </a>\n </li>\n }\n </ul>\n </div>\n }\n</div>\n"
85959
85510
  },
85960
85511
  {
85961
85512
  "name": "EclSiteHeaderLoginComponent",
85962
- "id": "component-EclSiteHeaderLoginComponent-eb7fc5e4df66b10b0bdb4a84f481ca049b63fb49582e2ad190720f2706e3c6e4c4f3bc45b3958b1824b0d1b708f74debb946c2b1ba735e5bc06a162503e8a000",
85513
+ "id": "component-EclSiteHeaderLoginComponent-19cf290d806bdaee64ed7b5689860e5d3113d6c5ebbfad60be450af5436bbb1012751c4ad894f93127962cf02d3e5439962e464de02158c40d0e7663b76b451e",
85963
85514
  "file": "packages/ecl/components/ecl-site-header/login/ecl-site-header-login.component.ts",
85964
85515
  "encapsulation": [],
85965
85516
  "entryComponents": [],
85517
+ "host": {},
85966
85518
  "inputs": [],
85967
85519
  "outputs": [],
85968
85520
  "providers": [],
@@ -85977,11 +85529,6 @@
85977
85529
  "templateVariables": [],
85978
85530
  "viewProviders": [],
85979
85531
  "hostDirectives": [
85980
- {
85981
- "name": "ECLBaseDirective",
85982
- "inputs": [],
85983
- "outputs": []
85984
- },
85985
85532
  {
85986
85533
  "name": "ECLClickOutsideDirective",
85987
85534
  "inputs": [],
@@ -86001,7 +85548,7 @@
86001
85548
  "indexKey": "",
86002
85549
  "optional": false,
86003
85550
  "description": "",
86004
- "line": 37,
85551
+ "line": 41,
86005
85552
  "rawdescription": "\n",
86006
85553
  "modifierKind": [
86007
85554
  148
@@ -86059,7 +85606,7 @@
86059
85606
  "defaultValue": "new EventEmitter<EclSiteHeaderLoginBoxToggleEvent>()",
86060
85607
  "deprecated": false,
86061
85608
  "deprecationMessage": "",
86062
- "line": 43,
85609
+ "line": 44,
86063
85610
  "type": "EventEmitter"
86064
85611
  },
86065
85612
  {
@@ -86071,7 +85618,7 @@
86071
85618
  "indexKey": "",
86072
85619
  "optional": false,
86073
85620
  "description": "",
86074
- "line": 42,
85621
+ "line": 43,
86075
85622
  "rawdescription": "\n",
86076
85623
  "modifierKind": [
86077
85624
  148
@@ -86080,28 +85627,6 @@
86080
85627
  }
86081
85628
  ],
86082
85629
  "propertiesClass": [
86083
- {
86084
- "name": "class",
86085
- "coverageIgnore": false,
86086
- "defaultValue": "'ecl-site-header__login-container'",
86087
- "deprecated": false,
86088
- "deprecationMessage": "",
86089
- "type": "string",
86090
- "indexKey": "",
86091
- "optional": false,
86092
- "description": "",
86093
- "line": 38,
86094
- "rawdescription": "\n",
86095
- "decorators": [
86096
- {
86097
- "name": "HostBinding",
86098
- "stringifiedArguments": "'class'"
86099
- }
86100
- ],
86101
- "modifierKind": [
86102
- 171
86103
- ]
86104
- },
86105
85630
  {
86106
85631
  "name": "isLoginBoxActive",
86107
85632
  "coverageIgnore": false,
@@ -86111,57 +85636,24 @@
86111
85636
  "type": "unknown",
86112
85637
  "indexKey": "",
86113
85638
  "optional": false,
86114
- "description": "<p>If login popover is open (true) or closed (false).</p>\n",
86115
- "line": 48,
86116
- "rawdescription": "\n\nIf login popover is open (true) or closed (false).\n",
86117
- "modifierKind": [
86118
- 125
86119
- ]
85639
+ "description": "<p>If login popover is open (true) or closed (false). Kept public because the parent\n<code>ecl-site-header</code> resets it directly when the search box opens.</p>\n",
85640
+ "line": 50,
85641
+ "rawdescription": "\n\nIf login popover is open (true) or closed (false). Kept public because the parent\n`ecl-site-header` resets it directly when the search box opens.\n"
86120
85642
  },
86121
85643
  {
86122
85644
  "name": "loginArrowPosition",
86123
85645
  "coverageIgnore": false,
86124
- "deprecated": false,
86125
- "deprecationMessage": "",
86126
- "type": "string",
86127
- "indexKey": "",
86128
- "optional": false,
86129
- "description": "<p>The position of the arrow of the popover.</p>\n",
86130
- "line": 52,
86131
- "rawdescription": "\n\nThe position of the arrow of the popover.\n",
86132
- "modifierKind": [
86133
- 125
86134
- ]
86135
- },
86136
- {
86137
- "name": "loginLinkElement",
86138
- "coverageIgnore": false,
86139
- "defaultValue": "viewChild('loginLink', { read: ElementRef })",
85646
+ "defaultValue": "signal<string | undefined>(undefined)",
86140
85647
  "deprecated": false,
86141
85648
  "deprecationMessage": "",
86142
85649
  "type": "unknown",
86143
85650
  "indexKey": "",
86144
85651
  "optional": false,
86145
- "description": "",
86146
- "line": 40,
86147
- "rawdescription": "\n",
86148
- "modifierKind": [
86149
- 148
86150
- ]
86151
- },
86152
- {
86153
- "name": "TABLET_BREAKPOINT",
86154
- "coverageIgnore": false,
86155
- "defaultValue": "996",
86156
- "deprecated": false,
86157
- "deprecationMessage": "",
86158
- "type": "number",
86159
- "indexKey": "",
86160
- "optional": false,
86161
- "description": "",
86162
- "line": 53,
86163
- "rawdescription": "\n",
85652
+ "description": "<p>The position of the arrow of the popover, when in mobile (full-width) mode.</p>\n",
85653
+ "line": 55,
85654
+ "rawdescription": "\n\nThe position of the arrow of the popover, when in mobile (full-width) mode.\n",
86164
85655
  "modifierKind": [
85656
+ 124,
86165
85657
  148
86166
85658
  ]
86167
85659
  }
@@ -86174,16 +85666,19 @@
86174
85666
  "optional": false,
86175
85667
  "returnType": "string",
86176
85668
  "typeParameters": [],
86177
- "line": 91,
85669
+ "line": 108,
86178
85670
  "deprecated": false,
86179
85671
  "deprecationMessage": "",
86180
85672
  "rawdescription": "\n\n",
86181
85673
  "description": "",
85674
+ "modifierKind": [
85675
+ 124
85676
+ ],
86182
85677
  "jsdoctags": [
86183
85678
  {
86184
85679
  "tagName": {
86185
- "pos": 3024,
86186
- "end": 3031,
85680
+ "pos": 3907,
85681
+ "end": 3914,
86187
85682
  "kind": 80,
86188
85683
  "id": 0,
86189
85684
  "flags": 16842752,
@@ -86210,7 +85705,7 @@
86210
85705
  "optional": false,
86211
85706
  "returnType": "void",
86212
85707
  "typeParameters": [],
86213
- "line": 68,
85708
+ "line": 86,
86214
85709
  "deprecated": false,
86215
85710
  "deprecationMessage": "",
86216
85711
  "rawdescription": "\n",
@@ -86236,32 +85731,26 @@
86236
85731
  "optional": false,
86237
85732
  "returnType": "void",
86238
85733
  "typeParameters": [],
86239
- "line": 75,
85734
+ "line": 93,
86240
85735
  "deprecated": false,
86241
85736
  "deprecationMessage": "",
86242
85737
  "rawdescription": "\n",
86243
85738
  "description": ""
86244
85739
  },
86245
85740
  {
86246
- "name": "onClickOutsideMegaMenu",
85741
+ "name": "onClickOutside",
86247
85742
  "coverageIgnore": false,
86248
85743
  "args": [],
86249
85744
  "optional": false,
86250
85745
  "returnType": "void",
86251
85746
  "typeParameters": [],
86252
- "line": 84,
85747
+ "line": 101,
86253
85748
  "deprecated": false,
86254
85749
  "deprecationMessage": "",
86255
85750
  "rawdescription": "\n\nClose the login popover on click outside.\n",
86256
85751
  "description": "<p>Close the login popover on click outside.</p>\n",
86257
- "decorators": [
86258
- {
86259
- "name": "HostListener",
86260
- "stringifiedArguments": "'eclClickOutside'"
86261
- }
86262
- ],
86263
85752
  "modifierKind": [
86264
- 171
85753
+ 124
86265
85754
  ]
86266
85755
  },
86267
85756
  {
@@ -86280,11 +85769,14 @@
86280
85769
  "optional": false,
86281
85770
  "returnType": "void",
86282
85771
  "typeParameters": [],
86283
- "line": 101,
85772
+ "line": 118,
86284
85773
  "deprecated": false,
86285
85774
  "deprecationMessage": "",
86286
85775
  "rawdescription": "\n",
86287
85776
  "description": "",
85777
+ "modifierKind": [
85778
+ 124
85779
+ ],
86288
85780
  "jsdoctags": [
86289
85781
  {
86290
85782
  "name": "evt",
@@ -86315,11 +85807,14 @@
86315
85807
  "optional": false,
86316
85808
  "returnType": "void",
86317
85809
  "typeParameters": [],
86318
- "line": 95,
85810
+ "line": 112,
86319
85811
  "deprecated": false,
86320
85812
  "deprecationMessage": "",
86321
85813
  "rawdescription": "\n",
86322
85814
  "description": "",
85815
+ "modifierKind": [
85816
+ 124
85817
+ ],
86323
85818
  "jsdoctags": [
86324
85819
  {
86325
85820
  "name": "evt",
@@ -86376,34 +85871,8 @@
86376
85871
  "coverageIgnore": false,
86377
85872
  "deprecated": false,
86378
85873
  "deprecationMessage": "",
86379
- "hostBindings": [
86380
- {
86381
- "coverageIgnore": false,
86382
- "name": "class",
86383
- "actualName": "class",
86384
- "defaultValue": "'ecl-site-header__login-container'",
86385
- "deprecated": false,
86386
- "deprecationMessage": "",
86387
- "rawdescription": "\n",
86388
- "description": "",
86389
- "line": 38,
86390
- "type": "string",
86391
- "decorators": []
86392
- }
86393
- ],
86394
- "hostListeners": [
86395
- {
86396
- "coverageIgnore": false,
86397
- "name": "eclClickOutside",
86398
- "args": [],
86399
- "argsDecorator": [],
86400
- "deprecated": false,
86401
- "deprecationMessage": "",
86402
- "rawdescription": "\n\nClose the login popover on click outside.\n",
86403
- "description": "<p>Close the login popover on click outside.</p>\n",
86404
- "line": 84
86405
- }
86406
- ],
85874
+ "hostBindings": [],
85875
+ "hostListeners": [],
86407
85876
  "standalone": false,
86408
85877
  "imports": [
86409
85878
  {
@@ -86417,14 +85886,14 @@
86417
85886
  "description": "<p>Component for login/logout as part of the harmonised site header. Emits events when user logs in and when user opens the\nlogin dropdown.</p>\n",
86418
85887
  "rawdescription": "\n\nComponent for login/logout as part of the harmonised site header. Emits events when user logs in and when user opens the\nlogin dropdown.\n",
86419
85888
  "type": "component",
86420
- "sourceCode": "import { Component, DOCUMENT, ElementRef, EventEmitter, HostBinding, HostListener, OnChanges, OnDestroy, Output, SimpleChanges, afterNextRender, booleanAttribute, inject, output, input, viewChild } from '@angular/core';\nimport { Subject, debounceTime, takeUntil } from 'rxjs';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { ECLBaseDirective, ECLClickOutsideDirective } from '@eui/ecl/core';\nimport { EclRtlService } from '@eui/ecl/core';\nimport { EclSiteHeaderLoginBoxToggleEvent, EclSiteHeaderLoginEvent } from '../events';\nimport { EclAreaDataService } from '../services/ecl-area-data.service';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\n\n/**\n * Component for login/logout as part of the harmonised site header. Emits events when user logs in and when user opens the\n * login dropdown.\n */\n@Component({\n selector: 'ecl-site-header-login',\n templateUrl: './ecl-site-header-login.component.html',\n imports: [TranslatePipe, ...EUI_ECL_ICON],\n styles: [\n `\n :host {\n display: block;\n }\n `,\n ],\n hostDirectives: [\n {\n directive: ECLBaseDirective,\n },\n {\n directive: ECLClickOutsideDirective,\n \n outputs: ['eclClickOutside'],\n },\n ],\n})\nexport class EclSiteHeaderLoginComponent extends ECLBaseDirective implements OnChanges, OnDestroy {\n readonly isLoggedIn = input(false, { transform: booleanAttribute });\n @HostBinding('class') class = 'ecl-site-header__login-container';\n\n readonly loginLinkElement = viewChild('loginLink', { read: ElementRef });\n\n readonly login = output<EclSiteHeaderLoginEvent>();\n @Output() loginBoxToggle = new EventEmitter<EclSiteHeaderLoginBoxToggleEvent>();\n\n /**\n * If login popover is open (true) or closed (false).\n */\n public isLoginBoxActive = false;\n /**\n * The position of the arrow of the popover.\n */\n public loginArrowPosition: string;\n readonly TABLET_BREAKPOINT = 996;\n private parentHeaderRight: number | undefined;\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private eclAreaDataService = inject(EclAreaDataService);\n private eclRtlService = inject(EclRtlService);\n private document = inject<Document>(DOCUMENT);\n\n constructor() {\n super();\n afterNextRender(() => {\n this.handleRtlChangeState();\n this.handleSiteHeaderAreaChangeEvent();\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n const isLoggedInChange = changes.isLoggedIn;\n if (isLoggedInChange && isLoggedInChange.previousValue === true) {\n this.isLoginBoxActive = false;\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * Close the login popover on click outside.\n */\n @HostListener('eclClickOutside')\n onClickOutsideMegaMenu(): void {\n this.onLoginBoxClose();\n }\n\n /**\n * @returns classes for the login popover.\n */\n getLoginBoxCssClasses(): string {\n return ['ecl-site-header__login-box', this.isLoginBoxActive ? 'ecl-site-header__login-box--active' : ''].join(' ');\n }\n\n onLoginClick(evt: MouseEvent): void {\n const event = new EclSiteHeaderLoginEvent();\n this.login.emit(event);\n evt.preventDefault();\n }\n\n onLoginBoxToggle(evt: MouseEvent): void {\n this.isLoginBoxActive = !this.isLoginBoxActive;\n const event = new EclSiteHeaderLoginBoxToggleEvent(this.isLoginBoxActive);\n this.loginBoxToggle.next(event);\n evt.preventDefault();\n }\n\n private onLoginBoxClose(): void {\n if (this.isLoginBoxActive) {\n this.isLoginBoxActive = false;\n const event = new EclSiteHeaderLoginBoxToggleEvent(this.isLoginBoxActive);\n this.loginBoxToggle.next(event);\n }\n }\n\n private handleRtlChangeState(): void {\n this.eclRtlService.currentRtlState$.pipe(debounceTime(50), takeUntil(this.destroy$)).subscribe(() => {\n this.calculateLoginArrowPosition(this.parentHeaderRight);\n });\n }\n\n /**\n * On resize -> calculate the popover arrow position, using parent element ecl-header html parameters.\n */\n private handleSiteHeaderAreaChangeEvent(): void {\n this.eclAreaDataService.dataSubject$.pipe(takeUntil(this.destroy$)).subscribe(\n parentHeaderRect => {\n this.parentHeaderRight = parentHeaderRect.right;\n this.calculateLoginArrowPosition(this.parentHeaderRight);\n });\n }\n\n private calculateLoginArrowPosition(parentHeaderRight: number | undefined): void {\n\n const vw = this.document.documentElement.clientWidth;\n const arrowSize = '0.5rem';\n const loginLink = this.loginLinkElement()?.nativeElement.getBoundingClientRect();\n const arrowPosition = parentHeaderRight - loginLink?.right + loginLink?.width /2;\n if (parentHeaderRight === undefined) {\n return;\n }\n if (this.isLoginBoxActive && vw < this.TABLET_BREAKPOINT) {\n this.loginArrowPosition = `calc(${arrowPosition}px + ${arrowSize})`;\n } else if (this.isLoginBoxActive ) {\n this.loginArrowPosition = null;\n }\n }\n}\n",
85889
+ "sourceCode": "import { Component, DOCUMENT, ElementRef, EventEmitter, OnChanges, OnDestroy, Output, SimpleChanges, afterNextRender, booleanAttribute, inject, signal, output, input, viewChild } from '@angular/core';\nimport { Subject, debounceTime, fromEvent, takeUntil } from 'rxjs';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { ECLBaseDirective, ECLClickOutsideDirective } from '@eui/ecl/core';\nimport { EclRtlService } from '@eui/ecl/core';\nimport { EclSiteHeaderLoginBoxToggleEvent, EclSiteHeaderLoginEvent } from '../events';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\n\n/** Half the arrow's own width, matching ECL's `arrowSize`. */\nconst ARROW_SIZE = '0.5rem';\n/** Debounce for the resize recomputation, matching ECL's `handleResize`. */\nconst RESIZE_DEBOUNCE = 200;\n\n/**\n * Component for login/logout as part of the harmonised site header. Emits events when user logs in and when user opens the\n * login dropdown.\n */\n@Component({\n selector: 'ecl-site-header-login',\n templateUrl: './ecl-site-header-login.component.html',\n imports: [TranslatePipe, ...EUI_ECL_ICON],\n styles: [\n `\n :host {\n display: block;\n }\n `,\n ],\n hostDirectives: [\n {\n directive: ECLClickOutsideDirective,\n outputs: ['eclClickOutside'],\n },\n ],\n host: {\n class: 'ecl-site-header__login-container',\n '(eclClickOutside)': 'onClickOutside()',\n },\n})\nexport class EclSiteHeaderLoginComponent extends ECLBaseDirective implements OnChanges, OnDestroy {\n readonly isLoggedIn = input(false, { transform: booleanAttribute });\n\n readonly login = output<EclSiteHeaderLoginEvent>();\n @Output() loginBoxToggle = new EventEmitter<EclSiteHeaderLoginBoxToggleEvent>();\n\n /**\n * If login popover is open (true) or closed (false). Kept public because the parent\n * `ecl-site-header` resets it directly when the search box opens.\n */\n isLoginBoxActive = false;\n\n /**\n * The position of the arrow of the popover, when in mobile (full-width) mode.\n */\n protected readonly loginArrowPosition = signal<string | undefined>(undefined);\n\n /**\n * The login link element from the view, i.e. the login button (the toggle).\n */\n private readonly loginLinkElement = viewChild('loginLink', { read: ElementRef });\n /**\n * The login box element from the view, i.e. the dropdown the arrow points at.\n */\n private readonly loginBoxElement = viewChild('loginBox', { read: ElementRef });\n\n private readonly destroy$: Subject<boolean> = new Subject<boolean>();\n private readonly eclRtlService = inject(EclRtlService);\n private readonly document = inject<Document>(DOCUMENT);\n private readonly window = this.document.defaultView;\n\n constructor() {\n super();\n afterNextRender(() => {\n // Recompute the arrow only while the box is open.\n this.eclRtlService.currentRtlState$.pipe(debounceTime(50), takeUntil(this.destroy$)).subscribe(() => {\n if (this.isLoginBoxActive) this.setLoginArrow();\n });\n if (this.window) {\n fromEvent(this.window, 'resize').pipe(debounceTime(RESIZE_DEBOUNCE), takeUntil(this.destroy$)).subscribe(() => {\n if (this.isLoginBoxActive) this.setLoginArrow();\n });\n }\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n const isLoggedInChange = changes.isLoggedIn;\n if (isLoggedInChange && isLoggedInChange.previousValue === true) {\n this.isLoginBoxActive = false;\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.unsubscribe();\n }\n\n /**\n * Close the login popover on click outside.\n */\n protected onClickOutside(): void {\n this.onLoginBoxClose();\n }\n\n /**\n * @returns classes for the login popover.\n */\n protected getLoginBoxCssClasses(): string {\n return ['ecl-site-header__login-box', this.isLoginBoxActive ? 'ecl-site-header__login-box--active' : ''].join(' ');\n }\n\n protected onLoginClick(evt: MouseEvent): void {\n const event = new EclSiteHeaderLoginEvent();\n this.login.emit(event);\n evt.preventDefault();\n }\n\n protected onLoginBoxToggle(evt: MouseEvent): void {\n this.isLoginBoxActive = !this.isLoginBoxActive;\n const event = new EclSiteHeaderLoginBoxToggleEvent(this.isLoginBoxActive);\n this.loginBoxToggle.next(event);\n evt.preventDefault();\n\n if (this.isLoginBoxActive) {\n // Measure after the '--active' class is applied and the box reflows to full width.\n this.window?.requestAnimationFrame(() => this.setLoginArrow());\n }\n }\n\n private onLoginBoxClose(): void {\n if (this.isLoginBoxActive) {\n this.isLoginBoxActive = false;\n const event = new EclSiteHeaderLoginBoxToggleEvent(this.isLoginBoxActive);\n this.loginBoxToggle.next(event);\n this.loginArrowPosition.set(undefined);\n }\n }\n\n /**\n * Position the dropdown arrow so it points at the toggle button.\n * The arrow only exists on the mobile full-width dropdown, so the calculation is gated on the box\n * spanning (almost) the full viewport width. The offset is relative to the box's own left edge.\n * Mirrors ECL's 'setLoginArrow' in site-header.js.\n */\n private setLoginArrow(): void {\n const loginBoxRect = this.loginBoxElement()?.nativeElement.getBoundingClientRect();\n const toggleButtonRect = this.loginLinkElement()?.nativeElement.getBoundingClientRect();\n if (!loginBoxRect || !toggleButtonRect) return;\n\n const clientWidth = this.document.documentElement.clientWidth;\n if (loginBoxRect.width >= clientWidth - 1) {\n const arrowOffset = toggleButtonRect.left - loginBoxRect.left + toggleButtonRect.width / 2;\n this.loginArrowPosition.set(`calc(${arrowOffset}px - ${ARROW_SIZE})`);\n } else {\n this.loginArrowPosition.set(undefined);\n }\n }\n}\n",
86421
85890
  "assetsDirs": [],
86422
85891
  "styleUrlsData": "",
86423
85892
  "stylesData": "\n :host {\n display: block;\n }\n \n",
86424
85893
  "jsdoctags": [
86425
85894
  {
86426
- "pos": 674,
86427
- "end": 824,
85895
+ "pos": 793,
85896
+ "end": 943,
86428
85897
  "kind": 321,
86429
85898
  "id": 0,
86430
85899
  "flags": 16777216,
@@ -86439,7 +85908,7 @@
86439
85908
  "deprecated": false,
86440
85909
  "deprecationMessage": "",
86441
85910
  "args": [],
86442
- "line": 58,
85911
+ "line": 69,
86443
85912
  "rawdescription": "\n"
86444
85913
  },
86445
85914
  "extends": [
@@ -86461,11 +85930,11 @@
86461
85930
  "type": "module"
86462
85931
  },
86463
85932
  {
86464
- "name": "ECLBaseDirective",
85933
+ "name": "ECLClickOutsideDirective",
86465
85934
  "type": "directive"
86466
85935
  },
86467
85936
  {
86468
- "name": "ECLClickOutsideDirective",
85937
+ "name": "ECLBaseDirective",
86469
85938
  "type": "directive"
86470
85939
  },
86471
85940
  {
@@ -86478,7 +85947,7 @@
86478
85947
  }
86479
85948
  ]
86480
85949
  },
86481
- "templateData": "@if (isLoggedIn()) {\n <a\n #loginLink\n href=\"#\"\n class=\"ecl-button ecl-button--tertiary ecl-button--neutral ecl-site-header__login-toggle\"\n aria-controls=\"login-box-id\"\n [attr.aria-expanded]=\"isLoginBoxActive\"\n (click)=\"onLoginBoxToggle($event)\">\n <ecl-icon icon=\"logged-in\" size=\"m\" class=\"ecl-site-header__icon\"></ecl-icon>\n {{ 'ecl.site-header.LOGGED-IN' | translate }}\n </a>\n <div\n id=\"login-box-id\"\n [style]=\"{'--ecl-login-arrow-position': loginArrowPosition}\"\n class=\"{{ getLoginBoxCssClasses() }}\">\n <ng-content></ng-content>\n </div>\n} @else {\n <a\n href=\"#\"\n class=\"ecl-button ecl-button--tertiary ecl-button--neutral ecl-site-header__login-toggle\"\n [attr.aria-expanded]=\"isLoginBoxActive\"\n (click)=\"onLoginClick($event)\">\n <ecl-icon icon=\"log-in\" size=\"m\" class=\"ecl-site-header__icon\"></ecl-icon>\n {{ 'ecl.site-header.LOGIN' | translate }}\n </a>\n}\n"
85950
+ "templateData": "@if (isLoggedIn()) {\n <a\n #loginLink\n href=\"#\"\n class=\"ecl-button ecl-button--tertiary ecl-button--neutral ecl-site-header__login-toggle\"\n aria-controls=\"login-box-id\"\n [attr.aria-expanded]=\"isLoginBoxActive\"\n (click)=\"onLoginBoxToggle($event)\">\n <ecl-icon icon=\"logged-in\" size=\"m\" class=\"ecl-site-header__icon\"></ecl-icon>\n {{ 'ecl.site-header.LOGGED-IN' | translate }}\n </a>\n <div\n #loginBox\n id=\"login-box-id\"\n [style]=\"{'--ecl-login-arrow-position': loginArrowPosition()}\"\n class=\"{{ getLoginBoxCssClasses() }}\">\n <ng-content></ng-content>\n </div>\n} @else {\n <a\n href=\"#\"\n class=\"ecl-button ecl-button--tertiary ecl-button--neutral ecl-site-header__login-toggle\"\n [attr.aria-expanded]=\"isLoginBoxActive\"\n (click)=\"onLoginClick($event)\">\n <ecl-icon icon=\"log-in\" size=\"m\" class=\"ecl-site-header__icon\"></ecl-icon>\n {{ 'ecl.site-header.LOGIN' | translate }}\n </a>\n}\n"
86482
85951
  },
86483
85952
  {
86484
85953
  "name": "EclSiteHeaderNotificationComponent",
@@ -86716,10 +86185,11 @@
86716
86185
  },
86717
86186
  {
86718
86187
  "name": "EclSiteHeaderSearchComponent",
86719
- "id": "component-EclSiteHeaderSearchComponent-d336067a35121cbc3e209e6d7efc56189b0cc7fe678f129591c3c53efc2527183ef93a4441f10af3c84f8f55f0cb6eec03525508b6b070af720b82296f8c3599",
86188
+ "id": "component-EclSiteHeaderSearchComponent-f2c0c32058c22e107aa32c83d7149c58b3c0b5f941191d41160d6a1cb598d61204cdd35709bde16564d408b29b6baa2a4fc1d59a815075d744b7a06bd0e874c7",
86720
86189
  "file": "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts",
86721
86190
  "encapsulation": [],
86722
86191
  "entryComponents": [],
86192
+ "host": {},
86723
86193
  "inputs": [],
86724
86194
  "outputs": [],
86725
86195
  "providers": [
@@ -86737,7 +86207,15 @@
86737
86207
  ],
86738
86208
  "templateVariables": [],
86739
86209
  "viewProviders": [],
86740
- "hostDirectives": [],
86210
+ "hostDirectives": [
86211
+ {
86212
+ "name": "ECLClickOutsideDirective",
86213
+ "inputs": [],
86214
+ "outputs": [
86215
+ "eclClickOutside"
86216
+ ]
86217
+ }
86218
+ ],
86741
86219
  "inputsClass": [
86742
86220
  {
86743
86221
  "coverageIgnore": false,
@@ -86746,7 +86224,7 @@
86746
86224
  "deprecationMessage": "",
86747
86225
  "rawdescription": "\n",
86748
86226
  "description": "",
86749
- "line": 46,
86227
+ "line": 56,
86750
86228
  "type": "string",
86751
86229
  "decorators": []
86752
86230
  },
@@ -86760,7 +86238,7 @@
86760
86238
  "indexKey": "",
86761
86239
  "optional": false,
86762
86240
  "description": "",
86763
- "line": 48,
86241
+ "line": 58,
86764
86242
  "rawdescription": "\n",
86765
86243
  "modifierKind": [
86766
86244
  148
@@ -86777,7 +86255,7 @@
86777
86255
  "indexKey": "",
86778
86256
  "optional": false,
86779
86257
  "description": "",
86780
- "line": 47,
86258
+ "line": 57,
86781
86259
  "rawdescription": "\n",
86782
86260
  "modifierKind": [
86783
86261
  148
@@ -86835,7 +86313,7 @@
86835
86313
  "defaultValue": "new EventEmitter<EclSiteHeaderSearchToggleEvent>()",
86836
86314
  "deprecated": false,
86837
86315
  "deprecationMessage": "",
86838
- "line": 56,
86316
+ "line": 61,
86839
86317
  "type": "EventEmitter"
86840
86318
  },
86841
86319
  {
@@ -86847,7 +86325,7 @@
86847
86325
  "indexKey": "",
86848
86326
  "optional": false,
86849
86327
  "description": "",
86850
- "line": 55,
86328
+ "line": 60,
86851
86329
  "rawdescription": "\n",
86852
86330
  "modifierKind": [
86853
86331
  148
@@ -86856,28 +86334,6 @@
86856
86334
  }
86857
86335
  ],
86858
86336
  "propertiesClass": [
86859
- {
86860
- "name": "class",
86861
- "coverageIgnore": false,
86862
- "defaultValue": "'ecl-site-header__search-container'",
86863
- "deprecated": false,
86864
- "deprecationMessage": "",
86865
- "type": "string",
86866
- "indexKey": "",
86867
- "optional": false,
86868
- "description": "",
86869
- "line": 40,
86870
- "rawdescription": "\n",
86871
- "decorators": [
86872
- {
86873
- "name": "HostBinding",
86874
- "stringifiedArguments": "'class'"
86875
- }
86876
- ],
86877
- "modifierKind": [
86878
- 171
86879
- ]
86880
- },
86881
86337
  {
86882
86338
  "name": "isSearchBoxActive",
86883
86339
  "coverageIgnore": false,
@@ -86887,63 +86343,24 @@
86887
86343
  "type": "unknown",
86888
86344
  "indexKey": "",
86889
86345
  "optional": false,
86890
- "description": "",
86891
- "line": 62,
86892
- "rawdescription": "\n",
86893
- "modifierKind": [
86894
- 125
86895
- ]
86896
- },
86897
- {
86898
- "name": "role",
86899
- "coverageIgnore": false,
86900
- "defaultValue": "'search'",
86901
- "deprecated": false,
86902
- "deprecationMessage": "",
86903
- "type": "string",
86904
- "indexKey": "",
86905
- "optional": false,
86906
- "description": "<p>The default role of the component is &#39;search&#39;, should not be changed.</p>\n",
86907
- "line": 44,
86908
- "rawdescription": "\n\nThe default role of the component is 'search', should not be changed.\n",
86909
- "decorators": [
86910
- {
86911
- "name": "HostBinding",
86912
- "stringifiedArguments": "'attr.role'"
86913
- }
86914
- ],
86915
- "modifierKind": [
86916
- 171
86917
- ]
86346
+ "description": "<p>Whether the search dropdown is open. Kept public because the parent\n<code>ecl-site-header</code> resets it directly when the login box opens.</p>\n",
86347
+ "line": 67,
86348
+ "rawdescription": "\n\nWhether the search dropdown is open. Kept public because the parent\n`ecl-site-header` resets it directly when the login box opens.\n"
86918
86349
  },
86919
86350
  {
86920
86351
  "name": "searchArrowPosition",
86921
86352
  "coverageIgnore": false,
86922
- "deprecated": false,
86923
- "deprecationMessage": "",
86924
- "type": "string",
86925
- "indexKey": "",
86926
- "optional": false,
86927
- "description": "<p>The arrow position of the serahc dropdown, when in mobile mode.</p>\n",
86928
- "line": 61,
86929
- "rawdescription": "\n\nThe arrow position of the serahc dropdown, when in mobile mode.\n",
86930
- "modifierKind": [
86931
- 125
86932
- ]
86933
- },
86934
- {
86935
- "name": "searchLinkElement",
86936
- "coverageIgnore": false,
86937
- "defaultValue": "viewChild('searchLink', { read: ElementRef })",
86353
+ "defaultValue": "signal<string | undefined>(undefined)",
86938
86354
  "deprecated": false,
86939
86355
  "deprecationMessage": "",
86940
86356
  "type": "unknown",
86941
86357
  "indexKey": "",
86942
86358
  "optional": false,
86943
- "description": "<p>The search link element from the view, i.e. the search button.</p>\n",
86944
- "line": 53,
86945
- "rawdescription": "\n\nThe search link element from the view, i.e. the search button.\n",
86359
+ "description": "<p>The arrow position of the search dropdown, when in mobile (full-width) mode.</p>\n",
86360
+ "line": 72,
86361
+ "rawdescription": "\n\nThe arrow position of the search dropdown, when in mobile (full-width) mode.\n",
86946
86362
  "modifierKind": [
86363
+ 124,
86947
86364
  148
86948
86365
  ]
86949
86366
  }
@@ -86956,16 +86373,19 @@
86956
86373
  "optional": false,
86957
86374
  "returnType": "string",
86958
86375
  "typeParameters": [],
86959
- "line": 116,
86376
+ "line": 158,
86960
86377
  "deprecated": false,
86961
86378
  "deprecationMessage": "",
86962
86379
  "rawdescription": "\n\n\n",
86963
86380
  "description": "",
86381
+ "modifierKind": [
86382
+ 124
86383
+ ],
86964
86384
  "jsdoctags": [
86965
86385
  {
86966
86386
  "tagName": {
86967
- "pos": 4301,
86968
- "end": 4308,
86387
+ "pos": 5933,
86388
+ "end": 5940,
86969
86389
  "kind": 80,
86970
86390
  "id": 0,
86971
86391
  "flags": 16842752,
@@ -86983,7 +86403,7 @@
86983
86403
  "optional": false,
86984
86404
  "returnType": "void",
86985
86405
  "typeParameters": [],
86986
- "line": 77,
86406
+ "line": 94,
86987
86407
  "deprecated": false,
86988
86408
  "deprecationMessage": "",
86989
86409
  "rawdescription": "\n",
@@ -86996,12 +86416,28 @@
86996
86416
  "optional": false,
86997
86417
  "returnType": "void",
86998
86418
  "typeParameters": [],
86999
- "line": 93,
86419
+ "line": 108,
87000
86420
  "deprecated": false,
87001
86421
  "deprecationMessage": "",
87002
86422
  "rawdescription": "\n",
87003
86423
  "description": ""
87004
86424
  },
86425
+ {
86426
+ "name": "onClickOutside",
86427
+ "coverageIgnore": false,
86428
+ "args": [],
86429
+ "optional": false,
86430
+ "returnType": "void",
86431
+ "typeParameters": [],
86432
+ "line": 131,
86433
+ "deprecated": false,
86434
+ "deprecationMessage": "",
86435
+ "rawdescription": "\n\nClose the search dropdown on click outside, matching ECL's `handleClickGlobal`.\n",
86436
+ "description": "<p>Close the search dropdown on click outside, matching ECL&#39;s <code>handleClickGlobal</code>.</p>\n",
86437
+ "modifierKind": [
86438
+ 124
86439
+ ]
86440
+ },
87005
86441
  {
87006
86442
  "name": "onModelChange",
87007
86443
  "coverageIgnore": false,
@@ -87018,11 +86454,14 @@
87018
86454
  "optional": false,
87019
86455
  "returnType": "void",
87020
86456
  "typeParameters": [],
87021
- "line": 120,
86457
+ "line": 162,
87022
86458
  "deprecated": false,
87023
86459
  "deprecationMessage": "",
87024
86460
  "rawdescription": "\n",
87025
86461
  "description": "",
86462
+ "modifierKind": [
86463
+ 124
86464
+ ],
87026
86465
  "jsdoctags": [
87027
86466
  {
87028
86467
  "name": "newValue",
@@ -87053,11 +86492,14 @@
87053
86492
  "optional": false,
87054
86493
  "returnType": "boolean",
87055
86494
  "typeParameters": [],
87056
- "line": 99,
86495
+ "line": 135,
87057
86496
  "deprecated": false,
87058
86497
  "deprecationMessage": "",
87059
86498
  "rawdescription": "\n",
87060
86499
  "description": "",
86500
+ "modifierKind": [
86501
+ 124
86502
+ ],
87061
86503
  "jsdoctags": [
87062
86504
  {
87063
86505
  "name": "evt",
@@ -87088,11 +86530,14 @@
87088
86530
  "optional": false,
87089
86531
  "returnType": "void",
87090
86532
  "typeParameters": [],
87091
- "line": 105,
86533
+ "line": 141,
87092
86534
  "deprecated": false,
87093
86535
  "deprecationMessage": "",
87094
86536
  "rawdescription": "\n",
87095
86537
  "description": "",
86538
+ "modifierKind": [
86539
+ 124
86540
+ ],
87096
86541
  "jsdoctags": [
87097
86542
  {
87098
86543
  "name": "evt",
@@ -87123,7 +86568,7 @@
87123
86568
  "optional": false,
87124
86569
  "returnType": "void",
87125
86570
  "typeParameters": [],
87126
- "line": 131,
86571
+ "line": 119,
87127
86572
  "deprecated": false,
87128
86573
  "deprecationMessage": "",
87129
86574
  "rawdescription": "\n",
@@ -87158,7 +86603,7 @@
87158
86603
  "optional": false,
87159
86604
  "returnType": "void",
87160
86605
  "typeParameters": [],
87161
- "line": 136,
86606
+ "line": 124,
87162
86607
  "deprecated": false,
87163
86608
  "deprecationMessage": "",
87164
86609
  "rawdescription": "\n",
@@ -87193,7 +86638,7 @@
87193
86638
  "optional": false,
87194
86639
  "returnType": "void",
87195
86640
  "typeParameters": [],
87196
- "line": 126,
86641
+ "line": 114,
87197
86642
  "deprecated": false,
87198
86643
  "deprecationMessage": "",
87199
86644
  "rawdescription": "\n",
@@ -87254,34 +86699,7 @@
87254
86699
  "coverageIgnore": false,
87255
86700
  "deprecated": false,
87256
86701
  "deprecationMessage": "",
87257
- "hostBindings": [
87258
- {
87259
- "coverageIgnore": false,
87260
- "name": "attr.role",
87261
- "actualName": "role",
87262
- "defaultValue": "'search'",
87263
- "deprecated": false,
87264
- "deprecationMessage": "",
87265
- "rawdescription": "\n\nThe default role of the component is 'search', should not be changed.\n",
87266
- "description": "<p>The default role of the component is &#39;search&#39;, should not be changed.</p>\n",
87267
- "line": 44,
87268
- "type": "string",
87269
- "decorators": []
87270
- },
87271
- {
87272
- "coverageIgnore": false,
87273
- "name": "class",
87274
- "actualName": "class",
87275
- "defaultValue": "'ecl-site-header__search-container'",
87276
- "deprecated": false,
87277
- "deprecationMessage": "",
87278
- "rawdescription": "\n",
87279
- "description": "",
87280
- "line": 40,
87281
- "type": "string",
87282
- "decorators": []
87283
- }
87284
- ],
86702
+ "hostBindings": [],
87285
86703
  "hostListeners": [],
87286
86704
  "standalone": false,
87287
86705
  "imports": [
@@ -87303,14 +86721,14 @@
87303
86721
  "description": "<p>This component builds the search box in the ecl-site-header component. Adds specific style and functionality, emits\n events on search and search toggle.</p>\n",
87304
86722
  "rawdescription": "\n\nThis component builds the search box in the ecl-site-header component. Adds specific style and functionality, emits\n events on search and search toggle.\n",
87305
86723
  "type": "component",
87306
- "sourceCode": "import { isPlatformBrowser } from '@angular/common';\nimport { AfterViewInit, ChangeDetectorRef, Component, DOCUMENT, ElementRef, EventEmitter, forwardRef, HostBinding, inject, Input, OnDestroy, Output, PLATFORM_ID, Provider, output, input, viewChild } from '@angular/core';\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EclSearchFormEvent, EUI_ECL_SEARCH_FORM } from '@eui/ecl/components/ecl-search-form';\nimport { ECLBaseDirective, EclRtlService } from '@eui/ecl/core';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { debounceTime, Subject, takeUntil } from 'rxjs';\nimport { EclSiteHeaderSearchEvent, EclSiteHeaderSearchToggleEvent } from '../events';\nimport { EclAreaDataService } from '../services/ecl-area-data.service';\n\nexport const ECL_SITE_HEADER_SEARCH_VALUE_ACCESSOR: Provider = {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => EclSiteHeaderSearchComponent),\n multi: true,\n};\n\nconst noop = (): void => {\n /** empty*/\n};\n\n/**\n * This component builds the search box in the ecl-site-header component. Adds specific style and functionality, emits\n * events on search and search toggle.\n */\n@Component({\n selector: 'ecl-site-header-search',\n templateUrl: './ecl-site-header-search.component.html',\n imports: [FormsModule, TranslatePipe, ...EUI_ECL_SEARCH_FORM, ...EUI_ECL_ICON],\n styles: [\n `\n :host {\n display: block;\n }\n `,\n ],\n providers: [ECL_SITE_HEADER_SEARCH_VALUE_ACCESSOR],\n})\nexport class EclSiteHeaderSearchComponent extends ECLBaseDirective implements ControlValueAccessor, AfterViewInit, OnDestroy {\n @HostBinding('class') class = 'ecl-site-header__search-container';\n /**\n * The default role of the component is 'search', should not be changed.\n */\n @HostBinding('attr.role') role = 'search';\n\n @Input() searchInputText: string;\n readonly searchInputPlaceholder = input<string>(undefined);\n readonly searchButtonLabel = input<string>(undefined);\n\n /**\n * The search link element from the view, i.e. the search button.\n */\n readonly searchLinkElement = viewChild('searchLink', { read: ElementRef });\n\n readonly searchEvent = output<EclSiteHeaderSearchEvent>();\n @Output() searchToggle = new EventEmitter<EclSiteHeaderSearchToggleEvent>();\n\n /**\n * The arrow position of the serahc dropdown, when in mobile mode.\n */\n public searchArrowPosition: string;\n public isSearchBoxActive = false;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private onChange: (_: any) => void = noop;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private onTouched: (_: any) => void = noop;\n\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private parentHeaderRight: number | undefined;\n private eclAreaDataService = inject(EclAreaDataService);\n private eclRtlService = inject(EclRtlService);\n private cdr = inject(ChangeDetectorRef);\n private platformId = inject(PLATFORM_ID);\n private ro?: ResizeObserver;\n private document = inject<Document>(DOCUMENT);\n\n ngAfterViewInit(): void {\n if (!isPlatformBrowser(this.platformId)) return;\n\n this.handleRtlChangeState();\n this.handleSiteHeaderAreaChangeEvent();\n\n const el = (this as any).elementRef?.nativeElement ?? null; // if ECLBaseDirective exposes it\n if (!el) return;\n\n this.ro = new ResizeObserver(() => {\n this.calculateSearchFormArrowPosition(this.parentHeaderRight);\n });\n\n this.ro.observe(el);\n }\n\n ngOnDestroy(): void {\n this.ro?.disconnect();\n this.destroy$.next(true);\n this.destroy$.complete();\n }\n\n onSearch(evt: EclSearchFormEvent): boolean {\n this.searchEvent.emit(new EclSiteHeaderSearchEvent(evt.keyword));\n this.onChange(evt.keyword);\n return false;\n }\n\n onSearchBoxToggle(evt: MouseEvent): void {\n this.isSearchBoxActive = !this.isSearchBoxActive;\n const event = new EclSiteHeaderSearchToggleEvent(this.isSearchBoxActive);\n this.searchToggle.next(event);\n evt.preventDefault();\n }\n\n /**\n *\n * @returns The classes for the ecl search form.\n */\n getSearchBoxCssClasses(): string {\n return ['ecl-site-header__search', this.isSearchBoxActive ? 'ecl-site-header__search--active' : ''].join(' ');\n }\n\n onModelChange(newValue: string): void {\n this.searchInputText = newValue;\n this.onChange(newValue);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n writeValue(value: any): void {\n this.searchInputText = value;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n registerOnChange(fn: any): void {\n this.onChange = fn;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n registerOnTouched(fn: any): void {\n this.onTouched = fn;\n }\n\n private handleRtlChangeState(): void {\n this.eclRtlService.currentRtlState$.pipe(debounceTime(50), takeUntil(this.destroy$)).subscribe(() => {\n this.calculateSearchFormArrowPosition(this.parentHeaderRight);\n });\n }\n\n private handleSiteHeaderAreaChangeEvent(): void {\n this.eclAreaDataService.dataSubject$.pipe(takeUntil(this.destroy$)).subscribe(\n parentHeaderRect => {\n this.parentHeaderRight = parentHeaderRect.right;\n this.calculateSearchFormArrowPosition(this.parentHeaderRight);\n });\n }\n\n private calculateSearchFormArrowPosition(parentHeaderRight: number | undefined): void {\n const searchLink = this.searchLinkElement().nativeElement.getBoundingClientRect();\n const viewportWidth = this.document.documentElement.clientWidth;\n const arrowPosition = viewportWidth - searchLink.right + searchLink.width / 2;\n const arrowSize = '0.5rem';\n if (this.isSearchBoxActive || parentHeaderRight !== undefined) {\n this.searchArrowPosition = `calc(${arrowPosition}px + ${arrowSize})`;\n this.cdr.detectChanges();\n }\n }\n}\n",
86724
+ "sourceCode": "import { isPlatformBrowser } from '@angular/common';\nimport { AfterViewInit, Component, DOCUMENT, ElementRef, EventEmitter, forwardRef, inject, Input, OnDestroy, Output, PLATFORM_ID, Provider, output, input, signal, viewChild } from '@angular/core';\nimport { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EclSearchFormEvent, EUI_ECL_SEARCH_FORM } from '@eui/ecl/components/ecl-search-form';\nimport { ECLBaseDirective, ECLClickOutsideDirective, EclRtlService } from '@eui/ecl/core';\nimport { TranslatePipe } from '@ngx-translate/core';\nimport { debounceTime, fromEvent, Subject, takeUntil } from 'rxjs';\nimport { EclSiteHeaderSearchEvent, EclSiteHeaderSearchToggleEvent } from '../events';\n\nexport const ECL_SITE_HEADER_SEARCH_VALUE_ACCESSOR: Provider = {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => EclSiteHeaderSearchComponent),\n multi: true,\n};\n\nconst noop = (): void => {\n /** empty*/\n};\n\n/** Half the arrow's own width, matching ECL's `arrowSize`. */\nconst ARROW_SIZE = '0.5rem';\n/** Debounce for the resize recomputation, matching ECL's `handleResize`. */\nconst RESIZE_DEBOUNCE = 200;\n\n/**\n * This component builds the search box in the ecl-site-header component. Adds specific style and functionality, emits\n * events on search and search toggle.\n */\n@Component({\n selector: 'ecl-site-header-search',\n templateUrl: './ecl-site-header-search.component.html',\n imports: [FormsModule, TranslatePipe, ...EUI_ECL_SEARCH_FORM, ...EUI_ECL_ICON],\n styles: [\n `\n :host {\n display: block;\n }\n `,\n ],\n providers: [ECL_SITE_HEADER_SEARCH_VALUE_ACCESSOR],\n hostDirectives: [\n {\n directive: ECLClickOutsideDirective,\n outputs: ['eclClickOutside'],\n },\n ],\n host: {\n class: 'ecl-site-header__search-container',\n // The default role of the component is 'search', should not be changed.\n role: 'search',\n '(eclClickOutside)': 'onClickOutside()',\n },\n})\nexport class EclSiteHeaderSearchComponent extends ECLBaseDirective implements ControlValueAccessor, AfterViewInit, OnDestroy {\n @Input() searchInputText: string;\n readonly searchInputPlaceholder = input<string>(undefined);\n readonly searchButtonLabel = input<string>(undefined);\n\n readonly searchEvent = output<EclSiteHeaderSearchEvent>();\n @Output() searchToggle = new EventEmitter<EclSiteHeaderSearchToggleEvent>();\n\n /**\n * Whether the search dropdown is open. Kept public because the parent\n * `ecl-site-header` resets it directly when the login box opens.\n */\n isSearchBoxActive = false;\n\n /**\n * The arrow position of the search dropdown, when in mobile (full-width) mode.\n */\n protected readonly searchArrowPosition = signal<string | undefined>(undefined);\n\n /**\n * The search link element from the view, i.e. the search button (the toggle).\n */\n private readonly searchLinkElement = viewChild('searchLink', { read: ElementRef });\n /**\n * The search form element from the view, i.e. the dropdown box the arrow points from.\n */\n private readonly searchFormElement = viewChild('searchForm', { read: ElementRef });\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private onChange: (_: any) => void = noop;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private onTouched: (_: any) => void = noop;\n\n private destroy$: Subject<boolean> = new Subject<boolean>();\n private readonly eclRtlService = inject(EclRtlService);\n private readonly platformId = inject(PLATFORM_ID);\n private readonly document = inject<Document>(DOCUMENT);\n private readonly window = this.document.defaultView; // Window | null\n\n ngAfterViewInit(): void {\n if (!isPlatformBrowser(this.platformId)) return;\n\n // Recompute while open on resize (debounced, matching ECL's handleResize).\n if (this.window) {\n fromEvent(this.window, 'resize')\n .pipe(debounceTime(RESIZE_DEBOUNCE), takeUntil(this.destroy$))\n .subscribe(() => this.setSearchArrow());\n }\n\n // Recompute while open on RTL direction change.\n this.eclRtlService.currentRtlState$.pipe(debounceTime(50), takeUntil(this.destroy$)).subscribe(() => this.setSearchArrow());\n }\n\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.complete();\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n writeValue(value: any): void {\n this.searchInputText = value;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n registerOnChange(fn: any): void {\n this.onChange = fn;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n registerOnTouched(fn: any): void {\n this.onTouched = fn;\n }\n\n /**\n * Close the search dropdown on click outside, matching ECL's `handleClickGlobal`.\n */\n protected onClickOutside(): void {\n this.closeSearchBox();\n }\n\n protected onSearch(evt: EclSearchFormEvent): boolean {\n this.searchEvent.emit(new EclSiteHeaderSearchEvent(evt.keyword));\n this.onChange(evt.keyword);\n return false;\n }\n\n protected onSearchBoxToggle(evt: MouseEvent): void {\n this.isSearchBoxActive = !this.isSearchBoxActive;\n const event = new EclSiteHeaderSearchToggleEvent(this.isSearchBoxActive);\n this.searchToggle.next(event);\n evt.preventDefault();\n\n // Measure after the `--active` class is applied and the box reflows to\n // full width (matching ECL's toggleSearch -> setSearchArrow order).\n if (this.isSearchBoxActive) {\n this.window?.requestAnimationFrame(() => this.setSearchArrow());\n }\n }\n\n /**\n *\n * @returns The classes for the ecl search form.\n */\n protected getSearchBoxCssClasses(): string {\n return ['ecl-site-header__search', this.isSearchBoxActive ? 'ecl-site-header__search--active' : ''].join(' ');\n }\n\n protected onModelChange(newValue: string): void {\n this.searchInputText = newValue;\n this.onChange(newValue);\n }\n\n private closeSearchBox(): void {\n if (!this.isSearchBoxActive) return;\n\n this.isSearchBoxActive = false;\n this.searchToggle.next(new EclSiteHeaderSearchToggleEvent(this.isSearchBoxActive));\n this.searchArrowPosition.set(undefined);\n }\n\n /**\n * Positions the dropdown arrow so it points at the center of the search toggle button.\n * Mirrors ECL's `setSearchArrow`: the arrow position is an offset relative to the\n * search form's own left edge, and it only applies to the mobile full-width dropdown\n * (`searchFormRect.width >= clientWidth - 1`, the `- 1` absorbing subpixel rounding).\n */\n private setSearchArrow(): void {\n if (!this.isSearchBoxActive) return;\n\n const searchFormRect = this.searchFormElement()?.nativeElement.getBoundingClientRect();\n const toggleButtonRect = this.searchLinkElement()?.nativeElement.getBoundingClientRect();\n if (!searchFormRect || !toggleButtonRect) return;\n\n const clientWidth = this.document.documentElement.clientWidth;\n if (searchFormRect.width >= clientWidth - 1) {\n const arrowOffset = toggleButtonRect.left - searchFormRect.left + toggleButtonRect.width / 2;\n this.searchArrowPosition.set(`calc(${arrowOffset}px - ${ARROW_SIZE})`);\n } else {\n this.searchArrowPosition.set(undefined);\n }\n }\n}\n",
87307
86725
  "assetsDirs": [],
87308
86726
  "styleUrlsData": "",
87309
86727
  "stylesData": "\n :host {\n display: block;\n }\n \n",
87310
86728
  "jsdoctags": [
87311
86729
  {
87312
- "pos": 1081,
87313
- "end": 1247,
86730
+ "pos": 1221,
86731
+ "end": 1387,
87314
86732
  "kind": 321,
87315
86733
  "id": 0,
87316
86734
  "flags": 16777216,
@@ -87350,6 +86768,10 @@
87350
86768
  "name": "ECL_SITE_HEADER_SEARCH_VALUE_ACCESSOR",
87351
86769
  "type": "injectable"
87352
86770
  },
86771
+ {
86772
+ "name": "ECLClickOutsideDirective",
86773
+ "type": "directive"
86774
+ },
87353
86775
  {
87354
86776
  "name": "ECLBaseDirective",
87355
86777
  "type": "directive"
@@ -87368,7 +86790,7 @@
87368
86790
  }
87369
86791
  ]
87370
86792
  },
87371
- "templateData": "<a\n #searchLink\n href=\"#\"\n class=\"ecl-button ecl-button--tertiary ecl-site-header__search-toggle ecl-button--neutral\"\n data-ecl-search-toggle=\"true\"\n aria-controls=\"search-form-id\"\n [attr.aria-expanded]=\"isSearchBoxActive\"\n (click)=\"onSearchBoxToggle($event)\">\n <ecl-icon icon=\"search\" size=\"m\" class=\"ecl-site-header__icon\"></ecl-icon>\n {{ 'ecl.common.SEARCH' | translate }}\n</a>\n\n<ecl-search-form\n [style]=\"{'--ecl-search-arrow-position': searchArrowPosition}\"\n (searchEvent)=\"onSearch($event)\"\n [placeholder]=\"searchInputPlaceholder()\"\n (ngModelChange)=\"onModelChange($event)\"\n [(ngModel)]=\"searchInputText\"\n [searchButtonLabel]=\"searchButtonLabel()\"\n [class]=\"getSearchBoxCssClasses()\">\n</ecl-search-form>\n"
86793
+ "templateData": "<a\n #searchLink\n href=\"#\"\n class=\"ecl-button ecl-button--tertiary ecl-site-header__search-toggle ecl-button--neutral\"\n data-ecl-search-toggle=\"true\"\n aria-controls=\"search-form-id\"\n [attr.aria-expanded]=\"isSearchBoxActive\"\n (click)=\"onSearchBoxToggle($event)\">\n <ecl-icon icon=\"search\" size=\"m\" class=\"ecl-site-header__icon\"></ecl-icon>\n {{ 'ecl.common.SEARCH' | translate }}\n</a>\n\n<ecl-search-form\n #searchForm\n [style]=\"{'--ecl-search-arrow-position': searchArrowPosition()}\"\n (searchEvent)=\"onSearch($event)\"\n [placeholder]=\"searchInputPlaceholder()\"\n (ngModelChange)=\"onModelChange($event)\"\n [(ngModel)]=\"searchInputText\"\n [searchButtonLabel]=\"searchButtonLabel()\"\n [class]=\"getSearchBoxCssClasses()\">\n</ecl-search-form>\n"
87372
86794
  },
87373
86795
  {
87374
86796
  "name": "EclSloganTickerComponent",
@@ -87894,10 +87316,11 @@
87894
87316
  },
87895
87317
  {
87896
87318
  "name": "EclSocialMediaFollowComponent",
87897
- "id": "component-EclSocialMediaFollowComponent-f654af80b29a6bd0e224db14a80294d3f9980172f216037b2f5c7ee9ec02a36e2e8e6a4e45524230c9ed4ca8478a3a66a439b08f360d21fcaf2d6cb725787e9a",
87319
+ "id": "component-EclSocialMediaFollowComponent-fcab917e6198b64e907ac28615dad1cf477fb287a17e38ee55f63e5c5cebf077dd13d234b452e0e45a6191fd24561c50be0befe539635a09637022fc41c5ad91",
87898
87320
  "file": "packages/ecl/components/ecl-social-media-follow/ecl-social-media-follow.component.ts",
87899
87321
  "encapsulation": [],
87900
87322
  "entryComponents": [],
87323
+ "host": {},
87901
87324
  "inputs": [],
87902
87325
  "outputs": [],
87903
87326
  "providers": [],
@@ -87921,7 +87344,7 @@
87921
87344
  "indexKey": "",
87922
87345
  "optional": false,
87923
87346
  "description": "",
87924
- "line": 9,
87347
+ "line": 12,
87925
87348
  "rawdescription": "\n",
87926
87349
  "modifierKind": [
87927
87350
  148
@@ -87938,7 +87361,24 @@
87938
87361
  "indexKey": "",
87939
87362
  "optional": false,
87940
87363
  "description": "",
87941
- "line": 11,
87364
+ "line": 15,
87365
+ "rawdescription": "\n",
87366
+ "modifierKind": [
87367
+ 148
87368
+ ],
87369
+ "required": false
87370
+ },
87371
+ {
87372
+ "name": "isIconOnly",
87373
+ "coverageIgnore": false,
87374
+ "defaultValue": "false",
87375
+ "deprecated": false,
87376
+ "deprecationMessage": "",
87377
+ "type": "boolean",
87378
+ "indexKey": "",
87379
+ "optional": false,
87380
+ "description": "",
87381
+ "line": 13,
87942
87382
  "rawdescription": "\n",
87943
87383
  "modifierKind": [
87944
87384
  148
@@ -87955,7 +87395,7 @@
87955
87395
  "indexKey": "",
87956
87396
  "optional": false,
87957
87397
  "description": "",
87958
- "line": 10,
87398
+ "line": 14,
87959
87399
  "rawdescription": "\n",
87960
87400
  "modifierKind": [
87961
87401
  148
@@ -88051,27 +87491,14 @@
88051
87491
  "coverageIgnore": false,
88052
87492
  "deprecated": false,
88053
87493
  "deprecationMessage": "",
88054
- "hostBindings": [
88055
- {
88056
- "coverageIgnore": false,
88057
- "name": "class",
88058
- "actualName": "cssClasses",
88059
- "deprecated": false,
88060
- "deprecationMessage": "",
88061
- "rawdescription": "\n",
88062
- "description": "",
88063
- "line": 14,
88064
- "type": "string",
88065
- "decorators": []
88066
- }
88067
- ],
87494
+ "hostBindings": [],
88068
87495
  "hostListeners": [],
88069
87496
  "standalone": false,
88070
87497
  "imports": [],
88071
87498
  "description": "",
88072
87499
  "rawdescription": "\n",
88073
87500
  "type": "component",
88074
- "sourceCode": "import { Component, HostBinding, booleanAttribute, input } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n@Component({\n selector: 'ecl-social-media-follow',\n templateUrl: './ecl-social-media-follow.component.html',\n})\nexport class EclSocialMediaFollowComponent extends ECLBaseDirective {\n readonly description = input<string>(undefined);\n readonly isVertical = input(false, { transform: booleanAttribute });\n readonly horizontalAlignment = input<'right' | 'left' | string>('left');\n\n @HostBinding('class')\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-social-media-follow'),\n this.isVertical() ? 'ecl-social-media-follow--vertical' : '',\n `ecl-social-media-follow--${this.horizontalAlignment()}`,\n ]\n .join(' ')\n .trim();\n }\n}\n",
87501
+ "sourceCode": "import { Component, booleanAttribute, input } from '@angular/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\n\n@Component({\n selector: 'ecl-social-media-follow',\n templateUrl: './ecl-social-media-follow.component.html',\n host: {\n '[class]': 'cssClasses',\n },\n})\nexport class EclSocialMediaFollowComponent extends ECLBaseDirective {\n readonly description = input<string>(undefined);\n readonly isIconOnly = input(false, { transform: booleanAttribute });\n readonly isVertical = input(false, { transform: booleanAttribute });\n readonly horizontalAlignment = input<'right' | 'left' | string>('left');\n\n get cssClasses(): string {\n return [\n super.getCssClasses('ecl-social-media-follow'),\n this.isVertical() ? 'ecl-social-media-follow--vertical' : '',\n `ecl-social-media-follow--${this.horizontalAlignment()}`,\n ]\n .join(' ')\n .trim();\n }\n}\n",
88075
87502
  "assetsDirs": [],
88076
87503
  "styleUrlsData": "",
88077
87504
  "stylesData": "",
@@ -88085,7 +87512,7 @@
88085
87512
  "name": "cssClasses",
88086
87513
  "type": "string",
88087
87514
  "returnType": "string",
88088
- "line": 14,
87515
+ "line": 17,
88089
87516
  "rawdescription": "\n",
88090
87517
  "description": ""
88091
87518
  }
@@ -88104,10 +87531,11 @@
88104
87531
  },
88105
87532
  {
88106
87533
  "name": "EclSocialMediaFollowItemComponent",
88107
- "id": "component-EclSocialMediaFollowItemComponent-ed2164f85b7d64f8d8fac99dbd85b9daf46f2c0f6adb24b7cdeb865f195926ad0eee3b826c46f06ca87a06f0c0c5b7d1a996ce2d1ed4d4882aec79e8595572d9",
87534
+ "id": "component-EclSocialMediaFollowItemComponent-a5a386ce91d38e0d4ebb07c2085b8c669354f1a816b2677b7dde9628c9a14908687d7a7d0f9f6e66e8172233d257ac2a1145254275a03f9216caa201b32c6018",
88108
87535
  "file": "packages/ecl/components/ecl-social-media-follow/ecl-social-media-follow-item.component.ts",
88109
87536
  "encapsulation": [],
88110
87537
  "entryComponents": [],
87538
+ "host": {},
88111
87539
  "inputs": [],
88112
87540
  "outputs": [],
88113
87541
  "providers": [],
@@ -88131,7 +87559,7 @@
88131
87559
  "indexKey": "",
88132
87560
  "optional": false,
88133
87561
  "description": "",
88134
- "line": 25,
87562
+ "line": 29,
88135
87563
  "rawdescription": "\n",
88136
87564
  "modifierKind": [
88137
87565
  148
@@ -88148,7 +87576,7 @@
88148
87576
  "indexKey": "",
88149
87577
  "optional": false,
88150
87578
  "description": "",
88151
- "line": 21,
87579
+ "line": 25,
88152
87580
  "rawdescription": "\n",
88153
87581
  "modifierKind": [
88154
87582
  148
@@ -88164,7 +87592,7 @@
88164
87592
  "indexKey": "",
88165
87593
  "optional": false,
88166
87594
  "description": "",
88167
- "line": 19,
87595
+ "line": 23,
88168
87596
  "rawdescription": "\n",
88169
87597
  "required": false
88170
87598
  },
@@ -88178,7 +87606,7 @@
88178
87606
  "indexKey": "",
88179
87607
  "optional": false,
88180
87608
  "description": "",
88181
- "line": 20,
87609
+ "line": 24,
88182
87610
  "rawdescription": "\n",
88183
87611
  "required": false
88184
87612
  },
@@ -88192,7 +87620,7 @@
88192
87620
  "indexKey": "",
88193
87621
  "optional": false,
88194
87622
  "description": "",
88195
- "line": 17,
87623
+ "line": 22,
88196
87624
  "rawdescription": "\n",
88197
87625
  "modifierKind": [
88198
87626
  148
@@ -88209,7 +87637,7 @@
88209
87637
  "indexKey": "",
88210
87638
  "optional": false,
88211
87639
  "description": "",
88212
- "line": 22,
87640
+ "line": 26,
88213
87641
  "rawdescription": "\n",
88214
87642
  "modifierKind": [
88215
87643
  148
@@ -88226,7 +87654,7 @@
88226
87654
  "indexKey": "",
88227
87655
  "optional": false,
88228
87656
  "description": "",
88229
- "line": 24,
87657
+ "line": 28,
88230
87658
  "rawdescription": "\n",
88231
87659
  "modifierKind": [
88232
87660
  148
@@ -88243,7 +87671,7 @@
88243
87671
  "indexKey": "",
88244
87672
  "optional": false,
88245
87673
  "description": "",
88246
- "line": 23,
87674
+ "line": 27,
88247
87675
  "rawdescription": "\n",
88248
87676
  "modifierKind": [
88249
87677
  148
@@ -88304,7 +87732,7 @@
88304
87732
  "indexKey": "",
88305
87733
  "optional": false,
88306
87734
  "description": "",
88307
- "line": 35,
87735
+ "line": 44,
88308
87736
  "rawdescription": "\n",
88309
87737
  "modifierKind": [
88310
87738
  148
@@ -88312,30 +87740,7 @@
88312
87740
  "required": false
88313
87741
  }
88314
87742
  ],
88315
- "propertiesClass": [
88316
- {
88317
- "name": "role",
88318
- "coverageIgnore": false,
88319
- "defaultValue": "'listitem'",
88320
- "deprecated": false,
88321
- "deprecationMessage": "",
88322
- "type": "string",
88323
- "indexKey": "",
88324
- "optional": false,
88325
- "description": "",
88326
- "line": 18,
88327
- "rawdescription": "\n",
88328
- "decorators": [
88329
- {
88330
- "name": "HostBinding",
88331
- "stringifiedArguments": "'attr.role'"
88332
- }
88333
- ],
88334
- "modifierKind": [
88335
- 171
88336
- ]
88337
- }
88338
- ],
87743
+ "propertiesClass": [],
88339
87744
  "methodsClass": [
88340
87745
  {
88341
87746
  "name": "onItemClick",
@@ -88353,7 +87758,7 @@
88353
87758
  "optional": false,
88354
87759
  "returnType": "void",
88355
87760
  "typeParameters": [],
88356
- "line": 37,
87761
+ "line": 46,
88357
87762
  "deprecated": false,
88358
87763
  "deprecationMessage": "",
88359
87764
  "rawdescription": "\n",
@@ -88414,33 +87819,7 @@
88414
87819
  "coverageIgnore": false,
88415
87820
  "deprecated": false,
88416
87821
  "deprecationMessage": "",
88417
- "hostBindings": [
88418
- {
88419
- "coverageIgnore": false,
88420
- "name": "attr.role",
88421
- "actualName": "role",
88422
- "defaultValue": "'listitem'",
88423
- "deprecated": false,
88424
- "deprecationMessage": "",
88425
- "rawdescription": "\n",
88426
- "description": "",
88427
- "line": 18,
88428
- "type": "string",
88429
- "decorators": []
88430
- },
88431
- {
88432
- "coverageIgnore": false,
88433
- "name": "class",
88434
- "actualName": "cssClasses",
88435
- "deprecated": false,
88436
- "deprecationMessage": "",
88437
- "rawdescription": "\n",
88438
- "description": "",
88439
- "line": 31,
88440
- "type": "string",
88441
- "decorators": []
88442
- }
88443
- ],
87822
+ "hostBindings": [],
88444
87823
  "hostListeners": [],
88445
87824
  "standalone": false,
88446
87825
  "imports": [
@@ -88463,7 +87842,7 @@
88463
87842
  "description": "",
88464
87843
  "rawdescription": "\n",
88465
87844
  "type": "component",
88466
- "sourceCode": "import { booleanAttribute, Component, HostBinding, input, output } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EclBaseEvent } from '@eui/ecl/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\nimport { RouterLink, RouterLinkWithHref } from '@angular/router';\n\nexport class EclSocialMediaFollowItemClickEvent extends EclBaseEvent {}\n\n@Component({\n selector: 'ecl-social-media-follow-item',\n templateUrl: './ecl-social-media-follow-item.component.html',\n imports: [...EUI_ECL_ICON, ...EUI_ECL_LINK, NgTemplateOutlet, RouterLink, RouterLinkWithHref],\n})\nexport class EclSocialMediaFollowItemComponent extends ECLBaseDirective {\n readonly isInverted = input<false, unknown>(undefined, { transform: (booleanAttribute) as any });\n @HostBinding('attr.role') role = 'listitem';\n icon = input<string>();\n iconSet = input<string>('social-media');\n readonly href = input('');\n readonly routerLink = input('');\n readonly target = input<string>(undefined);\n readonly size = input('m');\n readonly extraAttributes = input<{\n name: string;\n value?: string | null;\n }[]>(undefined);\n\n @HostBinding('class')\n get cssClasses(): string {\n return [super.getCssClasses('ecl-social-media-follow__item')].join(' ').trim();\n }\n\n readonly itemClick = output<EclSocialMediaFollowItemClickEvent>();\n\n onItemClick(evt): void {\n this.itemClick.emit(new EclSocialMediaFollowItemClickEvent());\n if (!this.href() && !this.routerLink()) {\n evt.preventDefault();\n }\n }\n}\n",
87845
+ "sourceCode": "import { booleanAttribute, Component, inject, input, output } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { EUI_ECL_ICON } from '@eui/ecl/components/ecl-icon';\nimport { EclBaseEvent } from '@eui/ecl/core';\nimport { ECLBaseDirective } from '@eui/ecl/core';\nimport { EUI_ECL_LINK } from '@eui/ecl/components/ecl-link';\nimport { RouterLink, RouterLinkWithHref } from '@angular/router';\nimport { EclSocialMediaFollowComponent } from './ecl-social-media-follow.component';\n\nexport class EclSocialMediaFollowItemClickEvent extends EclBaseEvent {}\n\n@Component({\n selector: 'ecl-social-media-follow-item',\n templateUrl: './ecl-social-media-follow-item.component.html',\n imports: [...EUI_ECL_ICON, ...EUI_ECL_LINK, NgTemplateOutlet, RouterLink, RouterLinkWithHref],\n host: {\n 'role': 'listitem',\n '[class]': 'cssClasses',\n },\n})\nexport class EclSocialMediaFollowItemComponent extends ECLBaseDirective {\n readonly isInverted = input<false, unknown>(undefined, { transform: (booleanAttribute) as any });\n icon = input<string>();\n iconSet = input<string>('social-media');\n readonly href = input('');\n readonly routerLink = input('');\n readonly target = input<string>(undefined);\n readonly size = input('m');\n readonly extraAttributes = input<{\n name: string;\n value?: string | null;\n }[]>(undefined);\n\n private parent = inject(EclSocialMediaFollowComponent);\n\n get isIconOnly(): boolean {\n return this.parent?.isIconOnly() ?? false;\n }\n\n get cssClasses(): string {\n return [super.getCssClasses('ecl-social-media-follow__item')].join(' ').trim();\n }\n\n readonly itemClick = output<EclSocialMediaFollowItemClickEvent>();\n\n onItemClick(evt): void {\n this.itemClick.emit(new EclSocialMediaFollowItemClickEvent());\n if (!this.href() && !this.routerLink()) {\n evt.preventDefault();\n }\n }\n}\n",
88467
87846
  "assetsDirs": [],
88468
87847
  "styleUrlsData": "",
88469
87848
  "stylesData": "",
@@ -88471,13 +87850,24 @@
88471
87850
  "ECLBaseDirective"
88472
87851
  ],
88473
87852
  "accessors": {
87853
+ "isIconOnly": {
87854
+ "name": "isIconOnly",
87855
+ "getSignature": {
87856
+ "name": "isIconOnly",
87857
+ "type": "boolean",
87858
+ "returnType": "boolean",
87859
+ "line": 36,
87860
+ "rawdescription": "\n",
87861
+ "description": ""
87862
+ }
87863
+ },
88474
87864
  "cssClasses": {
88475
87865
  "name": "cssClasses",
88476
87866
  "getSignature": {
88477
87867
  "name": "cssClasses",
88478
87868
  "type": "string",
88479
87869
  "returnType": "string",
88480
- "line": 31,
87870
+ "line": 40,
88481
87871
  "rawdescription": "\n",
88482
87872
  "description": ""
88483
87873
  }
@@ -88512,7 +87902,7 @@
88512
87902
  }
88513
87903
  ]
88514
87904
  },
88515
- "templateData": "@if(href()) {\n<a eclLink (click)=\"onItemClick($event)\" variant=\"standalone\" [href]=\"href()\" [attr.target]=\"target()\"\n class=\"ecl-social-media-follow__link\" [isInverted]=\"isInverted()\" [extraAttributes]=\"extraAttributes()\">\n @if(icon()) {\n <ecl-icon [iconSet]=\"iconSet()\" icon=\"{{ icon() }}\" [size]=\"size()\" class=\"ecl-social-media-follow__icon\"> </ecl-icon>\n }\n <span eclLinkLabel>\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n </span>\n</a>\n}\n\n@if(!href() && routerLink()) {\n<a eclLink (click)=\"onItemClick($event)\" variant=\"standalone\" [routerLink]=\"routerLink()\" [attr.target]=\"target()\"\n class=\"ecl-social-media-follow__link\" [isInverted]=\"isInverted()\" [extraAttributes]=\"extraAttributes()\">\n @if(icon()) {\n <ecl-icon [iconSet]=\"iconSet()\" icon=\"{{ icon() }}\" [size]=\"size()\" class=\"ecl-social-media-follow__icon\"> </ecl-icon>\n }\n <span eclLinkLabel>\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n </span>\n</a>\n}\n\n@if(!href() && !routerLink()) {\n<ng-container *ngTemplateOutlet=\"content\"></ng-container>\n}\n\n<ng-template #content>\n <ng-content></ng-content>\n</ng-template>\n"
87905
+ "templateData": "@if(href()) {\n<a eclLink (click)=\"onItemClick($event)\" variant=\"standalone\" [href]=\"href()\" [attr.target]=\"target()\"\n class=\"ecl-social-media-follow__link\" [isInverted]=\"isInverted()\" [isIconOnly]=\"isIconOnly\" [extraAttributes]=\"extraAttributes()\">\n @if(icon()) {\n <ecl-icon [iconSet]=\"iconSet()\" icon=\"{{ icon() }}\" [size]=\"size()\" class=\"ecl-social-media-follow__icon\"> </ecl-icon>\n }\n <span eclLinkLabel>\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n </span>\n</a>\n}\n\n@if(!href() && routerLink()) {\n<a eclLink (click)=\"onItemClick($event)\" variant=\"standalone\" [routerLink]=\"routerLink()\" [attr.target]=\"target()\"\n class=\"ecl-social-media-follow__link\" [isInverted]=\"isInverted()\" [isIconOnly]=\"isIconOnly\" [extraAttributes]=\"extraAttributes()\">\n @if(icon()) {\n <ecl-icon [iconSet]=\"iconSet()\" icon=\"{{ icon() }}\" [size]=\"size()\" class=\"ecl-social-media-follow__icon\"> </ecl-icon>\n }\n <span eclLinkLabel>\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n </span>\n</a>\n}\n\n@if(!href() && !routerLink()) {\n<ng-container *ngTemplateOutlet=\"content\"></ng-container>\n}\n\n<ng-template #content>\n <ng-content></ng-content>\n</ng-template>\n"
88516
87906
  },
88517
87907
  {
88518
87908
  "name": "EclSplashPageComponent",
@@ -95634,6 +95024,45 @@
95634
95024
  ],
95635
95025
  "miscellaneous": {
95636
95026
  "variables": [
95027
+ {
95028
+ "name": "ARROW_SIZE",
95029
+ "ctype": "miscellaneous",
95030
+ "subtype": "variable",
95031
+ "file": "packages/ecl/components/ecl-site-header/language/ecl-site-header-language.component.ts",
95032
+ "coverageIgnore": false,
95033
+ "deprecated": false,
95034
+ "deprecationMessage": "",
95035
+ "type": "string",
95036
+ "defaultValue": "'0.5rem'",
95037
+ "rawdescription": "Half the arrow's own width, matching ECL's `arrowSize`.",
95038
+ "description": "<p>Half the arrow&#39;s own width, matching ECL&#39;s <code>arrowSize</code>.</p>\n"
95039
+ },
95040
+ {
95041
+ "name": "ARROW_SIZE",
95042
+ "ctype": "miscellaneous",
95043
+ "subtype": "variable",
95044
+ "file": "packages/ecl/components/ecl-site-header/login/ecl-site-header-login.component.ts",
95045
+ "coverageIgnore": false,
95046
+ "deprecated": false,
95047
+ "deprecationMessage": "",
95048
+ "type": "string",
95049
+ "defaultValue": "'0.5rem'",
95050
+ "rawdescription": "Half the arrow's own width, matching ECL's `arrowSize`.",
95051
+ "description": "<p>Half the arrow&#39;s own width, matching ECL&#39;s <code>arrowSize</code>.</p>\n"
95052
+ },
95053
+ {
95054
+ "name": "ARROW_SIZE",
95055
+ "ctype": "miscellaneous",
95056
+ "subtype": "variable",
95057
+ "file": "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts",
95058
+ "coverageIgnore": false,
95059
+ "deprecated": false,
95060
+ "deprecationMessage": "",
95061
+ "type": "string",
95062
+ "defaultValue": "'0.5rem'",
95063
+ "rawdescription": "Half the arrow's own width, matching ECL's `arrowSize`.",
95064
+ "description": "<p>Half the arrow&#39;s own width, matching ECL&#39;s <code>arrowSize</code>.</p>\n"
95065
+ },
95637
95066
  {
95638
95067
  "name": "AVAILABLE_NON_EU_LOGO_COUNTRY_CODES",
95639
95068
  "ctype": "miscellaneous",
@@ -96577,6 +96006,32 @@
96577
96006
  "type": "unknown",
96578
96007
  "defaultValue": "(): void => {\n /** empty*/\n}"
96579
96008
  },
96009
+ {
96010
+ "name": "RESIZE_DEBOUNCE",
96011
+ "ctype": "miscellaneous",
96012
+ "subtype": "variable",
96013
+ "file": "packages/ecl/components/ecl-site-header/login/ecl-site-header-login.component.ts",
96014
+ "coverageIgnore": false,
96015
+ "deprecated": false,
96016
+ "deprecationMessage": "",
96017
+ "type": "number",
96018
+ "defaultValue": "200",
96019
+ "rawdescription": "Debounce for the resize recomputation, matching ECL's `handleResize`.",
96020
+ "description": "<p>Debounce for the resize recomputation, matching ECL&#39;s <code>handleResize</code>.</p>\n"
96021
+ },
96022
+ {
96023
+ "name": "RESIZE_DEBOUNCE",
96024
+ "ctype": "miscellaneous",
96025
+ "subtype": "variable",
96026
+ "file": "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts",
96027
+ "coverageIgnore": false,
96028
+ "deprecated": false,
96029
+ "deprecationMessage": "",
96030
+ "type": "number",
96031
+ "defaultValue": "200",
96032
+ "rawdescription": "Debounce for the resize recomputation, matching ECL's `handleResize`.",
96033
+ "description": "<p>Debounce for the resize recomputation, matching ECL&#39;s <code>handleResize</code>.</p>\n"
96034
+ },
96580
96035
  {
96581
96036
  "name": "testBed",
96582
96037
  "ctype": "miscellaneous",
@@ -97043,6 +96498,99 @@
97043
96498
  }
97044
96499
  ],
97045
96500
  "groupedVariables": {
96501
+ "packages/ecl/components/ecl-site-header/language/ecl-site-header-language.component.ts": [
96502
+ {
96503
+ "name": "ARROW_SIZE",
96504
+ "ctype": "miscellaneous",
96505
+ "subtype": "variable",
96506
+ "file": "packages/ecl/components/ecl-site-header/language/ecl-site-header-language.component.ts",
96507
+ "coverageIgnore": false,
96508
+ "deprecated": false,
96509
+ "deprecationMessage": "",
96510
+ "type": "string",
96511
+ "defaultValue": "'0.5rem'",
96512
+ "rawdescription": "Half the arrow's own width, matching ECL's `arrowSize`.",
96513
+ "description": "<p>Half the arrow&#39;s own width, matching ECL&#39;s <code>arrowSize</code>.</p>\n"
96514
+ }
96515
+ ],
96516
+ "packages/ecl/components/ecl-site-header/login/ecl-site-header-login.component.ts": [
96517
+ {
96518
+ "name": "ARROW_SIZE",
96519
+ "ctype": "miscellaneous",
96520
+ "subtype": "variable",
96521
+ "file": "packages/ecl/components/ecl-site-header/login/ecl-site-header-login.component.ts",
96522
+ "coverageIgnore": false,
96523
+ "deprecated": false,
96524
+ "deprecationMessage": "",
96525
+ "type": "string",
96526
+ "defaultValue": "'0.5rem'",
96527
+ "rawdescription": "Half the arrow's own width, matching ECL's `arrowSize`.",
96528
+ "description": "<p>Half the arrow&#39;s own width, matching ECL&#39;s <code>arrowSize</code>.</p>\n"
96529
+ },
96530
+ {
96531
+ "name": "RESIZE_DEBOUNCE",
96532
+ "ctype": "miscellaneous",
96533
+ "subtype": "variable",
96534
+ "file": "packages/ecl/components/ecl-site-header/login/ecl-site-header-login.component.ts",
96535
+ "coverageIgnore": false,
96536
+ "deprecated": false,
96537
+ "deprecationMessage": "",
96538
+ "type": "number",
96539
+ "defaultValue": "200",
96540
+ "rawdescription": "Debounce for the resize recomputation, matching ECL's `handleResize`.",
96541
+ "description": "<p>Debounce for the resize recomputation, matching ECL&#39;s <code>handleResize</code>.</p>\n"
96542
+ }
96543
+ ],
96544
+ "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts": [
96545
+ {
96546
+ "name": "ARROW_SIZE",
96547
+ "ctype": "miscellaneous",
96548
+ "subtype": "variable",
96549
+ "file": "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts",
96550
+ "coverageIgnore": false,
96551
+ "deprecated": false,
96552
+ "deprecationMessage": "",
96553
+ "type": "string",
96554
+ "defaultValue": "'0.5rem'",
96555
+ "rawdescription": "Half the arrow's own width, matching ECL's `arrowSize`.",
96556
+ "description": "<p>Half the arrow&#39;s own width, matching ECL&#39;s <code>arrowSize</code>.</p>\n"
96557
+ },
96558
+ {
96559
+ "name": "ECL_SITE_HEADER_SEARCH_VALUE_ACCESSOR",
96560
+ "ctype": "miscellaneous",
96561
+ "subtype": "variable",
96562
+ "file": "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts",
96563
+ "coverageIgnore": false,
96564
+ "deprecated": false,
96565
+ "deprecationMessage": "",
96566
+ "type": "Provider",
96567
+ "defaultValue": "{\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => EclSiteHeaderSearchComponent),\n multi: true,\n}"
96568
+ },
96569
+ {
96570
+ "name": "noop",
96571
+ "ctype": "miscellaneous",
96572
+ "subtype": "variable",
96573
+ "file": "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts",
96574
+ "coverageIgnore": false,
96575
+ "deprecated": false,
96576
+ "deprecationMessage": "",
96577
+ "type": "unknown",
96578
+ "defaultValue": "(): void => {\n /** empty*/\n}"
96579
+ },
96580
+ {
96581
+ "name": "RESIZE_DEBOUNCE",
96582
+ "ctype": "miscellaneous",
96583
+ "subtype": "variable",
96584
+ "file": "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts",
96585
+ "coverageIgnore": false,
96586
+ "deprecated": false,
96587
+ "deprecationMessage": "",
96588
+ "type": "number",
96589
+ "defaultValue": "200",
96590
+ "rawdescription": "Debounce for the resize recomputation, matching ECL's `handleResize`.",
96591
+ "description": "<p>Debounce for the resize recomputation, matching ECL&#39;s <code>handleResize</code>.</p>\n"
96592
+ }
96593
+ ],
97046
96594
  "packages/ecl/core/utils/constants/constants.ts": [
97047
96595
  {
97048
96596
  "name": "AVAILABLE_NON_EU_LOGO_COUNTRY_CODES",
@@ -97128,30 +96676,6 @@
97128
96676
  "defaultValue": "(): void => {\n /** empty*/\n}"
97129
96677
  }
97130
96678
  ],
97131
- "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts": [
97132
- {
97133
- "name": "ECL_SITE_HEADER_SEARCH_VALUE_ACCESSOR",
97134
- "ctype": "miscellaneous",
97135
- "subtype": "variable",
97136
- "file": "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts",
97137
- "coverageIgnore": false,
97138
- "deprecated": false,
97139
- "deprecationMessage": "",
97140
- "type": "Provider",
97141
- "defaultValue": "{\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => EclSiteHeaderSearchComponent),\n multi: true,\n}"
97142
- },
97143
- {
97144
- "name": "noop",
97145
- "ctype": "miscellaneous",
97146
- "subtype": "variable",
97147
- "file": "packages/ecl/components/ecl-site-header/search/ecl-site-header-search.component.ts",
97148
- "coverageIgnore": false,
97149
- "deprecated": false,
97150
- "deprecationMessage": "",
97151
- "type": "unknown",
97152
- "defaultValue": "(): void => {\n /** empty*/\n}"
97153
- }
97154
- ],
97155
96679
  "packages/ecl/components/ecl-accordion/index.ts": [
97156
96680
  {
97157
96681
  "name": "EUI_ECL_ACCORDION",