import * as i0 from '@angular/core';
import { inject, TemplateRef, Input, Directive, HostBinding, ChangeDetectionStrategy, Component, ElementRef, booleanAttribute, numberAttribute, HostListener, EventEmitter, Renderer2, Output, signal, ViewContainerRef, PLATFORM_ID, Injector, input, ViewEncapsulation, ChangeDetectorRef, effect } from '@angular/core';
import { Overlay, ConnectionPositionPair } from '@angular/cdk/overlay';
import { Subject, BehaviorSubject, Subscription, timer, fromEvent, take } from 'rxjs';
import { ComponentPortal } from '@angular/cdk/portal';
import { trigger, state, transition, style, animate, keyframes } from '@angular/animations';
import { NgControl, NgModel } from '@angular/forms';
import { EuiPermissionService, CssUtils } from '@eui/core';
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import * as i1 from '@eui/components/eui-icon';
import { EuiIconSvgComponent, EUI_ICON } from '@eui/components/eui-icon';
import { tap, takeUntil, map, distinctUntilChanged } from 'rxjs/operators';

/**
 * Directive for defining named template references that can be dynamically rendered.
 * Provides a way to identify and retrieve templates by name for content projection.
 * Commonly used in components that accept multiple template slots (headers, footers, custom content).
 * Works with TemplateRef to enable flexible content customization.
 *
 * @usageNotes
 * ```html
 * <ng-template euiTemplate="header">
 *   <h2>Custom Header</h2>
 * </ng-template>
 *
 * <ng-template euiTemplate="footer">
 *   <button>Custom Action</button>
 * </ng-template>
 * ```
 *
 * In component:
 * ```typescript
 * @ContentChildren(EuiTemplateDirective) templates: QueryList<EuiTemplateDirective>;
 *
 * getTemplate(name: string) {
 *   return this.templates.find(t => t.getType() === name)?.template;
 * }
 * ```
 *
 * ### Accessibility
 * - Template content should follow accessibility guidelines
 * - Ensure dynamic content maintains proper heading hierarchy
 * - Screen readers will announce template content when rendered
 *
 * ### Notes
 * - Use euiTemplate input to assign template name
 * - Templates retrieved via ContentChildren query in parent component
 * - getType() method returns template name for identification
 * - Supports generic typing for template context
 */
class EuiTemplateDirective {
    constructor() {
        this.template = inject(TemplateRef);
    }
    getType() {
        return this.name;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.16", type: EuiTemplateDirective, isStandalone: true, selector: "[euiTemplate]", inputs: { type: "type", name: ["euiTemplate", "name"] }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiTemplateDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[euiTemplate]',
                }]
        }], propDecorators: { type: [{
                type: Input
            }], name: [{
                type: Input,
                args: ['euiTemplate']
            }] } });

/**
 * Tooltip display animation.
 */
const showHide = trigger('showHide', [
    state('initial, void, hidden', style({ opacity: 0, transform: 'scale(0)' })),
    state('visible', style({ transform: 'scale(1)' })),
    transition('* => visible', animate('200ms cubic-bezier(0, 0, 0.2, 1)', keyframes([
        style({ opacity: 0, transform: 'scale(0)', offset: 0 }),
        style({ opacity: 0.5, transform: 'scale(0.99)', offset: 0.5 }),
        style({ opacity: 1, transform: 'scale(1)', offset: 1 }),
    ]))),
    transition('* => hidden', animate('100ms cubic-bezier(0, 0, 0.2, 1)', style({ opacity: 0 }))),
]);

class EuiTooltipContainerComponent {
    constructor() {
        /**
         * Sets the `data-e2e` attribute for the host element.
         *
         * @default 'eui-tooltip'
         */
        this.e2e = 'eui-tooltip';
    }
    /**
     * @description
     * Computes and returns the CSS classes for the component based on its current state.
     *
     * @returns {string} Space-separated string of CSS class names
     */
    get cssClasses() {
        return ['eui-tooltip', 'eui-tooltip--content-' + this.config.contentAlign, 'eui-tooltip--' + this.config.colorClass]
            .join(' ')
            .trim();
    }
    get showHide() {
        return 'visible';
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiTooltipContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.16", type: EuiTooltipContainerComponent, isStandalone: true, selector: "eui-tooltip-container.component", inputs: { config: "config" }, host: { properties: { "attr.data-e2e": "this.e2e", "class": "this.cssClasses", "@showHide": "this.showHide" } }, ngImport: i0, template: "<div [innerHTML]=\"config.tooltipContent\"></div>\n", animations: [showHide], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiTooltipContainerComponent, decorators: [{
            type: Component,
            args: [{ selector: 'eui-tooltip-container.component', animations: [showHide], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [innerHTML]=\"config.tooltipContent\"></div>\n" }]
        }], propDecorators: { config: [{
                type: Input
            }], e2e: [{
                type: HostBinding,
                args: ['attr.data-e2e']
            }], cssClasses: [{
                type: HostBinding,
                args: ['class']
            }], showHide: [{
                type: HostBinding,
                args: ['@showHide']
            }] } });

/**
 * Directive for displaying contextual information in a tooltip overlay on hover or focus.
 * Provides semantic color variants and flexible positioning relative to the trigger element.
 * Automatically handles show/hide behavior with configurable delays and keyboard dismissal.
 * Built on Angular CDK Overlay for robust positioning and scroll handling.
 *
 * @usageNotes
 * Basic tooltip:
 * ```html
 * <button euiTooltip="Save your changes">Save</button>
 * ```
 *
 * Tooltip with position and variant:
 * ```html
 * <span euiTooltip="Error occurred" position="below" euiTooltipDanger>!</span>
 * ```
 *
 * Tooltip with delays:
 * ```html
 * <a euiTooltip="Click for details" [showDelay]="500" [hideDelay]="200">Info</a>
 * ```
 *
 * ### Accessibility
 * - Tooltip appears on both hover and keyboard focus for screen reader compatibility
 * - Press Escape key to dismiss tooltip
 * - Ensure tooltip content is non-essential as it may not be announced by all screen readers
 *
 * ### Notes
 * - Tooltip content should be brief and contextual
 * - Use semantic variants (euiTooltipDanger, euiTooltipWarning) to convey meaning
 * - Position automatically adjusts if space is insufficient (fallback positioning)
 * - Tooltip is disabled when isDisabled is true or tooltipContent is empty
 */
class EuiTooltipDirective {
    constructor() {
        /**
         * Sets the `data-e2e` attribute for the host element.
         *
         * @default 'eui-tooltip'
         */
        this.e2eAttr = 'eui-tooltip';
        /**
         * Sets the delay for the tooltip to be visible.
         *
         * @default 0
         */
        this.showDelay = 0;
        /**
         * Sets the delay for the tooltip to be hidden
         *
         * @default 0
         */
        this.hideDelay = 0;
        /**
         * Sets the alignment of the content in the tooltip.
         *
         * @default 'center''
         */
        this.contentAlignment = 'center';
        /**
         * Sets the position of the tooltip relative to its trigger element.
         *
         * @default 'center''
         */
        this.position = 'above';
        /**
         * Whether the tooltip is disabled.
         *
         * @default false (enable)
         */
        this.isDisabled = false;
        /**
         * Whether the tooltip has a Primary state.
         *
         * @default false
         */
        this.euiTooltipPrimary = false;
        /**
         * Whether the tooltip has a Secondary state.
         *
         * @default false
         */
        this.euiTooltipSecondary = false;
        /**
         * Whether the tooltip has Info state.
         *
         * @default false
         */
        this.euiTooltipInfo = false;
        /**
         * Whether the tooltip has a Success state.
         *
         * @default false
         */
        this.euiTooltipSuccess = false;
        /**
         * Whether the tooltip has a Warning state.
         *
         * @default false
         */
        this.euiTooltipWarning = false;
        /**
         * Whether the tooltip has a Danger state.
         *
         * @default false
         */
        this.euiTooltipDanger = false;
        /**
         * Whether the tooltip has Accent state.
         *
         * @default false
         */
        this.euiTooltipAccent = false;
        this.originX = 'center';
        this.originY = 'top';
        this.overlayX = 'center';
        this.overlayY = 'bottom';
        this.fallbackOriginX = 'center';
        this.fallbackOriginY = 'bottom';
        this.fallbackOverlayX = 'center';
        this.fallbackOverlayY = 'top';
        this.destroy$ = new Subject();
        this.isOpen$ = new BehaviorSubject(false);
        this.mouseleaveSubscription = new Subscription();
        this.blurSubscription = new Subscription();
        this.showDelaySubscription = new Subscription();
        this.positionStrategySubscription = new Subscription();
        this.overlay = inject(Overlay);
        this.host = inject(ElementRef);
    }
    ngOnChanges() {
        if (this.tooltipInstance) {
            this.tooltipInstance.setInput('config', this.getTooltipConfig());
        }
        this.setPosition();
    }
    ngOnInit() {
        this.setPosition();
    }
    ngOnDestroy() {
        this.destroy$.next(true);
        this.destroy$.unsubscribe();
        this.mouseleaveSubscription.unsubscribe();
        this.blurSubscription.unsubscribe();
        this.showDelaySubscription.unsubscribe();
        this.positionStrategySubscription.unsubscribe();
        this.overlayRef?.dispose();
        this.overlayRef = null;
    }
    mouseEntering(event) {
        this.show(event.target);
    }
    focused(event) {
        this.show(event.target);
    }
    /**
     * Returns the current open state.
     *
     * @returns {boolean} `true` if the element is open, otherwise `false`.
     */
    get isOpen() {
        return this.isOpen$.value;
    }
    /**
     * Method that shows a tooltip.
     *
     * @param origin Origin of the tooltip. Where it will be displayed.
     */
    show(origin = this.host.nativeElement) {
        this.mouseleaveSubscription.unsubscribe();
        this.blurSubscription.unsubscribe();
        this.showDelaySubscription.unsubscribe();
        this.showDelaySubscription = timer(this.showDelay).subscribe(() => {
            if (!this.isOpen && !this.isDisabled && this.tooltipContent) {
                const positionStrategy = this.overlay
                    .position()
                    .flexibleConnectedTo(origin)
                    .withPositions([
                    new ConnectionPositionPair({ originX: this.originX, originY: this.originY }, { overlayX: this.overlayX, overlayY: this.overlayY }),
                    new ConnectionPositionPair({ originX: this.fallbackOriginX, originY: this.fallbackOriginY }, { overlayX: this.fallbackOverlayX, overlayY: this.fallbackOverlayY }),
                ])
                    .withFlexibleDimensions(false)
                    .withLockedPosition(true);
                const scrollStrategy = this.overlay.scrollStrategies.reposition({ scrollThrottle: 10 });
                this.overlayRef = this.overlay.create({
                    hasBackdrop: false,
                    panelClass: ['eui-tooltip__container', 'eui-21'],
                    positionStrategy,
                    scrollStrategy,
                });
                this.positionStrategySubscription = positionStrategy.positionChanges.subscribe((overlayPosition) => {
                    this.position = this.getPosition(overlayPosition);
                    const positionClasses = [
                        'eui-tooltip--left',
                        'eui-tooltip--right',
                        'eui-tooltip--above',
                        'eui-tooltip--below',
                        'eui-tooltip--before',
                        'eui-tooltip--after',
                    ];
                    this.overlayRef.removePanelClass(positionClasses);
                    this.overlayRef.addPanelClass(['eui-tooltip--' + this.position]);
                });
                const componentPortal = new ComponentPortal(EuiTooltipContainerComponent, null);
                this.tooltipInstance = this.overlayRef.attach(componentPortal);
                this.tooltipInstance.setInput('config', this.getTooltipConfig());
                this.isOpen$.next(true);
            }
        });
        this.mouseleaveSubscription = fromEvent(origin, 'mouseleave').subscribe(() => {
            this.hide();
        });
        this.blurSubscription = fromEvent(origin, 'blur').subscribe(() => {
            this.hide();
        });
    }
    /**
     * Method that closes a tooltip.
     */
    hide() {
        timer(this.hideDelay)
            .pipe(take(1))
            .subscribe(() => {
            this.isOpen$.next(false);
            this.mouseleaveSubscription.unsubscribe();
            this.blurSubscription.unsubscribe();
            this.showDelaySubscription.unsubscribe();
            this.positionStrategySubscription.unsubscribe();
            this.overlayRef?.dispose();
            this.overlayRef = null;
        });
    }
    onEscapePressed(event) {
        if (this.isOpen) {
            event.stopPropagation();
            this.hide();
        }
    }
    /**
     * Generates and returns the tooltip configuration based on the defined tooltip properties.
     *
     * @returns {EuiTooltipInterface} The tooltip configuration object, including attributes used in container component.
     */
    getTooltipConfig() {
        let colorClass = 'secondary';
        if (this.euiTooltipPrimary) {
            colorClass = 'primary';
        }
        if (this.euiTooltipSecondary) {
            colorClass = 'secondary';
        }
        if (this.euiTooltipInfo) {
            colorClass = 'info';
        }
        if (this.euiTooltipSuccess) {
            colorClass = 'success';
        }
        if (this.euiTooltipWarning) {
            colorClass = 'warning';
        }
        if (this.euiTooltipDanger) {
            colorClass = 'danger';
        }
        if (this.euiTooltipAccent) {
            colorClass = 'accent';
        }
        return {
            e2eAttr: this.e2eAttr,
            tooltipContent: this.tooltipContent,
            position: this.position,
            contentAlign: this.contentAlignment,
            colorClass,
        };
    }
    /**
     * Determines and returns the tooltip's position based on the overlay's connection pair.
     *
     * @param {ConnectedOverlayPositionChange} overlayPosition - The overlay position change event.
     * @returns {string} The calculated position (`'above'`, `'below'`, `'left'`, or `'right'`).
     */
    getPosition(overlayPosition) {
        if (overlayPosition.connectionPair.originY === 'top' && overlayPosition.connectionPair.overlayY === 'bottom') {
            return 'above';
        }
        if (overlayPosition.connectionPair.originY === 'bottom' && overlayPosition.connectionPair.overlayY === 'top') {
            return 'below';
        }
        if (overlayPosition.connectionPair.originX === 'start' && overlayPosition.connectionPair.overlayX === 'end') {
            return 'left';
        }
        if (overlayPosition.connectionPair.originX === 'end' && overlayPosition.connectionPair.overlayX === 'start') {
            return 'right';
        }
    }
    /**
     * Sets the position-related properties based on the current `position` value.
     */
    setPosition() {
        if (this.position === 'above') {
            this.originY = 'top';
            this.overlayY = 'bottom';
            this.fallbackOriginY = 'bottom';
            this.fallbackOverlayY = 'top';
        }
        if (this.position === 'right' || this.position === 'after') {
            this.originX = 'end';
            this.originY = 'center';
            this.overlayX = 'start';
            this.overlayY = 'center';
            this.fallbackOriginX = 'start';
            this.fallbackOriginY = 'center';
            this.fallbackOverlayX = 'end';
            this.fallbackOverlayY = 'center';
        }
        if (this.position === 'below') {
            this.originY = 'bottom';
            this.overlayY = 'top';
            this.fallbackOriginY = 'top';
            this.fallbackOverlayY = 'bottom';
        }
        if (this.position === 'left' || this.position === 'before') {
            this.originX = 'start';
            this.originY = 'center';
            this.overlayX = 'end';
            this.overlayY = 'center';
            this.fallbackOriginX = 'end';
            this.fallbackOriginY = 'center';
            this.fallbackOverlayX = 'start';
            this.fallbackOverlayY = 'center';
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.16", type: EuiTooltipDirective, isStandalone: true, selector: "[euiTooltip]", inputs: { e2eAttr: "e2eAttr", showDelay: ["showDelay", "showDelay", numberAttribute], hideDelay: ["hideDelay", "hideDelay", numberAttribute], contentAlignment: "contentAlignment", position: "position", isDisabled: ["isDisabled", "isDisabled", booleanAttribute], tooltipContent: ["euiTooltip", "tooltipContent"], euiTooltipPrimary: ["euiTooltipPrimary", "euiTooltipPrimary", booleanAttribute], euiTooltipSecondary: ["euiTooltipSecondary", "euiTooltipSecondary", booleanAttribute], euiTooltipInfo: ["euiTooltipInfo", "euiTooltipInfo", booleanAttribute], euiTooltipSuccess: ["euiTooltipSuccess", "euiTooltipSuccess", booleanAttribute], euiTooltipWarning: ["euiTooltipWarning", "euiTooltipWarning", booleanAttribute], euiTooltipDanger: ["euiTooltipDanger", "euiTooltipDanger", booleanAttribute], euiTooltipAccent: ["euiTooltipAccent", "euiTooltipAccent", booleanAttribute] }, host: { listeners: { "mouseenter": "mouseEntering($event)", "focus": "focused($event)", "keydown.esc": "onEscapePressed($any($event))" } }, exportAs: ["euiTooltip"], usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiTooltipDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[euiTooltip]',
                    exportAs: 'euiTooltip',
                }]
        }], propDecorators: { e2eAttr: [{
                type: Input
            }], showDelay: [{
                type: Input,
                args: [{ transform: numberAttribute }]
            }], hideDelay: [{
                type: Input,
                args: [{ transform: numberAttribute }]
            }], contentAlignment: [{
                type: Input
            }], position: [{
                type: Input
            }], isDisabled: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], tooltipContent: [{
                type: Input,
                args: ['euiTooltip']
            }], euiTooltipPrimary: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], euiTooltipSecondary: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], euiTooltipInfo: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], euiTooltipSuccess: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], euiTooltipWarning: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], euiTooltipDanger: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], euiTooltipAccent: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], mouseEntering: [{
                type: HostListener,
                args: ['mouseenter', ['$event']]
            }], focused: [{
                type: HostListener,
                args: ['focus', ['$event']]
            }], onEscapePressed: [{
                type: HostListener,
                args: ['keydown.esc', ['$any($event)']]
            }] } });

/**
 * @description
 * A directive that adds maxLength functionality to input and textarea elements with visual feedback.
 * It shows the remaining characters count and provides visual indication when the limit is reached.
 *
 * @selector input[euiMaxlength], textarea[euiMaxlength], [ngModel][euiMaxlength], [formControlName][euiMaxlength]
 *
 * @example
 * ### Basic usage
 * ```html
 * <input [euiMaxlength]="50">
 * ```
 *
 * ### With form control
 * ```html
 * <input [formControlName]="'name'" [euiMaxlength]="100">
 * ```
 *
 * ### Hide maxlength indicator
 * ```html
 * <textarea [euiMaxlength]="200" [isShowMaxlength]="false"></textarea>
 * ```
 *
 * @publicApi
 */
class EuiMaxLengthDirective {
    constructor() {
        /**
         * @description
         * Controls the visibility of the maxLength indicator.
         * When true, shows a counter with remaining characters.
         * When false, hides the counter but maintains the maxLength restriction.
         *
         * @default true
         */
        this.isShowMaxlength = true;
        /**
         * @description
         * Emits when the input value length reaches or exceeds the maxLength limit.
         * Emits true when a limit is reached, false when below limit.
         *
         * @emits {boolean} True when max length is reached, false otherwise
         */
        this.maxLengthReached = new EventEmitter();
        this.el = inject(ElementRef);
        this.renderer = inject(Renderer2);
        this.control = inject(NgControl, { self: true, optional: true });
        // set the default length calculation behavior
        this.setLengthCalcFactory((value) => value?.length || 0);
    }
    ngOnDestroy() {
        // remove all DOM added elements
        this.destroyMaxLengthBox();
        // unsubscribe from valueChanges
        if (this.valueChangesSubscription) {
            this.valueChangesSubscription.unsubscribe();
        }
    }
    ngOnChanges(changes) {
        if (changes['isShowMaxlength']) {
            if (this.isShowMaxlength) {
                this.createMaxLengthBox();
                this._refreshValue();
            }
            else {
                this.destroyMaxLengthBox();
            }
        }
        if (changes['maxLength']) {
            if (this.maxLength < 0) {
                throw new Error('euiMaxlength of an input or a textarea cannot be negative.');
            }
            if (this.maxLength) {
                // re-create in case you previously destroyed it
                if (this.isShowMaxlength && !this.maxLengthSpan) {
                    this.createMaxLengthBox();
                }
                this._refreshValue();
            }
            else {
                this.renderer.removeAttribute(this.el.nativeElement, 'maxLength');
                this.destroyMaxLengthBox();
            }
        }
    }
    ngAfterContentInit() {
        if (this.maxLength) {
            this.createMaxLengthBox();
            this._refreshValue();
        }
        // this subscription is needed apart from HostListener to Changes in case usage of this directive
        // in custom component that implements ngDefaultControl
        if (this.control?.valueChanges) {
            this.valueChangesSubscription = this.control.valueChanges.subscribe(() => {
                this._refreshValue();
            });
        }
    }
    onChange() {
        if (!this.control || this.control?.control.updateOn !== 'change') {
            this._refreshValue();
        }
    }
    onInput() {
        if (!this.control || this.control?.control.updateOn !== 'change') {
            this._refreshValue();
        }
    }
    onPaste(event) {
        // get the value from clipboard
        const value = (event.clipboardData || window['clipboardData']).getData('text');
        // calculate and set the maxLength based on the clipboard value
        const input = this.el.nativeElement;
        if (this.maxLength) {
            this.renderer.setProperty(input, 'maxLength', this.calculateMaxLength(value));
        }
    }
    /**
     * Sets a custom function to calculate the length of the input value.
     * Useful for implementing custom length calculation logic (e.g., counting characters differently).
     *
     * @param fn Function that takes a string input and returns its calculated length
     *
     * @example
     * ```typescript
     * // Custom length calculation excluding spaces
     * directive.setLengthCalcFactory((value: string) => value.replace(/\s/g, '').length);
     * ```
     */
    setLengthCalcFactory(fn) {
        this.lengthCalcFn = () => {
            const value = this.getValue();
            return fn(value);
        };
    }
    /**
     * Calculates the maximum length for the input element based on current value or provided value.
     *
     * @param value Optional value to calculate max length against (overrides the current input value)
     * @returns {number} Calculated maximum length
     * @private
     */
    calculateMaxLength(value) {
        const inputValue = this.getValue();
        return (value?.length || (inputValue?.length || 0) - this.lengthCalcFn()) + this.maxLength;
    }
    /**
     * @description
     * Refreshes the visual state of the maxLength indicator and updates input restrictions.
     * - Updates the remaining characters count
     * - Applies/removes error styling
     * - Emits maxLengthReached event
     * - Truncates value if it exceeds maxLength
     *
     * @private
     */
    _refreshValue() {
        if (isNaN(this.maxLength)) {
            return;
        }
        const input = this.el.nativeElement;
        const valueLength = this.lengthCalcFn();
        const remainingLength = this.maxLength - valueLength;
        this.renderer.setProperty(input, 'maxLength', this.calculateMaxLength());
        if (this.maxLengthSpan) {
            // based on the remaining length add/remove the error class
            if (remainingLength <= 0) {
                this.renderer.addClass(this.maxLengthSpan, 'eui-input-maxlength--invalid');
                this.maxLengthReached.emit(true);
            }
            else {
                this.renderer.removeClass(this.maxLengthSpan, 'eui-input-maxlength--invalid');
                this.maxLengthReached.emit(false);
            }
            // set the value of remaining characters
            if (remainingLength < 0) {
                // this feature is only available when the calculation of length is not custom
                // to support this feature you need to calculate this.maxLength also
                if (this.control) {
                    this.control.control.setValue(input.value.substring(0, this.calculateMaxLength()));
                }
                else {
                    input.value = input.value.substring(0, this.calculateMaxLength());
                }
                this.renderer.setProperty(this.maxLengthSpan, 'textContent', '0');
            }
            else if (remainingLength >= 0) {
                this.renderer.setProperty(this.maxLengthSpan, 'textContent', (this.maxLength - valueLength).toString());
            }
        }
    }
    /**
     * @description
     * Creates the maxLength indicator box in the DOM.
     * Wraps the input element and adds the counter span with appropriate styling.
     *
     * @private
     */
    createMaxLengthBox() {
        if (this.maxLengthSpan) {
            this.destroyMaxLengthBox();
        }
        // creates the span that holds the max length value which changes according to input
        this.maxLengthSpan = this.renderer.createElement('span');
        this.renderer.addClass(this.maxLengthSpan, 'eui-input-maxlength');
        this.renderer.setAttribute(this.maxLengthSpan, 'textContent', this.maxLength.toString());
        // create wrapper element
        const nativeElement = this.el.nativeElement;
        if (nativeElement != null) {
            // set width to 100%
            this.renderer.setStyle(nativeElement, 'width', '100%');
            const parent = nativeElement.parentNode;
            if (parent != null && this.isShowMaxlength) {
                // creates wrapper div of input and maxLength span
                this.wrapper = this.renderer.createElement('div');
                this.renderer.addClass(this.wrapper, 'eui-input-maxlength-wrapper');
                // swap, wrapper should wrap the nativeElement and maxLength span
                parent.replaceChild(this.wrapper, nativeElement);
                this.renderer.appendChild(this.wrapper, nativeElement);
                this.renderer.appendChild(this.wrapper, this.maxLengthSpan);
            }
        }
    }
    /**
     * @description
     * Removes the maxLength indicator box from the DOM.
     * Restores the original DOM structure by unwrapping the input element.
     *
     * @private
     */
    destroyMaxLengthBox() {
        // removes maxlength element from DOM
        if (this.maxLengthSpan) {
            this.renderer.removeChild(this.maxLengthSpan.parentElement, this.maxLengthSpan);
            this.maxLengthSpan = undefined;
        }
        // remove wrapper from DOM
        if (this.wrapper) {
            // get parent node of wrapper
            const parent = this.wrapper.parentNode;
            const nativeElement = this.el.nativeElement;
            // swap wrapper and nativeElement
            parent?.replaceChild(nativeElement, this.wrapper);
            // removes wrapper element from DOM
            this.renderer.removeChild(this.wrapper.parentElement, this.wrapper);
            this.wrapper = undefined;
        }
    }
    /**
     * @description
     * Returns the current value of the input element.
     * Handles different update strategies when used with forms.
     *
     * @returns {string} Current input value
     * @private
     */
    getValue() {
        const input = this.el.nativeElement;
        return this.control && this.control.control.updateOn === 'change' ? this.control.value : input.value;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiMaxLengthDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.16", type: EuiMaxLengthDirective, isStandalone: true, selector: "\n    input[euiMaxlength],\n    textarea[euiMaxlength],\n    [ngModel][euiMaxlength],\n    [formControlName][euiMaxlength]", inputs: { maxLength: ["euiMaxlength", "maxLength", numberAttribute], isShowMaxlength: ["isShowMaxlength", "isShowMaxlength", booleanAttribute] }, outputs: { maxLengthReached: "maxLengthReached" }, host: { listeners: { "change": "onChange()", "input": "onInput()", "paste": "onPaste($any($event))" } }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiMaxLengthDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: `
    input[euiMaxlength],
    textarea[euiMaxlength],
    [ngModel][euiMaxlength],
    [formControlName][euiMaxlength]`,
                }]
        }], ctorParameters: () => [], propDecorators: { maxLength: [{
                type: Input,
                args: [{ alias: 'euiMaxlength', transform: numberAttribute }]
            }], isShowMaxlength: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], maxLengthReached: [{
                type: Output
            }], onChange: [{
                type: HostListener,
                args: ['change']
            }], onInput: [{
                type: HostListener,
                args: ['input']
            }], onPaste: [{
                type: HostListener,
                args: ['paste', ['$any($event)']]
            }] } });

var ConditionOperator;
(function (ConditionOperator) {
    ConditionOperator["AND"] = "AND";
    ConditionOperator["OR"] = "OR";
})(ConditionOperator || (ConditionOperator = {}));
/**
 * Structural directive conditionally rendering content based on user permissions.
 * Checks permissions via EuiPermissionService and shows/hides content accordingly.
 * Supports single or multiple permission checks with AND/OR logical operators.
 * Similar to *ngIf but permission-based instead of boolean-based.
 *
 * @usageNotes
 * Single permission:
 * ```html
 * <button *euiHasPermission="['EDIT_USER']">Edit</button>
 * ```
 *
 * Multiple permissions (AND - all required):
 * ```html
 * <div *euiHasPermission="['READ_DATA', 'WRITE_DATA']">
 *   Admin content
 * </div>
 * ```
 *
 * Multiple permissions (OR - any required):
 * ```html
 * <div *euiHasPermission="['MANAGER', 'ADMIN']" euiHasPermissionOperator="OR">
 *   Manager or Admin content
 * </div>
 * ```
 *
 * ### Accessibility
 * - Content completely removed from DOM when permissions not granted
 * - No visual indication of hidden content to unauthorized users
 * - Screen readers will not encounter permission-restricted content
 *
 * ### Notes
 * - Default operator is AND (all permissions required)
 * - Use OR operator when any single permission should grant access
 * - Requires EuiPermissionService to be configured in application
 * - Permission checks happen synchronously on directive initialization and input changes
 */
class EuiHasPermissionDirective {
    constructor() {
        /**
         * @internal
         * Array storing the current permission requirements
         */
        this.permissions = signal([], ...(ngDevMode ? [{ debugName: "permissions" }] : /* istanbul ignore next */ []));
        /**
         * @internal
         * Logical operator for permission checks (AND/OR). Defaults to AND.
         */
        this.operator = signal(ConditionOperator.AND, ...(ngDevMode ? [{ debugName: "operator" }] : /* istanbul ignore next */ []));
        /**
         * @internal
         * Flag tracking whether the content is currently hidden
         */
        this.isHidden = true;
        this.templateRef = inject(TemplateRef);
        this.viewContainer = inject(ViewContainerRef);
        this.permissionService = inject(EuiPermissionService);
    }
    /**
     * Sets the logical operator for permission checks.
     * 'AND' requires all permissions, 'OR' requires at least one permission.
     * Default: 'AND'
     */
    set euiHasPermissionOperator(operator) {
        this.operator.set(operator || ConditionOperator.AND);
        this.updateView();
    }
    /**
     * Array of permission strings required to display the content.
     * Can be single permission or multiple permissions.
     */
    set euiHasPermission(val) {
        this.permissions.set(val);
        this.updateView();
    }
    /**
     * @internal
     * @description
     * Updates the view based on the current permission check results.
     * If permissions are granted, displays the content.
     * If permissions are not granted, hides the content.
     */
    updateView() {
        if (this.checkPermission()) {
            if (this.isHidden) {
                this.viewContainer.createEmbeddedView(this.templateRef);
                this.isHidden = false;
            }
        }
        else {
            this.isHidden = true;
            this.viewContainer.clear();
        }
    }
    /**
     * @internal
     * @description
     * Checks if all required permissions are granted.
     * Uses AND logic - all permissions must be granted for the method to return true.
     *
     * @returns {boolean} True if all permissions are granted, false otherwise
     */
    checkPermission() {
        if (this.operator() === ConditionOperator.OR) {
            return this.permissions().some((permission) => this.permissionService.checkAttributePermission(permission));
        }
        return this.permissions().every((permission) => this.permissionService.checkAttributePermission(permission));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiHasPermissionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.16", type: EuiHasPermissionDirective, isStandalone: true, selector: "[euiHasPermission]", inputs: { euiHasPermissionOperator: "euiHasPermissionOperator", euiHasPermission: "euiHasPermission" }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiHasPermissionDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[euiHasPermission]',
                }]
        }], propDecorators: { euiHasPermissionOperator: [{
                type: Input
            }], euiHasPermission: [{
                type: Input
            }] } });

/**
 * Directive toggling CSS class on app header when scrolling past a threshold.
 * Monitors window scroll position and adds 'shrink-header-active' class to app wrapper.
 * Requires specific DOM structure with 'app-wrapper' and 'app-header' element IDs.
 * Typically used for sticky headers that shrink or change appearance on scroll.
 *
 * @usageNotes
 * ```html
 * <div id="app-wrapper">
 *   <header id="app-header">Header content</header>
 *   <main [euiScrollHandler]="true">Main content</main>
 * </div>
 * ```
 *
 * ### Accessibility
 * - Visual feedback for scroll position
 * - Does not affect keyboard navigation or screen readers
 * - Ensure header remains accessible in both states
 *
 * ### Notes
 * - Requires elements with IDs 'app-wrapper' and 'app-header'
 * - Class 'shrink-header-active' added when scrolled past header height
 * - Scroll threshold automatically calculated from header height
 * - Set euiScrollHandler to false to disable
 */
class EuiScrollHandlerDirective {
    constructor() {
        this.navIsFixed = false;
        this.appHeaderHeight = 0;
        this.euiScrollHandler = false;
        this.document = inject(DOCUMENT);
    }
    ngOnInit() {
        this.appWrapper = this.document.getElementById('app-wrapper');
        this.appHeader = this.document.getElementById('app-header');
        if (this.appHeader) {
            this.appHeaderHeight = this.appHeader.scrollHeight;
        }
    }
    onWindowScroll() {
        if (this.euiScrollHandler && this.appHeaderHeight !== 0) {
            const number = this.document.body.scrollTop || this.document.documentElement.scrollTop; // Chrome || IE/FF
            if (number > this.appHeaderHeight) {
                this.navIsFixed = true;
                this.appWrapper.classList.add('shrink-header-active');
            }
            else if (this.navIsFixed && number < this.appHeaderHeight) {
                this.navIsFixed = false;
                this.appWrapper.classList.remove('shrink-header-active');
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiScrollHandlerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.16", type: EuiScrollHandlerDirective, isStandalone: true, selector: "[euiScrollHandler]", inputs: { euiScrollHandler: ["euiScrollHandler", "euiScrollHandler", booleanAttribute] }, host: { listeners: { "window:scroll": "onWindowScroll()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiScrollHandlerDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[euiScrollHandler]',
                }]
        }], propDecorators: { euiScrollHandler: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], onWindowScroll: [{
                type: HostListener,
                args: ['window:scroll', []]
            }] } });
/**
 * Directive toggling CSS class on any element when scrolling past a custom threshold.
 * More flexible alternative to euiScrollHandler with configurable element ID, class, and height.
 * Monitors window scroll and applies specified class when threshold exceeded.
 *
 * @usageNotes
 * ```html
 * <div euiScrollHandlerElement="myNav"
 *      toggleClass="nav-fixed"
 *      [toggleActiveHeight]="100">
 *   Navigation content
 * </div>
 * ```
 *
 * ### Accessibility
 * - Visual feedback for scroll position
 * - Does not affect keyboard navigation or screen readers
 * - Ensure element remains accessible in both states
 *
 * ### Notes
 * - Element ID specified via euiScrollHandlerElement input
 * - CSS class specified via toggleClass input
 * - Scroll threshold specified via toggleActiveHeight input (in pixels)
 * - Class added when scroll position exceeds toggleActiveHeight
 */
class EuiScrollHandlerElementDirective {
    constructor() {
        this.navIsFixed = false;
        this.document = inject(DOCUMENT);
    }
    onWindowScroll() {
        const element = this.document.getElementById(this.euiScrollHandlerElement);
        const number = this.document.body.scrollTop || this.document.documentElement.scrollTop; // Chrome || IE/FF
        if (number > this.toggleActiveHeight) {
            this.navIsFixed = true;
            element.classList.add(this.toggleClass);
        }
        else if (this.navIsFixed && number < this.toggleActiveHeight) {
            this.navIsFixed = false;
            element.classList.remove(this.toggleClass);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiScrollHandlerElementDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.16", type: EuiScrollHandlerElementDirective, isStandalone: true, selector: "[euiScrollHandlerElement]", inputs: { euiScrollHandlerElement: "euiScrollHandlerElement", toggleClass: "toggleClass", toggleActiveHeight: ["toggleActiveHeight", "toggleActiveHeight", numberAttribute] }, host: { listeners: { "window:scroll": "onWindowScroll()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiScrollHandlerElementDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[euiScrollHandlerElement]',
                }]
        }], propDecorators: { euiScrollHandlerElement: [{
                type: Input
            }], toggleClass: [{
                type: Input
            }], toggleActiveHeight: [{
                type: Input,
                args: [{ transform: numberAttribute }]
            }], onWindowScroll: [{
                type: HostListener,
                args: ['window:scroll', []]
            }] } });

/* https://www.npmjs.com/package/ng2-smooth-scroll
   https://github.com/kavil/ng2SmoothScroll/blob/master/lib/ng2-SmoothScroll.directive.ts
*/
/* eslint-disable */
/**
 * Directive scrolling smoothly to a target element when clicked.
 * Provides animated scroll with configurable duration, offset, and easing.
 * Supports scrolling within containers and callbacks before/after scroll.
 *
 * @usageNotes
 * ```html
 * <button euiScrollTo="targetSection">Scroll to section</button>
 * <div id="targetSection">Target content</div>
 * ```
 *
 * With options:
 * ```html
 * <a euiScrollTo="footer" [duration]="1000" [offset]="-50">Go to footer</a>
 * ```
 *
 * ### Accessibility
 * - Smooth scroll provides better UX than instant jump
 * - Ensure target element has proper focus management
 * - Consider reduced motion preferences for accessibility
 *
 * ### Notes
 * - Target element identified by ID via euiScrollTo input
 * - Default duration is 800ms
 * - Offset adjusts final scroll position (negative scrolls higher)
 * - Supports multiple easing functions (easeInOutQuart default)
 * - Can scroll within specific container via containerId
 */
class EuiSmoothScrollToDirective {
    onClick() {
        this.targetElement = document.getElementById(this.scrollTo);
        if (!this.targetElement) {
            return;
        }
        new SmoothScroll(this.targetElement, {
            duration: this.duration,
            offset: this.offset,
            easing: this.easing,
            callbackBefore: this.callbackBefore,
            callbackAfter: this.callbackAfter,
            containerId: this.containerId,
            middleAlign: this.middleAlign
        });
    }
    ;
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiSmoothScrollToDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.16", type: EuiSmoothScrollToDirective, isStandalone: true, selector: "[euiScrollTo]", inputs: { scrollTo: ["euiScrollTo", "scrollTo"], duration: ["duration", "duration", numberAttribute], offset: ["offset", "offset", numberAttribute], easing: "easing", callbackBefore: "callbackBefore", callbackAfter: "callbackAfter", containerId: "containerId", middleAlign: "middleAlign" }, host: { listeners: { "click": "onClick()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiSmoothScrollToDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[euiScrollTo]',
                }]
        }], propDecorators: { scrollTo: [{
                type: Input,
                args: ['euiScrollTo']
            }], duration: [{
                type: Input,
                args: [{ alias: 'duration', transform: numberAttribute }]
            }], offset: [{
                type: Input,
                args: [{ transform: numberAttribute }]
            }], easing: [{
                type: Input,
                args: ['easing']
            }], callbackBefore: [{
                type: Input,
                args: ['callbackBefore']
            }], callbackAfter: [{
                type: Input,
                args: ['callbackAfter']
            }], containerId: [{
                type: Input,
                args: ['containerId']
            }], middleAlign: [{
                type: Input,
                args: ['middleAlign']
            }], onClick: [{
                type: HostListener,
                args: ['click']
            }] } });
/**
 * Directive automatically scrolling to host element on initialization or click.
 * Provides animated scroll with configurable duration, offset, and easing.
 * Supports conditional scrolling and callbacks before/after scroll.
 *
 * @usageNotes
 * Scroll on init:
 * ```html
 * <div euiSmoothScroll [scrollIf]="shouldScroll">Content</div>
 * ```
 *
 * Scroll on click:
 * ```html
 * <div euiSmoothScroll [scrollOnClick]="true" [duration]="500">Click to scroll here</div>
 * ```
 *
 * ### Accessibility
 * - Smooth scroll provides better UX than instant jump
 * - Use scrollIf to conditionally enable scrolling
 * - Consider reduced motion preferences for accessibility
 *
 * ### Notes
 * - Scrolls to host element automatically on init (unless scrollIf is false)
 * - Set scrollOnClick to true for click-triggered scrolling
 * - Default duration is 800ms
 * - Offset adjusts final scroll position
 * - Supports scrolling within specific container via containerId
 * - middleAlign centers element in viewport
 */
class EuiSmoothScrollDirective {
    constructor() {
        this.platformId = inject(PLATFORM_ID);
        this.el = inject(ElementRef);
    }
    onClick(target) {
        if (this.scrollOnClick) {
            this.scroll();
        }
    }
    ;
    ngOnInit() {
        this.scroll();
    }
    scroll() {
        if (typeof this.scrollIf === 'undefined' || this.scrollIf === true) {
            if (isPlatformBrowser(this.platformId)) {
                setTimeout(() => {
                    new SmoothScroll(this.el.nativeElement, {
                        duration: this.duration,
                        offset: this.offset,
                        easing: this.easing,
                        callbackBefore: this.callbackBefore,
                        callbackAfter: this.callbackAfter,
                        containerId: this.containerId,
                        middleAlign: this.middleAlign
                    });
                }, 0);
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiSmoothScrollDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.16", type: EuiSmoothScrollDirective, isStandalone: true, selector: "[euiSmoothScroll]", inputs: { scrollIf: "scrollIf", duration: ["duration", "duration", numberAttribute], offset: ["offset", "offset", numberAttribute], easing: "easing", callbackBefore: "callbackBefore", callbackAfter: "callbackAfter", containerId: "containerId", scrollOnClick: ["scrollOnClick", "scrollOnClick", booleanAttribute], middleAlign: "middleAlign" }, host: { listeners: { "click": "onClick($event.target)" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiSmoothScrollDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[euiSmoothScroll]',
                }]
        }], propDecorators: { scrollIf: [{
                type: Input,
                args: ['scrollIf']
            }], duration: [{
                type: Input,
                args: [{ transform: numberAttribute }]
            }], offset: [{
                type: Input,
                args: [{ transform: numberAttribute }]
            }], easing: [{
                type: Input,
                args: ['easing']
            }], callbackBefore: [{
                type: Input,
                args: ['callbackBefore']
            }], callbackAfter: [{
                type: Input,
                args: ['callbackAfter']
            }], containerId: [{
                type: Input,
                args: ['containerId']
            }], scrollOnClick: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], middleAlign: [{
                type: Input,
                args: ['middleAlign']
            }], onClick: [{
                type: HostListener,
                args: ['click', ['$event.target']]
            }] } });
class SmoothScroll {
    constructor(element, options) {
        this.smoothScroll(element, options);
    }
    smoothScroll(element, options) {
        options = options || {};
        // Options
        let duration = options.duration || 800, offset = options.offset || 0, easing = options.easing || 'easeInOutQuart', callbackBefore = options.callbackBefore || function () { }, callbackAfter = options.callbackAfter || function () { }, container = document.getElementById(options.containerId) || null, containerPresent = (container != undefined && container != null), middleAlign = options.middleAlign || false;
        /**
         * Retrieve current location
         */
        let getScrollLocation = function () {
            if (containerPresent) {
                return container.scrollTop;
            }
            else {
                if (window.pageYOffset) {
                    return window.pageYOffset;
                }
                else {
                    return document.documentElement.scrollTop;
                }
            }
        };
        /**
         * Calculate easing pattern.
         *
         * 20150713 edit - zephinzer
         * - changed if-else to switch
         * @see http://archive.oreilly.com/pub/a/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html
         */
        let getEasingPattern = function (type, time) {
            switch (type) {
                case 'easeInQuad': return time * time; // accelerating from zero velocity
                case 'easeOutQuad': return time * (2 - time); // decelerating to zero velocity
                case 'easeInOutQuad': return time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
                case 'easeInCubic': return time * time * time; // accelerating from zero velocity
                case 'easeOutCubic': return (--time) * time * time + 1; // decelerating to zero velocity
                case 'easeInOutCubic': return time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
                case 'easeInQuart': return time * time * time * time; // accelerating from zero velocity
                case 'easeOutQuart': return 1 - (--time) * time * time * time; // decelerating to zero velocity
                case 'easeInOutQuart': return time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
                case 'easeInQuint': return time * time * time * time * time; // accelerating from zero velocity
                case 'easeOutQuint': return 1 + (--time) * time * time * time * time; // decelerating to zero velocity
                case 'easeInOutQuint': return time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
                default: return time;
            }
        };
        /**
         * Calculate how far to scroll
         */
        let getEndLocation = function (element) {
            let location = 0, elementRect = element.getBoundingClientRect(), absoluteElementTop = elementRect.top + window.pageYOffset;
            if (middleAlign) {
                location = (absoluteElementTop + (element.offsetHeight / 2)) - (window.innerHeight / 2);
            }
            else {
                location = absoluteElementTop;
            }
            if (offset) {
                location = location - offset;
            }
            return Math.max(location, 0);
        };
        // Initialize the whole thing
        setTimeout(function () {
            let currentLocation = null, startLocation = getScrollLocation(), endLocation = getEndLocation(element), timeLapsed = 0, distance = endLocation - startLocation, percentage, position, scrollHeight, internalHeight;
            /**
             * Stop the scrolling animation when the anchor is reached (or at the top/bottom of the page)
             */
            let stopAnimation = function () {
                currentLocation = getScrollLocation();
                if (containerPresent) {
                    scrollHeight = container.scrollHeight;
                    internalHeight = container.clientHeight + currentLocation;
                }
                else {
                    scrollHeight = document.body.scrollHeight;
                    internalHeight = window.innerHeight + currentLocation;
                }
                if (( // condition 1
                position == endLocation) ||
                    ( // condition 2
                    currentLocation == endLocation) ||
                    ( // condition 3
                    internalHeight > scrollHeight)) { // stop
                    clearInterval(runAnimation);
                    callbackAfter(element);
                }
            };
            /**
             * Scroll the page by an increment, and check if it's time to stop
             */
            let animateScroll = function () {
                timeLapsed += 16;
                percentage = (timeLapsed / duration);
                percentage = (percentage > 1) ? 1 : percentage;
                position = startLocation + (distance * getEasingPattern(easing, percentage));
                if (containerPresent) {
                    container.scrollTop = position;
                }
                else {
                    window.scrollTo(0, position);
                }
                stopAnimation();
            };
            callbackBefore(element);
            let runAnimation = setInterval(animateScroll, 16);
        }, 0);
    }
}

/**
 * Directive adding a clear button to text and number input fields for quick value reset.
 * Dynamically creates a close icon that appears when input has content and clears value on click.
 * Automatically handles form control integration and disabled/readonly states.
 * Only works with euiInputText and euiInputNumber input types.
 *
 * @usageNotes
 * ```html
 * <input euiInputText euiClearable [(ngModel)]="searchTerm" />
 * ```
 *
 * ```html
 * <input euiInputNumber euiClearable formControlName="amount" />
 * ```
 *
 * ### Accessibility
 * - Clear icon has aria-label="Clear input field" for screen readers
 * - Icon is keyboard accessible with Enter key support
 * - Icon hidden when input is empty to avoid confusion
 * - Disabled state removes keyboard access and pointer events
 *
 * ### Notes
 * - Only compatible with text, search, and eui-number input types
 * - Clear icon visibility toggles based on input value presence
 * - Works with both ngModel and reactive forms
 * - Dispatches 'clear' event when value is cleared
 * - Automatically manages wrapper div for icon positioning
 */
class EuiClearableDirective {
    constructor() {
        this._elementRef = inject(ElementRef);
        this._viewContainerRef = inject(ViewContainerRef);
        this._renderer = inject(Renderer2);
        this.injector = inject(Injector);
    }
    get readonly() {
        return this._isReadonly ? '' : null;
    }
    set readonly(v) {
        this._isReadonly = coerceBooleanProperty(v);
    }
    get disabled() {
        return this._disabled ? '' : null;
    }
    set disabled(v) {
        this._disabled = coerceBooleanProperty(v);
    }
    get cssClasses() {
        return [this._cssClasses, this.euiClearable ? `${this._elementRef.nativeElement.rootClassName}--clearable` : ''].join(' ').trim();
    }
    set cssClasses(value) {
        this._cssClasses = value;
    }
    ngAfterViewInit() {
        if (this._clearableIcon) {
            const control = this.injector.get(NgControl, null, { optional: true });
            const value = control
                ? control instanceof NgModel
                    ? control.model?.toString()
                    : control.value?.toString()
                : this._elementRef.nativeElement.value;
            this._renderer.setStyle(this._clearableIcon.location.nativeElement, 'visibility', value?.length > 0 ? 'visible' : 'hidden');
        }
    }
    ngOnChanges(changes) {
        if (changes.euiClearable) {
            // get a type of the control
            const type = this._elementRef.nativeElement.type;
            if (coerceBooleanProperty(changes['euiClearable'].currentValue)) {
                // check if the type is not euiInputNumber or euiInputText, reset and throw error
                if (type !== 'eui-number' && type !== 'text' && type !== 'search') {
                    this.euiClearable = true;
                    throw new Error('euiClearable is only allowed in euiInputNumber or euiInputText');
                }
                // dynamically create the icon
                this.createClearableIcon();
                // wrap them all in an eui-u-flex class
                this.createFlexWrapper();
                this._renderer.appendChild(this._euiUFlexWrapper, this._clearableIcon.location.nativeElement);
            }
            else if (this._clearableIcon) {
                this.removeClearableIcon();
                const euiLoading = this.injector.get(EuiLoadingDirective, null, { optional: true })?.euiLoading;
                if (!euiLoading) {
                    this.removeFlexWrapper();
                }
            }
        }
        if (changes['readonly']) {
            if (changes['readonly'].currentValue === false && this.euiClearable) {
                // create wrapper
                this.createFlexWrapper();
                // dynamically create the icon
                this.createClearableIcon();
                this._renderer.appendChild(this._euiUFlexWrapper, this._clearableIcon.location.nativeElement);
            }
            if (changes['readonly'].currentValue === true) {
                this.removeClearableIcon();
                this.removeFlexWrapper();
            }
        }
        if (changes['disabled']) {
            if (this._clearableIcon) {
                const disabled = changes['disabled']?.currentValue;
                if (disabled) {
                    this._renderer.setStyle(this._clearableIcon.location.nativeElement, 'pointer-events', 'none');
                    this._renderer.removeAttribute(this._clearableIcon.location.nativeElement, 'tabindex');
                }
                else {
                    this._renderer.removeStyle(this._clearableIcon.location.nativeElement, 'pointer-events');
                    this._renderer.setAttribute(this._clearableIcon.location.nativeElement, 'tabindex', '0');
                }
            }
        }
    }
    onKeyUpAndModelChange(value) {
        if (this.euiClearable) {
            const visibility = value?.toString().length > 0 ? 'visible' : 'hidden';
            this._renderer.setStyle(this._clearableIcon.location.nativeElement, 'visibility', visibility);
        }
    }
    onClearableClicked() {
        if (this._elementRef.nativeElement.disabled) {
            return;
        }
        const control = this.injector.get(NgControl, undefined, { optional: true });
        if (control) {
            control.reset();
        }
        else {
            const inputEvent = new InputEvent('input', { data: null });
            this._elementRef.nativeElement.value = null;
            this._elementRef.nativeElement.dispatchEvent(inputEvent);
        }
        const clearEvent = new InputEvent('clear');
        this._elementRef.nativeElement.dispatchEvent(clearEvent);
        this._elementRef.nativeElement.focus();
    }
    /**
     * creates the Clearable icon component
     *
     * @private
     */
    createClearableIcon() {
        if (!this._clearableIcon) {
            // TODO: turn import of EuiIconSvgComponent into a type?
            this._clearableIcon = this._viewContainerRef.createComponent(EuiIconSvgComponent);
            this._clearableIcon.instance.set = 'eui';
            this._clearableIcon.instance.icon = 'eui-close';
            this._clearableIcon.instance.ariaLabel = 'Clear input field';
            this._renderer.addClass(this._clearableIcon.location.nativeElement, 'eui-input-text--clearable-icon');
            this._renderer.listen(this._clearableIcon.location.nativeElement, 'click', this.onClearableClicked.bind(this));
            this._renderer.listen(this._clearableIcon.location.nativeElement, 'keydown.enter', this.onClearableClicked.bind(this));
            const control = this.injector.get(NgControl, null, { optional: true });
            const value = control
                ? control instanceof NgModel
                    ? control.model?.toString()
                    : control.value?.toString()
                : this._elementRef.nativeElement.value;
            this._renderer.setStyle(this._clearableIcon.location.nativeElement, 'visibility', value?.length > 0 ? 'visible' : 'hidden');
            if (!this._elementRef.nativeElement.disabled) {
                this._renderer.setAttribute(this._clearableIcon.location.nativeElement, 'tabindex', '0');
                this._clearableIcon.instance.ariaRole = 'button';
                this._clearableIcon.instance.ariaHidden = false;
            }
            else {
                this._renderer.setStyle(this._clearableIcon.location.nativeElement, 'pointer-events', 'none');
            }
        }
    }
    /**
     * detach the Clearable icon from the view
     *
     * @private
     */
    removeClearableIcon() {
        if (this._clearableIcon) {
            const index = this._viewContainerRef.indexOf(this._clearableIcon.hostView);
            this._viewContainerRef.detach(index);
            this._clearableIcon = null;
        }
    }
    /**
     * create a flex wrapper for the input to hold the icon
     *
     * @private
     */
    createFlexWrapper() {
        if (!this._euiUFlexWrapper && !this.doesParentHasAFlexWrapper()) {
            this._euiUFlexWrapper = this._renderer.createElement('div');
            this._renderer.addClass(this._euiUFlexWrapper, 'eui-u-flex');
            this._renderer.addClass(this._euiUFlexWrapper, 'eui-u-p-relative');
            this._renderer.setAttribute(this._euiUFlexWrapper, 'flexWrapper', null);
            this._renderer.insertBefore(this._elementRef.nativeElement.parentElement, this._euiUFlexWrapper, this._elementRef.nativeElement);
            this._renderer.appendChild(this._euiUFlexWrapper, this._elementRef.nativeElement);
        }
        if (!this._euiUFlexWrapper && this.doesParentHasAFlexWrapper()) {
            this._euiUFlexWrapper = this._elementRef.nativeElement.parentElement;
        }
    }
    /**
     * checks if the parent has a flexWrapper. This is used to avoid creating multiple flexWrappers
     *
     * @private
     */
    doesParentHasAFlexWrapper() {
        return this._elementRef.nativeElement.parentElement.hasAttribute('flexWrapper');
    }
    /**
     * removes the flexWrapper while keeping the input element intact
     *
     * @private
     */
    removeFlexWrapper() {
        if (this._euiUFlexWrapper) {
            this._renderer.insertBefore(this._euiUFlexWrapper.parentElement, this._elementRef.nativeElement, this._euiUFlexWrapper);
            this._renderer.removeChild(this._euiUFlexWrapper.parentElement, this._euiUFlexWrapper);
            this._euiUFlexWrapper.remove();
            this._euiUFlexWrapper = null;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiClearableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.16", type: EuiClearableDirective, isStandalone: true, selector: "input[euiClearable]", inputs: { euiClearable: ["euiClearable", "euiClearable", booleanAttribute], readonly: "readonly", disabled: "disabled" }, host: { listeners: { "input": "onKeyUpAndModelChange($any($event.target).value)", "ngModelChange": "onKeyUpAndModelChange($event)" }, properties: { "attr.readonly": "this.readonly", "disabled": "this.disabled", "class": "this.cssClasses" } }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiClearableDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: 'input[euiClearable]',
                }]
        }], propDecorators: { euiClearable: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], readonly: [{
                type: HostBinding,
                args: ['attr.readonly']
            }, {
                type: Input
            }], disabled: [{
                type: HostBinding,
                args: ['disabled']
            }, {
                type: Input
            }], cssClasses: [{
                type: HostBinding,
                args: ['class']
            }], onKeyUpAndModelChange: [{
                type: HostListener,
                args: ['input', ['$any($event.target).value']]
            }, {
                type: HostListener,
                args: ['ngModelChange', ['$event']]
            }] } });

/**
 * Directive displaying a loading spinner icon inside input fields during async operations.
 * Dynamically creates and positions a loading icon that appears when euiLoading is true.
 * Automatically manages wrapper div for icon positioning and handles readonly state.
 * Compatible with euiClearable directive for combined loading and clear functionality.
 *
 * @usageNotes
 * ```html
 * <input euiInputText [euiLoading]="isSearching" [(ngModel)]="searchTerm" />
 * ```
 *
 * ```typescript
 * isSearching = false;
 *
 * onSearch() {
 *   this.isSearching = true;
 *   this.api.search().subscribe(() => this.isSearching = false);
 * }
 * ```
 *
 * ### Accessibility
 * - Loading icon positioned at end of input for visual feedback
 * - Input becomes readonly while loading to prevent changes during operation
 * - Icon has aria-label for screen reader announcement
 *
 * ### Notes
 * - Loading icon automatically positioned at input end
 * - Works alongside euiClearable directive without conflicts
 * - Wrapper div created automatically for icon positioning
 * - Input set to readonly state when loading is active
 */
class EuiLoadingDirective {
    constructor() {
        this._elementRef = inject(ElementRef);
        this._viewContainerRef = inject(ViewContainerRef);
        this._renderer = inject(Renderer2);
        this.injector = inject(Injector);
    }
    get readonly() {
        return this._isReadonly ? '' : null;
    }
    set readonly(v) {
        this._isReadonly = coerceBooleanProperty(v);
    }
    get cssClasses() {
        return [this._cssClasses, this.euiLoading ? `${this._elementRef.nativeElement.rootClassName}--loading` : ''].join(' ').trim();
    }
    set cssClasses(value) {
        this._cssClasses = value;
    }
    ngOnChanges(changes) {
        if (changes.euiLoading) {
            const euiClearable = this.injector.get(EuiClearableDirective, undefined, { optional: true })?.euiClearable;
            if (coerceBooleanProperty(changes['euiLoading'].currentValue)) {
                // wrap them all in an eui-u-flex class
                this.createFlexWrapper();
                // dynamically create the icon
                this.createLoadingIcon();
            }
            else if (this._loadingIcon) {
                this.removeLoadingIcon();
                if (!euiClearable) {
                    this.removeFlexWrapper();
                }
            }
        }
        if (changes['readonly']) {
            if (changes['readonly'].currentValue === false && this.euiLoading) {
                // create wrapper
                this.createFlexWrapper();
                // dynamically create the icon
                this.createLoadingIcon();
                this._renderer.appendChild(this._euiUFlexWrapper, this._loadingIcon.location.nativeElement);
            }
            if (changes['readonly'].currentValue === true) {
                this.removeLoadingIcon();
                this.removeFlexWrapper();
            }
        }
    }
    /**
     * create a flex wrapper for the input to hold the icon
     *
     * @private
     */
    createFlexWrapper() {
        if (!this._euiUFlexWrapper && !this.doesParentHasAFlexWrapper()) {
            this._euiUFlexWrapper = this._renderer.createElement('div');
            this._renderer.addClass(this._euiUFlexWrapper, 'eui-u-flex');
            this._renderer.setAttribute(this._euiUFlexWrapper, 'flexWrapper', null);
            this._renderer.setStyle(this._euiUFlexWrapper, 'position', 'relative');
            this._renderer.insertBefore(this._elementRef.nativeElement.parentElement, this._euiUFlexWrapper, this._elementRef.nativeElement);
            this._renderer.appendChild(this._euiUFlexWrapper, this._elementRef.nativeElement);
        }
        if (!this._euiUFlexWrapper && this.doesParentHasAFlexWrapper()) {
            this._euiUFlexWrapper = this._elementRef.nativeElement.parentElement;
        }
    }
    /**
     * checks if the parent has a flexWrapper. This is used to avoid creating multiple flexWrappers
     *
     * @private
     */
    doesParentHasAFlexWrapper() {
        return this._elementRef.nativeElement.parentElement.hasAttribute('flexWrapper');
    }
    /**
     * removes the flexWrapper while keeping the input element intact
     *
     * @private
     */
    removeFlexWrapper() {
        if (this._euiUFlexWrapper) {
            this._renderer.insertBefore(this._euiUFlexWrapper.parentElement, this._elementRef.nativeElement, this._euiUFlexWrapper);
            this._renderer.removeChild(this._euiUFlexWrapper.parentElement, this._euiUFlexWrapper);
            this._euiUFlexWrapper.remove();
            this._euiUFlexWrapper = null;
        }
    }
    /**
     * creates the loading icon component
     *
     * @private
     */
    createLoadingIcon() {
        if (!this._loadingIcon) {
            this._loadingIcon = this._viewContainerRef.createComponent(EuiIconSvgComponent);
            this._loadingIcon.instance.isLoading = true;
            this._loadingIcon.instance.isInputIcon = true;
            this._loadingIcon.instance.euiEnd = true;
            this._loadingIcon.instance.ariaLabel = 'XXXXX';
            this._renderer.appendChild(this._euiUFlexWrapper, this._loadingIcon.location.nativeElement);
        }
    }
    /**
     * removes the loading icon component
     *
     * @private
     */
    removeLoadingIcon() {
        if (this._loadingIcon) {
            const index = this._viewContainerRef.indexOf(this._loadingIcon.hostView);
            this._viewContainerRef.detach(index);
            this._loadingIcon = null;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiLoadingDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.16", type: EuiLoadingDirective, isStandalone: true, selector: "[euiLoading]", inputs: { euiLoading: ["euiLoading", "euiLoading", booleanAttribute], readonly: "readonly" }, host: { properties: { "attr.readonly": "this.readonly", "class": "this.cssClasses" } }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiLoadingDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[euiLoading]',
                }]
        }], propDecorators: { euiLoading: [{
                type: Input,
                args: [{ transform: booleanAttribute }]
            }], readonly: [{
                type: HostBinding,
                args: ['attr.readonly']
            }, {
                type: Input
            }], cssClasses: [{
                type: HostBinding,
                args: ['class']
            }] } });

/**
 * A resizable container component that allows users to dynamically adjust the width of its content.
 * The component provides a draggable handle positioned on either the left or right edge, enabling
 * flexible layout adjustments. Commonly used for collapsible sidebars, adjustable panels, or
 * responsive content areas where users need manual control over element dimensions.
 */
class EuiResizableComponent {
    constructor() {
        /**
         * Determines the placement of the resizable handle and the direction of resize behavior.
         * When set to 'left', the handle appears on the left edge and resizing expands/contracts from the left.
         * When set to 'right', the handle appears on the right edge and resizing expands/contracts from the right.
         * @default 'right'
         */
        this.position = input('right', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
        /** Accessible label for the separator handle. */
        this.ariaLabel = input('Press the left or right arrow key to resize the panel', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
        /** Current width value in pixels for aria-valuenow. */
        this.ariaValueNow = input(undefined, ...(ngDevMode ? [{ debugName: "ariaValueNow" }] : /* istanbul ignore next */ []));
        /** Minimum width value in pixels for aria-valuemin. */
        this.ariaValueMin = input(0, ...(ngDevMode ? [{ debugName: "ariaValueMin" }] : /* istanbul ignore next */ []));
        /** Maximum width value in pixels for aria-valuemax. */
        this.ariaValueMax = input(undefined, ...(ngDevMode ? [{ debugName: "ariaValueMax" }] : /* istanbul ignore next */ []));
        /** Determines if the resizable feature is disable or not */
        this.euiResizableHidden = input(false, { ...(ngDevMode ? { debugName: "euiResizableHidden" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
        this.e2e = 'eui-resizable';
    }
    get cssClasses() {
        return [
            'eui-resizable',
            this.position() === 'left' ? 'eui-resizable--left' : 'eui-resizable--right',
            this.euiResizableHidden() ? 'eui-resizable--disabled' : '',
        ].join(' ').trim();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiResizableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.16", type: EuiResizableComponent, isStandalone: true, selector: "eui-resizable", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaValueNow: { classPropertyName: "ariaValueNow", publicName: "ariaValueNow", isSignal: true, isRequired: false, transformFunction: null }, ariaValueMin: { classPropertyName: "ariaValueMin", publicName: "ariaValueMin", isSignal: true, isRequired: false, transformFunction: null }, ariaValueMax: { classPropertyName: "ariaValueMax", publicName: "ariaValueMax", isSignal: true, isRequired: false, transformFunction: null }, euiResizableHidden: { classPropertyName: "euiResizableHidden", publicName: "euiResizableHidden", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.cssClasses", "attr.data-e2e": "this.e2e" } }, ngImport: i0, template: "<div class=\"eui-resizable-icon__container\">\n    <eui-icon-svg icon=\"eui-arrows-left-right\" size=\"xs\" fillColor=\"primary\" class=\"eui-resizable-icon\"/>\n</div>\n<div\n    class=\"eui-resizable-bar\"\n    role=\"separator\"\n    aria-orientation=\"vertical\"\n    tabindex=\"0\"\n    [attr.aria-label]=\"ariaLabel()\"\n    [attr.aria-valuenow]=\"ariaValueNow()\"\n    [attr.aria-valuemin]=\"ariaValueMin()\"\n    [attr.aria-valuemax]=\"ariaValueMax()\"\n></div>\n", styles: [".eui-21 .eui-resizable{display:flex;vertical-align:middle}.eui-21 .eui-resizable--left{justify-content:flex-start}.eui-21 .eui-resizable--left .eui-resizable-bar{left:15px}.eui-21 .eui-resizable--right{justify-content:flex-end}.eui-21 .eui-resizable--disabled{display:none}.eui-21 .eui-resizable .eui-resizable-bar{background:var(--eui-c-primary-surface);background-clip:content-box;bottom:0;border-left:var(--eui-s-3xs) solid transparent;border-right:var(--eui-s-3xs) solid transparent;cursor:ew-resize;margin:0 calc(-1.1 * var(--eui-s-m));opacity:var(--eui-o-none);position:absolute;top:0;transition:opacity .3s;width:var(--eui-s-s)}.eui-21 .eui-resizable .eui-resizable-bar:focus:not([readonly]){outline:2px solid var(--eui-c-focus)!important;outline-offset:-2px!important;transition:none}.eui-21 .eui-resizable .eui-resizable-bar:focus-visible:not([readonly]){outline:2px solid var(--eui-c-focus-visible)!important;outline-offset:-2px!important;transition:none}.eui-21 .eui-resizable .eui-resizable-bar [tabindex=\"0\"]:focus:not([readonly]){outline:2px solid var(--eui-c-focus-visible)!important;outline-offset:-2px!important;transition:none}.eui-21 .eui-resizable .eui-resizable-bar:hover,.eui-21 .eui-resizable .eui-resizable-bar:active,.eui-21 .eui-resizable .eui-resizable-bar:focus{opacity:var(--eui-o-100)}.eui-21 .eui-resizable .eui-resizable-icon__container{height:var(--eui-s-m);margin-right:calc(-1 * (var(--eui-s-m) + var(--eui-s-3xs)));position:absolute;top:calc(-1 * var(--eui-s-3xs));transform:translateY(calc(var(--eui-s-m) + 2px))}.eui-21 .eui-resizable .eui-resizable-icon__container .eui-resizable-icon{color:var(--eui-c-primary);fill:var(--eui-c-primary);height:var(--eui-is-s);width:var(--eui-is-s)}.eui-21 *:not(th)[euiresizable]{position:relative}\n"], dependencies: [{ kind: "component", type: i1.EuiIconSvgComponent, selector: "eui-icon-svg, span[euiIconSvg], i[euiIconSvg]", inputs: ["icon", "fillColor", "set", "size", "style", "iconUrl", "transform", "ariaLabel", "ariaHidden", "focusable", "isLoading", "isInputIcon", "euiStart", "euiEnd"] }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiResizableComponent, decorators: [{
            type: Component,
            args: [{ selector: 'eui-resizable', encapsulation: ViewEncapsulation.None, imports: [
                        ...EUI_ICON,
                    ], standalone: true, template: "<div class=\"eui-resizable-icon__container\">\n    <eui-icon-svg icon=\"eui-arrows-left-right\" size=\"xs\" fillColor=\"primary\" class=\"eui-resizable-icon\"/>\n</div>\n<div\n    class=\"eui-resizable-bar\"\n    role=\"separator\"\n    aria-orientation=\"vertical\"\n    tabindex=\"0\"\n    [attr.aria-label]=\"ariaLabel()\"\n    [attr.aria-valuenow]=\"ariaValueNow()\"\n    [attr.aria-valuemin]=\"ariaValueMin()\"\n    [attr.aria-valuemax]=\"ariaValueMax()\"\n></div>\n", styles: [".eui-21 .eui-resizable{display:flex;vertical-align:middle}.eui-21 .eui-resizable--left{justify-content:flex-start}.eui-21 .eui-resizable--left .eui-resizable-bar{left:15px}.eui-21 .eui-resizable--right{justify-content:flex-end}.eui-21 .eui-resizable--disabled{display:none}.eui-21 .eui-resizable .eui-resizable-bar{background:var(--eui-c-primary-surface);background-clip:content-box;bottom:0;border-left:var(--eui-s-3xs) solid transparent;border-right:var(--eui-s-3xs) solid transparent;cursor:ew-resize;margin:0 calc(-1.1 * var(--eui-s-m));opacity:var(--eui-o-none);position:absolute;top:0;transition:opacity .3s;width:var(--eui-s-s)}.eui-21 .eui-resizable .eui-resizable-bar:focus:not([readonly]){outline:2px solid var(--eui-c-focus)!important;outline-offset:-2px!important;transition:none}.eui-21 .eui-resizable .eui-resizable-bar:focus-visible:not([readonly]){outline:2px solid var(--eui-c-focus-visible)!important;outline-offset:-2px!important;transition:none}.eui-21 .eui-resizable .eui-resizable-bar [tabindex=\"0\"]:focus:not([readonly]){outline:2px solid var(--eui-c-focus-visible)!important;outline-offset:-2px!important;transition:none}.eui-21 .eui-resizable .eui-resizable-bar:hover,.eui-21 .eui-resizable .eui-resizable-bar:active,.eui-21 .eui-resizable .eui-resizable-bar:focus{opacity:var(--eui-o-100)}.eui-21 .eui-resizable .eui-resizable-icon__container{height:var(--eui-s-m);margin-right:calc(-1 * (var(--eui-s-m) + var(--eui-s-3xs)));position:absolute;top:calc(-1 * var(--eui-s-3xs));transform:translateY(calc(var(--eui-s-m) + 2px))}.eui-21 .eui-resizable .eui-resizable-icon__container .eui-resizable-icon{color:var(--eui-c-primary);fill:var(--eui-c-primary);height:var(--eui-is-s);width:var(--eui-is-s)}.eui-21 *:not(th)[euiresizable]{position:relative}\n"] }]
        }], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaValueNow: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaValueNow", required: false }] }], ariaValueMin: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaValueMin", required: false }] }], ariaValueMax: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaValueMax", required: false }] }], euiResizableHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "euiResizableHidden", required: false }] }], cssClasses: [{
                type: HostBinding,
                args: ['class']
            }], e2e: [{
                type: HostBinding,
                args: ['attr.data-e2e']
            }] } });

/**
 * Ensures the value is a non-negative pixel number.
 * @param value
 */
const pixelTransform = (value) => {
    value = numberAttribute(value, 0);
    return Math.max(0, value);
};
/**
 * Enables interactive resizing of a container element by dragging a handle.
 * Applies width constraints dynamically and supports left or right-side handle placement.
 * Intended for use in layouts requiring user-adjustable panel widths, such as sidebars or split views.
 */
class EuiResizableDirective {
    constructor() {
        /**
         * Minimum width constraint for the resizable container in pixels. Prevents the container from being resized below this value.
         * Accepts string or number values, automatically converted to non-negative pixels. Defaults to 0.
         */
        this.euiResizableMinWidth = input(0, { ...(ngDevMode ? { debugName: "euiResizableMinWidth" } : /* istanbul ignore next */ {}), transform: pixelTransform });
        /**
         * Determines the placement of the resizable handle and the direction of resizing behavior.
         * 'left' positions the handle on the left edge; 'right' positions it on the right edge. Defaults to 'right'.
         */
        this.euiResizablePosition = input('right', ...(ngDevMode ? [{ debugName: "euiResizablePosition" }] : /* istanbul ignore next */ []));
        /**
         * Determines if the resizable directive is affecting eui-app-side-container
         */
        this.euiResizableSideContainer = input(false, { ...(ngDevMode ? { debugName: "euiResizableSideContainer" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
        /**
         * Determines if the resizable feature is disable or not
         */
        this.euiResizableHidden = input(false, { ...(ngDevMode ? { debugName: "euiResizableHidden" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
        /**
         * Accessible label for the separator handle.
         * @default 'Press the left or right arrow key to resize the panel'
         */
        this.euiResizableAriaLabel = input('Press the left or right arrow key to resize the panel', ...(ngDevMode ? [{ debugName: "euiResizableAriaLabel" }] : /* istanbul ignore next */ []));
        /**
         * Maximum width constraint for the resizable container in pixels.
         * Used for aria-valuemax on the separator handle.
         */
        this.euiResizableMaxWidth = input(undefined, { ...(ngDevMode ? { debugName: "euiResizableMaxWidth" } : /* istanbul ignore next */ {}), transform: pixelTransform });
        /**
         * Step size in pixels for keyboard arrow key resizing.
         * @default 10
         */
        this.euiResizableKeyStep = input(10, { ...(ngDevMode ? { debugName: "euiResizableKeyStep" } : /* istanbul ignore next */ {}), transform: pixelTransform });
        this.destroy$ = new Subject();
        this.interaction$ = new Subject();
        this._initialized = false;
        this._documentRef = inject(DOCUMENT);
        this._elementRef = inject(ElementRef);
        this._renderer = inject(Renderer2);
        this._viewContainerRef = inject(ViewContainerRef);
        this.cd = inject(ChangeDetectorRef);
        effect(() => {
            const disabled = this.euiResizableHidden();
            if (this._resizableBar) {
                this._resizableBar.setInput('euiResizableHidden', disabled);
            }
            if (!this._initialized) {
                return;
            }
            if (disabled) {
                this._teardownInteraction();
            }
            else {
                this._setupInteraction();
            }
        });
    }
    ngOnInit() {
        this._createResizableBar();
        this._initialized = true;
        if (!this.euiResizableHidden()) {
            this._setupInteraction();
        }
        else {
            this._teardownInteraction();
        }
    }
    ngOnDestroy() {
        this.destroy$.next(true);
        this.destroy$.unsubscribe();
    }
    _applySize(size) {
        const minWidth = this.euiResizableMinWidth();
        const maxWidth = this.euiResizableMaxWidth();
        let constrained = Math.max(Math.round(size), minWidth);
        if (maxWidth !== undefined) {
            constrained = Math.min(constrained, maxWidth);
        }
        this.styleWidth = constrained;
        this.styleMinWidth = constrained;
        this.styleMaxWidth = constrained;
        this.styleFlexBasisWidth = constrained;
        this._resizableBar.setInput('ariaValueNow', constrained);
        if (this.euiResizableSideContainer()) {
            CssUtils.setSideContainerWidth(constrained, this._documentRef);
        }
        this.cd.markForCheck();
    }
    _onKeydown(e) {
        const currentWidth = this.styleWidth ?? this._elementRef.nativeElement.getBoundingClientRect().width;
        const step = this.euiResizableKeyStep();
        const isLeft = this.euiResizablePosition() === 'left';
        let newSize = null;
        switch (e.key) {
            case 'ArrowRight':
                newSize = isLeft ? currentWidth - step : currentWidth + step;
                break;
            case 'ArrowLeft':
                newSize = isLeft ? currentWidth + step : currentWidth - step;
                break;
            case 'Home':
                newSize = this.euiResizableMinWidth();
                break;
            case 'End':
                newSize = this.euiResizableMaxWidth() ?? currentWidth;
                break;
            default:
                return;
        }
        e.preventDefault();
        this._applySize(newSize);
    }
    _setupInteraction() {
        this.interaction$.next();
        const bar = this._elementRef.nativeElement.querySelector('.eui-resizable-bar');
        if (!bar) {
            return;
        }
        bar.removeAttribute('aria-hidden');
        fromEvent(bar, 'mousedown').pipe(tap((e) => e.preventDefault()), takeUntil(this.interaction$), takeUntil(this.destroy$)).subscribe((e) => {
            if (e.button === 0) {
                const { width, right, left } = this._elementRef.nativeElement.getBoundingClientRect();
                fromEvent(this._documentRef, 'mousemove').pipe(map(({ clientX }) => {
                    if (this.euiResizablePosition() === 'right') {
                        return width + clientX - right;
                    }
                    else {
                        return width + (left - clientX);
                    }
                }), distinctUntilChanged(), takeUntil(fromEvent(this._documentRef, 'mouseup'))).subscribe((size) => {
                    this._applySize(size);
                });
            }
        });
        fromEvent(bar, 'keydown').pipe(takeUntil(this.interaction$), takeUntil(this.destroy$)).subscribe((e) => this._onKeydown(e));
    }
    _teardownInteraction() {
        this.interaction$.next();
        const bar = this._elementRef.nativeElement.querySelector('.eui-resizable-bar');
        if (bar) {
            bar.setAttribute('aria-hidden', 'true');
        }
    }
    _createResizableBar() {
        if (!this._resizableBar) {
            this._resizableBar = this._viewContainerRef.createComponent(EuiResizableComponent);
            this._resizableBar.setInput('position', this.euiResizablePosition());
            this._resizableBar.setInput('ariaLabel', this.euiResizableAriaLabel());
            this._resizableBar.setInput('ariaValueMin', this.euiResizableMinWidth());
            this._resizableBar.setInput('ariaValueNow', Math.round(this._elementRef.nativeElement.getBoundingClientRect().width));
            if (this.euiResizableMaxWidth() !== undefined) {
                this._resizableBar.setInput('ariaValueMax', this.euiResizableMaxWidth());
            }
            this._renderer.appendChild(this._elementRef.nativeElement, this._resizableBar.location.nativeElement);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiResizableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.16", type: EuiResizableDirective, isStandalone: true, selector: "[euiResizable]", inputs: { euiResizableMinWidth: { classPropertyName: "euiResizableMinWidth", publicName: "euiResizableMinWidth", isSignal: true, isRequired: false, transformFunction: null }, euiResizablePosition: { classPropertyName: "euiResizablePosition", publicName: "euiResizablePosition", isSignal: true, isRequired: false, transformFunction: null }, euiResizableSideContainer: { classPropertyName: "euiResizableSideContainer", publicName: "euiResizableSideContainer", isSignal: true, isRequired: false, transformFunction: null }, euiResizableHidden: { classPropertyName: "euiResizableHidden", publicName: "euiResizableHidden", isSignal: true, isRequired: false, transformFunction: null }, euiResizableAriaLabel: { classPropertyName: "euiResizableAriaLabel", publicName: "euiResizableAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, euiResizableMaxWidth: { classPropertyName: "euiResizableMaxWidth", publicName: "euiResizableMaxWidth", isSignal: true, isRequired: false, transformFunction: null }, euiResizableKeyStep: { classPropertyName: "euiResizableKeyStep", publicName: "euiResizableKeyStep", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.width.px": "this.styleWidth", "style.min-width.px": "this.styleMinWidth", "style.max-width.px": "this.styleMaxWidth", "style.flex-basis.px": "this.styleFlexBasisWidth" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiResizableDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[euiResizable]',
                }]
        }], ctorParameters: () => [], propDecorators: { euiResizableMinWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "euiResizableMinWidth", required: false }] }], euiResizablePosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "euiResizablePosition", required: false }] }], euiResizableSideContainer: [{ type: i0.Input, args: [{ isSignal: true, alias: "euiResizableSideContainer", required: false }] }], euiResizableHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "euiResizableHidden", required: false }] }], euiResizableAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "euiResizableAriaLabel", required: false }] }], euiResizableMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "euiResizableMaxWidth", required: false }] }], euiResizableKeyStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "euiResizableKeyStep", required: false }] }], styleWidth: [{
                type: HostBinding,
                args: ['style.width.px']
            }], styleMinWidth: [{
                type: HostBinding,
                args: ['style.min-width.px']
            }], styleMaxWidth: [{
                type: HostBinding,
                args: ['style.max-width.px']
            }], styleFlexBasisWidth: [{
                type: HostBinding,
                args: ['style.flex-basis.px']
            }] } });

/**
 * Directive enabling keyboard arrow key navigation for focusable content within list items.
 * Makes rich content elements keyboard-accessible by managing focus state and tabindex.
 * Typically used in dropdown menus, list boxes, or custom navigation components.
 *
 * @usageNotes
 * ```html
 * <div euiArrowKeyNavigable>
 *   <a href="#">Focusable link</a>
 *   <button>Focusable button</button>
 * </div>
 * ```
 *
 * ### Accessibility
 * - Sets tabindex="-1" to remove from default tab order while allowing programmatic focus
 * - Use with arrow key navigation logic in parent component
 *
 * ### Notes
 * - Element is not in default tab order but can receive focus programmatically
 * - Commonly paired with list navigation components that handle arrow key events
 */
class EuiArrowKeyNavigableDirective {
    constructor() {
        this.elementRef = inject(ElementRef);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiArrowKeyNavigableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.16", type: EuiArrowKeyNavigableDirective, isStandalone: true, selector: "[euiArrowKeyNavigable]", host: { attributes: { "tabIndex": "-1" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiArrowKeyNavigableDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[euiArrowKeyNavigable]',
                    standalone: true,
                    host: { tabIndex: '-1' },
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { ConditionOperator, EuiArrowKeyNavigableDirective, EuiClearableDirective, EuiHasPermissionDirective, EuiLoadingDirective, EuiMaxLengthDirective, EuiResizableDirective, EuiScrollHandlerDirective, EuiScrollHandlerElementDirective, EuiSmoothScrollDirective, EuiSmoothScrollToDirective, EuiTemplateDirective, EuiTooltipDirective };
//# sourceMappingURL=eui-components-directives.mjs.map
