UNPKG

@favian/headwind-ui

Version:

Headless UI for Angular - Styleless Angular components to integrate with Tailwind CSS

1 lines 157 kB
{"version":3,"file":"favian-headwind-ui.mjs","sources":["../../../projects/headwind-ui/src/components/headwind-accordion/headwind-accordion-content/headwind-accordion-content.directive.ts","../../../projects/headwind-ui/src/components/headwind-accordion/service/headwind-accordion.service.ts","../../../projects/headwind-ui/src/components/headwind-accordion/headwind-accordion.component.ts","../../../projects/headwind-ui/src/components/headwind-accordion/headwind-accordion.component.html","../../../projects/headwind-ui/src/components/headwind-accordion/headwind-accordion-button/headwind-accordion-button.component.ts","../../../projects/headwind-ui/src/components/headwind-accordion/headwind-accordion-button/headwind-accordion-button.component.html","../../../projects/headwind-ui/src/abstracts/headwind-control-value-accessor.ts","../../../projects/headwind-ui/src/constants/headwind-errors.ts","../../../projects/headwind-ui/src/services/headwind-platform.service.ts","../../../projects/headwind-ui/src/services/headwind-click-detector.service.ts","../../../projects/headwind-ui/src/components/headwind-checkbox/service/headwind-checkbox.service.ts","../../../projects/headwind-ui/src/components/headwind-checkbox/headwind-checkbox.component.ts","../../../projects/headwind-ui/src/components/headwind-checkbox/headwind-checkbox.component.html","../../../projects/headwind-ui/src/components/headwind-checkbox/headwind-checkbox-button/headwind-checkbox-checked/headwind-checkbox-checked.directive.ts","../../../projects/headwind-ui/src/components/headwind-checkbox/headwind-checkbox-button/headwind-checkbox-button.component.ts","../../../projects/headwind-ui/src/components/headwind-checkbox/headwind-checkbox-button/headwind-checkbox-button.component.html","../../../projects/headwind-ui/src/components/headwind-popover/services/headwind-popover.service.ts","../../../projects/headwind-ui/src/services/headwind-window.service.ts","../../../projects/headwind-ui/src/components/headwind-popover/headwind-popover-overlay/headwind-popover-overlay.component.ts","../../../projects/headwind-ui/src/components/headwind-popover/headwind-popover-overlay/headwind-popover-overlay.component.html","../../../projects/headwind-ui/src/components/headwind-popover/headwind-popover-overlay/headwind-popover-overlay.directive.ts","../../../projects/headwind-ui/src/components/headwind-popover/headwind-popover-button/headwind-popover-button.directive.ts","../../../projects/headwind-ui/src/components/headwind-overlay-outlet/headwind-overlay-outlet.component.ts","../../../projects/headwind-ui/src/components/headwind-overlay-outlet/headwind-overlay-outlet.component.html","../../../projects/headwind-ui/src/services/headwind-overlay.service.ts","../../../projects/headwind-ui/src/services/headwind-animator.ts","../../../projects/headwind-ui/src/components/headwind-popover/headwind-popover.component.ts","../../../projects/headwind-ui/src/components/headwind-popover/headwind-popover.component.html","../../../projects/headwind-ui/src/components/headwind-radio-group/headwind-radio/headwind-radio-button/headwind-radio-selected/headwind-radio-selected.directive.ts","../../../projects/headwind-ui/src/components/headwind-radio-group/headwind-radio/headwind-radio-button/headwind-radio-button.component.ts","../../../projects/headwind-ui/src/components/headwind-radio-group/headwind-radio/headwind-radio-button/headwind-radio-button.component.html","../../../projects/headwind-ui/src/components/headwind-radio-group/service/headwind-radio-group.service.ts","../../../projects/headwind-ui/src/components/headwind-radio-group/headwind-radio/headwind-radio.component.ts","../../../projects/headwind-ui/src/components/headwind-radio-group/headwind-radio/headwind-radio.component.html","../../../projects/headwind-ui/src/services/headwind-query-list.service.ts","../../../projects/headwind-ui/src/components/headwind-radio-group/headwind-radio-group.component.ts","../../../projects/headwind-ui/src/components/headwind-radio-group/headwind-radio-group.component.html","../../../projects/headwind-ui/src/components/headwind-select/service/headwind-select.service.ts","../../../projects/headwind-ui/src/components/headwind-select/headwind-options-overlay/headwind-options-overlay.directive.ts","../../../projects/headwind-ui/src/components/headwind-select/headwind-options-overlay/headwind-option/headwind-option.component.ts","../../../projects/headwind-ui/src/components/headwind-select/headwind-options-overlay/headwind-option/headwind-option.component.html","../../../projects/headwind-ui/src/components/headwind-select/headwind-options-overlay/headwind-options-overlay.component.ts","../../../projects/headwind-ui/src/components/headwind-select/headwind-options-overlay/headwind-options-overlay.component.html","../../../projects/headwind-ui/src/components/headwind-select/headwind-select.component.ts","../../../projects/headwind-ui/src/components/headwind-select/headwind-select.component.html","../../../projects/headwind-ui/src/components/headwind-switch/service/headwind-switch.service.ts","../../../projects/headwind-ui/src/components/headwind-switch/headwind-switch.component.ts","../../../projects/headwind-ui/src/components/headwind-switch/headwind-switch.component.html","../../../projects/headwind-ui/src/components/headwind-switch/headwind-switch-track/headwind-switch-track.component.ts","../../../projects/headwind-ui/src/components/headwind-switch/headwind-switch-track/headwind-switch-track.component.html","../../../projects/headwind-ui/src/components/headwind-switch/headwind-switch-track/headwind-switch-thumb/headwind-switch-thumb.component.ts","../../../projects/headwind-ui/src/components/headwind-switch/headwind-switch-track/headwind-switch-thumb/headwind-switch-thumb.component.html","../../../projects/headwind-ui/src/components/headwind-tab-group/service/headwind-tab-group.service.ts","../../../projects/headwind-ui/src/components/headwind-tab-group/headwind-tab-group.component.ts","../../../projects/headwind-ui/src/components/headwind-tab-group/headwind-tab-group.component.html","../../../projects/headwind-ui/src/components/headwind-tab-group/headwind-tab-button-group/headwind-tab-button-group.component.ts","../../../projects/headwind-ui/src/components/headwind-tab-group/headwind-tab-button-group/headwind-tab-button-group.component.html","../../../projects/headwind-ui/src/components/headwind-tab-group/headwind-tab-content-group/headwind-tab-content/headwind-tab-content.directive.ts","../../../projects/headwind-ui/src/components/headwind-tab-group/headwind-tab-content-group/headwind-tab-content-group.component.ts","../../../projects/headwind-ui/src/components/headwind-tab-group/headwind-tab-content-group/headwind-tab-content-group.component.html","../../../projects/headwind-ui/src/components/headwind-tab-group/headwind-tab-button-group/headwind-tab-button/headwind-tab-button.component.ts","../../../projects/headwind-ui/src/components/headwind-tab-group/headwind-tab-button-group/headwind-tab-button/headwind-tab-button.component.html","../../../projects/headwind-ui/src/public-api.ts","../../../projects/headwind-ui/src/favian-headwind-ui.ts"],"sourcesContent":["import { Directive, TemplateRef } from '@angular/core';\r\n\r\n@Directive({\r\n selector: 'ng-template[headwindAccordionContent]',\r\n standalone: true,\r\n})\r\nexport class HeadwindAccordionContentDirective {\r\n constructor(public readonly templateRef: TemplateRef<any>) {}\r\n}\r\n","import { EventEmitter, Injectable } from '@angular/core';\r\nimport { BehaviorSubject } from 'rxjs';\r\n\r\n@Injectable()\r\nexport class HeadwindAccordionService {\r\n /** Emits to toggle opened status */\r\n toggleOpened = new EventEmitter<void>();\r\n\r\n opened$ = new BehaviorSubject(false);\r\n\r\n get opened(): boolean {\r\n return this.opened$.value;\r\n }\r\n\r\n set opened(value: boolean) {\r\n this.opened$.next(value);\r\n }\r\n}\r\n","import {\r\n AfterViewInit,\r\n Component,\r\n ContentChild,\r\n EmbeddedViewRef,\r\n EventEmitter,\r\n Input,\r\n OnDestroy,\r\n Output,\r\n ViewChild,\r\n ViewContainerRef,\r\n} from '@angular/core';\r\nimport { HeadwindAccordionContentDirective } from './headwind-accordion-content/headwind-accordion-content.directive';\r\nimport { HeadwindAccordionService } from './service/headwind-accordion.service';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\n\r\n@Component({\r\n selector: 'headwind-accordion',\r\n standalone: true,\r\n imports: [],\r\n templateUrl: './headwind-accordion.component.html',\r\n styleUrl: './headwind-accordion.component.scss',\r\n providers: [HeadwindAccordionService],\r\n host: {\r\n class: 'headwind-accordion',\r\n ['[class.headwind-opened]']: 'opened',\r\n },\r\n})\r\nexport class HeadwindAccordionComponent implements AfterViewInit, OnDestroy {\r\n @Output() openedChange = new EventEmitter<boolean>();\r\n @ViewChild('accordionContentContainer', { read: ViewContainerRef }) accordionContentContainer?: ViewContainerRef;\r\n @ContentChild(HeadwindAccordionContentDirective, { descendants: true })\r\n accordionContent?: HeadwindAccordionContentDirective;\r\n\r\n private _contentEmbeddedViewRef?: EmbeddedViewRef<any>;\r\n private _openTimeoutId?: any;\r\n\r\n constructor(private readonly _headwindAccordionService: HeadwindAccordionService) {\r\n this._headwindAccordionService.toggleOpened.pipe(takeUntilDestroyed()).subscribe(() => {\r\n const opened = !this.opened;\r\n\r\n this.opened = opened; // to toggle content\r\n this.openedChange.emit(opened);\r\n });\r\n }\r\n\r\n get opened(): boolean {\r\n return this._headwindAccordionService.opened;\r\n }\r\n\r\n @Input()\r\n set opened(value: boolean) {\r\n this._headwindAccordionService.opened = value;\r\n\r\n if (value) {\r\n this.open();\r\n } else {\r\n this.close();\r\n }\r\n }\r\n\r\n ngAfterViewInit() {\r\n // use timeout to prevent NG0100 error\r\n this._openTimeoutId = setTimeout(() => {\r\n if (this.opened) {\r\n this.open();\r\n }\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n clearTimeout(this._openTimeoutId);\r\n }\r\n\r\n toggle(): void {\r\n if (this.opened) {\r\n this.close();\r\n } else {\r\n this.open();\r\n }\r\n }\r\n\r\n open(): void {\r\n if (this.accordionContentContainer && this.accordionContent && !this._contentEmbeddedViewRef) {\r\n this._contentEmbeddedViewRef = this.accordionContentContainer.createEmbeddedView(\r\n this.accordionContent.templateRef,\r\n );\r\n }\r\n\r\n this.openedChange.emit(true);\r\n this._headwindAccordionService.opened = true;\r\n }\r\n\r\n close(): void {\r\n this._contentEmbeddedViewRef?.destroy();\r\n\r\n delete this._contentEmbeddedViewRef;\r\n\r\n this.openedChange.emit(false);\r\n this._headwindAccordionService.opened = false;\r\n }\r\n}\r\n","<ng-content></ng-content>\r\n\r\n<ng-container #accordionContentContainer></ng-container>\r\n","import { Component, HostListener } from '@angular/core';\r\nimport { HeadwindAccordionService } from '../service/headwind-accordion.service';\r\n\r\n@Component({\r\n selector: 'headwind-accordion-button',\r\n standalone: true,\r\n imports: [],\r\n templateUrl: './headwind-accordion-button.component.html',\r\n styleUrl: './headwind-accordion-button.component.scss',\r\n host: {\r\n tabindex: '0',\r\n role: 'button',\r\n class: 'headwind-accordion-button',\r\n ['[attr.aria-expanded]']: 'opened',\r\n },\r\n})\r\nexport class HeadwindAccordionButtonComponent {\r\n constructor(private readonly _headwindAccordionService: HeadwindAccordionService) {}\r\n\r\n get opened(): boolean {\r\n return this._headwindAccordionService.opened;\r\n }\r\n\r\n @HostListener('click')\r\n onHostClick(): void {\r\n this._headwindAccordionService.toggleOpened.emit();\r\n }\r\n\r\n @HostListener('keydown.space', ['$event'])\r\n onHostSpaceKeydown(event: Event): void {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n this._headwindAccordionService.toggleOpened.emit();\r\n }\r\n\r\n @HostListener('keydown.enter', ['$event'])\r\n onHostEnterKeydown(event: Event): void {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n this._headwindAccordionService.toggleOpened.emit();\r\n }\r\n}\r\n","<ng-content></ng-content>\r\n","import { ControlValueAccessor, NgControl } from '@angular/forms';\r\nimport { ElementRef, inject, Renderer2 } from '@angular/core';\r\n\r\nexport abstract class HeadwindControlValueAccessor implements ControlValueAccessor {\r\n isDisabled = false;\r\n\r\n private readonly _internalNgControl: NgControl | null;\r\n private readonly _internalRenderer: Renderer2;\r\n private readonly _internalElementRef: ElementRef<HTMLElement>;\r\n\r\n protected constructor() {\r\n this._internalNgControl = inject(NgControl, { optional: true });\r\n this._internalRenderer = inject(Renderer2);\r\n this._internalElementRef = inject(ElementRef);\r\n\r\n if (this._internalNgControl) {\r\n this._internalNgControl.valueAccessor = this;\r\n }\r\n }\r\n\r\n onChange = (value: any) => {};\r\n\r\n onTouched = () => {};\r\n\r\n abstract writeValue(obj: any): void;\r\n\r\n registerOnChange(fn = (value: any) => {}): void {\r\n this.onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn = () => {}): void {\r\n this.onTouched = fn;\r\n }\r\n\r\n setDisabledState(isDisabled: boolean): void {\r\n this.isDisabled = isDisabled;\r\n\r\n if (isDisabled) {\r\n this._setAttribute('disabled');\r\n } else {\r\n this._removeAttribute('disabled');\r\n }\r\n }\r\n\r\n updateValue(value: any): void {\r\n this.onChange(value);\r\n this.writeValue(value);\r\n }\r\n\r\n private _setAttribute(name: string): void {\r\n this._internalRenderer.setAttribute(this._internalElementRef.nativeElement, name, '');\r\n }\r\n\r\n private _removeAttribute(name: string): void {\r\n this._internalRenderer.removeAttribute(this._internalElementRef.nativeElement, name);\r\n }\r\n}\r\n","export const HeadwindErrors = {\r\n headwindError0001:\r\n '[HEADWIND_E0001] HeadwindOptionsOverlayDirective should be bound to HeadwindOptionsOverlayComponent to open options of HeadwindSelectComponent',\r\n headwindError0002:\r\n '[HEADWIND_E0002] HeadwindOptionsOverlayComponent is required in HeadwindSelectComponent to open options',\r\n headwindError0003:\r\n '[HEADWIND_E0003] HeadwindPopoverOverlayDirective should be bound to HeadwindPopoverOverlayComponent to open popover of HeadwindPopoverComponent',\r\n headwindError0004:\r\n '[HEADWIND_E0004] HeadwindPopoverOverlayComponent is required in HeadwindPopoverComponent to open popover',\r\n} as const;\r\n","import { Inject, Injectable, PLATFORM_ID } from '@angular/core';\r\nimport { isPlatformBrowser } from '@angular/common';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class HeadwindPlatformService {\r\n constructor(@Inject(PLATFORM_ID) private readonly _platformId: Object) {}\r\n\r\n get isBrowser(): boolean {\r\n return isPlatformBrowser(this._platformId);\r\n }\r\n}\r\n","import { EventEmitter, Injectable, OnDestroy } from '@angular/core';\r\nimport { HeadwindErrors } from '../constants/headwind-errors';\r\nimport { HeadwindPlatformService } from './headwind-platform.service';\r\n\r\n@Injectable()\r\nexport class HeadwindClickDetector implements OnDestroy {\r\n outsideClick = new EventEmitter<void>();\r\n insideClick = new EventEmitter<void>();\r\n\r\n private _container?: Node;\r\n private _mouseDownDetectedFromOutside = false;\r\n private _mouseDownDetectedFromInside = false;\r\n\r\n constructor(private readonly _headwindPlatformService: HeadwindPlatformService) {}\r\n\r\n ngOnDestroy() {\r\n this.unregister();\r\n }\r\n\r\n register(container: Node): void {\r\n this._container = container;\r\n\r\n this._removeEventListeners();\r\n this._addEventListeners();\r\n }\r\n\r\n unregister(): void {\r\n delete this._container;\r\n\r\n this._removeEventListeners();\r\n }\r\n\r\n private _addEventListeners(): void {\r\n if (this._headwindPlatformService.isBrowser) {\r\n window.addEventListener('mousedown', this._windowMousedownListener);\r\n window.addEventListener('mouseup', this._windowMouseupListener);\r\n }\r\n }\r\n\r\n private _removeEventListeners(): void {\r\n if (this._headwindPlatformService.isBrowser) {\r\n window.removeEventListener('mousedown', this._windowMousedownListener);\r\n window.removeEventListener('mouseup', this._windowMouseupListener);\r\n }\r\n }\r\n\r\n private _windowMousedownListener = (event: Event) => {\r\n if (!this._container) {\r\n console.error(HeadwindErrors.headwindError0003);\r\n return;\r\n }\r\n\r\n this._mouseDownDetectedFromOutside = event.target instanceof Node && !this._container.contains(event.target);\r\n this._mouseDownDetectedFromInside = event.target instanceof Node && this._container.contains(event.target);\r\n };\r\n\r\n private _windowMouseupListener = (event: Event) => {\r\n if (!this._container) {\r\n console.error(HeadwindErrors.headwindError0003);\r\n return;\r\n }\r\n\r\n if (this._mouseDownDetectedFromOutside && event.target instanceof Node && !this._container.contains(event.target)) {\r\n this.outsideClick.emit();\r\n }\r\n\r\n if (this._mouseDownDetectedFromInside && event.target instanceof Node && this._container.contains(event.target)) {\r\n this.insideClick.emit();\r\n }\r\n };\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { BehaviorSubject } from 'rxjs';\r\n\r\n@Injectable()\r\nexport class HeadwindCheckboxService {\r\n checked$ = new BehaviorSubject(false);\r\n\r\n get checked(): boolean {\r\n return this.checked$.value;\r\n }\r\n\r\n set checked(value: boolean) {\r\n this.checked$.next(value);\r\n }\r\n}\r\n","import { booleanAttribute, Component, EventEmitter, HostListener, Input, Output } from '@angular/core';\r\nimport { HeadwindControlValueAccessor } from '../../abstracts/headwind-control-value-accessor';\r\nimport { HeadwindClickDetector } from '../../services/headwind-click-detector.service';\r\nimport { HeadwindCheckboxService } from './service/headwind-checkbox.service';\r\n\r\n@Component({\r\n selector: 'headwind-checkbox',\r\n standalone: true,\r\n imports: [],\r\n templateUrl: './headwind-checkbox.component.html',\r\n styleUrl: './headwind-checkbox.component.scss',\r\n providers: [HeadwindClickDetector, HeadwindCheckboxService],\r\n host: {\r\n tabindex: '0',\r\n class: 'headwind-checkbox',\r\n role: 'checkbox',\r\n ['[attr.aria-checked]']: 'checked',\r\n ['[class.headwind-checked]']: 'checked',\r\n },\r\n})\r\nexport class HeadwindCheckboxComponent extends HeadwindControlValueAccessor {\r\n @Output() checkedChange = new EventEmitter<boolean>();\r\n\r\n constructor(private readonly _headwindCheckboxService: HeadwindCheckboxService) {\r\n super();\r\n }\r\n\r\n @Input({ transform: booleanAttribute })\r\n get disabled(): boolean {\r\n return this.isDisabled;\r\n }\r\n\r\n set disabled(value: boolean) {\r\n this.setDisabledState(value);\r\n }\r\n\r\n @Input({ transform: booleanAttribute })\r\n get checked(): boolean {\r\n return this._headwindCheckboxService.checked;\r\n }\r\n\r\n set checked(value: boolean) {\r\n this._headwindCheckboxService.checked = value;\r\n }\r\n\r\n @HostListener('click')\r\n onHostClick(): void {\r\n this.toggle();\r\n }\r\n\r\n @HostListener('blur')\r\n onHostBlur(): void {\r\n this.onTouched();\r\n }\r\n\r\n @HostListener('keydown.space', ['$event'])\r\n onHostSpaceKeydown(event: Event): void {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n\r\n this.toggle();\r\n }\r\n\r\n override writeValue(obj: any) {\r\n this.checked = obj;\r\n }\r\n\r\n override updateValue(value: any) {\r\n super.updateValue(value);\r\n this.checkedChange.emit(value);\r\n }\r\n\r\n check(): void {\r\n if (this.disabled) {\r\n return;\r\n }\r\n\r\n this.updateValue(true);\r\n }\r\n\r\n uncheck(): void {\r\n if (this.disabled) {\r\n return;\r\n }\r\n\r\n this.updateValue(false);\r\n }\r\n\r\n toggle(): void {\r\n if (this.checked) {\r\n this.uncheck();\r\n } else {\r\n this.check();\r\n }\r\n }\r\n}\r\n","<ng-content></ng-content>\r\n","import { Directive, TemplateRef } from '@angular/core';\r\n\r\n@Directive({\r\n selector: 'ng-template[headwindCheckboxChecked]',\r\n standalone: true,\r\n})\r\nexport class HeadwindCheckboxCheckedDirective {\r\n constructor(public readonly templateRef: TemplateRef<any>) {}\r\n}\r\n","import {\r\n AfterViewInit,\r\n Component,\r\n ContentChild,\r\n DestroyRef,\r\n EmbeddedViewRef,\r\n OnDestroy,\r\n ViewChild,\r\n ViewContainerRef,\r\n} from '@angular/core';\r\nimport { HeadwindCheckboxCheckedDirective } from './headwind-checkbox-checked/headwind-checkbox-checked.directive';\r\nimport { HeadwindCheckboxService } from '../service/headwind-checkbox.service';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\n\r\n@Component({\r\n selector: 'headwind-checkbox-button',\r\n standalone: true,\r\n imports: [],\r\n templateUrl: './headwind-checkbox-button.component.html',\r\n styleUrl: './headwind-checkbox-button.component.scss',\r\n host: {\r\n class: 'headwind-checkbox-button',\r\n },\r\n})\r\nexport class HeadwindCheckboxButtonComponent implements AfterViewInit, OnDestroy {\r\n @ViewChild('checkboxCheckedContainer', { read: ViewContainerRef }) checkboxCheckedContainer?: ViewContainerRef;\r\n\r\n @ContentChild(HeadwindCheckboxCheckedDirective, { descendants: true })\r\n checkboxChecked?: HeadwindCheckboxCheckedDirective;\r\n\r\n private _timeoutId?: any;\r\n private _checkedEmbeddedViewRef?: EmbeddedViewRef<any>;\r\n\r\n constructor(\r\n private readonly _destroyRef: DestroyRef,\r\n private readonly _headwindCheckboxService: HeadwindCheckboxService,\r\n ) {}\r\n\r\n get checked(): boolean {\r\n return this._headwindCheckboxService.checked;\r\n }\r\n\r\n ngAfterViewInit() {\r\n // use timeout to prevent NG0100 error\r\n this._timeoutId = setTimeout(() => {\r\n this._headwindCheckboxService.checked$.pipe(takeUntilDestroyed(this._destroyRef)).subscribe((checked) => {\r\n if (this.checkboxCheckedContainer && this.checkboxChecked) {\r\n if (checked) {\r\n if (!this._checkedEmbeddedViewRef) {\r\n this._checkedEmbeddedViewRef = this.checkboxCheckedContainer.createEmbeddedView(\r\n this.checkboxChecked.templateRef,\r\n );\r\n }\r\n } else {\r\n this._checkedEmbeddedViewRef?.destroy();\r\n delete this._checkedEmbeddedViewRef;\r\n }\r\n }\r\n });\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n clearTimeout(this._timeoutId);\r\n }\r\n}\r\n","<ng-container #checkboxCheckedContainer></ng-container>\r\n","import { EventEmitter, Injectable } from '@angular/core';\r\nimport { BehaviorSubject } from 'rxjs';\r\n\r\n@Injectable()\r\nexport class HeadwindPopoverService {\r\n /** Emits to open popover */\r\n openPopover = new EventEmitter<void>();\r\n\r\n /** Emits to close popover */\r\n closePopover = new EventEmitter<void>();\r\n\r\n /** Popover opened status */\r\n popoverOpened$ = new BehaviorSubject(false);\r\n\r\n get popoverOpened(): boolean {\r\n return this.popoverOpened$.value;\r\n }\r\n\r\n set popoverOpened(value: boolean) {\r\n this.popoverOpened$.next(value);\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class HeadwindWindowService {\r\n /**\r\n * Returns whether there is space for an element at the bottom of the Window\r\n * @param y - Y-axis position of the top of the element\r\n * @param height - Height of the element\r\n */\r\n isBottomSpaceAvailable(y: number, height: number): boolean {\r\n return y + height < window.innerHeight;\r\n }\r\n\r\n /**\r\n * Returns whether there is space for an element at the top of the Window\r\n * @param y - Y-axis position of the bottom of the element\r\n * @param height - Height of the element\r\n */\r\n isTopSpaceAvailable(y: number, height: number): boolean {\r\n return y - height > 0;\r\n }\r\n\r\n isRightSpaceAvailable(x: number, width: number): boolean {\r\n return x + width < window.innerWidth;\r\n }\r\n\r\n isLeftSpaceAvailable(x: number, width: number): boolean {\r\n return x - width > 0;\r\n }\r\n}\r\n","import { AfterViewInit, Component, ElementRef, EventEmitter, Input, Output, Renderer2 } from '@angular/core';\r\nimport { HeadwindWindowService } from '../../../services/headwind-window.service';\r\nimport { HeadwindClickDetector } from '../../../services/headwind-click-detector.service';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { HeadwindPopoverService } from '../services/headwind-popover.service';\r\nimport { LinearDirections } from '../../../types/linear-directions';\r\nimport { XYDirections } from '../../../types/xy-directions';\r\n\r\n@Component({\r\n selector: 'headwind-popover-overlay',\r\n standalone: true,\r\n imports: [],\r\n templateUrl: './headwind-popover-overlay.component.html',\r\n styleUrl: './headwind-popover-overlay.component.scss',\r\n host: {\r\n class: 'headwind-popover-overlay',\r\n },\r\n providers: [HeadwindClickDetector],\r\n})\r\nexport class HeadwindPopoverOverlayComponent implements AfterViewInit {\r\n @Input() direction: LinearDirections = 'vertical';\r\n @Input() directionPriority: XYDirections = 'bottom';\r\n @Input() pinPriority: XYDirections = 'left';\r\n\r\n @Output() actualDirectionChange = new EventEmitter<XYDirections>();\r\n @Output() actualPinChange = new EventEmitter<XYDirections>();\r\n\r\n constructor(\r\n private readonly _renderer: Renderer2,\r\n private readonly _elementRef: ElementRef<HTMLElement>,\r\n private readonly _headwindWindowService: HeadwindWindowService,\r\n private readonly _headwindClickDetector: HeadwindClickDetector,\r\n private readonly _headwindPopoverService: HeadwindPopoverService,\r\n ) {\r\n this._headwindClickDetector.outsideClick.pipe(takeUntilDestroyed()).subscribe(() => {\r\n if (this._headwindPopoverService.popoverOpened) {\r\n this._headwindPopoverService.closePopover.emit();\r\n }\r\n });\r\n }\r\n\r\n ngAfterViewInit() {\r\n this._headwindClickDetector.register(this._elementRef.nativeElement);\r\n }\r\n\r\n updatePosition(button: HTMLElement): void {\r\n if (this._elementRef) {\r\n const host = this._elementRef.nativeElement;\r\n\r\n // clear all styles\r\n this._renderer.removeStyle(host, 'position');\r\n this._renderer.removeStyle(host, 'top');\r\n this._renderer.removeStyle(host, 'bottom');\r\n this._renderer.removeStyle(host, 'left');\r\n this._renderer.removeStyle(host, 'right');\r\n\r\n this._renderer.setStyle(host, 'position', 'fixed');\r\n\r\n const buttonDomRect = button.getBoundingClientRect();\r\n const hostDomRect = host.getBoundingClientRect();\r\n\r\n switch (this.direction) {\r\n case 'vertical': {\r\n this._updateVerticalDirectionByPriority(host, hostDomRect, buttonDomRect);\r\n this._updateVerticalDirectionPin(host, hostDomRect, buttonDomRect);\r\n\r\n break;\r\n }\r\n\r\n case 'horizontal': {\r\n this._updateHorizontalDirectionByPriority(host, hostDomRect, buttonDomRect);\r\n this._updateHorizontalDirectionPin(host, hostDomRect, buttonDomRect);\r\n\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n\r\n private _updateVerticalDirectionByPriority(host: HTMLElement, hostDomRect: DOMRect, buttonDomRect: DOMRect): void {\r\n if (this.directionPriority === 'top') {\r\n if (this._headwindWindowService.isTopSpaceAvailable(buttonDomRect.top, hostDomRect.height)) {\r\n this._renderer.setStyle(host, 'bottom', `calc(100% - ${buttonDomRect.top}px)`);\r\n this._emitActualDirectionTop();\r\n } else if (this._headwindWindowService.isBottomSpaceAvailable(buttonDomRect.bottom, hostDomRect.height)) {\r\n this._renderer.setStyle(host, 'top', buttonDomRect.bottom + 'px');\r\n this._emitActualDirectionBottom();\r\n } else {\r\n this._renderer.setStyle(host, 'bottom', `calc(100% - ${buttonDomRect.top}px)`);\r\n this._emitActualDirectionTop();\r\n }\r\n } else {\r\n if (this._headwindWindowService.isBottomSpaceAvailable(buttonDomRect.bottom, hostDomRect.height)) {\r\n this._renderer.setStyle(host, 'top', buttonDomRect.bottom + 'px');\r\n this._emitActualDirectionBottom();\r\n } else if (this._headwindWindowService.isTopSpaceAvailable(buttonDomRect.top, hostDomRect.height)) {\r\n this._renderer.setStyle(host, 'bottom', `calc(100% - ${buttonDomRect.top}px)`);\r\n this._emitActualDirectionTop();\r\n } else {\r\n this._renderer.setStyle(host, 'top', buttonDomRect.bottom + 'px');\r\n this._emitActualDirectionBottom();\r\n }\r\n }\r\n }\r\n\r\n private _updateHorizontalDirectionByPriority(host: HTMLElement, hostDomRect: DOMRect, buttonDomRect: DOMRect): void {\r\n if (this.directionPriority === 'left') {\r\n if (this._headwindWindowService.isLeftSpaceAvailable(buttonDomRect.left, hostDomRect.width)) {\r\n this._renderer.setStyle(host, 'right', `calc(100% - ${buttonDomRect.left}px)`);\r\n this._emitActualDirectionLeft();\r\n } else if (this._headwindWindowService.isRightSpaceAvailable(buttonDomRect.right, hostDomRect.width)) {\r\n this._renderer.setStyle(host, 'left', buttonDomRect.right + 'px');\r\n this._emitActualDirectionRight();\r\n } else {\r\n this._renderer.setStyle(host, 'right', `calc(100% - ${buttonDomRect.left}px)`);\r\n this._emitActualDirectionLeft();\r\n }\r\n } else {\r\n if (this._headwindWindowService.isRightSpaceAvailable(buttonDomRect.right, hostDomRect.width)) {\r\n this._renderer.setStyle(host, 'left', buttonDomRect.right + 'px');\r\n this._emitActualDirectionRight();\r\n } else if (this._headwindWindowService.isLeftSpaceAvailable(buttonDomRect.left, hostDomRect.width)) {\r\n this._renderer.setStyle(host, 'right', `calc(100% - ${buttonDomRect.left}px)`);\r\n this._emitActualDirectionLeft();\r\n } else {\r\n this._renderer.setStyle(host, 'left', buttonDomRect.right + 'px');\r\n this._emitActualDirectionRight();\r\n }\r\n }\r\n }\r\n\r\n private _updateVerticalDirectionPin(host: HTMLElement, hostDomRect: DOMRect, buttonDomRect: DOMRect): void {\r\n if (this.pinPriority === 'right') {\r\n if (this._headwindWindowService.isLeftSpaceAvailable(buttonDomRect.right, hostDomRect.width)) {\r\n this._renderer.setStyle(host, 'right', `calc(100% - ${buttonDomRect.right}px)`);\r\n this._emitActualPinRight();\r\n } else if (this._headwindWindowService.isRightSpaceAvailable(buttonDomRect.left, hostDomRect.width)) {\r\n this._renderer.setStyle(host, 'left', buttonDomRect.left + 'px');\r\n this._emitActualPinLeft();\r\n } else {\r\n this._renderer.setStyle(host, 'right', `calc(100% - ${buttonDomRect.right}px)`);\r\n this._emitActualPinRight();\r\n }\r\n } else {\r\n if (this._headwindWindowService.isRightSpaceAvailable(buttonDomRect.left, hostDomRect.width)) {\r\n this._renderer.setStyle(host, 'left', buttonDomRect.left + 'px');\r\n this._emitActualPinLeft();\r\n } else if (this._headwindWindowService.isLeftSpaceAvailable(buttonDomRect.right, hostDomRect.width)) {\r\n this._renderer.setStyle(host, 'right', `calc(100% - ${buttonDomRect.right}px)`);\r\n this._emitActualPinRight();\r\n } else {\r\n this._renderer.setStyle(host, 'left', buttonDomRect.left + 'px');\r\n this._emitActualPinLeft();\r\n }\r\n }\r\n }\r\n\r\n private _updateHorizontalDirectionPin(host: HTMLElement, hostDomRect: DOMRect, buttonDomRect: DOMRect): void {\r\n if (this.pinPriority === 'bottom') {\r\n if (this._headwindWindowService.isTopSpaceAvailable(buttonDomRect.bottom, hostDomRect.height)) {\r\n this._renderer.setStyle(host, 'bottom', `calc(100% - ${buttonDomRect.bottom}px)`);\r\n this._emitActualPinTop();\r\n } else if (this._headwindWindowService.isBottomSpaceAvailable(buttonDomRect.top, hostDomRect.height)) {\r\n this._renderer.setStyle(host, 'top', buttonDomRect.top + 'px');\r\n this._emitActualPinBottom();\r\n } else {\r\n this._renderer.setStyle(host, 'bottom', `calc(100% - ${buttonDomRect.bottom}px)`);\r\n this._emitActualPinTop();\r\n }\r\n } else {\r\n if (this._headwindWindowService.isBottomSpaceAvailable(buttonDomRect.top, hostDomRect.height)) {\r\n this._renderer.setStyle(host, 'top', buttonDomRect.top + 'px');\r\n this._emitActualPinBottom();\r\n } else if (this._headwindWindowService.isTopSpaceAvailable(buttonDomRect.bottom, hostDomRect.height)) {\r\n this._renderer.setStyle(host, 'bottom', `calc(100% - ${buttonDomRect.bottom}px)`);\r\n this._emitActualPinTop();\r\n } else {\r\n this._renderer.setStyle(host, 'top', buttonDomRect.top + 'px');\r\n this._emitActualPinBottom();\r\n }\r\n }\r\n }\r\n\r\n private _emitActualDirectionTop(): void {\r\n this.actualDirectionChange.emit('top');\r\n }\r\n\r\n private _emitActualDirectionBottom(): void {\r\n this.actualDirectionChange.emit('bottom');\r\n }\r\n\r\n private _emitActualDirectionLeft(): void {\r\n this.actualDirectionChange.emit('left');\r\n }\r\n\r\n private _emitActualDirectionRight(): void {\r\n this.actualDirectionChange.emit('right');\r\n }\r\n\r\n private _emitActualPinTop(): void {\r\n this.actualPinChange.emit('top');\r\n }\r\n\r\n private _emitActualPinBottom(): void {\r\n this.actualPinChange.emit('bottom');\r\n }\r\n\r\n private _emitActualPinLeft(): void {\r\n this.actualPinChange.emit('left');\r\n }\r\n\r\n private _emitActualPinRight(): void {\r\n this.actualPinChange.emit('right');\r\n }\r\n}\r\n","<ng-content></ng-content>\r\n","import { Directive, TemplateRef } from '@angular/core';\r\n\r\n@Directive({\r\n selector: '[headwindPopoverOverlay]',\r\n standalone: true,\r\n})\r\nexport class HeadwindPopoverOverlayDirective {\r\n constructor(public readonly templateRef: TemplateRef<any>) {}\r\n}\r\n","import { Directive, ElementRef, HostListener } from '@angular/core';\r\nimport { HeadwindPopoverService } from '../services/headwind-popover.service';\r\n\r\n@Directive({\r\n selector: '[headwindPopoverButton]',\r\n standalone: true,\r\n host: {\r\n class: 'headwind-popover-button',\r\n },\r\n})\r\nexport class HeadwindPopoverButtonDirective {\r\n constructor(\r\n private readonly _elementRef: ElementRef<HTMLElement>,\r\n private readonly _headwindPopoverService: HeadwindPopoverService,\r\n ) {}\r\n\r\n get nativeElement(): HTMLElement {\r\n return this._elementRef.nativeElement;\r\n }\r\n\r\n @HostListener('click')\r\n onHostClick(): void {\r\n this._headwindPopoverService.openPopover.emit();\r\n }\r\n}\r\n","import { Component, HostListener, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';\r\nimport { HeadwindOverlayService } from '../../services/headwind-overlay.service';\r\n\r\n@Component({\r\n selector: 'headwind-overlay-outlet',\r\n standalone: true,\r\n imports: [],\r\n templateUrl: './headwind-overlay-outlet.component.html',\r\n styleUrl: './headwind-overlay-outlet.component.scss',\r\n host: {\r\n class: 'headwind-overlay-outlet',\r\n },\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class HeadwindOverlayOutletComponent {\r\n @ViewChild('container', { read: ViewContainerRef }) viewContainerRef!: ViewContainerRef;\r\n\r\n constructor(private readonly _headwindOverlayService: HeadwindOverlayService) {}\r\n\r\n @HostListener('window:keydown.escape')\r\n onWindowEscapeKeydown(): void {\r\n this._headwindOverlayService.closeLatest();\r\n }\r\n}\r\n","<ng-container #container></ng-container>\r\n","import { ApplicationRef, EmbeddedViewRef, Injectable, TemplateRef, ViewContainerRef } from '@angular/core';\r\nimport { HeadwindOverlayOutletComponent } from '../components/headwind-overlay-outlet/headwind-overlay-outlet.component';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class HeadwindOverlayService {\r\n private _openedViewRefs: EmbeddedViewRef<any>[] = [];\r\n\r\n /**\r\n * By default, opening an overlay will create viewContainerRef to render overlay.\r\n * Once viewContainerRef is created, that is cached to this property to prevent creating multiple viewContainerRefs.\r\n */\r\n private _cachedViewContainerRef?: ViewContainerRef;\r\n\r\n constructor(private readonly _applicationRef: ApplicationRef) {}\r\n\r\n get viewContainerRef(): ViewContainerRef {\r\n if (!this._cachedViewContainerRef) {\r\n const rootViewContainerRef = this._applicationRef.components[0].injector.get(ViewContainerRef);\r\n const overlayOutletRef = rootViewContainerRef.createComponent(HeadwindOverlayOutletComponent);\r\n\r\n overlayOutletRef.changeDetectorRef.detectChanges();\r\n\r\n this._cachedViewContainerRef = overlayOutletRef.instance.viewContainerRef;\r\n }\r\n\r\n return this._cachedViewContainerRef;\r\n }\r\n\r\n /**\r\n * Open a template as overlay\r\n * @param templateRef - TemplateRef to open as an overlay\r\n * @param onDestroy - Callback to call when destroying EmbeddedViewRef\r\n */\r\n open<C = any>(templateRef: TemplateRef<C>, onDestroy?: () => void): EmbeddedViewRef<C> {\r\n const embeddedViewRef = this.viewContainerRef.createEmbeddedView(templateRef);\r\n\r\n this._openedViewRefs.push(embeddedViewRef);\r\n\r\n embeddedViewRef.onDestroy(() => {\r\n this._openedViewRefs = this._openedViewRefs.filter((_openedViewRef) => _openedViewRef !== embeddedViewRef);\r\n\r\n if (onDestroy) {\r\n onDestroy();\r\n }\r\n });\r\n\r\n return embeddedViewRef;\r\n }\r\n\r\n closeLatest(): void {\r\n const latestViewRef = this._openedViewRefs[this._openedViewRefs.length - 1]; // item is removed from the `onDestroy()` method\r\n\r\n latestViewRef?.destroy();\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\n\r\nexport type HeadwindAnimatorListener = () => void;\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class HeadwindAnimator {\r\n private _frame: any;\r\n private _animating = false;\r\n private _registeredListeners: HeadwindAnimatorListener[] = [];\r\n\r\n get hasListeners(): boolean {\r\n return this._registeredListeners.length > 0;\r\n }\r\n\r\n addListener(listener: HeadwindAnimatorListener): void {\r\n this.removeListener(listener); // remove duplicated one\r\n this._registeredListeners.push(listener);\r\n\r\n if (this.hasListeners && !this._animating) {\r\n this._animating = true;\r\n this._runAnimation();\r\n }\r\n }\r\n\r\n removeListener(listener: HeadwindAnimatorListener): void {\r\n this._registeredListeners = this._registeredListeners.filter((item) => item !== listener);\r\n\r\n if (!this.hasListeners) {\r\n this._stopAnimation();\r\n }\r\n }\r\n\r\n private _runAnimation(): void {\r\n this._registeredListeners.forEach((listener) => listener());\r\n\r\n if (this._animating) {\r\n this._frame = requestAnimationFrame(() => this._runAnimation());\r\n }\r\n }\r\n\r\n private _stopAnimation(): void {\r\n cancelAnimationFrame(this._frame);\r\n this._animating = false;\r\n }\r\n}\r\n","import { Component, ContentChild, EmbeddedViewRef, OnDestroy } from '@angular/core';\r\nimport { HeadwindPopoverService } from './services/headwind-popover.service';\r\nimport { HeadwindOverlayService } from '../../services/headwind-overlay.service';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { HeadwindPopoverOverlayComponent } from './headwind-popover-overlay/headwind-popover-overlay.component';\r\nimport { HeadwindAnimator } from '../../services/headwind-animator';\r\nimport { HeadwindPopoverOverlayDirective } from './headwind-popover-overlay/headwind-popover-overlay.directive';\r\nimport { HeadwindErrors } from '../../constants/headwind-errors';\r\nimport { HeadwindPopoverButtonDirective } from './headwind-popover-button/headwind-popover-button.directive';\r\n\r\n@Component({\r\n selector: 'headwind-popover',\r\n standalone: true,\r\n imports: [],\r\n templateUrl: './headwind-popover.component.html',\r\n styleUrl: './headwind-popover.component.scss',\r\n host: {\r\n class: 'headwind-popover',\r\n },\r\n providers: [HeadwindPopoverService],\r\n})\r\nexport class HeadwindPopoverComponent implements OnDestroy {\r\n @ContentChild(HeadwindPopoverOverlayDirective, { descendants: true })\r\n popoverOverlayTemplate?: HeadwindPopoverOverlayDirective;\r\n\r\n @ContentChild(HeadwindPopoverOverlayComponent, { descendants: true })\r\n popoverOverlay?: HeadwindPopoverOverlayComponent;\r\n\r\n @ContentChild(HeadwindPopoverButtonDirective, { descendants: true })\r\n popoverButton?: HeadwindPopoverButtonDirective;\r\n\r\n private _popoverEmbeddedViewRef?: EmbeddedViewRef<any>;\r\n private _openTimeoutId?: any;\r\n private _closeTimeoutId?: any;\r\n\r\n constructor(\r\n private readonly _headwindOverlayService: HeadwindOverlayService,\r\n private readonly _headwindPopoverService: HeadwindPopoverService,\r\n private readonly _headwindAnimator: HeadwindAnimator,\r\n ) {\r\n this._headwindPopoverService.openPopover.pipe(takeUntilDestroyed()).subscribe(() => {\r\n this.open();\r\n });\r\n\r\n this._headwindPopoverService.closePopover.pipe(takeUntilDestroyed()).subscribe(() => {\r\n this.close();\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n clearTimeout(this._openTimeoutId);\r\n clearTimeout(this._closeTimeoutId);\r\n }\r\n\r\n open(): void {\r\n if (!this.popoverOverlayTemplate) {\r\n console.error(HeadwindErrors.headwindError0003);\r\n return;\r\n }\r\n\r\n if (this._popoverEmbeddedViewRef) {\r\n return;\r\n }\r\n\r\n this._popoverEmbeddedViewRef = this._headwindOverlayService.open(this.popoverOverlayTemplate.templateRef, () =>\r\n this._afterClosed(),\r\n );\r\n\r\n this._headwindPopoverService.popoverOpened = true;\r\n\r\n this._headwindAnimator.addListener(this._popoverPositionListener);\r\n\r\n clearTimeout(this._openTimeoutId);\r\n\r\n this._openTimeoutId = setTimeout(() => {\r\n if (!this.popoverOverlay) {\r\n console.error(HeadwindErrors.headwindError0004);\r\n return;\r\n }\r\n });\r\n }\r\n\r\n close(): void {\r\n this._popoverEmbeddedViewRef?.destroy();\r\n\r\n this._afterClosed();\r\n }\r\n\r\n private _afterClosed(): void {\r\n clearTimeout(this._closeTimeoutId);\r\n\r\n // to prevent instant re-opening after closing, set a delay\r\n this._closeTimeoutId = setTimeout(() => {\r\n this._headwindAnimator.removeListener(this._popoverPositionListener);\r\n this._headwindPopoverService.popoverOpened = false;\r\n\r\n delete this._popoverEmbeddedViewRef;\r\n });\r\n }\r\n\r\n private _popoverPositionListener = () => {\r\n if (this.popoverButton) {\r\n this.popoverOverlay?.updatePosition(this.popoverButton.nativeElement);\r\n }\r\n };\r\n}\r\n","<ng-content></ng-content>\r\n","import { Directive, TemplateRef } from '@angular/core';\r\n\r\n@Directive({\r\n selector: 'ng-template[headwindRadioSelected]',\r\n standalone: true,\r\n})\r\nexport class HeadwindRadioSelectedDirective {\r\n constructor(public readonly templateRef: TemplateRef<any>) {}\r\n}\r\n","import { AfterViewInit, Component, ContentChild, EmbeddedViewRef, ViewChild, ViewContainerRef } from '@angular/core';\r\nimport { HeadwindRadioSelectedDirective } from './headwind-radio-selected/headwind-radio-selected.directive';\r\n\r\n@Component({\r\n selector: 'headwind-radio-button',\r\n standalone: true,\r\n imports: [],\r\n templateUrl: './headwind-radio-button.component.html',\r\n styleUrl: './headwind-radio-button.component.scss',\r\n host: {\r\n class: 'headwind-radio-button',\r\n },\r\n})\r\nexport class HeadwindRadioButtonComponent implements AfterViewInit {\r\n @ViewChild('radioSelectedContainer', { read: ViewContainerRef }) radioSelectedContainer?: ViewContainerRef;\r\n @ContentChild(HeadwindRadioSelectedDirective, { descendants: true }) radioSelected?: HeadwindRadioSelectedDirective;\r\n\r\n private _selectedEmbeddedViewRef?: EmbeddedViewRef<any>;\r\n\r\n /** Internal selected status to show and hide selected icon */\r\n private _selected = false;\r\n\r\n get selected(): boolean {\r\n return this._selected;\r\n }\r\n\r\n set selected(value: boolean) {\r\n this._selected = value;\r\n this._renderRadioSelected();\r\n }\r\n\r\n ngAfterViewInit() {\r\n this._renderRadioSelected();\r\n }\r\n\r\n private _renderRadioSelected(): void {\r\n if (this.radioSelectedContainer && this.radioSelected) {\r\n if (this.selected) {\r\n if (!this._selectedEmbeddedViewRef) {\r\n this._selectedEmbeddedViewRef = this.radioSelectedContainer.createEmbeddedView(\r\n this.radioSelected.templateRef,\r\n );\r\n }\r\n } else {\r\n this._selectedEmbeddedViewRef?.destroy();\r\n delete this._selectedEmbeddedViewRef;\r\n }\r\n }\r\n }\r\n}\r\n","<ng-container #radioSelectedContainer></ng-container>\r\n","import { EventEmitter, Injectable } from '@angular/core';\r\nimport { BehaviorSubject } from 'rxjs';\r\n\r\n@Injectable()\r\nexport class HeadwindRadioGroupService {\r\n /** Emits with value of option when selected */\r\n selectOption = new EventEmitter<any>();\r\n\r\n /** Selected value */\r\n value$ = new BehaviorSubject<any>(undefined);\r\n\r\n get value(): any {\r\n return this.value$.value;\r\n }\r\n\r\n set value(value: any) {\r\n this.value$.next(value);\r\n }\r\n}\r\n","import { AfterContentInit, Component, ContentChild, DestroyRef, HostListener, Input } from '@angular/core';\r\nimport { HeadwindClickDetector } from '../../../services/headwind-click-detector.service';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { HeadwindRadioButtonComponent } from './headwind-radio-button/headwind-radio-button.component';\r\nimport { HeadwindRadioGroupService } from '../service/headwind-radio-group.service';\r\n\r\n@Component({\r\n selector: 'headwind-radio',\r\n standalone: true,\r\n imports: [],\r\n templateUrl: './headwind-radio.component.html',\r\n styleUrl: './headwind-radio.component.scss',\r\n providers: [HeadwindClickDetector],\r\n host: {\r\n class: 'headwind-radio',\r\n ['[class.headwind-selected]']: 'selected',\r\n },\r\n})\r\nexport class HeadwindRadioComponent implements AfterContentInit {\r\n @Input({ required: true }) value: any;\r\n\r\n @ContentChild(HeadwindRadioButtonComponent, { descendants: true }) button?: HeadwindRadioButtonComponent;\r\n\r\n private _selected = false;\r\n\r\n constructor(\r\n private readonly _destroyRef: DestroyRef,\r\n private readonly _headwindRadioGroupService: HeadwindRadioGroupService,\r\n ) {}\r\n\r\n get selected(): boolean {\r\n return this._selected;\r\n }\r\n\r\n ngAfterContentInit() {\r\n this._headwindRadioGroupService.value$.pipe(takeUntilDestroyed(this._destroyRef)).subscribe((value) => {\r\n this._selected = this.value === value;\r\n\r\n if (this.button) {\r\n this.button.selected = this.selected;\r\n }\r\n });\r\n }\r\n\r\n @HostListener('click')\r\n onHostClick(): void {\r\n this._headwindRadioGroupService.selectOption.emit(this.value);\r\n }\r\n}\r\n","<ng-content></ng-content>\r\n","import { Injectable, QueryList } from '@angular/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class HeadwindQueryListService {\r\n findIndex<Comp>(queryList: QueryList<Comp> | undefined, comparator: (component: Comp) => boolean): number {\r\n let searchedIndex = -1;\r\n\r\n // To stop when searched, use 'some()' method\r\n queryList?.some((component, index) => {\r\n const result = comparator(component);\r\n\r\n if (result) {\r\n searchedIndex = index;\r\n }\r\n\r\n return result;\r\n });\r\n\r\n return searchedIndex;\r\n }\r\n}\r\n","import {\r\n booleanAttribute,\r\n Component,\r\n ContentChildren,\r\n EventEmitter,\r\n HostListener,\r\n Input,\r\n Output,\r\n QueryList,\r\n} from '@angular/core';\r\nimport { HeadwindControlValueAccessor } from '../../abstracts/headwind-control-value-accessor';\r\nimport { HeadwindRadioComponent } from './headwind-radio/headwind-radio.component';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { HeadwindRadioGroupService } from './service/headwind-radio-group.service';\r\nimport { HeadwindQueryListService } from '../../services/headwind-query-list.service';\r\n\r\n@Component({\r\n selector: 'headwind-radio-group',\r\n standalone: true,\r\n imports: [],\r\n templateUrl: './headwind-radio-group.component.html',\r\n styleUrl: './headwind-radio-group.component.scss',\r\n host: {\r\n tabindex: '0',\r\n class: 'headwind-radio-group',\r\n },\r\n providers: [HeadwindRadi