import { CdkMenuTrigger } from '@angular/cdk/menu';
import * as i0 from '@angular/core';
import { Directive, input, Component, viewChild, signal, effect, booleanAttribute, inject, output, PLATFORM_ID, model, computed } from '@angular/core';
import { SiIconComponent } from '@siemens/element-ng/icon';
import { SiMenuFactoryComponent } from '@siemens/element-ng/menu';
import { t, SiTranslatePipe } from '@siemens/element-translate-ng/translate';
import * as i1 from '@siemens/element-ng/resize-observer';
import { SiResponsiveContainerDirective } from '@siemens/element-ng/resize-observer';
import { SiModalService } from '@siemens/element-ng/modal';
import { isPlatformBrowser } from '@angular/common';
import * as i1$1 from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { SiFileUploadDirective } from '@siemens/element-ng/file-uploader';

/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
/**
 * Directive to mark content as chat message actions into {@link SiChatMessageComponent}.
 * Apply this directive to e.g. buttons that should be slotted into the message actions area.
 *
 * @example
 * ```html
 * <si-chat-message>
 *   Message content
 *   <button siChatMessageAction>Like</button>
 *   <button siChatMessageAction>Share</button>
 * </si-chat-message>
 * ```
 *
 * @see {@link SiChatMessageComponent} for the chat message wrapper component
 *
 * @experimental
 */
class SiChatMessageActionDirective {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatMessageActionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.6", type: SiChatMessageActionDirective, isStandalone: true, selector: "[siChatMessageAction]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatMessageActionDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siChatMessageAction]'
                }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
/**
 * Base declarative chat message component that provides the layout structure for chat messages.
 *
 * This component handles the core message layout including avatar positioning, loading states,
 * and action button as well as attachment list placement. It serves as the foundation for more specialized message components
 * like {@link SiUserMessageComponent} and {@link SiAiMessageComponent}.
 * Can be used within {@link SiChatContainerComponent}.
 *
 * The component provides:
 * - Flexible alignment (start/end) for different message types
 * - Avatar/icon slot for message attribution
 * - Loading state with skeleton UI
 * - Action buttons positioned on the side or bottom
 * - Attachment list display slot
 * - Responsive behavior that adapts to container size
 *
 * This is a low-level component designed for slotting in custom content, it provides slots via content projection:
 * - Default content: Main message content area (consider using {@link SiMarkdownRendererComponent} for markdown support)
 * - `si-avatar/si-icon/img` selector: Avatar or icon representing the message sender
 * - `si-chat-message-action` selector: Action buttons related to the message
 * - `si-attachment-list` selector: Attachment list component for displaying file attachments
 *
 * @see {@link SiUserMessageComponent} for user message display
 * @see {@link SiAiMessageComponent} for AI message display
 * @see {@link SiAttachmentListComponent} for attachment list to slot in
 * @see {@link SiChatMessageActionDirective} for action buttons to slot in
 * @see {@link SiMarkdownRendererComponent} for markdown content rendering
 * @see {@link SiChatContainerComponent} for the chat container to use this within
 *
 * @experimental
 */
class SiChatMessageComponent {
    /**
     * Whether the message is currently loading
     * @defaultValue false
     */
    loading = input(false);
    /**
     * Alignment of the message
     * @defaultValue 'start'
     */
    alignment = input('start');
    /**
     * Where to display action buttons (if any)
     * @defaultValue 'side'
     */
    actionsPosition = input('side');
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatMessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: SiChatMessageComponent, isStandalone: true, selector: "si-chat-message", inputs: { loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null }, actionsPosition: { classPropertyName: "actionsPosition", publicName: "actionsPosition", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "d-block" }, hostDirectives: [{ directive: i1.SiResponsiveContainerDirective }], ngImport: i0, template: "<!--- Flex-row if alignment start, flex-row-reverse if alignment end, flex-column if mobile -->\n<div class=\"d-flex si-body-2 chat-message-container\" [class.start]=\"alignment() === 'start'\">\n  <div class=\"avatar-wrapper flex-shrink-0\" [class.end]=\"alignment() === 'end'\">\n    <ng-content select=\"si-icon,si-avatar,img\" />\n  </div>\n\n  <div class=\"d-flex flex-column flex-grow-1 w-100\">\n    <div class=\"attachment-slot\" [class.align-self-end]=\"alignment() === 'end'\">\n      <ng-content select=\"si-attachment-list,si-badge\" />\n    </div>\n\n    @if (loading()) {\n      <div\n        class=\"message-wrapper rounded-3 w-75 text-break loading-message-bubble mb-2\"\n        [class.align-self-end]=\"alignment() === 'end'\"\n      >\n        <div class=\"d-flex flex-column w-100 gap-2\">\n          <div class=\"si-skeleton skeleton-line skeleton-line-full\"></div>\n          <div class=\"si-skeleton skeleton-line skeleton-line-half\"></div>\n        </div>\n      </div>\n    } @else {\n      <!-- Flex-column if actions bottom, flex-row/flex-row-reverse if actions start -->\n      <div\n        class=\"message-wrapper mw-0 d-flex mb-2\"\n        [class.start]=\"alignment() === 'start'\"\n        [class.end]=\"alignment() === 'end'\"\n        [class.flex-column]=\"actionsPosition() === 'bottom'\"\n        [class.flex-row]=\"actionsPosition() === 'side' && alignment() === 'start'\"\n        [class.flex-row-reverse]=\"actionsPosition() === 'side' && alignment() === 'end'\"\n        [class.align-items-start]=\"actionsPosition() === 'side'\"\n        [class.align-items-end]=\"actionsPosition() === 'bottom' && alignment() === 'end'\"\n        [class.justify-content-end]=\"alignment() === 'end' && actionsPosition() === 'bottom'\"\n        [class.justify-content-start]=\"alignment() === 'start' && actionsPosition() === 'bottom'\"\n      >\n        <div\n          class=\"rounded-3 text-break message-bubble\"\n          [class.end]=\"alignment() === 'end' && actionsPosition() === 'bottom'\"\n        >\n          <ng-content />\n        </div>\n\n        <div\n          class=\"actions-wrapper d-flex gap-4\"\n          [class.ms-3]=\"actionsPosition() === 'side' && alignment() === 'start'\"\n          [class.me-3]=\"actionsPosition() === 'side' && alignment() === 'end'\"\n          [class.mt-2]=\"actionsPosition() === 'bottom'\"\n          [class.actions-horizontal]=\"actionsPosition() !== 'bottom'\"\n          [class.align-self-start]=\"actionsPosition() === 'side'\"\n        >\n          <ng-content select=\"[siChatMessageAction]\" />\n        </div>\n      </div>\n    }\n  </div>\n</div>\n", styles: [":host{display:block;--chat-message-bubble-bg: var(--element-base-1);--chat-message-bubble-padding: 12px}:host ::ng-deep si-loading-spinner{--loading-spinner-size: 1.5em}.skeleton-line-full{inline-size:100%}.skeleton-line-half{inline-size:50%}.loading-message-bubble,.message-bubble{padding:var(--chat-message-bubble-padding)}.loading-message-bubble{inline-size:max-content;min-inline-size:75%;margin-block-end:auto;background-color:var(--chat-message-bubble-bg)}.message-bubble{margin-block-end:auto;background-color:var(--chat-message-bubble-bg);min-inline-size:0;overflow-wrap:break-word;word-break:break-word}.message-bubble:empty{display:none}.message-bubble:empty~.actions-wrapper{margin-inline:0!important}.message-wrapper{min-inline-size:0}.attachment-slot:empty{display:none}.attachment-slot:not(:empty)~.message-wrapper:not(:has(.message-bubble:empty)){margin-block-start:4px}.attachment-slot:not(:empty)~.message-wrapper:has(.message-bubble:empty) .actions-wrapper.actions-horizontal{margin-block-start:4px}.actions-wrapper:empty{display:none!important}.avatar-wrapper{align-self:flex-start}.avatar-wrapper:not(.end){margin-inline-end:6px}.avatar-wrapper.end{margin-inline-start:6px}.avatar-wrapper:empty{display:none}.message-wrapper{min-inline-size:0;inline-size:auto}.message-wrapper.start{margin-inline-end:auto}.message-wrapper.end{margin-inline-start:auto}:host-context(.si-container-md,.si-container-lg,.si-container-xl,.si-container-xxl) .chat-message-container{flex-direction:row}:host-context(.si-container-md,.si-container-lg,.si-container-xl,.si-container-xxl) .chat-message-container.start{align-items:flex-start}:host-context(.si-container-md,.si-container-lg,.si-container-xl,.si-container-xxl) .chat-message-container:not(.start){flex-direction:row-reverse}:host-context(.si-container-md,.si-container-lg,.si-container-xl,.si-container-xxl) .message-bubble.end{margin-inline-start:auto}.attachment-slot ::ng-deep si-attachment-list{--attachment-list-bg: transparent;--attachment-name-color: var(--element-text-secondary)}:host-context(.si-container-xs,.si-container-sm) .chat-message-container{flex-direction:column}:host-context(.si-container-xs,.si-container-sm) .avatar-wrapper{margin-block-end:6px}:host-context(.si-container-xs,.si-container-sm) .avatar-wrapper.end{align-self:flex-end}:host-context(.si-container-xs,.si-container-sm) .avatar-wrapper::ng-deep:has(si-icon) .end{margin-inline-end:4px!important}:host-context(.si-container-xs,.si-container-sm) .avatar-wrapper::ng-deep:has(si-icon):not(.end){margin-inline-start:4px!important}\n"] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatMessageComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-chat-message', host: {
                        class: 'd-block'
                    }, hostDirectives: [SiResponsiveContainerDirective], template: "<!--- Flex-row if alignment start, flex-row-reverse if alignment end, flex-column if mobile -->\n<div class=\"d-flex si-body-2 chat-message-container\" [class.start]=\"alignment() === 'start'\">\n  <div class=\"avatar-wrapper flex-shrink-0\" [class.end]=\"alignment() === 'end'\">\n    <ng-content select=\"si-icon,si-avatar,img\" />\n  </div>\n\n  <div class=\"d-flex flex-column flex-grow-1 w-100\">\n    <div class=\"attachment-slot\" [class.align-self-end]=\"alignment() === 'end'\">\n      <ng-content select=\"si-attachment-list,si-badge\" />\n    </div>\n\n    @if (loading()) {\n      <div\n        class=\"message-wrapper rounded-3 w-75 text-break loading-message-bubble mb-2\"\n        [class.align-self-end]=\"alignment() === 'end'\"\n      >\n        <div class=\"d-flex flex-column w-100 gap-2\">\n          <div class=\"si-skeleton skeleton-line skeleton-line-full\"></div>\n          <div class=\"si-skeleton skeleton-line skeleton-line-half\"></div>\n        </div>\n      </div>\n    } @else {\n      <!-- Flex-column if actions bottom, flex-row/flex-row-reverse if actions start -->\n      <div\n        class=\"message-wrapper mw-0 d-flex mb-2\"\n        [class.start]=\"alignment() === 'start'\"\n        [class.end]=\"alignment() === 'end'\"\n        [class.flex-column]=\"actionsPosition() === 'bottom'\"\n        [class.flex-row]=\"actionsPosition() === 'side' && alignment() === 'start'\"\n        [class.flex-row-reverse]=\"actionsPosition() === 'side' && alignment() === 'end'\"\n        [class.align-items-start]=\"actionsPosition() === 'side'\"\n        [class.align-items-end]=\"actionsPosition() === 'bottom' && alignment() === 'end'\"\n        [class.justify-content-end]=\"alignment() === 'end' && actionsPosition() === 'bottom'\"\n        [class.justify-content-start]=\"alignment() === 'start' && actionsPosition() === 'bottom'\"\n      >\n        <div\n          class=\"rounded-3 text-break message-bubble\"\n          [class.end]=\"alignment() === 'end' && actionsPosition() === 'bottom'\"\n        >\n          <ng-content />\n        </div>\n\n        <div\n          class=\"actions-wrapper d-flex gap-4\"\n          [class.ms-3]=\"actionsPosition() === 'side' && alignment() === 'start'\"\n          [class.me-3]=\"actionsPosition() === 'side' && alignment() === 'end'\"\n          [class.mt-2]=\"actionsPosition() === 'bottom'\"\n          [class.actions-horizontal]=\"actionsPosition() !== 'bottom'\"\n          [class.align-self-start]=\"actionsPosition() === 'side'\"\n        >\n          <ng-content select=\"[siChatMessageAction]\" />\n        </div>\n      </div>\n    }\n  </div>\n</div>\n", styles: [":host{display:block;--chat-message-bubble-bg: var(--element-base-1);--chat-message-bubble-padding: 12px}:host ::ng-deep si-loading-spinner{--loading-spinner-size: 1.5em}.skeleton-line-full{inline-size:100%}.skeleton-line-half{inline-size:50%}.loading-message-bubble,.message-bubble{padding:var(--chat-message-bubble-padding)}.loading-message-bubble{inline-size:max-content;min-inline-size:75%;margin-block-end:auto;background-color:var(--chat-message-bubble-bg)}.message-bubble{margin-block-end:auto;background-color:var(--chat-message-bubble-bg);min-inline-size:0;overflow-wrap:break-word;word-break:break-word}.message-bubble:empty{display:none}.message-bubble:empty~.actions-wrapper{margin-inline:0!important}.message-wrapper{min-inline-size:0}.attachment-slot:empty{display:none}.attachment-slot:not(:empty)~.message-wrapper:not(:has(.message-bubble:empty)){margin-block-start:4px}.attachment-slot:not(:empty)~.message-wrapper:has(.message-bubble:empty) .actions-wrapper.actions-horizontal{margin-block-start:4px}.actions-wrapper:empty{display:none!important}.avatar-wrapper{align-self:flex-start}.avatar-wrapper:not(.end){margin-inline-end:6px}.avatar-wrapper.end{margin-inline-start:6px}.avatar-wrapper:empty{display:none}.message-wrapper{min-inline-size:0;inline-size:auto}.message-wrapper.start{margin-inline-end:auto}.message-wrapper.end{margin-inline-start:auto}:host-context(.si-container-md,.si-container-lg,.si-container-xl,.si-container-xxl) .chat-message-container{flex-direction:row}:host-context(.si-container-md,.si-container-lg,.si-container-xl,.si-container-xxl) .chat-message-container.start{align-items:flex-start}:host-context(.si-container-md,.si-container-lg,.si-container-xl,.si-container-xxl) .chat-message-container:not(.start){flex-direction:row-reverse}:host-context(.si-container-md,.si-container-lg,.si-container-xl,.si-container-xxl) .message-bubble.end{margin-inline-start:auto}.attachment-slot ::ng-deep si-attachment-list{--attachment-list-bg: transparent;--attachment-name-color: var(--element-text-secondary)}:host-context(.si-container-xs,.si-container-sm) .chat-message-container{flex-direction:column}:host-context(.si-container-xs,.si-container-sm) .avatar-wrapper{margin-block-end:6px}:host-context(.si-container-xs,.si-container-sm) .avatar-wrapper.end{align-self:flex-end}:host-context(.si-container-xs,.si-container-sm) .avatar-wrapper::ng-deep:has(si-icon) .end{margin-inline-end:4px!important}:host-context(.si-container-xs,.si-container-sm) .avatar-wrapper::ng-deep:has(si-icon):not(.end){margin-inline-start:4px!important}\n"] }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
/**
 * AI message component for displaying AI-generated responses in conversational interfaces.
 *
 * The AI message component renders AI-generated content in chat interfaces,
 * supporting text formatting, markdown, loading states, and contextual actions.
 * It appears as text (no bubble) aligned to the left side without any avatar/icon slot.
 * Can be used within {@link SiChatContainerComponent}.
 *
 * The component automatically handles:
 * - Styling for AI messages distinct from user or generic chat messages
 * - Option to render markdown content, provide via `contentFormatter` input with a markdown renderer function (e.g., from {@link getMarkdownRenderer})
 * - Showing loading states with skeleton UI during generation
 * - Displaying primary and secondary actions
 *
 * @see {@link SiChatMessageComponent} for the base message wrapper component
 * @see {@link SiUserMessageComponent} for the user message component
 * @see {@link getMarkdownRenderer} for markdown formatting support
 * @see {@link SiChatContainerComponent} for the chat container to use this within
 *
 * @experimental
 */
class SiAiMessageComponent {
    formattedContent = viewChild('formattedContent');
    /**
     * The AI-generated message content
     * @defaultValue ''
     */
    content = input('');
    /**
     * Optional formatter function to transform content before display.
     * - Returns string: Content will be sanitized using Angular's DomSanitizer
     * - Returns Node: DOM node will be inserted directly without sanitization
     *
     * **Note:** If using a markdown renderer, make sure to apply the `markdown-content` class
     * to the root element to ensure proper styling using the Element theme (e.g., `div.className = 'markdown-content'`).
     * The function returned by {@link getMarkdownRenderer} does this automatically.
     *
     * **Warning:** When returning a Node, ensure the content is safe to prevent XSS attacks
     * @defaultValue undefined
     */
    contentFormatter = input(undefined);
    textContent = signal(undefined);
    constructor() {
        effect(() => {
            const formatter = this.contentFormatter();
            const contentValue = this.content();
            const container = this.formattedContent()?.nativeElement;
            if (container && contentValue) {
                if (formatter) {
                    const formatted = formatter(contentValue);
                    if (typeof formatted === 'string') {
                        this.textContent.set(formatted);
                    }
                    else if (formatted instanceof Node) {
                        this.textContent.set(undefined);
                        container.innerHTML = '';
                        container.appendChild(formatted);
                    }
                }
                else {
                    this.textContent.set(contentValue);
                }
            }
        });
    }
    /**
     * Whether the message is currently being generated (shows skeleton)
     * @defaultValue false
     */
    loading = input(false, { transform: booleanAttribute });
    /**
     * Primary actions available for this message (thumbs up/down, copy, retry, etc.)
     * All actions displayed inline
     * @defaultValue []
     */
    actions = input([]);
    /**
     * Secondary actions available in dropdown menu, first use primary actions and only add secondary actions additionally
     * @defaultValue []
     */
    secondaryActions = input([]);
    /** Parameter to pass to action handlers */
    actionParam = input();
    /**
     * More actions button aria label
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_AI_MESSAGE.SECONDARY_ACTIONS:More actions`)
     * ```
     */
    secondaryActionsLabel = input(t(() => $localize `:@@SI_AI_MESSAGE.SECONDARY_ACTIONS:More actions`));
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiAiMessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: SiAiMessageComponent, isStandalone: true, selector: "si-ai-message", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, contentFormatter: { classPropertyName: "contentFormatter", publicName: "contentFormatter", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, secondaryActions: { classPropertyName: "secondaryActions", publicName: "secondaryActions", isSignal: true, isRequired: false, transformFunction: null }, actionParam: { classPropertyName: "actionParam", publicName: "actionParam", isSignal: true, isRequired: false, transformFunction: null }, secondaryActionsLabel: { classPropertyName: "secondaryActionsLabel", publicName: "secondaryActionsLabel", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "formattedContent", first: true, predicate: ["formattedContent"], descendants: true, isSignal: true }], ngImport: i0, template: "<si-chat-message alignment=\"start\" actionsPosition=\"bottom\" [loading]=\"loading()\">\n  @if (content()) {\n    @let content = textContent();\n    @if (content) {\n      <span class=\"text-pre-wrap\">{{ content }}</span>\n    } @else {\n      <div #formattedContent> </div>\n    }\n  }\n\n  @if ((actions()?.length ?? 0 > 0) || (secondaryActions()?.length ?? 0 > 0)) {\n    <div class=\"d-flex gap-4 ai-message-actions\" siChatMessageAction>\n      @for (action of actions(); track $index) {\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm\"\n          [disabled]=\"action.disabled\"\n          [attr.aria-label]=\"action.label | translate\"\n          (click)=\"action.action(actionParam(), action)\"\n        >\n          <si-icon [icon]=\"action.icon\" />\n        </button>\n      }\n\n      @if (secondaryActions()?.length ?? 0 > 0) {\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm\"\n          [cdkMenuTriggerFor]=\"secondaryActionsMenu\"\n          [attr.aria-label]=\"secondaryActionsLabel() | translate\"\n          [attr.title]=\"secondaryActionsLabel() | translate\"\n        >\n          <si-icon icon=\"element-optionsVertical\" />\n        </button>\n\n        <ng-template #secondaryActionsMenu>\n          <si-menu-factory [items]=\"secondaryActions()\" [actionParam]=\"actionParam()\" />\n        </ng-template>\n      }\n    </div>\n  }\n</si-chat-message>\n", styles: [":host{display:block}si-chat-message{--chat-message-bubble-bg: transparent;--chat-message-bubble-padding: 0;margin-block-end:-4px}.ai-message-actions{margin-block-start:8px}:host ::ng-deep si-loading-spinner{--loading-spinner-size: 1.5em}\n"], dependencies: [{ kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "component", type: SiChatMessageComponent, selector: "si-chat-message", inputs: ["loading", "alignment", "actionsPosition"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "component", type: SiMenuFactoryComponent, selector: "si-menu-factory", inputs: ["items", "actionParam"] }, { kind: "directive", type: SiChatMessageActionDirective, selector: "[siChatMessageAction]" }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiAiMessageComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-ai-message', imports: [
                        CdkMenuTrigger,
                        SiChatMessageComponent,
                        SiIconComponent,
                        SiMenuFactoryComponent,
                        SiChatMessageActionDirective,
                        SiTranslatePipe
                    ], template: "<si-chat-message alignment=\"start\" actionsPosition=\"bottom\" [loading]=\"loading()\">\n  @if (content()) {\n    @let content = textContent();\n    @if (content) {\n      <span class=\"text-pre-wrap\">{{ content }}</span>\n    } @else {\n      <div #formattedContent> </div>\n    }\n  }\n\n  @if ((actions()?.length ?? 0 > 0) || (secondaryActions()?.length ?? 0 > 0)) {\n    <div class=\"d-flex gap-4 ai-message-actions\" siChatMessageAction>\n      @for (action of actions(); track $index) {\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm\"\n          [disabled]=\"action.disabled\"\n          [attr.aria-label]=\"action.label | translate\"\n          (click)=\"action.action(actionParam(), action)\"\n        >\n          <si-icon [icon]=\"action.icon\" />\n        </button>\n      }\n\n      @if (secondaryActions()?.length ?? 0 > 0) {\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm\"\n          [cdkMenuTriggerFor]=\"secondaryActionsMenu\"\n          [attr.aria-label]=\"secondaryActionsLabel() | translate\"\n          [attr.title]=\"secondaryActionsLabel() | translate\"\n        >\n          <si-icon icon=\"element-optionsVertical\" />\n        </button>\n\n        <ng-template #secondaryActionsMenu>\n          <si-menu-factory [items]=\"secondaryActions()\" [actionParam]=\"actionParam()\" />\n        </ng-template>\n      }\n    </div>\n  }\n</si-chat-message>\n", styles: [":host{display:block}si-chat-message{--chat-message-bubble-bg: transparent;--chat-message-bubble-padding: 0;margin-block-end:-4px}.ai-message-actions{margin-block-start:8px}:host ::ng-deep si-loading-spinner{--loading-spinner-size: 1.5em}\n"] }]
        }], ctorParameters: () => [] });

/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
/**
 * Attachment list component for displaying file attachments in chat messages.
 *
 * This component renders a list of file attachments with icons, names, and optional
 * preview and remove functionality. It's designed to work with chat message components
 * to show files that have been uploaded or shared in conversations.
 *
 * This component provides:
 * - A list of pills showing each attachment's name and an icon
 * - Optional preview modal for attachments
 * - Optional remove functionality for editable messages
 *
 * The component is included within {@link SiUserMessageComponent}, {@link SiAiMessageComponent} and {@link SiChatInputComponent} but can also be used inside custom chat messages with {@link SiChatMessageComponent}
 *
 * @see {@link SiUserMessageComponent} for user message display
 * @see {@link SiAiMessageComponent} for AI message display
 * @see {@link SiChatMessageComponent} for custom chat message display
 * @see {@link SiChatInputComponent} for chat input with attachment support
 * @see {@link Attachment} for attachment data structure
 *
 * @experimental
 */
class SiAttachmentListComponent {
    modalService = inject(SiModalService);
    /**
     * List of attachments to display
     * @defaultValue []
     */
    attachments = input([]);
    /**
     * Whether to align attachments to the end (right) or start (left)
     * @defaultValue 'start'
     */
    alignment = input('start');
    /**
     * Whether to show remove buttons on attachments
     * @defaultValue false
     */
    removable = input(false, { transform: booleanAttribute });
    /**
     * Label for remove attachment button
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_ATTACHMENT_LIST.REMOVE_ATTACHMENT:Remove attachment`)
     * ```
     */
    removeLabel = input(t(() => $localize `:@@SI_ATTACHMENT_LIST.REMOVE_ATTACHMENT:Remove attachment`));
    /**
     * Emitted when an attachment should be removed
     */
    remove = output();
    getPreviewTemplate(attachment) {
        if (attachment.previewTemplate) {
            return typeof attachment.previewTemplate === 'function'
                ? attachment.previewTemplate()
                : attachment.previewTemplate;
        }
        return undefined;
    }
    openPreview(event, attachment) {
        const template = this.getPreviewTemplate(attachment);
        if (template) {
            event.preventDefault();
            this.modalService.show(template, {
                inputValues: { 'attachment': attachment }
            });
        }
    }
    getFileIcon(name) {
        // TODO: Accept map and default it in file upload directive.
        return 'element-document';
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiAttachmentListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: SiAttachmentListComponent, isStandalone: true, selector: "si-attachment-list", inputs: { attachments: { classPropertyName: "attachments", publicName: "attachments", isSignal: true, isRequired: false, transformFunction: null }, alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { remove: "remove" }, ngImport: i0, template: "<div class=\"d-flex flex-wrap gap-4\" [class.justify-content-end]=\"alignment() === 'end'\">\n  @for (attachment of attachments(); track $index) {\n    <div class=\"attachment-item d-flex align-items-stretch\" role=\"group\">\n      @if (attachment.previewTemplate) {\n        <button\n          type=\"button\"\n          class=\"attachment-main focus-inside d-flex align-items-center flex-grow-1 min-width-0\"\n          [attr.title]=\"attachment.name\"\n          [attr.aria-label]=\"attachment.name\"\n          (click)=\"openPreview($event, attachment)\"\n          (keydown.enter)=\"openPreview($event, attachment)\"\n          (keydown.space)=\"openPreview($event, attachment)\"\n        >\n          <si-icon\n            class=\"attachment-icon icon flex-shrink-0 mx-1\"\n            [icon]=\"getFileIcon(attachment.name)\"\n          />\n          <div class=\"attachment-info flex-grow-1 min-width-0\">\n            <span\n              class=\"attachment-name me-4 text-truncate si-body-2 d-block\"\n              [title]=\"attachment.name\"\n            >\n              {{ attachment.name }}\n            </span>\n          </div>\n        </button>\n      } @else {\n        <div class=\"attachment-main--static d-flex align-items-center flex-grow-1 min-width-0\">\n          <si-icon\n            class=\"attachment-icon icon flex-shrink-0 mx-1\"\n            [icon]=\"getFileIcon(attachment.name)\"\n          />\n          <div class=\"attachment-info flex-grow-1 min-width-0\">\n            <span\n              class=\"attachment-name me-4 text-truncate si-body-2 d-block\"\n              [title]=\"attachment.name\"\n            >\n              {{ attachment.name }}\n            </span>\n          </div>\n        </div>\n      }\n\n      @if (removable()) {\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm expand-button flex-shrink-0 ms-auto align-self-center focus-inside\"\n          [attr.aria-label]=\"(removeLabel() | translate) + ' ' + attachment.name\"\n          (click)=\"remove.emit(attachment); $event.stopPropagation()\"\n        >\n          <si-icon class=\"icon\" icon=\"element-delete\" />\n        </button>\n      }\n    </div>\n  }\n</div>\n", styles: [":host{--attachment-list-bg: var(--element-base-1-hover);--attachment-name-color: var(--element-text-primary)}.attachment-item{border-radius:var(--element-radius-2);overflow:hidden;background-color:var(--attachment-list-bg);color:var(--attachment-name-color)}.attachment-main{appearance:none;border:0;background:none;padding:0;margin:0;inline-size:100%;text-align:inherit;color:inherit;cursor:pointer}.attachment-icon{display:flex;align-items:center;justify-content:center}.attachment-info{display:flex;flex-direction:column;gap:2px;min-inline-size:0}.attachment-info .attachment-name{line-height:1.2}.attachment-info .attachment-size{line-height:1}.expand-button{border-radius:0}\n"], dependencies: [{ kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiAttachmentListComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-attachment-list', imports: [SiIconComponent, SiTranslatePipe], template: "<div class=\"d-flex flex-wrap gap-4\" [class.justify-content-end]=\"alignment() === 'end'\">\n  @for (attachment of attachments(); track $index) {\n    <div class=\"attachment-item d-flex align-items-stretch\" role=\"group\">\n      @if (attachment.previewTemplate) {\n        <button\n          type=\"button\"\n          class=\"attachment-main focus-inside d-flex align-items-center flex-grow-1 min-width-0\"\n          [attr.title]=\"attachment.name\"\n          [attr.aria-label]=\"attachment.name\"\n          (click)=\"openPreview($event, attachment)\"\n          (keydown.enter)=\"openPreview($event, attachment)\"\n          (keydown.space)=\"openPreview($event, attachment)\"\n        >\n          <si-icon\n            class=\"attachment-icon icon flex-shrink-0 mx-1\"\n            [icon]=\"getFileIcon(attachment.name)\"\n          />\n          <div class=\"attachment-info flex-grow-1 min-width-0\">\n            <span\n              class=\"attachment-name me-4 text-truncate si-body-2 d-block\"\n              [title]=\"attachment.name\"\n            >\n              {{ attachment.name }}\n            </span>\n          </div>\n        </button>\n      } @else {\n        <div class=\"attachment-main--static d-flex align-items-center flex-grow-1 min-width-0\">\n          <si-icon\n            class=\"attachment-icon icon flex-shrink-0 mx-1\"\n            [icon]=\"getFileIcon(attachment.name)\"\n          />\n          <div class=\"attachment-info flex-grow-1 min-width-0\">\n            <span\n              class=\"attachment-name me-4 text-truncate si-body-2 d-block\"\n              [title]=\"attachment.name\"\n            >\n              {{ attachment.name }}\n            </span>\n          </div>\n        </div>\n      }\n\n      @if (removable()) {\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm expand-button flex-shrink-0 ms-auto align-self-center focus-inside\"\n          [attr.aria-label]=\"(removeLabel() | translate) + ' ' + attachment.name\"\n          (click)=\"remove.emit(attachment); $event.stopPropagation()\"\n        >\n          <si-icon class=\"icon\" icon=\"element-delete\" />\n        </button>\n      }\n    </div>\n  }\n</div>\n", styles: [":host{--attachment-list-bg: var(--element-base-1-hover);--attachment-name-color: var(--element-text-primary)}.attachment-item{border-radius:var(--element-radius-2);overflow:hidden;background-color:var(--attachment-list-bg);color:var(--attachment-name-color)}.attachment-main{appearance:none;border:0;background:none;padding:0;margin:0;inline-size:100%;text-align:inherit;color:inherit;cursor:pointer}.attachment-icon{display:flex;align-items:center;justify-content:center}.attachment-info{display:flex;flex-direction:column;gap:2px;min-inline-size:0}.attachment-info .attachment-name{line-height:1.2}.attachment-info .attachment-size{line-height:1}.expand-button{border-radius:0}\n"] }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
/**
 * A declarative container component for displaying a chat interface with automatic scroll-to-bottom behavior.
 *
 * This component provides the layout and styling for a chat interface, managing scrolling behavior
 * to keep the newest messages visible while respecting user scrolling actions. It automatically
 * scrolls to the bottom when new content is added, unless the user has scrolled up to view older messages.
 *
 * Use via content projection:
 * - Default content: Chat messages displayed in the scrollable messages container or something like an empty state.
 * - `si-inline-notification` selector: Notification component displayed above the input area
 * - `si-chat-input` or `[siChatContainerInput]` selector: Input controls for composing messages
 *
 * @see {@link SiChatInputComponent} for the chat input wrapper component
 * @see {@link SiChatContainerInputDirective} for other input controls to slot in
 * @see {@link SiAiMessageComponent} for AI messages to slot in
 * @see {@link SiUserMessageComponent} for user messages (in AI chats) to slot in
 * @see {@link SiChatMessageComponent} for the chat message wrapper component to slot in other messages
 *
 * @experimental
 */
class SiChatContainerComponent {
    messagesContainer = viewChild('messagesContainer');
    platformId = inject(PLATFORM_ID);
    isUserAtBottom = true;
    scrollTimeout;
    resizeObserver;
    contentObserver;
    /**
     * The color variant to apply to the container.
     * @defaultValue 'base-0'
     */
    colorVariant = input('base-0');
    /**
     * Disables automatic scrolling to the bottom when new content is added.
     * @defaultValue false
     */
    noAutoScroll = input(false, {
        transform: (value) => value === '' || value === true
    });
    constructor() {
        effect(() => {
            if (this.messagesContainer()) {
                this.setupResizeObserver();
                this.setupContentObserver();
            }
        });
    }
    ngAfterContentInit() {
        this.scrollToBottom();
    }
    ngOnDestroy() {
        if (this.scrollTimeout) {
            clearTimeout(this.scrollTimeout);
        }
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
        }
        if (this.contentObserver) {
            this.contentObserver.disconnect();
        }
    }
    scrollToBottom() {
        if (this.noAutoScroll() || !this.isUserAtBottom) {
            return;
        }
        const container = this.messagesContainer();
        if (!container) {
            return;
        }
        const element = container.nativeElement;
        element.scrollTop = element.scrollHeight;
    }
    debouncedScrollToBottom() {
        if (this.scrollTimeout) {
            clearTimeout(this.scrollTimeout);
        }
        this.scrollTimeout = setTimeout(() => {
            this.scrollToBottom();
        }, 100);
    }
    setupResizeObserver() {
        if (!isPlatformBrowser(this.platformId)) {
            return;
        }
        const container = this.messagesContainer();
        if (!container || this.resizeObserver) {
            return;
        }
        this.resizeObserver = new ResizeObserver(() => {
            this.debouncedScrollToBottom();
        });
        this.resizeObserver.observe(container.nativeElement);
    }
    setupContentObserver() {
        if (!isPlatformBrowser(this.platformId)) {
            return;
        }
        const container = this.messagesContainer();
        if (!container || this.contentObserver) {
            return;
        }
        this.contentObserver = new MutationObserver(() => {
            this.debouncedScrollToBottom();
        });
        this.contentObserver.observe(container.nativeElement, {
            childList: true,
            subtree: true,
            characterData: true
        });
    }
    checkIfUserAtBottom() {
        const container = this.messagesContainer();
        if (!container) {
            return;
        }
        const element = container.nativeElement;
        const threshold = 100;
        this.isUserAtBottom =
            element.scrollHeight - element.scrollTop - element.clientHeight < threshold;
    }
    onScroll() {
        this.checkIfUserAtBottom();
    }
    /**
     * Focuses the messages container element.
     */
    focus() {
        const container = this.messagesContainer();
        container?.nativeElement.focus();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.6", type: SiChatContainerComponent, isStandalone: true, selector: "si-chat-container", inputs: { colorVariant: { classPropertyName: "colorVariant", publicName: "colorVariant", isSignal: true, isRequired: false, transformFunction: null }, noAutoScroll: { classPropertyName: "noAutoScroll", publicName: "noAutoScroll", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "colorVariant()" }, classAttribute: "d-flex si-layout-inner flex-grow-1 flex-column h-100 w-100" }, viewQueries: [{ propertyName: "messagesContainer", first: true, predicate: ["messagesContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"chat-container d-flex flex-column flex-grow-1 px-6 px-md-9 py-6 w-100\">\n  <div\n    #messagesContainer\n    class=\"messages-container d-flex flex-column flex-grow-1 w-100 align-self-center\"\n    tabindex=\"0\"\n    (scroll)=\"onScroll()\"\n  >\n    <ng-content />\n  </div>\n\n  <div class=\"chat-input-area py-3 pt-0 mt-6 d-flex flex-column align-items-center\">\n    <ng-content select=\"si-inline-notification\" />\n    <ng-content select=\"si-chat-input,[siChatContainerInput]\" />\n  </div>\n</div>\n", styles: [":host{overflow-y:hidden;overflow-x:visible}:host.base-0{background-color:var(--element-base-0)}:host.base-1{background-color:var(--element-base-1)}.chat-container{min-block-size:0;overflow-y:hidden;overflow-x:visible}.chat-container.initialized{scroll-behavior:smooth}.messages-container{max-inline-size:720px;overflow-y:auto;overflow-x:visible;gap:40px}.messages-container ::ng-deep si-user-message:not(.last){margin-block-end:-40px}.chat-input-area{justify-self:flex-end;align-self:center;overflow:visible;inline-size:100%;max-inline-size:720px}::ng-deep .chat-input-area:empty:not(:has(si-inline-notification)),::ng-deep .chat-input-area:has([sichatcontainerinput]:empty):not(:has(si-inline-notification)){display:none!important}.chat-input-area:empty ::ng-deep>si-inline-notification,.chat-input-area:empty ::ng-deep *>si-inline-notification,.chat-input-area:has([sichatcontainerinput]:empty) ::ng-deep>si-inline-notification,.chat-input-area:has([sichatcontainerinput]:empty) ::ng-deep *>si-inline-notification{margin-block-end:0!important}.chat-container:has(.messages-container:not(:empty)) .messages-empty-state{display:none!important}:host-context(.si-container-xs,.si-container-sm) ::ng-deep si-inline-notification .alert,:host-context(.si-container-xs,.si-container-sm) ::ng-deep si-inline-notification .alert-link{font-size:.875rem}\n"] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatContainerComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-chat-container', host: {
                        class: 'd-flex si-layout-inner flex-grow-1 flex-column h-100 w-100',
                        '[class]': 'colorVariant()'
                    }, template: "<div class=\"chat-container d-flex flex-column flex-grow-1 px-6 px-md-9 py-6 w-100\">\n  <div\n    #messagesContainer\n    class=\"messages-container d-flex flex-column flex-grow-1 w-100 align-self-center\"\n    tabindex=\"0\"\n    (scroll)=\"onScroll()\"\n  >\n    <ng-content />\n  </div>\n\n  <div class=\"chat-input-area py-3 pt-0 mt-6 d-flex flex-column align-items-center\">\n    <ng-content select=\"si-inline-notification\" />\n    <ng-content select=\"si-chat-input,[siChatContainerInput]\" />\n  </div>\n</div>\n", styles: [":host{overflow-y:hidden;overflow-x:visible}:host.base-0{background-color:var(--element-base-0)}:host.base-1{background-color:var(--element-base-1)}.chat-container{min-block-size:0;overflow-y:hidden;overflow-x:visible}.chat-container.initialized{scroll-behavior:smooth}.messages-container{max-inline-size:720px;overflow-y:auto;overflow-x:visible;gap:40px}.messages-container ::ng-deep si-user-message:not(.last){margin-block-end:-40px}.chat-input-area{justify-self:flex-end;align-self:center;overflow:visible;inline-size:100%;max-inline-size:720px}::ng-deep .chat-input-area:empty:not(:has(si-inline-notification)),::ng-deep .chat-input-area:has([sichatcontainerinput]:empty):not(:has(si-inline-notification)){display:none!important}.chat-input-area:empty ::ng-deep>si-inline-notification,.chat-input-area:empty ::ng-deep *>si-inline-notification,.chat-input-area:has([sichatcontainerinput]:empty) ::ng-deep>si-inline-notification,.chat-input-area:has([sichatcontainerinput]:empty) ::ng-deep *>si-inline-notification{margin-block-end:0!important}.chat-container:has(.messages-container:not(:empty)) .messages-empty-state{display:none!important}:host-context(.si-container-xs,.si-container-sm) ::ng-deep si-inline-notification .alert,:host-context(.si-container-xs,.si-container-sm) ::ng-deep si-inline-notification .alert-link{font-size:.875rem}\n"] }]
        }], ctorParameters: () => [] });

/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
/**
 * A directive to mark elements as input controls within a {@link SiChatContainerComponent}.
 *
 * This directive is used to identify and style input elements that belong to
 * the chat container component, typically applied to form inputs or textareas
 * used for composing chat messages.
 *
 * @example
 * ```html
 * <si-chat-container>
 *   <si-chat-message>Hello!</si-chat-message>
 *   <si-chat-message>How are you?</si-chat-message>
 *
 *   <input siChatContainerInput type="text" placeholder="Type a message..." />
 * </si-chat-container>
 * ```
 *
 * @see {@link SiChatContainerComponent} for the chat container wrapper component
 *
 * @experimental
 */
class SiChatContainerInputDirective {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatContainerInputDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.6", type: SiChatContainerInputDirective, isStandalone: true, selector: "[siChatContainerInput]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatContainerInputDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siChatContainerInput]'
                }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
/**
 * Chat input component for composing and sending messages in conversational interfaces.
 *
 * The chat input component provides a text area for users to compose messages,
 * supporting text, attachments, and contextual actions. It appears as a textarea
 * with buttons for adding attachments and sending messages, as well as an optional disclaimer.
 *
 * The component automatically handles:
 * - Styling for chat input and actions.
 * - Dynamic resizing of the textarea based on content.
 * - Uploading of and displaying of attachments above the input area.
 * - Displaying primary and secondary actions.
 *
 * Additionally to the inputs and outputs documented here, the component supports content projection via the following slots:
 * - Default content: Custom action buttons to display inline, prefer using the `actions` input for buttons, can be used in addition.
 * - `siChatInputDisclaimer` selector: Custom disclaimer content to display below the input area, prefer using the `disclaimer` input for simple text disclaimers.
 *
 * @see {@link SiAttachmentListComponent} for the base attachment component
 * @see {@link SiChatInputDisclaimerDirective} to slot in custom disclaimer content
 *
 * @experimental
 */
class SiChatInputComponent {
    static idCounter = 0;
    textInput = viewChild('textInput');
    projectedContent = viewChild('projected');
    fileUploadDirective = viewChild(SiFileUploadDirective);
    /**
     * Current input value
     * @defaultValue ''
     */
    value = model('');
    /**
     * Placeholder text for the input
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_CHAT_INPUT.PLACEHOLDER:Enter a message…`)
     * ```
     */
    placeholder = input(t(() => $localize `:@@SI_CHAT_INPUT.PLACEHOLDER:Enter a message…`));
    /**
     * Whether the input is disabled
     * @defaultValue false
     */
    disabled = input(false, { transform: booleanAttribute });
    /**
     * Whether a message is currently being sent, also prevent the sending of new ones while still allowing the user to type
     * @defaultValue false
     */
    sending = input(false, { transform: booleanAttribute });
    /**
     * Whether the input supports interrupting ongoing operations. When active,
     * the send button transforms into an interrupt button (with element-stop-filled icon).
     * If sending is true, the interrupt button will be disabled.
     * @defaultValue false
     */
    interruptible = input(false, { transform: booleanAttribute });
    /**
     * Maximum number of characters allowed
     */
    maxLength = input();
    /**
     * A disclaimer to display.
     *
     * If not provided, the component will look for projected content with the `siChatInputDisclaimer` directive.
     * If both are empty, no disclaimer section will be shown (handled via CSS :empty).
     */
    disclaimer = input();
    /**
     * Primary actions available in the input (attach files, etc.)
     * All actions displayed inline
     * @defaultValue []
     */
    actions = input([]);
    /**
     * Secondary actions available in dropdown menu
     * @defaultValue []
     */
    secondaryActions = input([]);
    /**
     * Whether file attachments are supported
     * @defaultValue false
     */
    allowAttachments = input(false);
    /**
     * Accepted file types for attachments (as accept string)
     * @defaultValue undefined
     */
    accept = input();
    /**
     * Maximum file size in bytes
     * @defaultValue 10485760 (10MB)
     */
    maxFileSize = input(10485760);
    /**
     * Current attachments
     * @defaultValue []
     */
    attachments = model([]);
    /**
     * The label for the input, used for accessibility
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_CHAT_INPUT.LABEL:Chat message input`)
     * ```
     */
    label = input(t(() => $localize `:@@SI_CHAT_INPUT.LABEL:Chat message input`));
    /** Parameter to pass to action handlers */
    actionParam = input();
    /**
     * Send button label
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_CHAT_INPUT.SEND:Send`)
     * ```
     */
    sendButtonLabel = input(t(() => $localize `:@@SI_CHAT_INPUT.SEND:Send`));
    /**
     * Send button icon
     *
     * @defaultValue 'element-send-filled'
     */
    sendButtonIcon = input('element-send-filled');
    /**
     * Interrupt button label
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_CHAT_INPUT.INTERRUPT:Interrupt`)
     * ```
     */
    interruptButtonLabel = input(t(() => $localize `:@@SI_CHAT_INPUT.INTERRUPT:Interrupt`));
    /**
     * Auto-focus the input on component initialization
     * @defaultValue false
     */
    autoFocus = input(false, { transform: booleanAttribute });
    /**
     * Attach file button aria label
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_CHAT_INPUT.ATTACH_FILE:Attach file`)
     * ```
     */
    attachFileLabel = input(t(() => $localize `:@@SI_CHAT_INPUT.ATTACH_FILE:Attach file`));
    /**
     * Remove attachment aria label prefix
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_ATTACHMENT_LIST.REMOVE_ATTACHMENT:Remove attachment`)
     * ```
     */
    removeAttachmentLabel = input(t(() => $localize `:@@SI_ATTACHMENT_LIST.REMOVE_ATTACHMENT:Remove attachment`));
    /**
     * More actions button aria label
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_CHAT_INPUT.SECONDARY_ACTIONS:More actions`)
     * ```
     */
    secondaryActionsLabel = input(t(() => $localize `:@@SI_CHAT_INPUT.SECONDARY_ACTIONS:More actions`));
    /**
     * Emitted when the user wants to send a message
     */
    send = output();
    /**
     * Emitted when the user wants to interrupt the current operation
     */
    interrupt = output();
    /**
     * Emitted when file upload errors occur
     */
    fileError = output();
    id = `__si-chat-input-${SiChatInputComponent.idCounter++}`;
    hasContent = computed(() => this.value().trim().length > 0);
    hasAttachments = computed(() => this.attachments().length > 0);
    hasActions = computed(() => this.actions().length > 0);
    hasSecondaryActions = computed(() => this.secondaryActions().length > 0);
    canSend = computed(() => (this.hasContent() || this.hasAttachments()) && !this.disabled() && !this.sending());
    showInterruptButton = computed(() => this.interruptible());
    buttonDisabled = computed(() => {
        if (this.showInterruptButton()) {
            return this.disabled() || this.sending();
        }
        return !this.canSend();
    });
    buttonIcon = computed(() => this.showInterruptButton() ? 'element-stop-filled' : this.sendButtonIcon());
    buttonLabel = computed(() => this.showInterruptButton() ? this.interruptButtonLabel() : this.sendButtonLabel());
    dragOver = false;
    get attachmentList() {
        return this.attachments();
    }
    onInputChange(value) {
        this.value.set(value);
    }
    onSend() {
        if (this.canSend()) {
            this.send.emit({
                content: this.value(),
                attachments: this.attachments()
            });
            this.value.set('');
            this.attachments.set([]);
        }
    }
    onButtonClick() {
        if (this.showInterruptButton()) {
            this.interrupt.emit();
        }
        else {
            this.onSend();
        }
    }
    onKeyDown(event) {
        if (event.key === 'Enter' && !event.shiftKey) {
            event.preventDefault();
            if (!this.canSend()) {
                return;
            }
            if (this.showInterruptButton()) {
                this.interrupt.emit();
            }
            this.onSend();
        }
    }
    onFilesAdded(uploadFiles) {
        const validFiles = uploadFiles.filter(uploadFile => uploadFile.status === 'added');
        validFiles.forEach(uploadFile => {
            const size = parseInt(uploadFile.size, 10);
            const attachment = {
                name: uploadFile.fileName,
                size: isNaN(size) ? uploadFile.file.size : size,
                type: uploadFile.file.type,
                file: uploadFile.file
            };
            this.attachments.update(current => [...current, attachment]);
        });
    }
    onFileError(error) {
        this.fileError.emit(error);
    }
    removeAttachment(attachment) {
        this.attachments.update(current => {
            return current.filter(a => a !== attachment);
        });
    }
    onContainerClick(event) {
        const target = event.target;
        // Don't focus if clicking on interactive elements
        if (target.tagName === 'BUTTON' ||
            target.tagName === 'INPUT' ||
            target.tagName === 'TEXTAREA' ||
            target.closest('button') ||
            target.closest('[siChatMessageAction]') ||
            (target.closest('si-attachment-list') && target.closest('.attachment-item')) ||
            this.projectedContent()?.nativeElement?.contains(target)) {
            return;
        }
        this.focus();
    }
    ngAfterViewInit() {
        const textarea = this.textInput();
        if (textarea?.nativeElement) {
            this.setTextareaHeight(textarea.nativeElement);
            if (this.autoFocus()) {
                // Use setTimeout to ensure the element is fully rendered
                setTimeout(() => {
                    textarea.nativeElement.focus();
                }, 0);
            }
        }
    }
    adjustTextareaHeight(event) {
        const textarea = event.target;
        this.setTextareaHeight(textarea);
    }
    /**
     * Focus the textarea input
     */
    focus() {
        const textarea = this.textInput();
        if (textarea?.nativeElement) {
            textarea.nativeElement.focus();
        }
    }
    dropHandler(event) {
        event.preventDefault();
        event.stopPropagation();
        this.dragOver = false;
        if (!this.allowAttachments() || this.disabled()) {
            return;
        }
        const directive = this.fileUploadDirective();
        if (directive && event.dataTransfer?.files) {
            directive.handleFiles(event.dataTransfer.files);
        }
    }
    dragOverHandler(event) {
        if (!this.allowAttachments() || this.disabled()) {
            return;
        }
        event.preventDefault();
        event.stopPropagation();
        this.dragOver = true;
    }
    setTextareaHeight(textarea) {
        textarea.style.blockSize = 'auto';
        const computedStyle = window.getComputedStyle(textarea);
        const lineHeight = parseInt(computedStyle.lineHeight, 10) || parseInt(computedStyle.fontSize, 10) * 1.2;
        const paddingTop = parseInt(computedStyle.paddingBlockStart, 10) || 0;
        const paddingBottom = parseInt(computedStyle.paddingBlockEnd, 10) || 0;
        const minHeight = lineHeight + paddingTop + paddingBottom;
        const viewportHeight = window.innerHeight;
        const maxViewportHeight = viewportHeight * 0.3;
        const maxLinesHeight = lineHeight * 8;
        const maxHeight = Math.min(maxViewportHeight, maxLinesHeight) + paddingTop + paddingBottom;
        const scrollHeight = textarea.scrollHeight;
        const finalHeight = Math.max(Math.min(scrollHeight, maxHeight), minHeight);
        textarea.style.height = finalHeight + 'px';
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: SiChatInputComponent, isStandalone: true, selector: "si-chat-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, sending: { classPropertyName: "sending", publicName: "sending", isSignal: true, isRequired: false, transformFunction: null }, interruptible: { classPropertyName: "interruptible", publicName: "interruptible", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, disclaimer: { classPropertyName: "disclaimer", publicName: "disclaimer", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, secondaryActions: { classPropertyName: "secondaryActions", publicName: "secondaryActions", isSignal: true, isRequired: false, transformFunction: null }, allowAttachments: { classPropertyName: "allowAttachments", publicName: "allowAttachments", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, attachments: { classPropertyName: "attachments", publicName: "attachments", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, actionParam: { classPropertyName: "actionParam", publicName: "actionParam", isSignal: true, isRequired: false, transformFunction: null }, sendButtonLabel: { classPropertyName: "sendButtonLabel", publicName: "sendButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, sendButtonIcon: { classPropertyName: "sendButtonIcon", publicName: "sendButtonIcon", isSignal: true, isRequired: false, transformFunction: null }, interruptButtonLabel: { classPropertyName: "interruptButtonLabel", publicName: "interruptButtonLabel", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, attachFileLabel: { classPropertyName: "attachFileLabel", publicName: "attachFileLabel", isSignal: true, isRequired: false, transformFunction: null }, removeAttachmentLabel: { classPropertyName: "removeAttachmentLabel", publicName: "removeAttachmentLabel", isSignal: true, isRequired: false, transformFunction: null }, secondaryActionsLabel: { classPropertyName: "secondaryActionsLabel", publicName: "secondaryActionsLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", attachments: "attachmentsChange", send: "send", interrupt: "interrupt", fileError: "fileError" }, viewQueries: [{ propertyName: "textInput", first: true, predicate: ["textInput"], descendants: true, isSignal: true }, { propertyName: "projectedContent", first: true, predicate: ["projected"], descendants: true, isSignal: true }, { propertyName: "fileUploadDirective", first: true, predicate: SiFileUploadDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<div\n  class=\"input-wrapper border rounded-3 bg-body\"\n  [class.drag-over]=\"dragOver\"\n  (click)=\"onContainerClick($event)\"\n  (drop)=\"dropHandler($event)\"\n  (dragover)=\"dragOverHandler($event)\"\n  (dragleave)=\"dragOver = false\"\n>\n  @if (hasAttachments()) {\n    <div class=\"p-4 pb-0\">\n      <si-attachment-list\n        [attachments]=\"attachmentList\"\n        [removeLabel]=\"removeAttachmentLabel()\"\n        [removable]=\"true\"\n        (remove)=\"removeAttachment($event)\"\n      />\n    </div>\n  }\n\n  <div class=\"p-4 pe-2 pb-0 si-body-2\">\n    <label class=\"form-label d-none\" [for]=\"id\">{{ label() | translate }}</label>\n    <textarea\n      #textInput\n      class=\"chat-textarea w-100 border-0 p-2\"\n      rows=\"1\"\n      [id]=\"id\"\n      [placeholder]=\"placeholder() | translate\"\n      [disabled]=\"disabled()\"\n      [maxlength]=\"maxLength() || null\"\n      [(ngModel)]=\"value\"\n      (keydown)=\"onKeyDown($event)\"\n      (input)=\"adjustTextareaHeight($event)\"\n    ></textarea>\n  </div>\n\n  <div class=\"d-flex align-items-center justify-content-between px-4 ps-5 pb-2\">\n    <div class=\"d-flex align-items-center gap-4\">\n      @if (allowAttachments()) {\n        <input\n          #fileInput\n          type=\"file\"\n          class=\"d-none\"\n          siFileUpload\n          [accept]=\"accept()\"\n          [maxFileSize]=\"maxFileSize()\"\n          [multiple]=\"true\"\n          (validFiles)=\"onFilesAdded($event)\"\n          (fileError)=\"onFileError($event)\"\n        />\n\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm\"\n          [attr.aria-label]=\"attachFileLabel() | translate\"\n          [disabled]=\"disabled()\"\n          (click)=\"fileInput.click()\"\n        >\n          <si-icon icon=\"element-attachment\" />\n        </button>\n      }\n\n      @if (hasActions() || hasSecondaryActions()) {\n        <div class=\"d-flex gap-4 ai-message-actions\" siChatMessageAction>\n          @for (action of actions(); track $index) {\n            <button\n              type=\"button\"\n              class=\"btn btn-ghost btn-circle btn-sm\"\n              [disabled]=\"action.disabled\"\n              [attr.aria-label]=\"action.label | translate\"\n              (click)=\"action.action(actionParam(), action)\"\n            >\n              <si-icon [icon]=\"action.icon\" />\n            </button>\n          }\n\n          @if (secondaryActions().length > 0) {\n            <button\n              type=\"button\"\n              class=\"btn btn-ghost btn-circle btn-sm\"\n              [cdkMenuTriggerFor]=\"secondaryActionsMenu\"\n              [attr.aria-label]=\"secondaryActionsLabel() | translate\"\n              [attr.title]=\"secondaryActionsLabel() | translate\"\n            >\n              <si-icon icon=\"element-optionsVertical\" />\n            </button>\n\n            <ng-template #secondaryActionsMenu>\n              <si-menu-factory [items]=\"secondaryActions()\" [actionParam]=\"actionParam()\" />\n            </ng-template>\n          }\n        </div>\n      }\n      <div #projected class=\"d-flex flex-wrap align-items-start gap-4\">\n        <ng-content />\n      </div>\n    </div>\n\n    <button\n      type=\"button\"\n      class=\"btn btn-ghost btn-circle btn-sm\"\n      [disabled]=\"buttonDisabled()\"\n      [attr.aria-label]=\"buttonLabel() | translate\"\n      (click)=\"onButtonClick()\"\n    >\n      <si-icon class=\"text-primary\" [icon]=\"buttonIcon()\" />\n    </button>\n  </div>\n</div>\n\n<div class=\"disclaimer-wrapper text-center mt-4 px-3\">\n  @if (disclaimer()) {\n    <span class=\"si-caption text-secondary d-block\">{{ disclaimer() | translate }}</span>\n  }\n  <ng-content select=\"[siChatInputDisclaimer]\" />\n</div>\n", styles: [":host{max-inline-size:720px}.input-wrapper{border-color:var(--element-ui-4);background-color:var(--element-base-input-experimental)}.input-wrapper.drag-over{border:1px solid var(--element-focus-default);box-shadow:0 0 0 1px var(--element-focus-default)}.chat-textarea{min-block-size:1.7142857143em;font-family:inherit;outline:none;resize:none;background-color:transparent!important}.chat-textarea::placeholder{color:var(--element-text-secondary)}.chat-textarea:disabled{background-color:transparent!important;color:var(--element-text-disabled);cursor:not-allowed}.chat-textarea:disabled::placeholder{color:var(--element-text-disabled)}.input-wrapper:has(.chat-textarea:focus-visible){outline:var(--element-button-focus-width) solid var(--element-focus-default);outline-offset:var(--element-button-focus-overlay-width);border-color:var(--element-ui-1)}.disclaimer-wrapper:empty{display:none}\n"], dependencies: [{ kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }, { kind: "component", type: SiAttachmentListComponent, selector: "si-attachment-list", inputs: ["attachments", "alignment", "removable", "removeLabel"], outputs: ["remove"] }, { kind: "component", type: SiMenuFactoryComponent, selector: "si-menu-factory", inputs: ["items", "actionParam"] }, { kind: "directive", type: SiFileUploadDirective, selector: "input[type=\"file\"][siFileUpload]", inputs: ["errorTextFileType", "errorTextFileMaxSize", "accept", "maxFileSize", "multiple", "directoryUpload"], outputs: ["validFiles", "filesAdded", "fileError"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatInputComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-chat-input', imports: [
                        CdkMenuTrigger,
                        FormsModule,
                        SiIconComponent,
                        SiTranslatePipe,
                        SiAttachmentListComponent,
                        SiMenuFactoryComponent,
                        SiFileUploadDirective
                    ], template: "<div\n  class=\"input-wrapper border rounded-3 bg-body\"\n  [class.drag-over]=\"dragOver\"\n  (click)=\"onContainerClick($event)\"\n  (drop)=\"dropHandler($event)\"\n  (dragover)=\"dragOverHandler($event)\"\n  (dragleave)=\"dragOver = false\"\n>\n  @if (hasAttachments()) {\n    <div class=\"p-4 pb-0\">\n      <si-attachment-list\n        [attachments]=\"attachmentList\"\n        [removeLabel]=\"removeAttachmentLabel()\"\n        [removable]=\"true\"\n        (remove)=\"removeAttachment($event)\"\n      />\n    </div>\n  }\n\n  <div class=\"p-4 pe-2 pb-0 si-body-2\">\n    <label class=\"form-label d-none\" [for]=\"id\">{{ label() | translate }}</label>\n    <textarea\n      #textInput\n      class=\"chat-textarea w-100 border-0 p-2\"\n      rows=\"1\"\n      [id]=\"id\"\n      [placeholder]=\"placeholder() | translate\"\n      [disabled]=\"disabled()\"\n      [maxlength]=\"maxLength() || null\"\n      [(ngModel)]=\"value\"\n      (keydown)=\"onKeyDown($event)\"\n      (input)=\"adjustTextareaHeight($event)\"\n    ></textarea>\n  </div>\n\n  <div class=\"d-flex align-items-center justify-content-between px-4 ps-5 pb-2\">\n    <div class=\"d-flex align-items-center gap-4\">\n      @if (allowAttachments()) {\n        <input\n          #fileInput\n          type=\"file\"\n          class=\"d-none\"\n          siFileUpload\n          [accept]=\"accept()\"\n          [maxFileSize]=\"maxFileSize()\"\n          [multiple]=\"true\"\n          (validFiles)=\"onFilesAdded($event)\"\n          (fileError)=\"onFileError($event)\"\n        />\n\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm\"\n          [attr.aria-label]=\"attachFileLabel() | translate\"\n          [disabled]=\"disabled()\"\n          (click)=\"fileInput.click()\"\n        >\n          <si-icon icon=\"element-attachment\" />\n        </button>\n      }\n\n      @if (hasActions() || hasSecondaryActions()) {\n        <div class=\"d-flex gap-4 ai-message-actions\" siChatMessageAction>\n          @for (action of actions(); track $index) {\n            <button\n              type=\"button\"\n              class=\"btn btn-ghost btn-circle btn-sm\"\n              [disabled]=\"action.disabled\"\n              [attr.aria-label]=\"action.label | translate\"\n              (click)=\"action.action(actionParam(), action)\"\n            >\n              <si-icon [icon]=\"action.icon\" />\n            </button>\n          }\n\n          @if (secondaryActions().length > 0) {\n            <button\n              type=\"button\"\n              class=\"btn btn-ghost btn-circle btn-sm\"\n              [cdkMenuTriggerFor]=\"secondaryActionsMenu\"\n              [attr.aria-label]=\"secondaryActionsLabel() | translate\"\n              [attr.title]=\"secondaryActionsLabel() | translate\"\n            >\n              <si-icon icon=\"element-optionsVertical\" />\n            </button>\n\n            <ng-template #secondaryActionsMenu>\n              <si-menu-factory [items]=\"secondaryActions()\" [actionParam]=\"actionParam()\" />\n            </ng-template>\n          }\n        </div>\n      }\n      <div #projected class=\"d-flex flex-wrap align-items-start gap-4\">\n        <ng-content />\n      </div>\n    </div>\n\n    <button\n      type=\"button\"\n      class=\"btn btn-ghost btn-circle btn-sm\"\n      [disabled]=\"buttonDisabled()\"\n      [attr.aria-label]=\"buttonLabel() | translate\"\n      (click)=\"onButtonClick()\"\n    >\n      <si-icon class=\"text-primary\" [icon]=\"buttonIcon()\" />\n    </button>\n  </div>\n</div>\n\n<div class=\"disclaimer-wrapper text-center mt-4 px-3\">\n  @if (disclaimer()) {\n    <span class=\"si-caption text-secondary d-block\">{{ disclaimer() | translate }}</span>\n  }\n  <ng-content select=\"[siChatInputDisclaimer]\" />\n</div>\n", styles: [":host{max-inline-size:720px}.input-wrapper{border-color:var(--element-ui-4);background-color:var(--element-base-input-experimental)}.input-wrapper.drag-over{border:1px solid var(--element-focus-default);box-shadow:0 0 0 1px var(--element-focus-default)}.chat-textarea{min-block-size:1.7142857143em;font-family:inherit;outline:none;resize:none;background-color:transparent!important}.chat-textarea::placeholder{color:var(--element-text-secondary)}.chat-textarea:disabled{background-color:transparent!important;color:var(--element-text-disabled);cursor:not-allowed}.chat-textarea:disabled::placeholder{color:var(--element-text-disabled)}.input-wrapper:has(.chat-textarea:focus-visible){outline:var(--element-button-focus-width) solid var(--element-focus-default);outline-offset:var(--element-button-focus-overlay-width);border-color:var(--element-ui-1)}.disclaimer-wrapper:empty{display:none}\n"] }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
/**
 * Directive to mark content as chat input disclaimer into {@link SiChatInputComponent}.
 * Apply this directive to content that should be slotted into the disclaimer area.
 *
 * @example
 * ```html
 * <si-chat-input>
 *   <div siChatInputDisclaimer>
 *     Custom disclaimer content
 *   </div>
 * </si-chat-input>
 * ```
 *
 * @see {@link SiChatInputComponent} for the chat input wrapper component
 *
 * @experimental
 */
class SiChatInputDisclaimerDirective {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatInputDisclaimerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.6", type: SiChatInputDisclaimerDirective, isStandalone: true, selector: "[siChatInputDisclaimer]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiChatInputDisclaimerDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[siChatInputDisclaimer]'
                }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
/**
 * User message component for displaying the user's messages in conversational interfaces.
 *
 * The user message component renders user-submitted content in (AI) chat interfaces,
 * supporting text, attachments, and contextual actions. It appears as a text bubble
 * aligned to the right side and supports markdown formatting for rich content.
 * Can be used within {@link SiChatContainerComponent}.
 *
 * The component automatically handles:
 * - Styling for user messages distinct from AI or generic chat messages
 * - Option to render markdown content, provide via `contentFormatter` input with a markdown renderer function (e.g., from {@link getMarkdownRenderer})
 * - Displaying attachments above the message bubble
 * - Displaying primary and secondary actions
 *
 * @see {@link SiChatMessageComponent} for the base message wrapper component
 * @see {@link SiAiMessageComponent} for the AI message component
 * @see {@link SiAttachmentListComponent} for the base attachment component
 * @see {@link getMarkdownRenderer} for markdown formatting support
 * @see {@link SiChatContainerComponent} for the chat container to use this within
 *
 * @experimental
 */
class SiUserMessageComponent {
    formattedContent = viewChild('formattedContent');
    /**
     * The user message content
     * @defaultValue ''
     */
    content = input('');
    /**
     * Optional formatter function to transform content before display.
     * - Returns string: Content will be inserted as text with built-in sanitization
     * - Returns Node: DOM node will be inserted directly without sanitization
     *
     * **Note:** When returning a Node with formatted content, apply the `markdown-content` class
     * to the root element to ensure proper styling (e.g., `div.className = 'markdown-content'`).
     * The function returned by {@link getMarkdownRenderer} does this automatically.
     *
     * **Warning:** When returning a Node, ensure the content is safe to prevent XSS attacks
     * @defaultValue undefined
     */
    contentFormatter = input(undefined);
    /**
     * Primary message actions (edit, delete, copy, etc.).
     * All actions displayed inline
     * @defaultValue []
     */
    actions = input([]);
    /**
     * Secondary actions available in dropdown menu, first use primary actions and only add secondary actions additionally
     * @defaultValue []
     */
    secondaryActions = input([]);
    /**
     * List of attachments included with this message
     * @defaultValue []
     */
    attachments = input([]);
    /** Parameter to pass to action handlers */
    actionParam = input();
    /**
     * More actions button aria label
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_USER_MESSAGE.SECONDARY_ACTIONS:More actions`)
     * ```
     */
    secondaryActionsLabel = input(t(() => $localize `:@@SI_USER_MESSAGE.SECONDARY_ACTIONS:More actions`));
    hasAttachments = computed(() => this.attachments()?.length > 0);
    textContent = signal(undefined);
    constructor() {
        effect(() => {
            const formatter = this.contentFormatter();
            const contentValue = this.content();
            const container = this.formattedContent()?.nativeElement;
            if (container && contentValue) {
                if (formatter) {
                    const formatted = formatter(contentValue);
                    if (typeof formatted === 'string') {
                        this.textContent.set(formatted);
                    }
                    else if (formatted instanceof Node) {
                        this.textContent.set(undefined);
                        container.innerHTML = '';
                        container.appendChild(formatted);
                    }
                }
                else {
                    this.textContent.set(contentValue);
                }
            }
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiUserMessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.6", type: SiUserMessageComponent, isStandalone: true, selector: "si-user-message", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, contentFormatter: { classPropertyName: "contentFormatter", publicName: "contentFormatter", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, secondaryActions: { classPropertyName: "secondaryActions", publicName: "secondaryActions", isSignal: true, isRequired: false, transformFunction: null }, attachments: { classPropertyName: "attachments", publicName: "attachments", isSignal: true, isRequired: false, transformFunction: null }, actionParam: { classPropertyName: "actionParam", publicName: "actionParam", isSignal: true, isRequired: false, transformFunction: null }, secondaryActionsLabel: { classPropertyName: "secondaryActionsLabel", publicName: "secondaryActionsLabel", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "formattedContent", first: true, predicate: ["formattedContent"], descendants: true, isSignal: true }], ngImport: i0, template: "<si-chat-message alignment=\"end\" actionsPosition=\"bottom\" [loading]=\"false\">\n  @if (hasAttachments()) {\n    <si-attachment-list alignment=\"end\" [attachments]=\"attachments()\" [removable]=\"false\" />\n  }\n\n  @if (content()) {\n    @let content = textContent();\n    @if (content) {\n      <span class=\"text-pre-wrap\">{{ content }}</span>\n    } @else {\n      <div #formattedContent> </div>\n    }\n  }\n  @if ((actions()?.length ?? 0 > 0) || (secondaryActions()?.length ?? 0 > 0)) {\n    <div class=\"d-flex gap-4 user-message-actions\" siChatMessageAction>\n      @for (action of actions(); track $index) {\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm\"\n          [disabled]=\"action.disabled\"\n          [attr.aria-label]=\"action.label | translate\"\n          (click)=\"action.action(actionParam(), action)\"\n        >\n          <si-icon [icon]=\"action.icon\" />\n        </button>\n      }\n\n      @if (secondaryActions()?.length ?? 0 > 0) {\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm\"\n          [cdkMenuTriggerFor]=\"secondaryActionsMenu\"\n          [attr.aria-label]=\"secondaryActionsLabel() | translate\"\n          [attr.title]=\"secondaryActionsLabel() | translate\"\n        >\n          <si-icon icon=\"element-optionsVertical\" />\n        </button>\n\n        <ng-template #secondaryActionsMenu>\n          <si-menu-factory [items]=\"secondaryActions()\" [actionParam]=\"actionParam()\" />\n        </ng-template>\n      }\n    </div>\n  }\n</si-chat-message>\n", styles: [":host{display:block}:host:not(:has([siChatMessageAction])) si-chat-message{padding-block-end:36px!important}.user-message-actions{opacity:0;transition:opacity .2s ease}si-chat-message{--chat-message-bubble-bg: var(--element-base-input-experimental);max-inline-size:600px;margin-inline-start:auto}:host:hover .user-message-actions,.user-message-actions:hover,.user-message-actions:has(::ng-deep [aria-expanded=true]),:host-context(.si-container-xs,.si-container-sm) .user-message-actions:active{opacity:1}\n"], dependencies: [{ kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "component", type: SiAttachmentListComponent, selector: "si-attachment-list", inputs: ["attachments", "alignment", "removable", "removeLabel"], outputs: ["remove"] }, { kind: "component", type: SiChatMessageComponent, selector: "si-chat-message", inputs: ["loading", "alignment", "actionsPosition"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "component", type: SiMenuFactoryComponent, selector: "si-menu-factory", inputs: ["items", "actionParam"] }, { kind: "directive", type: SiChatMessageActionDirective, selector: "[siChatMessageAction]" }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: SiUserMessageComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-user-message', imports: [
                        CdkMenuTrigger,
                        SiAttachmentListComponent,
                        SiChatMessageComponent,
                        SiIconComponent,
                        SiMenuFactoryComponent,
                        SiChatMessageActionDirective,
                        SiTranslatePipe
                    ], template: "<si-chat-message alignment=\"end\" actionsPosition=\"bottom\" [loading]=\"false\">\n  @if (hasAttachments()) {\n    <si-attachment-list alignment=\"end\" [attachments]=\"attachments()\" [removable]=\"false\" />\n  }\n\n  @if (content()) {\n    @let content = textContent();\n    @if (content) {\n      <span class=\"text-pre-wrap\">{{ content }}</span>\n    } @else {\n      <div #formattedContent> </div>\n    }\n  }\n  @if ((actions()?.length ?? 0 > 0) || (secondaryActions()?.length ?? 0 > 0)) {\n    <div class=\"d-flex gap-4 user-message-actions\" siChatMessageAction>\n      @for (action of actions(); track $index) {\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm\"\n          [disabled]=\"action.disabled\"\n          [attr.aria-label]=\"action.label | translate\"\n          (click)=\"action.action(actionParam(), action)\"\n        >\n          <si-icon [icon]=\"action.icon\" />\n        </button>\n      }\n\n      @if (secondaryActions()?.length ?? 0 > 0) {\n        <button\n          type=\"button\"\n          class=\"btn btn-ghost btn-circle btn-sm\"\n          [cdkMenuTriggerFor]=\"secondaryActionsMenu\"\n          [attr.aria-label]=\"secondaryActionsLabel() | translate\"\n          [attr.title]=\"secondaryActionsLabel() | translate\"\n        >\n          <si-icon icon=\"element-optionsVertical\" />\n        </button>\n\n        <ng-template #secondaryActionsMenu>\n          <si-menu-factory [items]=\"secondaryActions()\" [actionParam]=\"actionParam()\" />\n        </ng-template>\n      }\n    </div>\n  }\n</si-chat-message>\n", styles: [":host{display:block}:host:not(:has([siChatMessageAction])) si-chat-message{padding-block-end:36px!important}.user-message-actions{opacity:0;transition:opacity .2s ease}si-chat-message{--chat-message-bubble-bg: var(--element-base-input-experimental);max-inline-size:600px;margin-inline-start:auto}:host:hover .user-message-actions,.user-message-actions:hover,.user-message-actions:has(::ng-deep [aria-expanded=true]),:host-context(.si-container-xs,.si-container-sm) .user-message-actions:active{opacity:1}\n"] }]
        }], ctorParameters: () => [] });

/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */

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

export { SiAiMessageComponent, SiAttachmentListComponent, SiChatContainerComponent, SiChatContainerInputDirective, SiChatInputComponent, SiChatInputDisclaimerDirective, SiChatMessageActionDirective, SiChatMessageComponent, SiUserMessageComponent };
//# sourceMappingURL=siemens-element-ng-chat-messages.mjs.map
