@atelier-ui/angular 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3182 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, computed, ChangeDetectionStrategy, Component, model, viewChild, effect, InjectionToken, inject, ElementRef, signal, output, Directive, ViewEncapsulation, Injector, Injectable, DestroyRef, untracked, contentChildren } from '@angular/core';
3
+ import * as i1 from '@angular/cdk/text-field';
4
+ import { TextFieldModule } from '@angular/cdk/text-field';
5
+ import * as i1$1 from '@angular/cdk/a11y';
6
+ import { ActiveDescendantKeyManager, A11yModule } from '@angular/cdk/a11y';
7
+ import * as i1$2 from '@angular/cdk/accordion';
8
+ import { CdkAccordion, CdkAccordionItem } from '@angular/cdk/accordion';
9
+ import * as i1$3 from '@angular/cdk/menu';
10
+ import { CdkMenuTrigger, CdkMenu, CdkMenuItem } from '@angular/cdk/menu';
11
+ import { createFlexibleConnectedPositionStrategy, createRepositionScrollStrategy, createOverlayRef } from '@angular/cdk/overlay';
12
+ import { ComponentPortal } from '@angular/cdk/portal';
13
+
14
+ /**
15
+ * Accessible button component with visual variants and sizes.
16
+ *
17
+ * Usage:
18
+ * ```html
19
+ * <llm-button variant="primary" size="md" (click)="save()">Save</llm-button>
20
+ * <llm-button variant="outline" [disabled]="true">Cancel</llm-button>
21
+ * <llm-button [loading]="isSaving">Saving…</llm-button>
22
+ * ```
23
+ */
24
+ class LlmButton {
25
+ /** Visual style of the button. */
26
+ variant = input('primary', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
27
+ /** Size of the button. */
28
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
29
+ /** Disables the button, preventing interaction. */
30
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
31
+ /** Shows a loading spinner and disables interaction. */
32
+ loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
33
+ isDisabled = computed(() => this.disabled() || this.loading(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
34
+ hostClasses = computed(() => `variant-${this.variant()} size-${this.size()}${this.isDisabled() ? ' is-disabled' : ''}${this.loading() ? ' is-loading' : ''}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
35
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
36
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmButton, isStandalone: true, selector: "llm-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "button" }, properties: { "class": "hostClasses()", "attr.aria-disabled": "isDisabled()", "attr.disabled": "isDisabled() ? true : null" } }, ngImport: i0, template: `
37
+ @if (loading()) {
38
+ <span class="spinner" aria-hidden="true"></span>
39
+ }
40
+ <ng-content />
41
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;gap:var(--ui-spacing-2);border:1px solid transparent;border-radius:var(--ui-radius-md);font-family:var(--ui-font-family);font-size:var(--ui-font-size-md);font-weight:var(--ui-font-weight-medium);line-height:var(--ui-line-height-tight);cursor:pointer;transition:background-color var(--ui-transition-fast),border-color var(--ui-transition-fast),color var(--ui-transition-fast),box-shadow var(--ui-transition-fast),transform var(--ui-transition-fast);white-space:nowrap;text-decoration:none;-webkit-user-select:none;user-select:none}:host(:focus-visible){outline:none;box-shadow:var(--ui-focus-ring)}:host(.variant-primary){background-color:var(--ui-color-primary);color:var(--ui-color-text-on-primary);border-color:var(--ui-color-primary);box-shadow:var(--ui-shadow-xs)}:host(.variant-primary:hover:not(.is-disabled)){background-color:var(--ui-color-primary-hover);border-color:var(--ui-color-primary-hover);box-shadow:var(--ui-shadow-md);transform:translateY(-1px)}:host(.variant-primary:active:not(.is-disabled)){background-color:var(--ui-color-primary-active);border-color:var(--ui-color-primary-active);box-shadow:var(--ui-shadow-xs);transform:scale(.97)}:host(.variant-secondary){background-color:var(--ui-color-secondary);color:var(--ui-color-text-on-secondary);border-color:var(--ui-color-secondary);box-shadow:var(--ui-shadow-xs)}:host(.variant-secondary:hover:not(.is-disabled)){background-color:var(--ui-color-secondary-hover);border-color:var(--ui-color-secondary-hover);box-shadow:var(--ui-shadow-md);transform:translateY(-1px)}:host(.variant-secondary:active:not(.is-disabled)){background-color:var(--ui-color-secondary-active);border-color:var(--ui-color-secondary-active);box-shadow:var(--ui-shadow-xs);transform:scale(.97)}:host(.variant-outline){background-color:transparent;color:var(--ui-color-primary);border-color:var(--ui-color-border)}:host(.variant-outline:hover:not(.is-disabled)){background-color:var(--ui-color-primary-light);border-color:var(--ui-color-primary);transform:translateY(-1px)}:host(.variant-outline:active:not(.is-disabled)){background-color:color-mix(in srgb,var(--ui-color-primary) 12%,transparent);transform:scale(.97)}:host(.size-sm){padding:var(--ui-spacing-1) var(--ui-spacing-3);font-size:var(--ui-font-size-sm)}:host(.size-md){padding:var(--ui-spacing-2) var(--ui-spacing-4);font-size:var(--ui-font-size-md)}:host(.size-lg){padding:var(--ui-spacing-3) var(--ui-spacing-6);font-size:var(--ui-font-size-lg)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed;pointer-events:none}.spinner{display:inline-block;width:1em;height:1em;border:1.5px solid currentColor;border-top-color:transparent;border-radius:var(--ui-radius-full);animation:llm-spin .7s linear infinite;flex-shrink:0}@keyframes llm-spin{to{transform:rotate(360deg)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
42
+ }
43
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmButton, decorators: [{
44
+ type: Component,
45
+ args: [{ selector: 'llm-button', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
46
+ @if (loading()) {
47
+ <span class="spinner" aria-hidden="true"></span>
48
+ }
49
+ <ng-content />
50
+ `, host: {
51
+ role: 'button',
52
+ '[class]': 'hostClasses()',
53
+ '[attr.aria-disabled]': 'isDisabled()',
54
+ '[attr.disabled]': 'isDisabled() ? true : null',
55
+ }, styles: [":host{display:inline-flex;align-items:center;justify-content:center;gap:var(--ui-spacing-2);border:1px solid transparent;border-radius:var(--ui-radius-md);font-family:var(--ui-font-family);font-size:var(--ui-font-size-md);font-weight:var(--ui-font-weight-medium);line-height:var(--ui-line-height-tight);cursor:pointer;transition:background-color var(--ui-transition-fast),border-color var(--ui-transition-fast),color var(--ui-transition-fast),box-shadow var(--ui-transition-fast),transform var(--ui-transition-fast);white-space:nowrap;text-decoration:none;-webkit-user-select:none;user-select:none}:host(:focus-visible){outline:none;box-shadow:var(--ui-focus-ring)}:host(.variant-primary){background-color:var(--ui-color-primary);color:var(--ui-color-text-on-primary);border-color:var(--ui-color-primary);box-shadow:var(--ui-shadow-xs)}:host(.variant-primary:hover:not(.is-disabled)){background-color:var(--ui-color-primary-hover);border-color:var(--ui-color-primary-hover);box-shadow:var(--ui-shadow-md);transform:translateY(-1px)}:host(.variant-primary:active:not(.is-disabled)){background-color:var(--ui-color-primary-active);border-color:var(--ui-color-primary-active);box-shadow:var(--ui-shadow-xs);transform:scale(.97)}:host(.variant-secondary){background-color:var(--ui-color-secondary);color:var(--ui-color-text-on-secondary);border-color:var(--ui-color-secondary);box-shadow:var(--ui-shadow-xs)}:host(.variant-secondary:hover:not(.is-disabled)){background-color:var(--ui-color-secondary-hover);border-color:var(--ui-color-secondary-hover);box-shadow:var(--ui-shadow-md);transform:translateY(-1px)}:host(.variant-secondary:active:not(.is-disabled)){background-color:var(--ui-color-secondary-active);border-color:var(--ui-color-secondary-active);box-shadow:var(--ui-shadow-xs);transform:scale(.97)}:host(.variant-outline){background-color:transparent;color:var(--ui-color-primary);border-color:var(--ui-color-border)}:host(.variant-outline:hover:not(.is-disabled)){background-color:var(--ui-color-primary-light);border-color:var(--ui-color-primary);transform:translateY(-1px)}:host(.variant-outline:active:not(.is-disabled)){background-color:color-mix(in srgb,var(--ui-color-primary) 12%,transparent);transform:scale(.97)}:host(.size-sm){padding:var(--ui-spacing-1) var(--ui-spacing-3);font-size:var(--ui-font-size-sm)}:host(.size-md){padding:var(--ui-spacing-2) var(--ui-spacing-4);font-size:var(--ui-font-size-md)}:host(.size-lg){padding:var(--ui-spacing-3) var(--ui-spacing-6);font-size:var(--ui-font-size-lg)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed;pointer-events:none}.spinner{display:inline-block;width:1em;height:1em;border:1.5px solid currentColor;border-top-color:transparent;border-radius:var(--ui-radius-full);animation:llm-spin .7s linear infinite;flex-shrink:0}@keyframes llm-spin{to{transform:rotate(360deg)}}\n"] }]
56
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }] } });
57
+
58
+ /**
59
+ * Card container component supporting elevated, outlined, and flat visual variants.
60
+ * Compose with `llm-card-header`, `llm-card-content`, and `llm-card-footer` sub-components.
61
+ *
62
+ * Usage:
63
+ * ```html
64
+ * <llm-card variant="elevated" padding="md">
65
+ * <llm-card-header>Card Title</llm-card-header>
66
+ * <llm-card-content>Main content goes here.</llm-card-content>
67
+ * <llm-card-footer>
68
+ * <llm-button variant="primary">Save</llm-button>
69
+ * </llm-card-footer>
70
+ * </llm-card>
71
+ * ```
72
+ */
73
+ class LlmCard {
74
+ /** Visual style of the card. */
75
+ variant = input('elevated', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
76
+ /** Internal padding of the card. */
77
+ padding = input('md', ...(ngDevMode ? [{ debugName: "padding" }] : /* istanbul ignore next */ []));
78
+ hostClasses = computed(() => `variant-${this.variant()} padding-${this.padding()}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
79
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
80
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmCard, isStandalone: true, selector: "llm-card", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["llm-card{display:block;border-radius:var(--ui-radius-xl);background-color:var(--ui-color-surface);overflow:hidden}llm-card.variant-elevated{box-shadow:var(--ui-shadow-md);border:1px solid var(--ui-color-border)}llm-card.variant-outlined{border:1px solid var(--ui-color-border);background-color:var(--ui-color-surface)}llm-card.variant-flat{background-color:var(--ui-color-surface-sunken)}llm-card.padding-none llm-card-header,llm-card.padding-none llm-card-content,llm-card.padding-none llm-card-footer{padding:0}llm-card.padding-sm llm-card-header,llm-card.padding-sm llm-card-content,llm-card.padding-sm llm-card-footer{padding:var(--ui-spacing-3)}llm-card.padding-md llm-card-header,llm-card.padding-md llm-card-content,llm-card.padding-md llm-card-footer{padding:var(--ui-spacing-4)}llm-card.padding-lg llm-card-header,llm-card.padding-lg llm-card-content,llm-card.padding-lg llm-card-footer{padding:var(--ui-spacing-6)}llm-card-header{display:block;font-size:var(--ui-font-size-lg);font-weight:var(--ui-font-weight-semibold);color:var(--ui-color-text);border-bottom:1px solid var(--ui-color-border);letter-spacing:var(--ui-letter-spacing-tight)}llm-card-content{display:block;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}llm-card-footer{display:flex;align-items:center;gap:var(--ui-spacing-2);border-top:1px solid var(--ui-color-border)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
81
+ }
82
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmCard, decorators: [{
83
+ type: Component,
84
+ args: [{ selector: 'llm-card', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, host: {
85
+ '[class]': 'hostClasses()',
86
+ }, styles: ["llm-card{display:block;border-radius:var(--ui-radius-xl);background-color:var(--ui-color-surface);overflow:hidden}llm-card.variant-elevated{box-shadow:var(--ui-shadow-md);border:1px solid var(--ui-color-border)}llm-card.variant-outlined{border:1px solid var(--ui-color-border);background-color:var(--ui-color-surface)}llm-card.variant-flat{background-color:var(--ui-color-surface-sunken)}llm-card.padding-none llm-card-header,llm-card.padding-none llm-card-content,llm-card.padding-none llm-card-footer{padding:0}llm-card.padding-sm llm-card-header,llm-card.padding-sm llm-card-content,llm-card.padding-sm llm-card-footer{padding:var(--ui-spacing-3)}llm-card.padding-md llm-card-header,llm-card.padding-md llm-card-content,llm-card.padding-md llm-card-footer{padding:var(--ui-spacing-4)}llm-card.padding-lg llm-card-header,llm-card.padding-lg llm-card-content,llm-card.padding-lg llm-card-footer{padding:var(--ui-spacing-6)}llm-card-header{display:block;font-size:var(--ui-font-size-lg);font-weight:var(--ui-font-weight-semibold);color:var(--ui-color-text);border-bottom:1px solid var(--ui-color-border);letter-spacing:var(--ui-letter-spacing-tight)}llm-card-content{display:block;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}llm-card-footer{display:flex;align-items:center;gap:var(--ui-spacing-2);border-top:1px solid var(--ui-color-border)}\n"] }]
87
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }] } });
88
+ /**
89
+ * Header slot for `llm-card`. Renders above the main content with a bottom separator.
90
+ *
91
+ * Usage:
92
+ * ```html
93
+ * <llm-card-header>Card Title</llm-card-header>
94
+ * ```
95
+ */
96
+ class LlmCardHeader {
97
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmCardHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
98
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmCardHeader, isStandalone: true, selector: "llm-card-header", ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["llm-card{display:block;border-radius:var(--ui-radius-xl);background-color:var(--ui-color-surface);overflow:hidden}llm-card.variant-elevated{box-shadow:var(--ui-shadow-md);border:1px solid var(--ui-color-border)}llm-card.variant-outlined{border:1px solid var(--ui-color-border);background-color:var(--ui-color-surface)}llm-card.variant-flat{background-color:var(--ui-color-surface-sunken)}llm-card.padding-none llm-card-header,llm-card.padding-none llm-card-content,llm-card.padding-none llm-card-footer{padding:0}llm-card.padding-sm llm-card-header,llm-card.padding-sm llm-card-content,llm-card.padding-sm llm-card-footer{padding:var(--ui-spacing-3)}llm-card.padding-md llm-card-header,llm-card.padding-md llm-card-content,llm-card.padding-md llm-card-footer{padding:var(--ui-spacing-4)}llm-card.padding-lg llm-card-header,llm-card.padding-lg llm-card-content,llm-card.padding-lg llm-card-footer{padding:var(--ui-spacing-6)}llm-card-header{display:block;font-size:var(--ui-font-size-lg);font-weight:var(--ui-font-weight-semibold);color:var(--ui-color-text);border-bottom:1px solid var(--ui-color-border);letter-spacing:var(--ui-letter-spacing-tight)}llm-card-content{display:block;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}llm-card-footer{display:flex;align-items:center;gap:var(--ui-spacing-2);border-top:1px solid var(--ui-color-border)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
99
+ }
100
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmCardHeader, decorators: [{
101
+ type: Component,
102
+ args: [{ selector: 'llm-card-header', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, styles: ["llm-card{display:block;border-radius:var(--ui-radius-xl);background-color:var(--ui-color-surface);overflow:hidden}llm-card.variant-elevated{box-shadow:var(--ui-shadow-md);border:1px solid var(--ui-color-border)}llm-card.variant-outlined{border:1px solid var(--ui-color-border);background-color:var(--ui-color-surface)}llm-card.variant-flat{background-color:var(--ui-color-surface-sunken)}llm-card.padding-none llm-card-header,llm-card.padding-none llm-card-content,llm-card.padding-none llm-card-footer{padding:0}llm-card.padding-sm llm-card-header,llm-card.padding-sm llm-card-content,llm-card.padding-sm llm-card-footer{padding:var(--ui-spacing-3)}llm-card.padding-md llm-card-header,llm-card.padding-md llm-card-content,llm-card.padding-md llm-card-footer{padding:var(--ui-spacing-4)}llm-card.padding-lg llm-card-header,llm-card.padding-lg llm-card-content,llm-card.padding-lg llm-card-footer{padding:var(--ui-spacing-6)}llm-card-header{display:block;font-size:var(--ui-font-size-lg);font-weight:var(--ui-font-weight-semibold);color:var(--ui-color-text);border-bottom:1px solid var(--ui-color-border);letter-spacing:var(--ui-letter-spacing-tight)}llm-card-content{display:block;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}llm-card-footer{display:flex;align-items:center;gap:var(--ui-spacing-2);border-top:1px solid var(--ui-color-border)}\n"] }]
103
+ }] });
104
+ /**
105
+ * Content slot for `llm-card`. Primary content area of the card.
106
+ *
107
+ * Usage:
108
+ * ```html
109
+ * <llm-card-content>Body text here.</llm-card-content>
110
+ * ```
111
+ */
112
+ class LlmCardContent {
113
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmCardContent, deps: [], target: i0.ɵɵFactoryTarget.Component });
114
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmCardContent, isStandalone: true, selector: "llm-card-content", ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["llm-card{display:block;border-radius:var(--ui-radius-xl);background-color:var(--ui-color-surface);overflow:hidden}llm-card.variant-elevated{box-shadow:var(--ui-shadow-md);border:1px solid var(--ui-color-border)}llm-card.variant-outlined{border:1px solid var(--ui-color-border);background-color:var(--ui-color-surface)}llm-card.variant-flat{background-color:var(--ui-color-surface-sunken)}llm-card.padding-none llm-card-header,llm-card.padding-none llm-card-content,llm-card.padding-none llm-card-footer{padding:0}llm-card.padding-sm llm-card-header,llm-card.padding-sm llm-card-content,llm-card.padding-sm llm-card-footer{padding:var(--ui-spacing-3)}llm-card.padding-md llm-card-header,llm-card.padding-md llm-card-content,llm-card.padding-md llm-card-footer{padding:var(--ui-spacing-4)}llm-card.padding-lg llm-card-header,llm-card.padding-lg llm-card-content,llm-card.padding-lg llm-card-footer{padding:var(--ui-spacing-6)}llm-card-header{display:block;font-size:var(--ui-font-size-lg);font-weight:var(--ui-font-weight-semibold);color:var(--ui-color-text);border-bottom:1px solid var(--ui-color-border);letter-spacing:var(--ui-letter-spacing-tight)}llm-card-content{display:block;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}llm-card-footer{display:flex;align-items:center;gap:var(--ui-spacing-2);border-top:1px solid var(--ui-color-border)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
115
+ }
116
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmCardContent, decorators: [{
117
+ type: Component,
118
+ args: [{ selector: 'llm-card-content', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, styles: ["llm-card{display:block;border-radius:var(--ui-radius-xl);background-color:var(--ui-color-surface);overflow:hidden}llm-card.variant-elevated{box-shadow:var(--ui-shadow-md);border:1px solid var(--ui-color-border)}llm-card.variant-outlined{border:1px solid var(--ui-color-border);background-color:var(--ui-color-surface)}llm-card.variant-flat{background-color:var(--ui-color-surface-sunken)}llm-card.padding-none llm-card-header,llm-card.padding-none llm-card-content,llm-card.padding-none llm-card-footer{padding:0}llm-card.padding-sm llm-card-header,llm-card.padding-sm llm-card-content,llm-card.padding-sm llm-card-footer{padding:var(--ui-spacing-3)}llm-card.padding-md llm-card-header,llm-card.padding-md llm-card-content,llm-card.padding-md llm-card-footer{padding:var(--ui-spacing-4)}llm-card.padding-lg llm-card-header,llm-card.padding-lg llm-card-content,llm-card.padding-lg llm-card-footer{padding:var(--ui-spacing-6)}llm-card-header{display:block;font-size:var(--ui-font-size-lg);font-weight:var(--ui-font-weight-semibold);color:var(--ui-color-text);border-bottom:1px solid var(--ui-color-border);letter-spacing:var(--ui-letter-spacing-tight)}llm-card-content{display:block;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}llm-card-footer{display:flex;align-items:center;gap:var(--ui-spacing-2);border-top:1px solid var(--ui-color-border)}\n"] }]
119
+ }] });
120
+ /**
121
+ * Footer slot for `llm-card`. Renders below the main content, typically holds actions.
122
+ *
123
+ * Usage:
124
+ * ```html
125
+ * <llm-card-footer>
126
+ * <llm-button variant="primary">Save</llm-button>
127
+ * </llm-card-footer>
128
+ * ```
129
+ */
130
+ class LlmCardFooter {
131
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmCardFooter, deps: [], target: i0.ɵɵFactoryTarget.Component });
132
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmCardFooter, isStandalone: true, selector: "llm-card-footer", ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["llm-card{display:block;border-radius:var(--ui-radius-xl);background-color:var(--ui-color-surface);overflow:hidden}llm-card.variant-elevated{box-shadow:var(--ui-shadow-md);border:1px solid var(--ui-color-border)}llm-card.variant-outlined{border:1px solid var(--ui-color-border);background-color:var(--ui-color-surface)}llm-card.variant-flat{background-color:var(--ui-color-surface-sunken)}llm-card.padding-none llm-card-header,llm-card.padding-none llm-card-content,llm-card.padding-none llm-card-footer{padding:0}llm-card.padding-sm llm-card-header,llm-card.padding-sm llm-card-content,llm-card.padding-sm llm-card-footer{padding:var(--ui-spacing-3)}llm-card.padding-md llm-card-header,llm-card.padding-md llm-card-content,llm-card.padding-md llm-card-footer{padding:var(--ui-spacing-4)}llm-card.padding-lg llm-card-header,llm-card.padding-lg llm-card-content,llm-card.padding-lg llm-card-footer{padding:var(--ui-spacing-6)}llm-card-header{display:block;font-size:var(--ui-font-size-lg);font-weight:var(--ui-font-weight-semibold);color:var(--ui-color-text);border-bottom:1px solid var(--ui-color-border);letter-spacing:var(--ui-letter-spacing-tight)}llm-card-content{display:block;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}llm-card-footer{display:flex;align-items:center;gap:var(--ui-spacing-2);border-top:1px solid var(--ui-color-border)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
133
+ }
134
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmCardFooter, decorators: [{
135
+ type: Component,
136
+ args: [{ selector: 'llm-card-footer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, styles: ["llm-card{display:block;border-radius:var(--ui-radius-xl);background-color:var(--ui-color-surface);overflow:hidden}llm-card.variant-elevated{box-shadow:var(--ui-shadow-md);border:1px solid var(--ui-color-border)}llm-card.variant-outlined{border:1px solid var(--ui-color-border);background-color:var(--ui-color-surface)}llm-card.variant-flat{background-color:var(--ui-color-surface-sunken)}llm-card.padding-none llm-card-header,llm-card.padding-none llm-card-content,llm-card.padding-none llm-card-footer{padding:0}llm-card.padding-sm llm-card-header,llm-card.padding-sm llm-card-content,llm-card.padding-sm llm-card-footer{padding:var(--ui-spacing-3)}llm-card.padding-md llm-card-header,llm-card.padding-md llm-card-content,llm-card.padding-md llm-card-footer{padding:var(--ui-spacing-4)}llm-card.padding-lg llm-card-header,llm-card.padding-lg llm-card-content,llm-card.padding-lg llm-card-footer{padding:var(--ui-spacing-6)}llm-card-header{display:block;font-size:var(--ui-font-size-lg);font-weight:var(--ui-font-weight-semibold);color:var(--ui-color-text);border-bottom:1px solid var(--ui-color-border);letter-spacing:var(--ui-letter-spacing-tight)}llm-card-content{display:block;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}llm-card-footer{display:flex;align-items:center;gap:var(--ui-spacing-2);border-top:1px solid var(--ui-color-border)}\n"] }]
137
+ }] });
138
+
139
+ /**
140
+ * Inline status badge for labeling items with semantic color variants.
141
+ *
142
+ * Usage:
143
+ * ```html
144
+ * <llm-badge variant="success">Active</llm-badge>
145
+ * <llm-badge variant="danger" size="sm">Error</llm-badge>
146
+ * <llm-badge variant="warning">Pending</llm-badge>
147
+ * ```
148
+ */
149
+ class LlmBadge {
150
+ /** Semantic color variant of the badge. */
151
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
152
+ /** Size of the badge. */
153
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
154
+ hostClasses = computed(() => `variant-${this.variant()} size-${this.size()}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
155
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmBadge, deps: [], target: i0.ɵɵFactoryTarget.Component });
156
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmBadge, isStandalone: true, selector: "llm-badge", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status" }, properties: { "class": "hostClasses()" } }, ngImport: i0, template: `<ng-content />`, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;border-radius:var(--ui-radius-full);font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-semibold);line-height:var(--ui-line-height-tight);white-space:nowrap;letter-spacing:.01em}:host(.size-sm){padding:.1875rem var(--ui-spacing-2);font-size:var(--ui-font-size-xs)}:host(.size-md){padding:.3125rem var(--ui-spacing-3);font-size:var(--ui-font-size-sm)}:host(.variant-default){background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text-muted);border:1px solid var(--ui-color-border)}:host(.variant-success){background-color:color-mix(in srgb,var(--ui-color-success) 12%,transparent);color:var(--ui-color-success);border:1px solid color-mix(in srgb,var(--ui-color-success) 25%,transparent)}:host(.variant-warning){background-color:color-mix(in srgb,var(--ui-color-warning) 12%,transparent);color:var(--ui-color-warning);border:1px solid color-mix(in srgb,var(--ui-color-warning) 25%,transparent)}:host(.variant-danger){background-color:color-mix(in srgb,var(--ui-color-danger) 12%,transparent);color:var(--ui-color-danger);border:1px solid color-mix(in srgb,var(--ui-color-danger) 25%,transparent)}:host(.variant-info){background-color:color-mix(in srgb,var(--ui-color-info) 12%,transparent);color:var(--ui-color-info);border:1px solid color-mix(in srgb,var(--ui-color-info) 25%,transparent)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
157
+ }
158
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmBadge, decorators: [{
159
+ type: Component,
160
+ args: [{ selector: 'llm-badge', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, host: {
161
+ '[class]': 'hostClasses()',
162
+ role: 'status',
163
+ }, styles: [":host{display:inline-flex;align-items:center;justify-content:center;border-radius:var(--ui-radius-full);font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-semibold);line-height:var(--ui-line-height-tight);white-space:nowrap;letter-spacing:.01em}:host(.size-sm){padding:.1875rem var(--ui-spacing-2);font-size:var(--ui-font-size-xs)}:host(.size-md){padding:.3125rem var(--ui-spacing-3);font-size:var(--ui-font-size-sm)}:host(.variant-default){background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text-muted);border:1px solid var(--ui-color-border)}:host(.variant-success){background-color:color-mix(in srgb,var(--ui-color-success) 12%,transparent);color:var(--ui-color-success);border:1px solid color-mix(in srgb,var(--ui-color-success) 25%,transparent)}:host(.variant-warning){background-color:color-mix(in srgb,var(--ui-color-warning) 12%,transparent);color:var(--ui-color-warning);border:1px solid color-mix(in srgb,var(--ui-color-warning) 25%,transparent)}:host(.variant-danger){background-color:color-mix(in srgb,var(--ui-color-danger) 12%,transparent);color:var(--ui-color-danger);border:1px solid color-mix(in srgb,var(--ui-color-danger) 25%,transparent)}:host(.variant-info){background-color:color-mix(in srgb,var(--ui-color-info) 12%,transparent);color:var(--ui-color-info);border:1px solid color-mix(in srgb,var(--ui-color-info) 25%,transparent)}\n"] }]
164
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
165
+
166
+ let nextId$a = 0;
167
+ /**
168
+ * Accessible text input component for use with Angular Signal Forms.
169
+ *
170
+ * Usage:
171
+ * ```html
172
+ * <llm-input type="email" placeholder="you@example.com" [(value)]="email" />
173
+ * <llm-input [formField]="loginForm.email" placeholder="Email" />
174
+ * ```
175
+ */
176
+ class LlmInput {
177
+ /** The current input value. Bound by [formField] directive. Supports [(value)] two-way binding. */
178
+ value = model('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
179
+ /** The type of input field. */
180
+ type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
181
+ /** Placeholder text shown when the input is empty. */
182
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
183
+ /** Whether the input is disabled. Bound by [formField] directive. */
184
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
185
+ /** Whether the input is read-only. Bound by [formField] directive. */
186
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
187
+ /** Whether the input has validation errors. Bound by [formField] directive. */
188
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
189
+ /** Validation errors from the form system. Bound by [formField] directive. */
190
+ errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
191
+ /** Whether the user has interacted with the input. Bound by [formField] directive. */
192
+ touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
193
+ /** Whether the input is required. Bound by [formField] directive. */
194
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
195
+ /** The input's name attribute. Bound by [formField] directive. */
196
+ name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
197
+ /** @internal */
198
+ errorId = `llm-input-errors-${nextId$a++}`;
199
+ /** @internal */
200
+ showErrors = computed(() => this.touched() && this.invalid() && this.errors().length > 0, ...(ngDevMode ? [{ debugName: "showErrors" }] : /* istanbul ignore next */ []));
201
+ /** @internal */
202
+ hostClasses = computed(() => {
203
+ const classes = [];
204
+ if (this.disabled())
205
+ classes.push('is-disabled');
206
+ if (this.invalid())
207
+ classes.push('is-invalid');
208
+ if (this.readonly())
209
+ classes.push('is-readonly');
210
+ if (this.touched())
211
+ classes.push('is-touched');
212
+ return classes.join(' ');
213
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
214
+ /** @internal */
215
+ onInput(event) {
216
+ const target = event.target;
217
+ this.value.set(target.value);
218
+ }
219
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
220
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmInput, isStandalone: true, selector: "llm-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", 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 }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
221
+ <input
222
+ [type]="type()"
223
+ [value]="value()"
224
+ (input)="onInput($event)"
225
+ (blur)="touched.set(true)"
226
+ [disabled]="disabled()"
227
+ [readOnly]="readonly()"
228
+ [placeholder]="placeholder()"
229
+ [attr.name]="name() || null"
230
+ [attr.aria-invalid]="invalid() || null"
231
+ [attr.aria-required]="required() || null"
232
+ [attr.aria-describedby]="showErrors() ? errorId : null"
233
+ />
234
+ @if (showErrors()) {
235
+ <div class="errors" [id]="errorId" aria-live="polite">
236
+ @for (error of errors(); track error.kind) {
237
+ <p class="error-message">{{ error.message }}</p>
238
+ }
239
+ </div>
240
+ }
241
+ `, isInline: true, styles: [":host{display:block;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}input{display:block;width:100%;padding:.625rem var(--ui-spacing-3);font-size:inherit;font-family:inherit;line-height:var(--ui-line-height-normal);color:var(--ui-color-text);background-color:var(--ui-color-input-bg);border:1px solid var(--ui-color-input-border);border-radius:var(--ui-radius-md);box-shadow:inset 0 1px 2px #0000000a;transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast),background-color var(--ui-transition-fast);outline:none;box-sizing:border-box}input::placeholder{color:var(--ui-color-placeholder)}input:hover:not(:disabled):not(:read-only){border-color:var(--ui-color-input-border-hover)}input:focus{border-color:var(--ui-color-input-border-focus);background-color:var(--ui-color-input-bg-focus);box-shadow:var(--ui-focus-ring)}:host(.is-invalid) input{border-color:var(--ui-color-input-border-invalid)}:host(.is-invalid) input:focus{border-color:var(--ui-color-input-border-invalid);box-shadow:0 0 0 2px var(--ui-color-surface),0 0 0 4px var(--ui-color-danger)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-disabled) input{cursor:not-allowed}:host(.is-readonly) input{background-color:var(--ui-color-surface-sunken);cursor:default;box-shadow:none}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-error-text);line-height:var(--ui-line-height-normal)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
242
+ }
243
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmInput, decorators: [{
244
+ type: Component,
245
+ args: [{ selector: 'llm-input', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
246
+ <input
247
+ [type]="type()"
248
+ [value]="value()"
249
+ (input)="onInput($event)"
250
+ (blur)="touched.set(true)"
251
+ [disabled]="disabled()"
252
+ [readOnly]="readonly()"
253
+ [placeholder]="placeholder()"
254
+ [attr.name]="name() || null"
255
+ [attr.aria-invalid]="invalid() || null"
256
+ [attr.aria-required]="required() || null"
257
+ [attr.aria-describedby]="showErrors() ? errorId : null"
258
+ />
259
+ @if (showErrors()) {
260
+ <div class="errors" [id]="errorId" aria-live="polite">
261
+ @for (error of errors(); track error.kind) {
262
+ <p class="error-message">{{ error.message }}</p>
263
+ }
264
+ </div>
265
+ }
266
+ `, host: {
267
+ '[class]': 'hostClasses()',
268
+ }, styles: [":host{display:block;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}input{display:block;width:100%;padding:.625rem var(--ui-spacing-3);font-size:inherit;font-family:inherit;line-height:var(--ui-line-height-normal);color:var(--ui-color-text);background-color:var(--ui-color-input-bg);border:1px solid var(--ui-color-input-border);border-radius:var(--ui-radius-md);box-shadow:inset 0 1px 2px #0000000a;transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast),background-color var(--ui-transition-fast);outline:none;box-sizing:border-box}input::placeholder{color:var(--ui-color-placeholder)}input:hover:not(:disabled):not(:read-only){border-color:var(--ui-color-input-border-hover)}input:focus{border-color:var(--ui-color-input-border-focus);background-color:var(--ui-color-input-bg-focus);box-shadow:var(--ui-focus-ring)}:host(.is-invalid) input{border-color:var(--ui-color-input-border-invalid)}:host(.is-invalid) input:focus{border-color:var(--ui-color-input-border-invalid);box-shadow:0 0 0 2px var(--ui-color-surface),0 0 0 4px var(--ui-color-danger)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-disabled) input{cursor:not-allowed}:host(.is-readonly) input{background-color:var(--ui-color-surface-sunken);cursor:default;box-shadow:none}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-error-text);line-height:var(--ui-line-height-normal)}\n"] }]
269
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }] } });
270
+
271
+ let nextId$9 = 0;
272
+ /**
273
+ * Accessible multiline text input component for use with Angular Signal Forms.
274
+ *
275
+ * Usage:
276
+ * ```html
277
+ * <llm-textarea placeholder="Enter a description" [(value)]="description" />
278
+ * <llm-textarea [formField]="form.bio" [rows]="4" />
279
+ * ```
280
+ */
281
+ class LlmTextarea {
282
+ /** The current textarea value. Supports [(value)] two-way binding. */
283
+ value = model('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
284
+ /** Number of visible text rows. */
285
+ rows = input(3, ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
286
+ /** Placeholder text shown when the textarea is empty. */
287
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
288
+ /** Whether the textarea is disabled. Bound by [formField] directive. */
289
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
290
+ /** Whether the textarea is read-only. Bound by [formField] directive. */
291
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
292
+ /** Whether the textarea has validation errors. Bound by [formField] directive. */
293
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
294
+ /** Validation errors from the form system. Bound by [formField] directive. */
295
+ errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
296
+ /** Whether the user has interacted with the textarea. Bound by [formField] directive. */
297
+ touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
298
+ /** Whether the textarea is required. Bound by [formField] directive. */
299
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
300
+ /** The textarea's name attribute. Bound by [formField] directive. */
301
+ name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
302
+ /** Whether to auto-resize the textarea height to fit its content. */
303
+ autoResize = input(false, ...(ngDevMode ? [{ debugName: "autoResize" }] : /* istanbul ignore next */ []));
304
+ /** @internal */
305
+ errorId = `llm-textarea-errors-${nextId$9++}`;
306
+ /** @internal */
307
+ showErrors = computed(() => this.touched() && this.invalid() && this.errors().length > 0, ...(ngDevMode ? [{ debugName: "showErrors" }] : /* istanbul ignore next */ []));
308
+ /** @internal */
309
+ hostClasses = computed(() => {
310
+ const classes = [];
311
+ if (this.disabled())
312
+ classes.push('is-disabled');
313
+ if (this.invalid())
314
+ classes.push('is-invalid');
315
+ if (this.readonly())
316
+ classes.push('is-readonly');
317
+ if (this.touched())
318
+ classes.push('is-touched');
319
+ if (this.autoResize())
320
+ classes.push('is-auto-resize');
321
+ return classes.join(' ');
322
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
323
+ /** @internal */
324
+ onInput(event) {
325
+ const target = event.target;
326
+ this.value.set(target.value);
327
+ }
328
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmTextarea, deps: [], target: i0.ɵɵFactoryTarget.Component });
329
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmTextarea, isStandalone: true, selector: "llm-textarea", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", 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 }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, autoResize: { classPropertyName: "autoResize", publicName: "autoResize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
330
+ <textarea
331
+ [value]="value()"
332
+ (input)="onInput($event)"
333
+ (blur)="touched.set(true)"
334
+ [disabled]="disabled()"
335
+ [readOnly]="readonly()"
336
+ [placeholder]="placeholder()"
337
+ [rows]="rows()"
338
+ [attr.name]="name() || null"
339
+ [attr.aria-invalid]="invalid() || null"
340
+ [attr.aria-required]="required() || null"
341
+ [attr.aria-describedby]="showErrors() ? errorId : null"
342
+ [cdkTextareaAutosize]="autoResize()"
343
+ [cdkAutosizeMinRows]="rows()"
344
+ ></textarea>
345
+ @if (showErrors()) {
346
+ <div class="errors" [id]="errorId" aria-live="polite">
347
+ @for (error of errors(); track error.kind) {
348
+ <p class="error-message">{{ error.message }}</p>
349
+ }
350
+ </div>
351
+ }
352
+ `, isInline: true, styles: [":host{display:block;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}textarea{display:block;width:100%;padding:.625rem var(--ui-spacing-3);font-size:inherit;font-family:inherit;line-height:var(--ui-line-height-normal);color:var(--ui-color-text);background-color:var(--ui-color-input-bg);border:1px solid var(--ui-color-input-border);border-radius:var(--ui-radius-md);box-shadow:inset 0 1px 2px #0000000a;transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast),background-color var(--ui-transition-fast);outline:none;box-sizing:border-box;resize:vertical;min-height:80px}textarea::placeholder{color:var(--ui-color-placeholder)}textarea:hover:not(:disabled):not(:read-only){border-color:var(--ui-color-input-border-hover)}textarea:focus{border-color:var(--ui-color-input-border-focus);background-color:var(--ui-color-input-bg-focus);box-shadow:var(--ui-focus-ring)}:host(.is-invalid) textarea{border-color:var(--ui-color-input-border-invalid)}:host(.is-invalid) textarea:focus{border-color:var(--ui-color-input-border-invalid);box-shadow:0 0 0 2px var(--ui-color-surface),0 0 0 4px var(--ui-color-danger)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-disabled) textarea{cursor:not-allowed}:host(.is-readonly) textarea{background-color:var(--ui-color-surface-sunken);cursor:default;box-shadow:none}:host(.is-auto-resize) textarea{resize:none;overflow:hidden}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-error-text);line-height:var(--ui-line-height-normal)}\n"], dependencies: [{ kind: "ngmodule", type: TextFieldModule }, { kind: "directive", type: i1.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
353
+ }
354
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmTextarea, decorators: [{
355
+ type: Component,
356
+ args: [{ selector: 'llm-textarea', standalone: true, imports: [TextFieldModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
357
+ <textarea
358
+ [value]="value()"
359
+ (input)="onInput($event)"
360
+ (blur)="touched.set(true)"
361
+ [disabled]="disabled()"
362
+ [readOnly]="readonly()"
363
+ [placeholder]="placeholder()"
364
+ [rows]="rows()"
365
+ [attr.name]="name() || null"
366
+ [attr.aria-invalid]="invalid() || null"
367
+ [attr.aria-required]="required() || null"
368
+ [attr.aria-describedby]="showErrors() ? errorId : null"
369
+ [cdkTextareaAutosize]="autoResize()"
370
+ [cdkAutosizeMinRows]="rows()"
371
+ ></textarea>
372
+ @if (showErrors()) {
373
+ <div class="errors" [id]="errorId" aria-live="polite">
374
+ @for (error of errors(); track error.kind) {
375
+ <p class="error-message">{{ error.message }}</p>
376
+ }
377
+ </div>
378
+ }
379
+ `, host: {
380
+ '[class]': 'hostClasses()',
381
+ }, styles: [":host{display:block;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}textarea{display:block;width:100%;padding:.625rem var(--ui-spacing-3);font-size:inherit;font-family:inherit;line-height:var(--ui-line-height-normal);color:var(--ui-color-text);background-color:var(--ui-color-input-bg);border:1px solid var(--ui-color-input-border);border-radius:var(--ui-radius-md);box-shadow:inset 0 1px 2px #0000000a;transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast),background-color var(--ui-transition-fast);outline:none;box-sizing:border-box;resize:vertical;min-height:80px}textarea::placeholder{color:var(--ui-color-placeholder)}textarea:hover:not(:disabled):not(:read-only){border-color:var(--ui-color-input-border-hover)}textarea:focus{border-color:var(--ui-color-input-border-focus);background-color:var(--ui-color-input-bg-focus);box-shadow:var(--ui-focus-ring)}:host(.is-invalid) textarea{border-color:var(--ui-color-input-border-invalid)}:host(.is-invalid) textarea:focus{border-color:var(--ui-color-input-border-invalid);box-shadow:0 0 0 2px var(--ui-color-surface),0 0 0 4px var(--ui-color-danger)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-disabled) textarea{cursor:not-allowed}:host(.is-readonly) textarea{background-color:var(--ui-color-surface-sunken);cursor:default;box-shadow:none}:host(.is-auto-resize) textarea{resize:none;overflow:hidden}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-error-text);line-height:var(--ui-line-height-normal)}\n"] }]
382
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], autoResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoResize", required: false }] }] } });
383
+
384
+ let nextId$8 = 0;
385
+ /**
386
+ * Accessible checkbox component for use with Angular Signal Forms.
387
+ *
388
+ * Usage:
389
+ * ```html
390
+ * <llm-checkbox [(checked)]="accepted">I agree to the terms</llm-checkbox>
391
+ * <llm-checkbox [formField]="form.accepted">Accept</llm-checkbox>
392
+ * ```
393
+ */
394
+ class LlmCheckbox {
395
+ /** The checked state. Bound by [formField] directive. Supports [(checked)] two-way binding. */
396
+ checked = model(false, ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
397
+ /** Whether the user has interacted with the input. Bound by [formField] directive. */
398
+ touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
399
+ /** Tri-state indeterminate mode (e.g. "select all"). Set via DOM property. */
400
+ indeterminate = input(false, ...(ngDevMode ? [{ debugName: "indeterminate" }] : /* istanbul ignore next */ []));
401
+ /** Whether the checkbox is disabled. Bound by [formField] directive. */
402
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
403
+ /** Whether the checkbox has validation errors. Bound by [formField] directive. */
404
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
405
+ /** Whether the checkbox is required. Bound by [formField] directive. */
406
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
407
+ /** The input's name attribute. Bound by [formField] directive. */
408
+ name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
409
+ /** Validation errors from the form system. Bound by [formField] directive. */
410
+ errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
411
+ /** @internal */
412
+ inputId = `llm-checkbox-${nextId$8++}`;
413
+ /** @internal */
414
+ errorId = `llm-checkbox-errors-${nextId$8++}`;
415
+ /** @internal */
416
+ nativeInput = viewChild('nativeInput', ...(ngDevMode ? [{ debugName: "nativeInput" }] : /* istanbul ignore next */ []));
417
+ /** @internal */
418
+ showErrors = computed(() => this.touched() && this.invalid() && this.errors().length > 0, ...(ngDevMode ? [{ debugName: "showErrors" }] : /* istanbul ignore next */ []));
419
+ /** @internal */
420
+ hostClasses = computed(() => {
421
+ const classes = [];
422
+ if (this.checked())
423
+ classes.push('is-checked');
424
+ if (this.disabled())
425
+ classes.push('is-disabled');
426
+ if (this.invalid())
427
+ classes.push('is-invalid');
428
+ if (this.touched())
429
+ classes.push('is-touched');
430
+ return classes.join(' ');
431
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
432
+ constructor() {
433
+ effect(() => {
434
+ const el = this.nativeInput()?.nativeElement;
435
+ if (el) {
436
+ el.indeterminate = this.indeterminate();
437
+ }
438
+ });
439
+ }
440
+ /** @internal */
441
+ onChange(event) {
442
+ const target = event.target;
443
+ this.checked.set(target.checked);
444
+ }
445
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
446
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmCheckbox, isStandalone: true, selector: "llm-checkbox", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", touched: "touchedChange" }, host: { properties: { "class": "hostClasses()" } }, viewQueries: [{ propertyName: "nativeInput", first: true, predicate: ["nativeInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
447
+ <label [attr.for]="inputId">
448
+ <input
449
+ #nativeInput
450
+ type="checkbox"
451
+ [id]="inputId"
452
+ [checked]="checked()"
453
+ (change)="onChange($event)"
454
+ (blur)="touched.set(true)"
455
+ [disabled]="disabled()"
456
+ [attr.name]="name() || null"
457
+ [attr.aria-invalid]="invalid() || null"
458
+ [attr.aria-required]="required() || null"
459
+ [attr.aria-describedby]="showErrors() ? errorId : null"
460
+ />
461
+ <ng-content />
462
+ </label>
463
+ @if (showErrors()) {
464
+ <div class="errors" [id]="errorId" aria-live="polite">
465
+ @for (error of errors(); track error.kind) {
466
+ <p class="error-message">{{ error.message }}</p>
467
+ }
468
+ </div>
469
+ }
470
+ `, isInline: true, styles: [":host{display:block;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}label{display:inline-flex;align-items:center;gap:var(--ui-spacing-2);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}input[type=checkbox]{appearance:none;-webkit-appearance:none;flex-shrink:0;width:1.25rem;height:1.25rem;border:1.5px solid var(--ui-color-input-border);border-radius:var(--ui-radius-sm);background-color:var(--ui-color-input-bg);cursor:pointer;position:relative;transition:border-color var(--ui-transition-fast),background-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);outline:none}input[type=checkbox]:hover:not(:disabled){border-color:var(--ui-color-input-border-hover);background-color:var(--ui-color-primary-light)}input[type=checkbox]:focus-visible{box-shadow:var(--ui-focus-ring);border-color:var(--ui-color-input-border-focus)}input[type=checkbox]:checked{background-color:var(--ui-color-primary);border-color:var(--ui-color-primary)}input[type=checkbox]:checked:after{content:\"\";position:absolute;inset:0;margin:auto;width:.35rem;height:.6rem;border:2px solid var(--ui-color-on-primary);border-top:none;border-left:none;transform:rotate(45deg) translate(-1px,-1px);animation:llm-check-pop var(--ui-duration-normal) var(--ui-ease-spring)}input[type=checkbox]:indeterminate{background-color:var(--ui-color-primary);border-color:var(--ui-color-primary)}input[type=checkbox]:indeterminate:after{content:\"\";position:absolute;inset:0;margin:auto;width:.5rem;height:2px;background-color:var(--ui-color-on-primary);animation:llm-check-pop var(--ui-duration-normal) var(--ui-ease-spring)}:host(.is-invalid) input[type=checkbox]{border-color:var(--ui-color-input-border-invalid)}:host(.is-invalid) input[type=checkbox]:focus-visible{border-color:var(--ui-color-input-border-invalid);box-shadow:0 0 0 2px var(--ui-color-surface),0 0 0 4px var(--ui-color-danger)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-disabled) label{cursor:not-allowed}:host(.is-disabled) input[type=checkbox]{cursor:not-allowed}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-error-text);line-height:var(--ui-line-height-normal)}@keyframes llm-check-pop{0%{transform:rotate(45deg) translate(-1px,-1px) scale(0)}60%{transform:rotate(45deg) translate(-1px,-1px) scale(1.15)}to{transform:rotate(45deg) translate(-1px,-1px) scale(1)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
471
+ }
472
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmCheckbox, decorators: [{
473
+ type: Component,
474
+ args: [{ selector: 'llm-checkbox', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
475
+ <label [attr.for]="inputId">
476
+ <input
477
+ #nativeInput
478
+ type="checkbox"
479
+ [id]="inputId"
480
+ [checked]="checked()"
481
+ (change)="onChange($event)"
482
+ (blur)="touched.set(true)"
483
+ [disabled]="disabled()"
484
+ [attr.name]="name() || null"
485
+ [attr.aria-invalid]="invalid() || null"
486
+ [attr.aria-required]="required() || null"
487
+ [attr.aria-describedby]="showErrors() ? errorId : null"
488
+ />
489
+ <ng-content />
490
+ </label>
491
+ @if (showErrors()) {
492
+ <div class="errors" [id]="errorId" aria-live="polite">
493
+ @for (error of errors(); track error.kind) {
494
+ <p class="error-message">{{ error.message }}</p>
495
+ }
496
+ </div>
497
+ }
498
+ `, host: {
499
+ '[class]': 'hostClasses()',
500
+ }, styles: [":host{display:block;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}label{display:inline-flex;align-items:center;gap:var(--ui-spacing-2);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}input[type=checkbox]{appearance:none;-webkit-appearance:none;flex-shrink:0;width:1.25rem;height:1.25rem;border:1.5px solid var(--ui-color-input-border);border-radius:var(--ui-radius-sm);background-color:var(--ui-color-input-bg);cursor:pointer;position:relative;transition:border-color var(--ui-transition-fast),background-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);outline:none}input[type=checkbox]:hover:not(:disabled){border-color:var(--ui-color-input-border-hover);background-color:var(--ui-color-primary-light)}input[type=checkbox]:focus-visible{box-shadow:var(--ui-focus-ring);border-color:var(--ui-color-input-border-focus)}input[type=checkbox]:checked{background-color:var(--ui-color-primary);border-color:var(--ui-color-primary)}input[type=checkbox]:checked:after{content:\"\";position:absolute;inset:0;margin:auto;width:.35rem;height:.6rem;border:2px solid var(--ui-color-on-primary);border-top:none;border-left:none;transform:rotate(45deg) translate(-1px,-1px);animation:llm-check-pop var(--ui-duration-normal) var(--ui-ease-spring)}input[type=checkbox]:indeterminate{background-color:var(--ui-color-primary);border-color:var(--ui-color-primary)}input[type=checkbox]:indeterminate:after{content:\"\";position:absolute;inset:0;margin:auto;width:.5rem;height:2px;background-color:var(--ui-color-on-primary);animation:llm-check-pop var(--ui-duration-normal) var(--ui-ease-spring)}:host(.is-invalid) input[type=checkbox]{border-color:var(--ui-color-input-border-invalid)}:host(.is-invalid) input[type=checkbox]:focus-visible{border-color:var(--ui-color-input-border-invalid);box-shadow:0 0 0 2px var(--ui-color-surface),0 0 0 4px var(--ui-color-danger)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-disabled) label{cursor:not-allowed}:host(.is-disabled) input[type=checkbox]{cursor:not-allowed}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-error-text);line-height:var(--ui-line-height-normal)}@keyframes llm-check-pop{0%{transform:rotate(45deg) translate(-1px,-1px) scale(0)}60%{transform:rotate(45deg) translate(-1px,-1px) scale(1.15)}to{transform:rotate(45deg) translate(-1px,-1px) scale(1)}}\n"] }]
501
+ }], ctorParameters: () => [], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], nativeInput: [{ type: i0.ViewChild, args: ['nativeInput', { isSignal: true }] }] } });
502
+
503
+ const LLM_RADIO_GROUP = new InjectionToken('LLM_RADIO_GROUP');
504
+
505
+ let nextId$7 = 0;
506
+ /**
507
+ * Individual radio button. Must be placed inside an `llm-radio-group`.
508
+ *
509
+ * Usage:
510
+ * ```html
511
+ * <llm-radio-group [(value)]="selected" name="plan">
512
+ * <llm-radio radioValue="free">Free</llm-radio>
513
+ * <llm-radio radioValue="pro">Pro</llm-radio>
514
+ * </llm-radio-group>
515
+ * ```
516
+ */
517
+ class LlmRadio {
518
+ /** The value this radio option represents within the group. */
519
+ radioValue = input.required(...(ngDevMode ? [{ debugName: "radioValue" }] : /* istanbul ignore next */ []));
520
+ /** Whether this specific radio is individually disabled (stacked with group disabled). */
521
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
522
+ /** @internal */
523
+ group = inject(LLM_RADIO_GROUP, { optional: true });
524
+ /** @internal */
525
+ el = inject(ElementRef);
526
+ /** @internal */
527
+ inputId = `llm-radio-${nextId$7++}`;
528
+ /** @internal */
529
+ isChecked = computed(() => this.group?.value() === this.radioValue(), ...(ngDevMode ? [{ debugName: "isChecked" }] : /* istanbul ignore next */ []));
530
+ /** @internal */
531
+ isDisabled = computed(() => this.disabled() || (this.group?.disabled() ?? false), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
532
+ /** @internal */
533
+ effectiveName = computed(() => this.group?.name() ?? '', ...(ngDevMode ? [{ debugName: "effectiveName" }] : /* istanbul ignore next */ []));
534
+ /** @internal */
535
+ hostClasses = computed(() => {
536
+ const classes = [];
537
+ if (this.isChecked())
538
+ classes.push('is-checked');
539
+ if (this.isDisabled())
540
+ classes.push('is-disabled');
541
+ return classes.join(' ');
542
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
543
+ /** @internal — for FocusKeyManager */
544
+ focusInput() {
545
+ this.el.nativeElement.querySelector('input')?.focus();
546
+ }
547
+ ngOnInit() {
548
+ this.group?.registerItem(this);
549
+ }
550
+ ngOnDestroy() {
551
+ this.group?.unregisterItem(this);
552
+ }
553
+ /** @internal */
554
+ onChange() {
555
+ this.group?.select(this.radioValue());
556
+ }
557
+ /** @internal */
558
+ onBlur() {
559
+ this.group?.markTouched();
560
+ }
561
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmRadio, deps: [], target: i0.ɵɵFactoryTarget.Component });
562
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmRadio, isStandalone: true, selector: "llm-radio", inputs: { radioValue: { classPropertyName: "radioValue", publicName: "radioValue", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
563
+ <label [attr.for]="inputId">
564
+ <input
565
+ type="radio"
566
+ [id]="inputId"
567
+ [value]="radioValue()"
568
+ [checked]="isChecked()"
569
+ [disabled]="isDisabled()"
570
+ [attr.name]="effectiveName() || null"
571
+ (change)="onChange()"
572
+ (blur)="onBlur()"
573
+ />
574
+ <ng-content />
575
+ </label>
576
+ `, isInline: true, styles: [":host{display:block;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}label{display:inline-flex;align-items:center;gap:var(--ui-spacing-2);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}input[type=radio]{appearance:none;-webkit-appearance:none;flex-shrink:0;width:1.25rem;height:1.25rem;border:1.5px solid var(--ui-color-input-border);border-radius:50%;background-color:var(--ui-color-input-bg);cursor:pointer;position:relative;transition:border-color var(--ui-transition-fast),background-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);outline:none}input[type=radio]:hover:not(:disabled){border-color:var(--ui-color-input-border-hover);background-color:var(--ui-color-primary-light)}input[type=radio]:focus-visible{box-shadow:var(--ui-focus-ring);border-color:var(--ui-color-input-border-focus)}input[type=radio]:checked{background-color:var(--ui-color-primary);border-color:var(--ui-color-primary)}input[type=radio]:checked:after{content:\"\";position:absolute;inset:0;margin:auto;width:.45rem;height:.45rem;border-radius:50%;background-color:var(--ui-color-on-primary);animation:llm-radio-pop var(--ui-duration-normal) var(--ui-ease-spring)}:host-context(llm-radio-group.is-invalid) input[type=radio],:host(.is-invalid) input[type=radio]{border-color:var(--ui-color-input-border-invalid)}:host-context(llm-radio-group.is-invalid) input[type=radio]:focus-visible,:host(.is-invalid) input[type=radio]:focus-visible{border-color:var(--ui-color-input-border-invalid);box-shadow:0 0 0 2px var(--ui-color-surface),0 0 0 4px var(--ui-color-danger)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-disabled) label{cursor:not-allowed}:host(.is-disabled) input[type=radio]{cursor:not-allowed}@keyframes llm-radio-pop{0%{transform:scale(0)}60%{transform:scale(1.2)}to{transform:scale(1)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
577
+ }
578
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmRadio, decorators: [{
579
+ type: Component,
580
+ args: [{ selector: 'llm-radio', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
581
+ <label [attr.for]="inputId">
582
+ <input
583
+ type="radio"
584
+ [id]="inputId"
585
+ [value]="radioValue()"
586
+ [checked]="isChecked()"
587
+ [disabled]="isDisabled()"
588
+ [attr.name]="effectiveName() || null"
589
+ (change)="onChange()"
590
+ (blur)="onBlur()"
591
+ />
592
+ <ng-content />
593
+ </label>
594
+ `, host: {
595
+ '[class]': 'hostClasses()',
596
+ }, styles: [":host{display:block;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}label{display:inline-flex;align-items:center;gap:var(--ui-spacing-2);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}input[type=radio]{appearance:none;-webkit-appearance:none;flex-shrink:0;width:1.25rem;height:1.25rem;border:1.5px solid var(--ui-color-input-border);border-radius:50%;background-color:var(--ui-color-input-bg);cursor:pointer;position:relative;transition:border-color var(--ui-transition-fast),background-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);outline:none}input[type=radio]:hover:not(:disabled){border-color:var(--ui-color-input-border-hover);background-color:var(--ui-color-primary-light)}input[type=radio]:focus-visible{box-shadow:var(--ui-focus-ring);border-color:var(--ui-color-input-border-focus)}input[type=radio]:checked{background-color:var(--ui-color-primary);border-color:var(--ui-color-primary)}input[type=radio]:checked:after{content:\"\";position:absolute;inset:0;margin:auto;width:.45rem;height:.45rem;border-radius:50%;background-color:var(--ui-color-on-primary);animation:llm-radio-pop var(--ui-duration-normal) var(--ui-ease-spring)}:host-context(llm-radio-group.is-invalid) input[type=radio],:host(.is-invalid) input[type=radio]{border-color:var(--ui-color-input-border-invalid)}:host-context(llm-radio-group.is-invalid) input[type=radio]:focus-visible,:host(.is-invalid) input[type=radio]:focus-visible{border-color:var(--ui-color-input-border-invalid);box-shadow:0 0 0 2px var(--ui-color-surface),0 0 0 4px var(--ui-color-danger)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-disabled) label{cursor:not-allowed}:host(.is-disabled) input[type=radio]{cursor:not-allowed}@keyframes llm-radio-pop{0%{transform:scale(0)}60%{transform:scale(1.2)}to{transform:scale(1)}}\n"] }]
597
+ }], propDecorators: { radioValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "radioValue", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
598
+
599
+ let nextId$6 = 0;
600
+ /**
601
+ * Container for a group of radio buttons. Manages keyboard navigation, shared name,
602
+ * and Signal Forms integration.
603
+ *
604
+ * Usage:
605
+ * ```html
606
+ * <llm-radio-group [(value)]="size" name="size">
607
+ * <llm-radio radioValue="sm">Small</llm-radio>
608
+ * <llm-radio radioValue="md">Medium</llm-radio>
609
+ * <llm-radio radioValue="lg">Large</llm-radio>
610
+ * </llm-radio-group>
611
+ *
612
+ * <!-- With Signal Forms -->
613
+ * <llm-radio-group [formField]="form.size">
614
+ * <llm-radio radioValue="sm">Small</llm-radio>
615
+ * </llm-radio-group>
616
+ * ```
617
+ */
618
+ class LlmRadioGroup {
619
+ /** The selected value. Bound by [formField] directive. Supports [(value)] two-way binding. */
620
+ value = model('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
621
+ /** Whether the user has interacted. Bound by [formField] directive. */
622
+ touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
623
+ /** Whether the group is disabled. Bound by [formField] directive. */
624
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
625
+ /** Whether the group has validation errors. Bound by [formField] directive. */
626
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
627
+ /** Whether the group is required. Bound by [formField] directive. */
628
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
629
+ /** Shared name attribute propagated to all child radio inputs. Bound by [formField] directive. */
630
+ name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
631
+ /** Validation errors from the form system. Bound by [formField] directive. */
632
+ errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
633
+ /** @internal */
634
+ errorId = `llm-radio-group-errors-${nextId$6++}`;
635
+ /** @internal */
636
+ items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
637
+ /** @internal */
638
+ showErrors = computed(() => this.touched() && this.invalid() && this.errors().length > 0, ...(ngDevMode ? [{ debugName: "showErrors" }] : /* istanbul ignore next */ []));
639
+ /** @internal */
640
+ hostClasses = computed(() => {
641
+ const classes = [];
642
+ if (this.disabled())
643
+ classes.push('is-disabled');
644
+ if (this.invalid())
645
+ classes.push('is-invalid');
646
+ if (this.touched())
647
+ classes.push('is-touched');
648
+ return classes.join(' ');
649
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
650
+ /** @internal — called by LlmRadio on change */
651
+ select(v) {
652
+ if (!this.disabled()) {
653
+ this.value.set(v);
654
+ }
655
+ }
656
+ /** @internal — called by LlmRadio on blur */
657
+ markTouched() {
658
+ this.touched.set(true);
659
+ }
660
+ /** @internal — called by LlmRadio on init */
661
+ registerItem(item) {
662
+ this.items.update((list) => [...list, item]);
663
+ }
664
+ /** @internal — called by LlmRadio on destroy */
665
+ unregisterItem(item) {
666
+ this.items.update((list) => list.filter((i) => i !== item));
667
+ }
668
+ /** @internal */
669
+ onKeydown(event) {
670
+ const key = event.key;
671
+ if (key !== 'ArrowDown' && key !== 'ArrowRight' && key !== 'ArrowUp' && key !== 'ArrowLeft')
672
+ return;
673
+ event.preventDefault();
674
+ const radioItems = this.items();
675
+ const enabled = radioItems.filter((item) => !item.isDisabled());
676
+ if (enabled.length === 0)
677
+ return;
678
+ const currentPos = enabled.findIndex((i) => i.radioValue() === this.value());
679
+ const isNext = key === 'ArrowDown' || key === 'ArrowRight';
680
+ const n = enabled.length;
681
+ const nextPos = isNext
682
+ ? (currentPos + 1) % n
683
+ : (currentPos - 1 + n) % n;
684
+ const target = enabled[nextPos];
685
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/strict-boolean-expressions
686
+ if (target) {
687
+ target.focusInput();
688
+ this.value.set(target.radioValue());
689
+ this.touched.set(true);
690
+ }
691
+ }
692
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmRadioGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
693
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmRadioGroup, isStandalone: true, selector: "llm-radio-group", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, host: { attributes: { "role": "radiogroup" }, listeners: { "keydown": "onKeydown($event)" }, properties: { "class": "hostClasses()", "attr.aria-invalid": "invalid() || null", "attr.aria-required": "required() || null", "attr.aria-describedby": "showErrors() ? errorId : null" } }, providers: [{ provide: LLM_RADIO_GROUP, useExisting: LlmRadioGroup }], ngImport: i0, template: `
694
+ <ng-content />
695
+ @if (showErrors()) {
696
+ <div class="errors" [id]="errorId" aria-live="polite">
697
+ @for (error of errors(); track error.kind) {
698
+ <p class="error-message">{{ error.message }}</p>
699
+ }
700
+ </div>
701
+ }
702
+ `, isInline: true, styles: [":host{display:block;font-family:var(--ui-font-family)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-error-text);line-height:var(--ui-line-height-normal)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
703
+ }
704
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmRadioGroup, decorators: [{
705
+ type: Component,
706
+ args: [{ selector: 'llm-radio-group', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
707
+ <ng-content />
708
+ @if (showErrors()) {
709
+ <div class="errors" [id]="errorId" aria-live="polite">
710
+ @for (error of errors(); track error.kind) {
711
+ <p class="error-message">{{ error.message }}</p>
712
+ }
713
+ </div>
714
+ }
715
+ `, host: {
716
+ role: 'radiogroup',
717
+ '[class]': 'hostClasses()',
718
+ '[attr.aria-invalid]': 'invalid() || null',
719
+ '[attr.aria-required]': 'required() || null',
720
+ '[attr.aria-describedby]': 'showErrors() ? errorId : null',
721
+ '(keydown)': 'onKeydown($event)',
722
+ }, providers: [{ provide: LLM_RADIO_GROUP, useExisting: LlmRadioGroup }], styles: [":host{display:block;font-family:var(--ui-font-family)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-error-text);line-height:var(--ui-line-height-normal)}\n"] }]
723
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }] } });
724
+
725
+ let nextId$5 = 0;
726
+ /**
727
+ * Accessible toggle (switch) component for use with Angular Signal Forms.
728
+ * Presents as a pill-shaped on/off slider instead of a checkbox box,
729
+ * but has identical boolean semantics and implements FormCheckboxControl.
730
+ *
731
+ * Usage:
732
+ * ```html
733
+ * <llm-toggle [(checked)]="enabled">Enable notifications</llm-toggle>
734
+ * <llm-toggle [formField]="form.enabled">Enable</llm-toggle>
735
+ * ```
736
+ */
737
+ class LlmToggle {
738
+ /** The checked state. Bound by [formField] directive. Supports [(checked)] two-way binding. */
739
+ checked = model(false, ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
740
+ /** Whether the user has interacted with the input. Bound by [formField] directive. */
741
+ touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
742
+ /** Whether the toggle is disabled. Bound by [formField] directive. */
743
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
744
+ /** Whether the toggle has validation errors. Bound by [formField] directive. */
745
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
746
+ /** Whether the toggle is required. Bound by [formField] directive. */
747
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
748
+ /** The input's name attribute. Bound by [formField] directive. */
749
+ name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
750
+ /** Validation errors from the form system. Bound by [formField] directive. */
751
+ errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
752
+ /** @internal */
753
+ inputId = `llm-toggle-${nextId$5++}`;
754
+ /** @internal */
755
+ errorId = `llm-toggle-errors-${nextId$5++}`;
756
+ /** @internal */
757
+ showErrors = computed(() => this.touched() && this.invalid() && this.errors().length > 0, ...(ngDevMode ? [{ debugName: "showErrors" }] : /* istanbul ignore next */ []));
758
+ /** @internal */
759
+ hostClasses = computed(() => {
760
+ const classes = [];
761
+ if (this.checked())
762
+ classes.push('is-checked');
763
+ if (this.disabled())
764
+ classes.push('is-disabled');
765
+ if (this.invalid())
766
+ classes.push('is-invalid');
767
+ if (this.touched())
768
+ classes.push('is-touched');
769
+ return classes.join(' ');
770
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
771
+ /** @internal */
772
+ onChange(event) {
773
+ const target = event.target;
774
+ this.checked.set(target.checked);
775
+ }
776
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmToggle, deps: [], target: i0.ɵɵFactoryTarget.Component });
777
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmToggle, isStandalone: true, selector: "llm-toggle", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", touched: "touchedChange" }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
778
+ <label [attr.for]="inputId">
779
+ <input
780
+ type="checkbox"
781
+ role="switch"
782
+ [id]="inputId"
783
+ [checked]="checked()"
784
+ (change)="onChange($event)"
785
+ (blur)="touched.set(true)"
786
+ [disabled]="disabled()"
787
+ [attr.name]="name() || null"
788
+ [attr.aria-checked]="checked()"
789
+ [attr.aria-invalid]="invalid() || null"
790
+ [attr.aria-required]="required() || null"
791
+ [attr.aria-describedby]="showErrors() ? errorId : null"
792
+ />
793
+ <span class="track" aria-hidden="true">
794
+ <span class="thumb"></span>
795
+ </span>
796
+ <ng-content />
797
+ </label>
798
+ @if (showErrors()) {
799
+ <div class="errors" [id]="errorId" aria-live="polite">
800
+ @for (error of errors(); track error.kind) {
801
+ <p class="error-message">{{ error.message }}</p>
802
+ }
803
+ </div>
804
+ }
805
+ `, isInline: true, styles: [":host{display:block;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}label{display:inline-flex;align-items:center;gap:var(--ui-spacing-2);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}input[type=checkbox]{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.track{position:relative;display:inline-flex;align-items:center;flex-shrink:0;width:2.75rem;height:1.5rem;border-radius:var(--ui-radius-full);border:1.5px solid var(--ui-color-input-border);background-color:var(--ui-color-input-bg);transition:background-color var(--ui-transition-fast),border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);cursor:pointer}.thumb{position:absolute;left:.125rem;width:1.125rem;height:1.125rem;border-radius:var(--ui-radius-full);background-color:var(--ui-color-input-border);box-shadow:var(--ui-shadow-xs);transition:transform var(--ui-transition-fast),background-color var(--ui-transition-fast)}label:hover:not(:has(input:disabled)) .track{border-color:var(--ui-color-input-border-hover)}input[type=checkbox]:focus-visible+.track{box-shadow:var(--ui-focus-ring);border-color:var(--ui-color-input-border-focus)}:host(.is-checked) .track{background-color:var(--ui-color-primary);border-color:var(--ui-color-primary)}:host(.is-checked) .thumb{transform:translate(1.25rem);background-color:var(--ui-color-surface)}:host(.is-invalid) .track{border-color:var(--ui-color-input-border-invalid)}:host(.is-invalid) input[type=checkbox]:focus-visible+.track{border-color:var(--ui-color-input-border-invalid);box-shadow:0 0 0 2px var(--ui-color-surface),0 0 0 4px var(--ui-color-danger)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-disabled) label{cursor:not-allowed}:host(.is-disabled) .track{cursor:not-allowed}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-error-text);line-height:var(--ui-line-height-normal)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
806
+ }
807
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmToggle, decorators: [{
808
+ type: Component,
809
+ args: [{ selector: 'llm-toggle', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
810
+ <label [attr.for]="inputId">
811
+ <input
812
+ type="checkbox"
813
+ role="switch"
814
+ [id]="inputId"
815
+ [checked]="checked()"
816
+ (change)="onChange($event)"
817
+ (blur)="touched.set(true)"
818
+ [disabled]="disabled()"
819
+ [attr.name]="name() || null"
820
+ [attr.aria-checked]="checked()"
821
+ [attr.aria-invalid]="invalid() || null"
822
+ [attr.aria-required]="required() || null"
823
+ [attr.aria-describedby]="showErrors() ? errorId : null"
824
+ />
825
+ <span class="track" aria-hidden="true">
826
+ <span class="thumb"></span>
827
+ </span>
828
+ <ng-content />
829
+ </label>
830
+ @if (showErrors()) {
831
+ <div class="errors" [id]="errorId" aria-live="polite">
832
+ @for (error of errors(); track error.kind) {
833
+ <p class="error-message">{{ error.message }}</p>
834
+ }
835
+ </div>
836
+ }
837
+ `, host: {
838
+ '[class]': 'hostClasses()',
839
+ }, styles: [":host{display:block;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}label{display:inline-flex;align-items:center;gap:var(--ui-spacing-2);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--ui-color-text);line-height:var(--ui-line-height-normal)}input[type=checkbox]{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.track{position:relative;display:inline-flex;align-items:center;flex-shrink:0;width:2.75rem;height:1.5rem;border-radius:var(--ui-radius-full);border:1.5px solid var(--ui-color-input-border);background-color:var(--ui-color-input-bg);transition:background-color var(--ui-transition-fast),border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);cursor:pointer}.thumb{position:absolute;left:.125rem;width:1.125rem;height:1.125rem;border-radius:var(--ui-radius-full);background-color:var(--ui-color-input-border);box-shadow:var(--ui-shadow-xs);transition:transform var(--ui-transition-fast),background-color var(--ui-transition-fast)}label:hover:not(:has(input:disabled)) .track{border-color:var(--ui-color-input-border-hover)}input[type=checkbox]:focus-visible+.track{box-shadow:var(--ui-focus-ring);border-color:var(--ui-color-input-border-focus)}:host(.is-checked) .track{background-color:var(--ui-color-primary);border-color:var(--ui-color-primary)}:host(.is-checked) .thumb{transform:translate(1.25rem);background-color:var(--ui-color-surface)}:host(.is-invalid) .track{border-color:var(--ui-color-input-border-invalid)}:host(.is-invalid) input[type=checkbox]:focus-visible+.track{border-color:var(--ui-color-input-border-invalid);box-shadow:0 0 0 2px var(--ui-color-surface),0 0 0 4px var(--ui-color-danger)}:host(.is-disabled){opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-disabled) label{cursor:not-allowed}:host(.is-disabled) .track{cursor:not-allowed}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-error-text);line-height:var(--ui-line-height-normal)}\n"] }]
840
+ }], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }] } });
841
+
842
+ /**
843
+ * Inline notification banner with semantic color variants and optional dismiss button.
844
+ *
845
+ * Usage:
846
+ * ```html
847
+ * <llm-alert variant="success">Your changes were saved.</llm-alert>
848
+ * <llm-alert variant="warning" [dismissible]="true" (dismissed)="onDismiss()">
849
+ * Your session expires soon.
850
+ * </llm-alert>
851
+ * ```
852
+ */
853
+ class LlmAlert {
854
+ /** Semantic color variant of the alert. */
855
+ variant = input('info', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
856
+ /** Whether to show a dismiss button. */
857
+ dismissible = input(false, ...(ngDevMode ? [{ debugName: "dismissible" }] : /* istanbul ignore next */ []));
858
+ /** Emitted when the dismiss button is clicked. */
859
+ dismissed = output();
860
+ hostClasses = computed(() => `variant-${this.variant()}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
861
+ /** @internal */
862
+ get isDismissible() {
863
+ return this.dismissible();
864
+ }
865
+ /** @internal */
866
+ get hostClassesValue() {
867
+ return this.hostClasses();
868
+ }
869
+ /** @internal */
870
+ get ariaLive() {
871
+ return this.variant() === 'danger' ? 'assertive' : 'polite';
872
+ }
873
+ dismiss() {
874
+ this.dismissed.emit();
875
+ }
876
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAlert, deps: [], target: i0.ɵɵFactoryTarget.Component });
877
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmAlert, isStandalone: true, selector: "llm-alert", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, host: { attributes: { "role": "alert" }, properties: { "class": "hostClassesValue", "attr.aria-live": "ariaLive" } }, ngImport: i0, template: `
878
+ <span class="content"><ng-content /></span>
879
+ @if (isDismissible) {
880
+ <button class="dismiss" type="button" aria-label="Dismiss" (click)="dismiss()">
881
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
882
+ <line x1="18" y1="6" x2="6" y2="18" />
883
+ <line x1="6" y1="6" x2="18" y2="18" />
884
+ </svg>
885
+ </button>
886
+ }
887
+ `, isInline: true, styles: [":host{display:flex;align-items:flex-start;gap:var(--ui-spacing-3);padding:var(--ui-spacing-3) var(--ui-spacing-4);border-radius:var(--ui-radius-md);border:1px solid transparent;font-family:var(--ui-font-family);font-size:var(--ui-font-size-sm);line-height:var(--ui-line-height-normal);box-sizing:border-box;width:100%}.content{flex:1}:host(.variant-info){background-color:color-mix(in srgb,var(--ui-color-info) 10%,transparent);color:var(--ui-color-info);border-color:color-mix(in srgb,var(--ui-color-info) 25%,transparent)}:host(.variant-success){background-color:color-mix(in srgb,var(--ui-color-success) 10%,transparent);color:var(--ui-color-success);border-color:color-mix(in srgb,var(--ui-color-success) 25%,transparent)}:host(.variant-warning){background-color:color-mix(in srgb,var(--ui-color-warning) 10%,transparent);color:var(--ui-color-warning);border-color:color-mix(in srgb,var(--ui-color-warning) 25%,transparent)}:host(.variant-danger){background-color:color-mix(in srgb,var(--ui-color-danger) 10%,transparent);color:var(--ui-color-danger);border-color:color-mix(in srgb,var(--ui-color-danger) 25%,transparent)}.dismiss{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:.125rem;background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:inherit;opacity:.7;transition:opacity var(--ui-transition-fast),background-color var(--ui-transition-fast);line-height:1}.dismiss:hover{opacity:1;background-color:color-mix(in srgb,currentColor 10%,transparent)}.dismiss:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);opacity:1}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
888
+ }
889
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAlert, decorators: [{
890
+ type: Component,
891
+ args: [{ selector: 'llm-alert', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
892
+ <span class="content"><ng-content /></span>
893
+ @if (isDismissible) {
894
+ <button class="dismiss" type="button" aria-label="Dismiss" (click)="dismiss()">
895
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
896
+ <line x1="18" y1="6" x2="6" y2="18" />
897
+ <line x1="6" y1="6" x2="18" y2="18" />
898
+ </svg>
899
+ </button>
900
+ }
901
+ `, host: {
902
+ '[class]': 'hostClassesValue',
903
+ role: 'alert',
904
+ '[attr.aria-live]': 'ariaLive',
905
+ }, styles: [":host{display:flex;align-items:flex-start;gap:var(--ui-spacing-3);padding:var(--ui-spacing-3) var(--ui-spacing-4);border-radius:var(--ui-radius-md);border:1px solid transparent;font-family:var(--ui-font-family);font-size:var(--ui-font-size-sm);line-height:var(--ui-line-height-normal);box-sizing:border-box;width:100%}.content{flex:1}:host(.variant-info){background-color:color-mix(in srgb,var(--ui-color-info) 10%,transparent);color:var(--ui-color-info);border-color:color-mix(in srgb,var(--ui-color-info) 25%,transparent)}:host(.variant-success){background-color:color-mix(in srgb,var(--ui-color-success) 10%,transparent);color:var(--ui-color-success);border-color:color-mix(in srgb,var(--ui-color-success) 25%,transparent)}:host(.variant-warning){background-color:color-mix(in srgb,var(--ui-color-warning) 10%,transparent);color:var(--ui-color-warning);border-color:color-mix(in srgb,var(--ui-color-warning) 25%,transparent)}:host(.variant-danger){background-color:color-mix(in srgb,var(--ui-color-danger) 10%,transparent);color:var(--ui-color-danger);border-color:color-mix(in srgb,var(--ui-color-danger) 25%,transparent)}.dismiss{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:.125rem;background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:inherit;opacity:.7;transition:opacity var(--ui-transition-fast),background-color var(--ui-transition-fast);line-height:1}.dismiss:hover{opacity:1;background-color:color-mix(in srgb,currentColor 10%,transparent)}.dismiss:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);opacity:1}\n"] }]
906
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], dismissible: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissible", required: false }] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }] } });
907
+
908
+ const LLM_SELECT = new InjectionToken('LLM_SELECT');
909
+
910
+ /** @internal — Wrapper item for ActiveDescendantKeyManager integration. */
911
+ class SelectOptionItem {
912
+ id;
913
+ value;
914
+ labelText;
915
+ activeOptionId;
916
+ disabled;
917
+ constructor(id, value, labelText, disabled, activeOptionId) {
918
+ this.id = id;
919
+ this.value = value;
920
+ this.labelText = labelText;
921
+ this.activeOptionId = activeOptionId;
922
+ this.disabled = disabled;
923
+ }
924
+ getLabel() {
925
+ return this.labelText;
926
+ }
927
+ setActiveStyles() {
928
+ this.activeOptionId.set(this.id);
929
+ }
930
+ setInactiveStyles() {
931
+ // Handled by key manager — no-op here
932
+ }
933
+ }
934
+ let nextId$4 = 0;
935
+ /**
936
+ * Accessible dropdown select component for use with Angular Signal Forms.
937
+ * Uses the native Popover API for the panel overlay.
938
+ *
939
+ * Usage:
940
+ * ```html
941
+ * <llm-select [(value)]="country" placeholder="Select a country">
942
+ * <llm-option optionValue="us">United States</llm-option>
943
+ * <llm-option optionValue="ca">Canada</llm-option>
944
+ * </llm-select>
945
+ *
946
+ * <!-- With Signal Forms -->
947
+ * <llm-select [formField]="form.country" placeholder="Select a country">
948
+ * <llm-option optionValue="us">United States</llm-option>
949
+ * </llm-select>
950
+ * ```
951
+ */
952
+ class LlmSelect {
953
+ /** The selected value. Bound by [formField] directive. Supports [(value)] two-way binding. */
954
+ value = model('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
955
+ /** Whether the user has interacted. Bound by [formField] directive. */
956
+ touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
957
+ /** Placeholder text shown when no option is selected. */
958
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
959
+ /** Whether the select is disabled. Bound by [formField] directive. */
960
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
961
+ /** Whether the select has validation errors. Bound by [formField] directive. */
962
+ invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
963
+ /** Whether the select is required. Bound by [formField] directive. */
964
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
965
+ /** The input's name attribute. Bound by [formField] directive. */
966
+ name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
967
+ /** Validation errors from the form system. Bound by [formField] directive. */
968
+ errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
969
+ /** @internal */
970
+ activeOptionId = signal(null, ...(ngDevMode ? [{ debugName: "activeOptionId" }] : /* istanbul ignore next */ []));
971
+ /** @internal */
972
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
973
+ /** @internal */
974
+ optionsList = signal([], ...(ngDevMode ? [{ debugName: "optionsList" }] : /* istanbul ignore next */ []));
975
+ /** @internal */
976
+ panelRef = viewChild('panel', ...(ngDevMode ? [{ debugName: "panelRef" }] : /* istanbul ignore next */ []));
977
+ /** @internal */
978
+ triggerId = `llm-select-trigger-${nextId$4}`;
979
+ /** @internal */
980
+ panelId = `llm-select-panel-${nextId$4}`;
981
+ /** @internal */
982
+ errorId = `llm-select-errors-${nextId$4++}`;
983
+ /** @internal */
984
+ selectedLabel = computed(() => this.optionsList().find((o) => o.value === this.value())?.labelText ?? '', ...(ngDevMode ? [{ debugName: "selectedLabel" }] : /* istanbul ignore next */ []));
985
+ /** @internal */
986
+ showErrors = computed(() => this.touched() && this.invalid() && this.errors().length > 0, ...(ngDevMode ? [{ debugName: "showErrors" }] : /* istanbul ignore next */ []));
987
+ /** @internal */
988
+ hostClasses = computed(() => {
989
+ const classes = [];
990
+ if (this.isOpen())
991
+ classes.push('is-open');
992
+ if (this.disabled())
993
+ classes.push('is-disabled');
994
+ if (this.invalid())
995
+ classes.push('is-invalid');
996
+ if (this.touched())
997
+ classes.push('is-touched');
998
+ return classes.join(' ');
999
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
1000
+ /** @internal */
1001
+ keyManager = null;
1002
+ outsideClickHandler = null;
1003
+ elementRef = inject(ElementRef);
1004
+ /** @internal — called by LlmOption on init */
1005
+ registerOption(id, value, labelText, disabled) {
1006
+ this.optionsList.update((list) => [...list, { id, value, labelText, disabled }]);
1007
+ }
1008
+ /** @internal — called by LlmOption on destroy */
1009
+ unregisterOption(id) {
1010
+ this.optionsList.update((list) => list.filter((o) => o.id !== id));
1011
+ }
1012
+ /** @internal — called by LlmOption on select */
1013
+ select(v) {
1014
+ if (!this.disabled()) {
1015
+ this.value.set(v);
1016
+ this.close();
1017
+ }
1018
+ }
1019
+ /** @internal — called by LlmOption on interaction */
1020
+ markTouched() {
1021
+ this.touched.set(true);
1022
+ }
1023
+ /** @internal */
1024
+ onTriggerClick() {
1025
+ if (this.disabled())
1026
+ return;
1027
+ if (this.isOpen()) {
1028
+ this.close();
1029
+ }
1030
+ else {
1031
+ this.open();
1032
+ }
1033
+ }
1034
+ /** @internal */
1035
+ onTriggerBlur() {
1036
+ if (!this.isOpen()) {
1037
+ this.touched.set(true);
1038
+ }
1039
+ }
1040
+ /** @internal */
1041
+ onPanelToggle(event) {
1042
+ const toggleEvent = event;
1043
+ if (toggleEvent.newState === 'closed') {
1044
+ this.isOpen.set(false);
1045
+ this.activeOptionId.set(null);
1046
+ }
1047
+ }
1048
+ /** @internal */
1049
+ onKeydown(event) {
1050
+ if (this.disabled())
1051
+ return;
1052
+ switch (event.key) {
1053
+ case 'Enter':
1054
+ case ' ': {
1055
+ event.preventDefault();
1056
+ if (!this.isOpen()) {
1057
+ this.open();
1058
+ }
1059
+ else {
1060
+ const activeItem = this.keyManager?.activeItem;
1061
+ if (activeItem) {
1062
+ this.select(activeItem.value);
1063
+ }
1064
+ }
1065
+ break;
1066
+ }
1067
+ case 'Escape': {
1068
+ event.preventDefault();
1069
+ this.close();
1070
+ break;
1071
+ }
1072
+ default: {
1073
+ const isNav = ['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key);
1074
+ const isTypeahead = event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
1075
+ if ((isNav || isTypeahead) && !this.isOpen()) {
1076
+ this.open();
1077
+ if (isNav)
1078
+ return; // open() already sets active item
1079
+ }
1080
+ this.keyManager?.onKeydown(event);
1081
+ }
1082
+ }
1083
+ }
1084
+ open() {
1085
+ const panel = this.panelRef();
1086
+ if (!panel)
1087
+ return;
1088
+ panel.nativeElement.showPopover();
1089
+ this.isOpen.set(true);
1090
+ // (Re)create key manager with current options
1091
+ const items = this.optionsList().map((o) => new SelectOptionItem(o.id, o.value, o.labelText, o.disabled, this.activeOptionId));
1092
+ this.keyManager = new ActiveDescendantKeyManager(items)
1093
+ .withWrap()
1094
+ .withTypeAhead(500)
1095
+ .withHomeAndEnd()
1096
+ .withVerticalOrientation();
1097
+ // Set active option to currently selected or first enabled
1098
+ const selectedIdx = items.findIndex((i) => i.value === this.value() && !i.disabled);
1099
+ const firstEnabledIdx = items.findIndex((i) => !i.disabled);
1100
+ const activeIdx = selectedIdx >= 0 ? selectedIdx : firstEnabledIdx;
1101
+ if (activeIdx >= 0) {
1102
+ this.keyManager.setActiveItem(activeIdx);
1103
+ }
1104
+ // Outside click listener
1105
+ this.outsideClickHandler = (e) => {
1106
+ if (!this.elementRef.nativeElement.contains(e.target)) {
1107
+ this.close();
1108
+ }
1109
+ };
1110
+ document.addEventListener('click', this.outsideClickHandler);
1111
+ }
1112
+ close() {
1113
+ const panel = this.panelRef();
1114
+ if (!panel)
1115
+ return;
1116
+ try {
1117
+ panel.nativeElement.hidePopover();
1118
+ }
1119
+ catch {
1120
+ // Panel may already be hidden
1121
+ }
1122
+ this.isOpen.set(false);
1123
+ this.activeOptionId.set(null);
1124
+ this.keyManager = null;
1125
+ if (this.outsideClickHandler) {
1126
+ document.removeEventListener('click', this.outsideClickHandler);
1127
+ this.outsideClickHandler = null;
1128
+ }
1129
+ }
1130
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
1131
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmSelect, isStandalone: true, selector: "llm-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", 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 }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, host: { attributes: { "role": "combobox" }, listeners: { "keydown": "onKeydown($event)" }, properties: { "class": "hostClasses()" } }, providers: [{ provide: LLM_SELECT, useExisting: LlmSelect }], viewQueries: [{ propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: `
1132
+ <button
1133
+ type="button"
1134
+ class="trigger"
1135
+ [id]="triggerId"
1136
+ [attr.aria-expanded]="isOpen()"
1137
+ aria-haspopup="listbox"
1138
+ [attr.aria-controls]="panelId"
1139
+ [attr.aria-activedescendant]="activeOptionId()"
1140
+ [attr.aria-invalid]="invalid() || null"
1141
+ [attr.disabled]="disabled() || null"
1142
+ (click)="onTriggerClick()"
1143
+ (blur)="onTriggerBlur()"
1144
+ >
1145
+ <span class="trigger-text">{{ selectedLabel() || placeholder() }}</span>
1146
+ <span class="trigger-icon" aria-hidden="true">▾</span>
1147
+ </button>
1148
+
1149
+ <div
1150
+ #panel
1151
+ [id]="panelId"
1152
+ popover="manual"
1153
+ role="listbox"
1154
+ class="panel"
1155
+ [attr.aria-labelledby]="triggerId"
1156
+ (toggle)="onPanelToggle($event)"
1157
+ >
1158
+ <ng-content />
1159
+ </div>
1160
+
1161
+ @if (showErrors()) {
1162
+ <div class="errors" [id]="errorId" aria-live="polite">
1163
+ @for (error of errors(); track error.kind) {
1164
+ <p class="error-message">{{ error.message }}</p>
1165
+ }
1166
+ </div>
1167
+ }
1168
+ `, isInline: true, styles: [":host{display:inline-block;position:relative;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}.trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--ui-spacing-2);width:100%;padding:var(--ui-spacing-2) var(--ui-spacing-3);background:var(--ui-color-input-bg);border:1px solid var(--ui-color-input-border);border-radius:var(--ui-radius-md);color:var(--ui-color-text);font-family:inherit;font-size:inherit;cursor:pointer;transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);anchor-name:--select-trigger}.trigger:hover:not(:disabled){border-color:var(--ui-color-input-border-hover)}.trigger:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);border-color:var(--ui-color-input-border-focus)}.trigger:disabled{opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-invalid) .trigger{border-color:var(--ui-color-input-border-invalid)}:host(.is-open) .trigger{border-color:var(--ui-color-input-border-focus);box-shadow:var(--ui-focus-ring)}.trigger-text{flex:1;text-align:start;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-color-text)}.trigger-text:empty,.trigger[data-placeholder] .trigger-text{color:var(--ui-color-placeholder)}.trigger-icon{flex-shrink:0;font-size:var(--ui-font-size-xs);color:var(--ui-color-text-muted);transition:transform var(--ui-transition-fast)}:host(.is-open) .trigger-icon{transform:rotate(180deg)}.panel[popover]{position:absolute;position-anchor:--select-trigger;inset-block-start:anchor(bottom);inset-inline-start:anchor(left);min-width:anchor-size(width);margin-block-start:var(--ui-spacing-1);padding:var(--ui-spacing-1) 0;background:var(--ui-color-surface-raised);border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-md);box-shadow:var(--ui-shadow-lg);z-index:var(--ui-z-dropdown);max-height:16rem;overflow-y:auto;opacity:0;transform:translateY(-4px);transition:opacity var(--ui-transition-normal),transform var(--ui-transition-normal)}.panel[popover]:popover-open{opacity:1;transform:translateY(0)}llm-option [role=option]{padding:var(--ui-spacing-2) var(--ui-spacing-3);cursor:pointer;color:var(--ui-color-text);transition:background var(--ui-transition-fast)}llm-option [role=option]:hover,llm-option [role=option].is-active{background:var(--ui-color-surface-sunken)}llm-option [role=option].is-selected{background:var(--ui-color-primary-light);color:var(--ui-color-primary);font-weight:var(--ui-font-weight-medium)}llm-option [role=option].is-disabled{opacity:var(--ui-opacity-disabled);cursor:not-allowed}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-xs);color:var(--ui-color-error-text)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1169
+ }
1170
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmSelect, decorators: [{
1171
+ type: Component,
1172
+ args: [{ selector: 'llm-select', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
1173
+ <button
1174
+ type="button"
1175
+ class="trigger"
1176
+ [id]="triggerId"
1177
+ [attr.aria-expanded]="isOpen()"
1178
+ aria-haspopup="listbox"
1179
+ [attr.aria-controls]="panelId"
1180
+ [attr.aria-activedescendant]="activeOptionId()"
1181
+ [attr.aria-invalid]="invalid() || null"
1182
+ [attr.disabled]="disabled() || null"
1183
+ (click)="onTriggerClick()"
1184
+ (blur)="onTriggerBlur()"
1185
+ >
1186
+ <span class="trigger-text">{{ selectedLabel() || placeholder() }}</span>
1187
+ <span class="trigger-icon" aria-hidden="true">▾</span>
1188
+ </button>
1189
+
1190
+ <div
1191
+ #panel
1192
+ [id]="panelId"
1193
+ popover="manual"
1194
+ role="listbox"
1195
+ class="panel"
1196
+ [attr.aria-labelledby]="triggerId"
1197
+ (toggle)="onPanelToggle($event)"
1198
+ >
1199
+ <ng-content />
1200
+ </div>
1201
+
1202
+ @if (showErrors()) {
1203
+ <div class="errors" [id]="errorId" aria-live="polite">
1204
+ @for (error of errors(); track error.kind) {
1205
+ <p class="error-message">{{ error.message }}</p>
1206
+ }
1207
+ </div>
1208
+ }
1209
+ `, host: {
1210
+ role: 'combobox',
1211
+ '[class]': 'hostClasses()',
1212
+ '(keydown)': 'onKeydown($event)',
1213
+ }, providers: [{ provide: LLM_SELECT, useExisting: LlmSelect }], styles: [":host{display:inline-block;position:relative;font-family:var(--ui-font-family);font-size:var(--ui-font-size-md)}.trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--ui-spacing-2);width:100%;padding:var(--ui-spacing-2) var(--ui-spacing-3);background:var(--ui-color-input-bg);border:1px solid var(--ui-color-input-border);border-radius:var(--ui-radius-md);color:var(--ui-color-text);font-family:inherit;font-size:inherit;cursor:pointer;transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);anchor-name:--select-trigger}.trigger:hover:not(:disabled){border-color:var(--ui-color-input-border-hover)}.trigger:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);border-color:var(--ui-color-input-border-focus)}.trigger:disabled{opacity:var(--ui-opacity-disabled);cursor:not-allowed}:host(.is-invalid) .trigger{border-color:var(--ui-color-input-border-invalid)}:host(.is-open) .trigger{border-color:var(--ui-color-input-border-focus);box-shadow:var(--ui-focus-ring)}.trigger-text{flex:1;text-align:start;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-color-text)}.trigger-text:empty,.trigger[data-placeholder] .trigger-text{color:var(--ui-color-placeholder)}.trigger-icon{flex-shrink:0;font-size:var(--ui-font-size-xs);color:var(--ui-color-text-muted);transition:transform var(--ui-transition-fast)}:host(.is-open) .trigger-icon{transform:rotate(180deg)}.panel[popover]{position:absolute;position-anchor:--select-trigger;inset-block-start:anchor(bottom);inset-inline-start:anchor(left);min-width:anchor-size(width);margin-block-start:var(--ui-spacing-1);padding:var(--ui-spacing-1) 0;background:var(--ui-color-surface-raised);border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-md);box-shadow:var(--ui-shadow-lg);z-index:var(--ui-z-dropdown);max-height:16rem;overflow-y:auto;opacity:0;transform:translateY(-4px);transition:opacity var(--ui-transition-normal),transform var(--ui-transition-normal)}.panel[popover]:popover-open{opacity:1;transform:translateY(0)}llm-option [role=option]{padding:var(--ui-spacing-2) var(--ui-spacing-3);cursor:pointer;color:var(--ui-color-text);transition:background var(--ui-transition-fast)}llm-option [role=option]:hover,llm-option [role=option].is-active{background:var(--ui-color-surface-sunken)}llm-option [role=option].is-selected{background:var(--ui-color-primary-light);color:var(--ui-color-primary);font-weight:var(--ui-font-weight-medium)}llm-option [role=option].is-disabled{opacity:var(--ui-opacity-disabled);cursor:not-allowed}.errors{margin-top:var(--ui-spacing-1)}.error-message{margin:0;font-size:var(--ui-font-size-xs);color:var(--ui-color-error-text)}\n"] }]
1214
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], panelRef: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
1215
+
1216
+ let nextOptionId = 0;
1217
+ /**
1218
+ * Option item for use inside `<llm-select>`.
1219
+ *
1220
+ * Usage:
1221
+ * ```html
1222
+ * <llm-option optionValue="us">United States</llm-option>
1223
+ * ```
1224
+ */
1225
+ class LlmOption {
1226
+ /** The value this option represents. Required. */
1227
+ optionValue = input.required(...(ngDevMode ? [{ debugName: "optionValue" }] : /* istanbul ignore next */ []));
1228
+ /** Whether this option is disabled. */
1229
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
1230
+ /** @internal */
1231
+ optionId = `llm-option-${nextOptionId++}`;
1232
+ /** @internal */
1233
+ context = inject(LLM_SELECT);
1234
+ /** @internal */
1235
+ elementRef = inject(ElementRef);
1236
+ /** @internal */
1237
+ isSelected = computed(() => this.context.value() === this.optionValue(), ...(ngDevMode ? [{ debugName: "isSelected" }] : /* istanbul ignore next */ []));
1238
+ /** @internal */
1239
+ isActive = computed(() => this.context.activeOptionId() === this.optionId, ...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
1240
+ ngOnInit() {
1241
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1242
+ const labelText = (this.elementRef.nativeElement.textContent ?? '').trim();
1243
+ this.context.registerOption(this.optionId, this.optionValue(), labelText, this.disabled());
1244
+ }
1245
+ ngOnDestroy() {
1246
+ this.context.unregisterOption(this.optionId);
1247
+ }
1248
+ /** @internal */
1249
+ onClick() {
1250
+ if (this.disabled())
1251
+ return;
1252
+ this.context.select(this.optionValue());
1253
+ this.context.markTouched();
1254
+ }
1255
+ /** @internal */
1256
+ onMouseEnter() {
1257
+ if (!this.disabled()) {
1258
+ this.context.activeOptionId.set(this.optionId);
1259
+ }
1260
+ }
1261
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmOption, deps: [], target: i0.ɵɵFactoryTarget.Component });
1262
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmOption, isStandalone: true, selector: "llm-option", inputs: { optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1263
+ <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
1264
+ <div
1265
+ role="option"
1266
+ [attr.id]="optionId"
1267
+ [attr.aria-selected]="isSelected()"
1268
+ [attr.aria-disabled]="disabled() || null"
1269
+ [class.is-selected]="isSelected()"
1270
+ [class.is-active]="isActive()"
1271
+ [class.is-disabled]="disabled()"
1272
+ (click)="onClick()"
1273
+ (mouseenter)="onMouseEnter()"
1274
+ >
1275
+ <ng-content />
1276
+ </div>
1277
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1278
+ }
1279
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmOption, decorators: [{
1280
+ type: Component,
1281
+ args: [{
1282
+ selector: 'llm-option',
1283
+ standalone: true,
1284
+ changeDetection: ChangeDetectionStrategy.OnPush,
1285
+ template: `
1286
+ <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
1287
+ <div
1288
+ role="option"
1289
+ [attr.id]="optionId"
1290
+ [attr.aria-selected]="isSelected()"
1291
+ [attr.aria-disabled]="disabled() || null"
1292
+ [class.is-selected]="isSelected()"
1293
+ [class.is-active]="isActive()"
1294
+ [class.is-disabled]="disabled()"
1295
+ (click)="onClick()"
1296
+ (mouseenter)="onMouseEnter()"
1297
+ >
1298
+ <ng-content />
1299
+ </div>
1300
+ `,
1301
+ }]
1302
+ }], propDecorators: { optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
1303
+
1304
+ const LLM_DIALOG = new InjectionToken('LLM_DIALOG');
1305
+
1306
+ let nextId$3 = 0;
1307
+ /**
1308
+ * Accessible modal dialog using the native `<dialog>` element.
1309
+ * Includes focus trap, Escape to close, backdrop click to close, and animation.
1310
+ * Compose with `llm-dialog-header`, `llm-dialog-content`, and `llm-dialog-footer`.
1311
+ *
1312
+ * Usage:
1313
+ * ```html
1314
+ * <llm-dialog [(open)]="isOpen">
1315
+ * <llm-dialog-header>Dialog Title</llm-dialog-header>
1316
+ * <llm-dialog-content>Dialog body content.</llm-dialog-content>
1317
+ * <llm-dialog-footer>
1318
+ * <llm-button variant="primary" (click)="isOpen = false">Confirm</llm-button>
1319
+ * </llm-dialog-footer>
1320
+ * </llm-dialog>
1321
+ * ```
1322
+ */
1323
+ class LlmDialog {
1324
+ /** Whether the dialog is open. Supports two-way binding: [(open)]="isOpen". */
1325
+ open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
1326
+ /** Whether clicking the backdrop closes the dialog. */
1327
+ closeOnBackdrop = input(true, ...(ngDevMode ? [{ debugName: "closeOnBackdrop" }] : /* istanbul ignore next */ []));
1328
+ /** Size of the dialog panel. */
1329
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
1330
+ /** Accessible label for the dialog (use instead of aria-labelledby when no header is present). */
1331
+ ariaLabel = input('', { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
1332
+ /** ID of the element that labels the dialog (defaults to the llm-dialog-header id). */
1333
+ ariaLabelledby = input('', { ...(ngDevMode ? { debugName: "ariaLabelledby" } : /* istanbul ignore next */ {}), alias: 'aria-labelledby' });
1334
+ /** @internal — referenced by LlmDialogHeader via LLM_DIALOG token */
1335
+ headerId = `llm-dialog-header-${nextId$3}`;
1336
+ dialogId = `llm-dialog-${nextId$3++}`;
1337
+ dialogRef = viewChild('dialogEl', ...(ngDevMode ? [{ debugName: "dialogRef" }] : /* istanbul ignore next */ []));
1338
+ triggerEl = signal(null, ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
1339
+ panelClass = computed(() => `panel size-${this.size()}`, ...(ngDevMode ? [{ debugName: "panelClass" }] : /* istanbul ignore next */ []));
1340
+ hostClasses = computed(() => (this.open() ? 'is-open' : ''), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
1341
+ constructor() {
1342
+ effect(() => {
1343
+ const dialog = this.dialogRef()?.nativeElement;
1344
+ if (!dialog)
1345
+ return;
1346
+ if (this.open()) {
1347
+ this.triggerEl.set(document.activeElement);
1348
+ dialog.showModal();
1349
+ }
1350
+ else {
1351
+ if (dialog.open)
1352
+ dialog.close();
1353
+ this.triggerEl()?.focus();
1354
+ this.triggerEl.set(null);
1355
+ }
1356
+ });
1357
+ }
1358
+ onCancel(event) {
1359
+ event.preventDefault();
1360
+ this.open.set(false);
1361
+ }
1362
+ onBackdropClick(event) {
1363
+ if (this.closeOnBackdrop() && event.target === this.dialogRef()?.nativeElement) {
1364
+ this.open.set(false);
1365
+ }
1366
+ }
1367
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
1368
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.4", type: LlmDialog, isStandalone: true, selector: "llm-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdrop: { classPropertyName: "closeOnBackdrop", publicName: "closeOnBackdrop", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { properties: { "class": "hostClasses()" } }, providers: [
1369
+ {
1370
+ provide: LLM_DIALOG,
1371
+ useFactory: (dialog) => ({
1372
+ headerId: dialog.headerId,
1373
+ close: () => dialog.open.set(false),
1374
+ }),
1375
+ deps: [LlmDialog],
1376
+ },
1377
+ ], viewQueries: [{ propertyName: "dialogRef", first: true, predicate: ["dialogEl"], descendants: true, isSignal: true }], ngImport: i0, template: `
1378
+ <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
1379
+ <dialog
1380
+ #dialogEl
1381
+ [attr.aria-label]="ariaLabel() || null"
1382
+ [attr.aria-labelledby]="ariaLabel() ? null : (ariaLabelledby() || headerId)"
1383
+ aria-modal="true"
1384
+ [cdkTrapFocus]="open()"
1385
+ (cancel)="onCancel($event)"
1386
+ (click)="onBackdropClick($event)"
1387
+ >
1388
+ <div [class]="panelClass()">
1389
+ <ng-content />
1390
+ </div>
1391
+ </dialog>
1392
+ `, isInline: true, styles: ["llm-dialog{display:contents}dialog{all:unset;position:fixed;inset:0;margin:auto;display:none;flex-direction:column;max-height:calc(100dvh - var(--ui-spacing-8));border-radius:var(--ui-radius-lg);background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;opacity:0;transform:scale(.95);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;opacity:1;transform:scale(1)}@starting-style{dialog[open]{opacity:0;transform:scale(.95)}}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;max-height:inherit;overflow:hidden}.size-sm{width:min(24rem,90vw)}.size-md{width:min(36rem,90vw)}.size-lg{width:min(48rem,90vw)}.size-xl{width:min(64rem,90vw)}.size-full{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;margin:0}llm-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-dialog-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-dialog-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"], dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1$1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1393
+ }
1394
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDialog, decorators: [{
1395
+ type: Component,
1396
+ args: [{ selector: 'llm-dialog', standalone: true, imports: [A11yModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
1397
+ {
1398
+ provide: LLM_DIALOG,
1399
+ useFactory: (dialog) => ({
1400
+ headerId: dialog.headerId,
1401
+ close: () => dialog.open.set(false),
1402
+ }),
1403
+ deps: [LlmDialog],
1404
+ },
1405
+ ], template: `
1406
+ <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
1407
+ <dialog
1408
+ #dialogEl
1409
+ [attr.aria-label]="ariaLabel() || null"
1410
+ [attr.aria-labelledby]="ariaLabel() ? null : (ariaLabelledby() || headerId)"
1411
+ aria-modal="true"
1412
+ [cdkTrapFocus]="open()"
1413
+ (cancel)="onCancel($event)"
1414
+ (click)="onBackdropClick($event)"
1415
+ >
1416
+ <div [class]="panelClass()">
1417
+ <ng-content />
1418
+ </div>
1419
+ </dialog>
1420
+ `, host: {
1421
+ '[class]': 'hostClasses()',
1422
+ }, styles: ["llm-dialog{display:contents}dialog{all:unset;position:fixed;inset:0;margin:auto;display:none;flex-direction:column;max-height:calc(100dvh - var(--ui-spacing-8));border-radius:var(--ui-radius-lg);background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;opacity:0;transform:scale(.95);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;opacity:1;transform:scale(1)}@starting-style{dialog[open]{opacity:0;transform:scale(.95)}}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;max-height:inherit;overflow:hidden}.size-sm{width:min(24rem,90vw)}.size-md{width:min(36rem,90vw)}.size-lg{width:min(48rem,90vw)}.size-xl{width:min(64rem,90vw)}.size-full{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;margin:0}llm-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-dialog-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-dialog-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"] }]
1423
+ }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], closeOnBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdrop", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], dialogRef: [{ type: i0.ViewChild, args: ['dialogEl', { isSignal: true }] }] } });
1424
+ /**
1425
+ * Header slot for `llm-dialog`. Renders above content with a bottom separator.
1426
+ * Automatically receives the correct `id` for `aria-labelledby` association.
1427
+ */
1428
+ class LlmDialogHeader {
1429
+ context = inject(LLM_DIALOG);
1430
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDialogHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
1431
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmDialogHeader, isStandalone: true, selector: "llm-dialog-header", host: { properties: { "attr.id": "context.headerId" } }, ngImport: i0, template: `
1432
+ <ng-content />
1433
+ <button
1434
+ class="close-btn"
1435
+ type="button"
1436
+ aria-label="Close dialog"
1437
+ (click)="context.close()"
1438
+ >
1439
+ <svg
1440
+ xmlns="http://www.w3.org/2000/svg"
1441
+ width="14"
1442
+ height="14"
1443
+ viewBox="0 0 24 24"
1444
+ fill="none"
1445
+ stroke="currentColor"
1446
+ stroke-width="2.5"
1447
+ stroke-linecap="round"
1448
+ stroke-linejoin="round"
1449
+ aria-hidden="true"
1450
+ focusable="false"
1451
+ >
1452
+ <line x1="18" y1="6" x2="6" y2="18" />
1453
+ <line x1="6" y1="6" x2="18" y2="18" />
1454
+ </svg>
1455
+ </button>
1456
+ `, isInline: true, styles: ["llm-dialog{display:contents}dialog{all:unset;position:fixed;inset:0;margin:auto;display:none;flex-direction:column;max-height:calc(100dvh - var(--ui-spacing-8));border-radius:var(--ui-radius-lg);background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;opacity:0;transform:scale(.95);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;opacity:1;transform:scale(1)}@starting-style{dialog[open]{opacity:0;transform:scale(.95)}}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;max-height:inherit;overflow:hidden}.size-sm{width:min(24rem,90vw)}.size-md{width:min(36rem,90vw)}.size-lg{width:min(48rem,90vw)}.size-xl{width:min(64rem,90vw)}.size-full{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;margin:0}llm-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-dialog-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-dialog-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1457
+ }
1458
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDialogHeader, decorators: [{
1459
+ type: Component,
1460
+ args: [{ selector: 'llm-dialog-header', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
1461
+ <ng-content />
1462
+ <button
1463
+ class="close-btn"
1464
+ type="button"
1465
+ aria-label="Close dialog"
1466
+ (click)="context.close()"
1467
+ >
1468
+ <svg
1469
+ xmlns="http://www.w3.org/2000/svg"
1470
+ width="14"
1471
+ height="14"
1472
+ viewBox="0 0 24 24"
1473
+ fill="none"
1474
+ stroke="currentColor"
1475
+ stroke-width="2.5"
1476
+ stroke-linecap="round"
1477
+ stroke-linejoin="round"
1478
+ aria-hidden="true"
1479
+ focusable="false"
1480
+ >
1481
+ <line x1="18" y1="6" x2="6" y2="18" />
1482
+ <line x1="6" y1="6" x2="18" y2="18" />
1483
+ </svg>
1484
+ </button>
1485
+ `, host: {
1486
+ '[attr.id]': 'context.headerId',
1487
+ }, styles: ["llm-dialog{display:contents}dialog{all:unset;position:fixed;inset:0;margin:auto;display:none;flex-direction:column;max-height:calc(100dvh - var(--ui-spacing-8));border-radius:var(--ui-radius-lg);background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;opacity:0;transform:scale(.95);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;opacity:1;transform:scale(1)}@starting-style{dialog[open]{opacity:0;transform:scale(.95)}}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;max-height:inherit;overflow:hidden}.size-sm{width:min(24rem,90vw)}.size-md{width:min(36rem,90vw)}.size-lg{width:min(48rem,90vw)}.size-xl{width:min(64rem,90vw)}.size-full{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;margin:0}llm-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-dialog-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-dialog-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"] }]
1488
+ }] });
1489
+ /**
1490
+ * Content slot for `llm-dialog`. Scrollable primary content area.
1491
+ */
1492
+ class LlmDialogContent {
1493
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDialogContent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1494
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmDialogContent, isStandalone: true, selector: "llm-dialog-content", ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["llm-dialog{display:contents}dialog{all:unset;position:fixed;inset:0;margin:auto;display:none;flex-direction:column;max-height:calc(100dvh - var(--ui-spacing-8));border-radius:var(--ui-radius-lg);background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;opacity:0;transform:scale(.95);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;opacity:1;transform:scale(1)}@starting-style{dialog[open]{opacity:0;transform:scale(.95)}}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;max-height:inherit;overflow:hidden}.size-sm{width:min(24rem,90vw)}.size-md{width:min(36rem,90vw)}.size-lg{width:min(48rem,90vw)}.size-xl{width:min(64rem,90vw)}.size-full{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;margin:0}llm-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-dialog-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-dialog-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1495
+ }
1496
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDialogContent, decorators: [{
1497
+ type: Component,
1498
+ args: [{ selector: 'llm-dialog-content', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, styles: ["llm-dialog{display:contents}dialog{all:unset;position:fixed;inset:0;margin:auto;display:none;flex-direction:column;max-height:calc(100dvh - var(--ui-spacing-8));border-radius:var(--ui-radius-lg);background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;opacity:0;transform:scale(.95);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;opacity:1;transform:scale(1)}@starting-style{dialog[open]{opacity:0;transform:scale(.95)}}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;max-height:inherit;overflow:hidden}.size-sm{width:min(24rem,90vw)}.size-md{width:min(36rem,90vw)}.size-lg{width:min(48rem,90vw)}.size-xl{width:min(64rem,90vw)}.size-full{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;margin:0}llm-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-dialog-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-dialog-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"] }]
1499
+ }] });
1500
+ /**
1501
+ * Footer slot for `llm-dialog`. Renders below content, typically holds action buttons.
1502
+ */
1503
+ class LlmDialogFooter {
1504
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDialogFooter, deps: [], target: i0.ɵɵFactoryTarget.Component });
1505
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmDialogFooter, isStandalone: true, selector: "llm-dialog-footer", ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["llm-dialog{display:contents}dialog{all:unset;position:fixed;inset:0;margin:auto;display:none;flex-direction:column;max-height:calc(100dvh - var(--ui-spacing-8));border-radius:var(--ui-radius-lg);background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;opacity:0;transform:scale(.95);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;opacity:1;transform:scale(1)}@starting-style{dialog[open]{opacity:0;transform:scale(.95)}}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;max-height:inherit;overflow:hidden}.size-sm{width:min(24rem,90vw)}.size-md{width:min(36rem,90vw)}.size-lg{width:min(48rem,90vw)}.size-xl{width:min(64rem,90vw)}.size-full{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;margin:0}llm-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-dialog-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-dialog-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1506
+ }
1507
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDialogFooter, decorators: [{
1508
+ type: Component,
1509
+ args: [{ selector: 'llm-dialog-footer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, styles: ["llm-dialog{display:contents}dialog{all:unset;position:fixed;inset:0;margin:auto;display:none;flex-direction:column;max-height:calc(100dvh - var(--ui-spacing-8));border-radius:var(--ui-radius-lg);background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;opacity:0;transform:scale(.95);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;opacity:1;transform:scale(1)}@starting-style{dialog[open]{opacity:0;transform:scale(.95)}}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;max-height:inherit;overflow:hidden}.size-sm{width:min(24rem,90vw)}.size-md{width:min(36rem,90vw)}.size-lg{width:min(48rem,90vw)}.size-xl{width:min(64rem,90vw)}.size-full{width:100vw;height:100dvh;max-height:100dvh;border-radius:0;margin:0}llm-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-dialog-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-dialog-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"] }]
1510
+ }] });
1511
+
1512
+ const LLM_TAB_GROUP = new InjectionToken('LLM_TAB_GROUP');
1513
+
1514
+ let nextId$2 = 0;
1515
+ /**
1516
+ * Accessible tabbed interface container. Renders a tab list and manages
1517
+ * keyboard navigation with roving tabindex.
1518
+ *
1519
+ * Usage:
1520
+ * ```html
1521
+ * <llm-tab-group [(selectedIndex)]="activeTab">
1522
+ * <llm-tab label="Account">Account settings here.</llm-tab>
1523
+ * <llm-tab label="Notifications">Notification prefs here.</llm-tab>
1524
+ * <llm-tab label="Billing" [disabled]="true">Billing info here.</llm-tab>
1525
+ * </llm-tab-group>
1526
+ * ```
1527
+ */
1528
+ class LlmTabGroup {
1529
+ /** Index of the currently active tab. Supports two-way binding. */
1530
+ selectedIndex = model(0, ...(ngDevMode ? [{ debugName: "selectedIndex" }] : /* istanbul ignore next */ []));
1531
+ /** Visual variant. */
1532
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
1533
+ /** @internal */
1534
+ tabs = signal([], ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
1535
+ /** @internal */
1536
+ elementRef = inject(ElementRef);
1537
+ /** @internal */
1538
+ hostClasses = computed(() => `variant-${this.variant()}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
1539
+ /** @internal — called by LlmTab on init */
1540
+ registerTab(info) {
1541
+ this.tabs.update((list) => [...list, info]);
1542
+ }
1543
+ /** @internal — called by LlmTab on destroy */
1544
+ unregisterTab(id) {
1545
+ this.tabs.update((list) => list.filter((t) => t.id !== id));
1546
+ }
1547
+ /** @internal */
1548
+ selectTab(index) {
1549
+ const tab = this.tabs()[index];
1550
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/strict-boolean-expressions
1551
+ if (tab && !tab.disabled) {
1552
+ this.selectedIndex.set(index);
1553
+ }
1554
+ }
1555
+ /** @internal */
1556
+ onTabKeydown(event) {
1557
+ const tabs = this.tabs();
1558
+ const enabled = tabs.map((tab, i) => ({ tab, i })).filter(({ tab }) => !tab.disabled);
1559
+ if (enabled.length === 0)
1560
+ return;
1561
+ const currentPos = enabled.findIndex(({ i }) => i === this.selectedIndex());
1562
+ const n = enabled.length;
1563
+ let targetEntry = null;
1564
+ switch (event.key) {
1565
+ case 'ArrowRight':
1566
+ event.preventDefault();
1567
+ targetEntry = enabled[(currentPos + 1) % n];
1568
+ break;
1569
+ case 'ArrowLeft':
1570
+ event.preventDefault();
1571
+ targetEntry = enabled[(currentPos - 1 + n) % n];
1572
+ break;
1573
+ case 'Home':
1574
+ event.preventDefault();
1575
+ targetEntry = enabled[0];
1576
+ break;
1577
+ case 'End':
1578
+ event.preventDefault();
1579
+ targetEntry = enabled[n - 1];
1580
+ break;
1581
+ }
1582
+ if (targetEntry) {
1583
+ this.selectedIndex.set(targetEntry.i);
1584
+ const buttons = this.elementRef.nativeElement.querySelectorAll('[role="tab"]');
1585
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1586
+ buttons[targetEntry.i]?.focus();
1587
+ }
1588
+ }
1589
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmTabGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
1590
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmTabGroup, isStandalone: true, selector: "llm-tab-group", inputs: { selectedIndex: { classPropertyName: "selectedIndex", publicName: "selectedIndex", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedIndex: "selectedIndexChange" }, host: { properties: { "class": "hostClasses()" } }, providers: [{ provide: LLM_TAB_GROUP, useExisting: LlmTabGroup }], ngImport: i0, template: `
1591
+ <div class="tablist" role="tablist">
1592
+ @for (tab of tabs(); track tab.id; let i = $index) {
1593
+ <button
1594
+ type="button"
1595
+ role="tab"
1596
+ [id]="tab.tabId"
1597
+ [attr.aria-selected]="selectedIndex() === i"
1598
+ [attr.aria-controls]="tab.panelId"
1599
+ [attr.aria-disabled]="tab.disabled || null"
1600
+ [attr.tabindex]="selectedIndex() === i ? 0 : -1"
1601
+ [class.is-active]="selectedIndex() === i"
1602
+ [class.is-disabled]="tab.disabled"
1603
+ (click)="selectTab(i)"
1604
+ (keydown)="onTabKeydown($event)"
1605
+ >
1606
+ {{ tab.label }}
1607
+ </button>
1608
+ }
1609
+ </div>
1610
+ <ng-content />
1611
+ `, isInline: true, styles: [":host{display:block;font-family:var(--ui-font-family)}.tablist{display:flex;gap:var(--ui-spacing-1);border-bottom:1px solid var(--ui-color-border);overflow-x:auto;scrollbar-width:none}.tablist::-webkit-scrollbar{display:none}.tablist button{all:unset;box-sizing:border-box;position:relative;display:inline-flex;align-items:center;padding:var(--ui-spacing-2) var(--ui-spacing-4);font-size:var(--ui-font-size-sm);font-weight:var(--ui-font-weight-medium);color:var(--ui-color-text-muted);cursor:pointer;transition:var(--ui-transition-fast);transition-property:color,background-color;border-radius:var(--ui-radius-md) var(--ui-radius-md) 0 0;white-space:nowrap;-webkit-user-select:none;user-select:none}.tablist button:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:2px;background:transparent;border-radius:var(--ui-radius-full);transition:background var(--ui-transition-fast)}.tablist button.is-active{color:var(--ui-color-primary)}.tablist button.is-active:after{background:var(--ui-color-primary)}.tablist button:hover:not(.is-disabled):not(.is-active){color:var(--ui-color-text);background:var(--ui-color-surface-sunken)}.tablist button:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);border-radius:var(--ui-radius-md)}.tablist button.is-disabled{opacity:.4;cursor:not-allowed}llm-tab [role=tabpanel]{padding:var(--ui-spacing-4) 0}llm-tab [role=tabpanel]:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);border-radius:var(--ui-radius-md)}:host(.variant-pills) .tablist{border-bottom:none;gap:var(--ui-spacing-2);padding:var(--ui-spacing-1);background:var(--ui-color-surface-sunken);border-radius:var(--ui-radius-lg)}:host(.variant-pills) .tablist button{border-radius:var(--ui-radius-md);padding:var(--ui-spacing-1) var(--ui-spacing-4);font-size:var(--ui-font-size-sm)}:host(.variant-pills) .tablist button:after{display:none}:host(.variant-pills) .tablist button.is-active{background:var(--ui-color-surface);color:var(--ui-color-text);box-shadow:var(--ui-shadow-sm)}:host(.variant-pills) .tablist button:hover:not(.is-disabled):not(.is-active){background:transparent;color:var(--ui-color-text)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1612
+ }
1613
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmTabGroup, decorators: [{
1614
+ type: Component,
1615
+ args: [{ selector: 'llm-tab-group', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
1616
+ <div class="tablist" role="tablist">
1617
+ @for (tab of tabs(); track tab.id; let i = $index) {
1618
+ <button
1619
+ type="button"
1620
+ role="tab"
1621
+ [id]="tab.tabId"
1622
+ [attr.aria-selected]="selectedIndex() === i"
1623
+ [attr.aria-controls]="tab.panelId"
1624
+ [attr.aria-disabled]="tab.disabled || null"
1625
+ [attr.tabindex]="selectedIndex() === i ? 0 : -1"
1626
+ [class.is-active]="selectedIndex() === i"
1627
+ [class.is-disabled]="tab.disabled"
1628
+ (click)="selectTab(i)"
1629
+ (keydown)="onTabKeydown($event)"
1630
+ >
1631
+ {{ tab.label }}
1632
+ </button>
1633
+ }
1634
+ </div>
1635
+ <ng-content />
1636
+ `, host: {
1637
+ '[class]': 'hostClasses()',
1638
+ }, providers: [{ provide: LLM_TAB_GROUP, useExisting: LlmTabGroup }], styles: [":host{display:block;font-family:var(--ui-font-family)}.tablist{display:flex;gap:var(--ui-spacing-1);border-bottom:1px solid var(--ui-color-border);overflow-x:auto;scrollbar-width:none}.tablist::-webkit-scrollbar{display:none}.tablist button{all:unset;box-sizing:border-box;position:relative;display:inline-flex;align-items:center;padding:var(--ui-spacing-2) var(--ui-spacing-4);font-size:var(--ui-font-size-sm);font-weight:var(--ui-font-weight-medium);color:var(--ui-color-text-muted);cursor:pointer;transition:var(--ui-transition-fast);transition-property:color,background-color;border-radius:var(--ui-radius-md) var(--ui-radius-md) 0 0;white-space:nowrap;-webkit-user-select:none;user-select:none}.tablist button:after{content:\"\";position:absolute;bottom:-1px;left:0;right:0;height:2px;background:transparent;border-radius:var(--ui-radius-full);transition:background var(--ui-transition-fast)}.tablist button.is-active{color:var(--ui-color-primary)}.tablist button.is-active:after{background:var(--ui-color-primary)}.tablist button:hover:not(.is-disabled):not(.is-active){color:var(--ui-color-text);background:var(--ui-color-surface-sunken)}.tablist button:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);border-radius:var(--ui-radius-md)}.tablist button.is-disabled{opacity:.4;cursor:not-allowed}llm-tab [role=tabpanel]{padding:var(--ui-spacing-4) 0}llm-tab [role=tabpanel]:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);border-radius:var(--ui-radius-md)}:host(.variant-pills) .tablist{border-bottom:none;gap:var(--ui-spacing-2);padding:var(--ui-spacing-1);background:var(--ui-color-surface-sunken);border-radius:var(--ui-radius-lg)}:host(.variant-pills) .tablist button{border-radius:var(--ui-radius-md);padding:var(--ui-spacing-1) var(--ui-spacing-4);font-size:var(--ui-font-size-sm)}:host(.variant-pills) .tablist button:after{display:none}:host(.variant-pills) .tablist button.is-active{background:var(--ui-color-surface);color:var(--ui-color-text);box-shadow:var(--ui-shadow-sm)}:host(.variant-pills) .tablist button:hover:not(.is-disabled):not(.is-active){background:transparent;color:var(--ui-color-text)}\n"] }]
1639
+ }], propDecorators: { selectedIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIndex", required: false }] }, { type: i0.Output, args: ["selectedIndexChange"] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }] } });
1640
+ /**
1641
+ * Individual tab definition. Place inside `<llm-tab-group>`.
1642
+ *
1643
+ * Usage:
1644
+ * ```html
1645
+ * <llm-tab label="Settings">Settings content here.</llm-tab>
1646
+ * ```
1647
+ */
1648
+ class LlmTab {
1649
+ /** Text displayed on the tab button. Required. */
1650
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
1651
+ /** Whether this tab is disabled. */
1652
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
1653
+ /** @internal */
1654
+ tabId = `llm-tab-${nextId$2}`;
1655
+ /** @internal */
1656
+ panelId = `llm-tab-panel-${nextId$2}`;
1657
+ /** @internal */
1658
+ id = `llm-tab-instance-${nextId$2++}`;
1659
+ /** @internal */
1660
+ context = inject(LLM_TAB_GROUP);
1661
+ /** @internal */
1662
+ isActive = computed(() => {
1663
+ const index = this.context.tabs().findIndex((t) => t.id === this.id);
1664
+ return this.context.selectedIndex() === index;
1665
+ }, ...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
1666
+ ngOnInit() {
1667
+ this.context.registerTab({
1668
+ id: this.id,
1669
+ label: this.label(),
1670
+ disabled: this.disabled(),
1671
+ panelId: this.panelId,
1672
+ tabId: this.tabId,
1673
+ });
1674
+ }
1675
+ ngOnDestroy() {
1676
+ this.context.unregisterTab(this.id);
1677
+ }
1678
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmTab, deps: [], target: i0.ɵɵFactoryTarget.Component });
1679
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmTab, isStandalone: true, selector: "llm-tab", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1680
+ @if (isActive()) {
1681
+ <div
1682
+ role="tabpanel"
1683
+ [id]="panelId"
1684
+ [attr.aria-labelledby]="tabId"
1685
+ [tabindex]="0"
1686
+ >
1687
+ <ng-content />
1688
+ </div>
1689
+ }
1690
+ `, isInline: true, styles: [":host{display:contents}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1691
+ }
1692
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmTab, decorators: [{
1693
+ type: Component,
1694
+ args: [{ selector: 'llm-tab', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
1695
+ @if (isActive()) {
1696
+ <div
1697
+ role="tabpanel"
1698
+ [id]="panelId"
1699
+ [attr.aria-labelledby]="tabId"
1700
+ [tabindex]="0"
1701
+ >
1702
+ <ng-content />
1703
+ </div>
1704
+ }
1705
+ `, styles: [":host{display:contents}\n"] }]
1706
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
1707
+
1708
+ const LLM_ACCORDION_GROUP = new InjectionToken('LLM_ACCORDION_GROUP');
1709
+
1710
+ let nextId$1 = 0;
1711
+ /**
1712
+ * Container that manages accordion items. Controls single vs multi expansion
1713
+ * and provides keyboard navigation across items.
1714
+ *
1715
+ * Usage:
1716
+ * ```html
1717
+ * <llm-accordion-group [multi]="true" variant="separated">
1718
+ * <llm-accordion-item [(expanded)]="open">
1719
+ * <span llmAccordionHeader>Title</span>
1720
+ * Body content here.
1721
+ * </llm-accordion-item>
1722
+ * </llm-accordion-group>
1723
+ * ```
1724
+ */
1725
+ class LlmAccordionGroup {
1726
+ /** Allow multiple items to be expanded simultaneously. */
1727
+ multi = input(false, ...(ngDevMode ? [{ debugName: "multi" }] : /* istanbul ignore next */ []));
1728
+ /** Visual variant. */
1729
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
1730
+ /** @internal */
1731
+ hostClasses = computed(() => `variant-${this.variant()}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
1732
+ /** @internal */
1733
+ get hostClassesValue() {
1734
+ return this.hostClasses();
1735
+ }
1736
+ /** @internal */
1737
+ items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
1738
+ register(item) {
1739
+ this.items.update((list) => [...list, item]);
1740
+ }
1741
+ unregister(item) {
1742
+ this.items.update((list) => list.filter((i) => i !== item));
1743
+ }
1744
+ handleKeydown(event, item) {
1745
+ const allItems = this.items();
1746
+ const enabled = allItems.filter((i) => !i.isItemDisabled());
1747
+ if (enabled.length === 0)
1748
+ return;
1749
+ const pos = enabled.indexOf(item);
1750
+ const n = enabled.length;
1751
+ let target = null;
1752
+ switch (event.key) {
1753
+ case 'ArrowDown':
1754
+ event.preventDefault();
1755
+ target = enabled[(pos + 1) % n];
1756
+ break;
1757
+ case 'ArrowUp':
1758
+ event.preventDefault();
1759
+ target = enabled[(pos - 1 + n) % n];
1760
+ break;
1761
+ case 'Home':
1762
+ event.preventDefault();
1763
+ target = enabled[0];
1764
+ break;
1765
+ case 'End':
1766
+ event.preventDefault();
1767
+ target = enabled[n - 1];
1768
+ break;
1769
+ }
1770
+ target?.focusTrigger();
1771
+ }
1772
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAccordionGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
1773
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmAccordionGroup, isStandalone: true, selector: "llm-accordion-group", inputs: { multi: { classPropertyName: "multi", publicName: "multi", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "presentation" }, properties: { "class": "hostClassesValue" } }, providers: [{ provide: LLM_ACCORDION_GROUP, useExisting: LlmAccordionGroup }], hostDirectives: [{ directive: i1$2.CdkAccordion, inputs: ["multi", "multi"] }], ngImport: i0, template: `<ng-content />`, isInline: true, styles: [":host{display:block;font-family:var(--ui-font-family)}:host(.variant-default){border-top:1px solid var(--ui-color-border)}:host(.variant-default) llm-accordion-item{border-bottom:1px solid var(--ui-color-border)}:host(.variant-bordered){border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-lg);overflow:hidden}:host(.variant-bordered) llm-accordion-item:not(:last-child){border-bottom:1px solid var(--ui-color-border)}:host(.variant-separated){display:flex;flex-direction:column;gap:var(--ui-spacing-2)}:host(.variant-separated) llm-accordion-item{border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-lg);overflow:hidden}llm-accordion-item{display:block}.accordion-heading{all:unset;display:block}.accordion-trigger{all:unset;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--ui-spacing-4);font-size:var(--ui-font-size-md);font-weight:var(--ui-font-weight-medium);color:var(--ui-color-text);cursor:pointer;transition:background-color var(--ui-transition-fast);-webkit-user-select:none;user-select:none}.accordion-trigger:hover:not(.is-disabled){background:var(--ui-color-surface-sunken)}.accordion-trigger:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);position:relative;z-index:1}.accordion-trigger.is-disabled{opacity:var(--ui-opacity-disabled);cursor:not-allowed}.chevron{flex-shrink:0;color:var(--ui-color-text-muted);transition:transform var(--ui-duration-normal) var(--ui-ease-out)}.chevron.is-expanded{transform:rotate(180deg)}.accordion-panel-wrapper{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--ui-duration-normal) var(--ui-ease-out)}.accordion-panel-wrapper.is-expanded{grid-template-rows:1fr}.accordion-panel{overflow:hidden}.accordion-panel-wrapper.is-expanded .accordion-panel{padding:0 var(--ui-spacing-4) var(--ui-spacing-4)}.accordion-panel-wrapper:not(.is-expanded) .accordion-panel{padding:0 var(--ui-spacing-4)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1774
+ }
1775
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAccordionGroup, decorators: [{
1776
+ type: Component,
1777
+ args: [{ selector: 'llm-accordion-group', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, hostDirectives: [{ directive: CdkAccordion, inputs: ['multi'] }], host: {
1778
+ '[class]': 'hostClassesValue',
1779
+ role: 'presentation',
1780
+ }, providers: [{ provide: LLM_ACCORDION_GROUP, useExisting: LlmAccordionGroup }], styles: [":host{display:block;font-family:var(--ui-font-family)}:host(.variant-default){border-top:1px solid var(--ui-color-border)}:host(.variant-default) llm-accordion-item{border-bottom:1px solid var(--ui-color-border)}:host(.variant-bordered){border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-lg);overflow:hidden}:host(.variant-bordered) llm-accordion-item:not(:last-child){border-bottom:1px solid var(--ui-color-border)}:host(.variant-separated){display:flex;flex-direction:column;gap:var(--ui-spacing-2)}:host(.variant-separated) llm-accordion-item{border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-lg);overflow:hidden}llm-accordion-item{display:block}.accordion-heading{all:unset;display:block}.accordion-trigger{all:unset;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--ui-spacing-4);font-size:var(--ui-font-size-md);font-weight:var(--ui-font-weight-medium);color:var(--ui-color-text);cursor:pointer;transition:background-color var(--ui-transition-fast);-webkit-user-select:none;user-select:none}.accordion-trigger:hover:not(.is-disabled){background:var(--ui-color-surface-sunken)}.accordion-trigger:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);position:relative;z-index:1}.accordion-trigger.is-disabled{opacity:var(--ui-opacity-disabled);cursor:not-allowed}.chevron{flex-shrink:0;color:var(--ui-color-text-muted);transition:transform var(--ui-duration-normal) var(--ui-ease-out)}.chevron.is-expanded{transform:rotate(180deg)}.accordion-panel-wrapper{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--ui-duration-normal) var(--ui-ease-out)}.accordion-panel-wrapper.is-expanded{grid-template-rows:1fr}.accordion-panel{overflow:hidden}.accordion-panel-wrapper.is-expanded .accordion-panel{padding:0 var(--ui-spacing-4) var(--ui-spacing-4)}.accordion-panel-wrapper:not(.is-expanded) .accordion-panel{padding:0 var(--ui-spacing-4)}\n"] }]
1781
+ }], propDecorators: { multi: [{ type: i0.Input, args: [{ isSignal: true, alias: "multi", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }] } });
1782
+ /**
1783
+ * Directive to mark the accordion header content.
1784
+ */
1785
+ class LlmAccordionHeader {
1786
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAccordionHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1787
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.4", type: LlmAccordionHeader, isStandalone: true, selector: "[llmAccordionHeader]", ngImport: i0 });
1788
+ }
1789
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAccordionHeader, decorators: [{
1790
+ type: Directive,
1791
+ args: [{
1792
+ selector: '[llmAccordionHeader]',
1793
+ standalone: true,
1794
+ }]
1795
+ }] });
1796
+ /**
1797
+ * Individual collapsible accordion item. Place inside `<llm-accordion-group>`.
1798
+ *
1799
+ * Usage:
1800
+ * ```html
1801
+ * <llm-accordion-item [(expanded)]="isOpen">
1802
+ * <span llmAccordionHeader>Section Title</span>
1803
+ * Section content goes here.
1804
+ * </llm-accordion-item>
1805
+ * ```
1806
+ */
1807
+ class LlmAccordionItem {
1808
+ /** Whether this item is expanded. Supports two-way binding. */
1809
+ expanded = model(false, ...(ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []));
1810
+ /** Whether this item is disabled. */
1811
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
1812
+ /** @internal */
1813
+ id = `llm-accordion-item-${nextId$1++}`;
1814
+ /** @internal */
1815
+ triggerId = `${this.id}-trigger`;
1816
+ /** @internal */
1817
+ panelId = `${this.id}-panel`;
1818
+ /** @internal */
1819
+ group = inject(LlmAccordionGroup);
1820
+ /** @internal */
1821
+ cdkItem = inject(CdkAccordionItem);
1822
+ /** @internal */
1823
+ el = inject(ElementRef);
1824
+ /** @internal */
1825
+ isExpanded = signal(false, ...(ngDevMode ? [{ debugName: "isExpanded" }] : /* istanbul ignore next */ []));
1826
+ /** @internal */
1827
+ get isExpandedValue() {
1828
+ return this.isExpanded();
1829
+ }
1830
+ /** @internal */
1831
+ get isDisabled() {
1832
+ return this.disabled();
1833
+ }
1834
+ /** @internal */
1835
+ get ariaDisabled() {
1836
+ return this.disabled() || null;
1837
+ }
1838
+ constructor() {
1839
+ this.cdkItem.expandedChange.subscribe((expanded) => {
1840
+ this.isExpanded.set(expanded);
1841
+ this.expanded.set(expanded);
1842
+ });
1843
+ }
1844
+ ngOnInit() {
1845
+ this.group.register(this);
1846
+ // Sync initial expanded model
1847
+ if (this.expanded()) {
1848
+ this.cdkItem.open();
1849
+ }
1850
+ }
1851
+ ngOnDestroy() {
1852
+ this.group.unregister(this);
1853
+ }
1854
+ /** @internal — for FocusKeyManager */
1855
+ focusTrigger() {
1856
+ this.el.nativeElement.querySelector('.accordion-trigger')?.focus();
1857
+ }
1858
+ /** @internal — for FocusKeyManager */
1859
+ isItemDisabled() {
1860
+ return this.disabled();
1861
+ }
1862
+ /** @internal */
1863
+ onToggle() {
1864
+ if (this.disabled())
1865
+ return;
1866
+ this.cdkItem.toggle();
1867
+ }
1868
+ /** @internal */
1869
+ onKeydown(event) {
1870
+ this.group.handleKeydown(event, this);
1871
+ }
1872
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAccordionItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
1873
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmAccordionItem, isStandalone: true, selector: "llm-accordion-item", inputs: { expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expanded: "expandedChange" }, host: { properties: { "attr.data-accordion-id": "id" } }, hostDirectives: [{ directive: i1$2.CdkAccordionItem }], ngImport: i0, template: `
1874
+ <h3 class="accordion-heading">
1875
+ <button
1876
+ type="button"
1877
+ class="accordion-trigger"
1878
+ [id]="triggerId"
1879
+ [attr.aria-expanded]="isExpandedValue"
1880
+ [attr.aria-controls]="panelId"
1881
+ [attr.aria-disabled]="ariaDisabled"
1882
+ [class.is-disabled]="isDisabled"
1883
+ (click)="onToggle()"
1884
+ (keydown)="onKeydown($event)"
1885
+ >
1886
+ <ng-content select="[llmAccordionHeader]" />
1887
+ <svg
1888
+ class="chevron"
1889
+ [class.is-expanded]="isExpandedValue"
1890
+ width="16"
1891
+ height="16"
1892
+ viewBox="0 0 16 16"
1893
+ fill="none"
1894
+ aria-hidden="true"
1895
+ >
1896
+ <path
1897
+ d="M4 6L8 10L12 6"
1898
+ stroke="currentColor"
1899
+ stroke-width="1.5"
1900
+ stroke-linecap="round"
1901
+ stroke-linejoin="round"
1902
+ />
1903
+ </svg>
1904
+ </button>
1905
+ </h3>
1906
+ <div
1907
+ class="accordion-panel-wrapper"
1908
+ [class.is-expanded]="isExpandedValue"
1909
+ >
1910
+ <div
1911
+ role="region"
1912
+ [id]="panelId"
1913
+ [attr.aria-labelledby]="triggerId"
1914
+ class="accordion-panel"
1915
+ >
1916
+ <ng-content />
1917
+ </div>
1918
+ </div>
1919
+ `, isInline: true, styles: [":host{display:block;font-family:var(--ui-font-family)}:host(.variant-default){border-top:1px solid var(--ui-color-border)}:host(.variant-default) llm-accordion-item{border-bottom:1px solid var(--ui-color-border)}:host(.variant-bordered){border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-lg);overflow:hidden}:host(.variant-bordered) llm-accordion-item:not(:last-child){border-bottom:1px solid var(--ui-color-border)}:host(.variant-separated){display:flex;flex-direction:column;gap:var(--ui-spacing-2)}:host(.variant-separated) llm-accordion-item{border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-lg);overflow:hidden}llm-accordion-item{display:block}.accordion-heading{all:unset;display:block}.accordion-trigger{all:unset;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--ui-spacing-4);font-size:var(--ui-font-size-md);font-weight:var(--ui-font-weight-medium);color:var(--ui-color-text);cursor:pointer;transition:background-color var(--ui-transition-fast);-webkit-user-select:none;user-select:none}.accordion-trigger:hover:not(.is-disabled){background:var(--ui-color-surface-sunken)}.accordion-trigger:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);position:relative;z-index:1}.accordion-trigger.is-disabled{opacity:var(--ui-opacity-disabled);cursor:not-allowed}.chevron{flex-shrink:0;color:var(--ui-color-text-muted);transition:transform var(--ui-duration-normal) var(--ui-ease-out)}.chevron.is-expanded{transform:rotate(180deg)}.accordion-panel-wrapper{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--ui-duration-normal) var(--ui-ease-out)}.accordion-panel-wrapper.is-expanded{grid-template-rows:1fr}.accordion-panel{overflow:hidden}.accordion-panel-wrapper.is-expanded .accordion-panel{padding:0 var(--ui-spacing-4) var(--ui-spacing-4)}.accordion-panel-wrapper:not(.is-expanded) .accordion-panel{padding:0 var(--ui-spacing-4)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1920
+ }
1921
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAccordionItem, decorators: [{
1922
+ type: Component,
1923
+ args: [{ selector: 'llm-accordion-item', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [CdkAccordionItem], template: `
1924
+ <h3 class="accordion-heading">
1925
+ <button
1926
+ type="button"
1927
+ class="accordion-trigger"
1928
+ [id]="triggerId"
1929
+ [attr.aria-expanded]="isExpandedValue"
1930
+ [attr.aria-controls]="panelId"
1931
+ [attr.aria-disabled]="ariaDisabled"
1932
+ [class.is-disabled]="isDisabled"
1933
+ (click)="onToggle()"
1934
+ (keydown)="onKeydown($event)"
1935
+ >
1936
+ <ng-content select="[llmAccordionHeader]" />
1937
+ <svg
1938
+ class="chevron"
1939
+ [class.is-expanded]="isExpandedValue"
1940
+ width="16"
1941
+ height="16"
1942
+ viewBox="0 0 16 16"
1943
+ fill="none"
1944
+ aria-hidden="true"
1945
+ >
1946
+ <path
1947
+ d="M4 6L8 10L12 6"
1948
+ stroke="currentColor"
1949
+ stroke-width="1.5"
1950
+ stroke-linecap="round"
1951
+ stroke-linejoin="round"
1952
+ />
1953
+ </svg>
1954
+ </button>
1955
+ </h3>
1956
+ <div
1957
+ class="accordion-panel-wrapper"
1958
+ [class.is-expanded]="isExpandedValue"
1959
+ >
1960
+ <div
1961
+ role="region"
1962
+ [id]="panelId"
1963
+ [attr.aria-labelledby]="triggerId"
1964
+ class="accordion-panel"
1965
+ >
1966
+ <ng-content />
1967
+ </div>
1968
+ </div>
1969
+ `, host: {
1970
+ '[attr.data-accordion-id]': 'id',
1971
+ }, styles: [":host{display:block;font-family:var(--ui-font-family)}:host(.variant-default){border-top:1px solid var(--ui-color-border)}:host(.variant-default) llm-accordion-item{border-bottom:1px solid var(--ui-color-border)}:host(.variant-bordered){border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-lg);overflow:hidden}:host(.variant-bordered) llm-accordion-item:not(:last-child){border-bottom:1px solid var(--ui-color-border)}:host(.variant-separated){display:flex;flex-direction:column;gap:var(--ui-spacing-2)}:host(.variant-separated) llm-accordion-item{border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-lg);overflow:hidden}llm-accordion-item{display:block}.accordion-heading{all:unset;display:block}.accordion-trigger{all:unset;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--ui-spacing-4);font-size:var(--ui-font-size-md);font-weight:var(--ui-font-weight-medium);color:var(--ui-color-text);cursor:pointer;transition:background-color var(--ui-transition-fast);-webkit-user-select:none;user-select:none}.accordion-trigger:hover:not(.is-disabled){background:var(--ui-color-surface-sunken)}.accordion-trigger:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);position:relative;z-index:1}.accordion-trigger.is-disabled{opacity:var(--ui-opacity-disabled);cursor:not-allowed}.chevron{flex-shrink:0;color:var(--ui-color-text-muted);transition:transform var(--ui-duration-normal) var(--ui-ease-out)}.chevron.is-expanded{transform:rotate(180deg)}.accordion-panel-wrapper{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--ui-duration-normal) var(--ui-ease-out)}.accordion-panel-wrapper.is-expanded{grid-template-rows:1fr}.accordion-panel{overflow:hidden}.accordion-panel-wrapper.is-expanded .accordion-panel{padding:0 var(--ui-spacing-4) var(--ui-spacing-4)}.accordion-panel-wrapper:not(.is-expanded) .accordion-panel{padding:0 var(--ui-spacing-4)}\n"] }]
1972
+ }], ctorParameters: () => [], propDecorators: { expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }, { type: i0.Output, args: ["expandedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
1973
+
1974
+ /**
1975
+ * Trigger directive that opens an `<llm-menu>` dropdown.
1976
+ * Apply to any element (typically `<llm-button>`) to wire up click + keyboard open/close.
1977
+ *
1978
+ * Usage:
1979
+ * ```html
1980
+ * <llm-button [llmMenuTriggerFor]="myMenu">Open</llm-button>
1981
+ * <ng-template #myMenu>
1982
+ * <llm-menu>
1983
+ * <llm-menu-item (triggered)="action()">Action</llm-menu-item>
1984
+ * </llm-menu>
1985
+ * </ng-template>
1986
+ * ```
1987
+ */
1988
+ class LlmMenuTrigger {
1989
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmMenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1990
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.4", type: LlmMenuTrigger, isStandalone: true, selector: "[llmMenuTriggerFor]", hostDirectives: [{ directive: i1$3.CdkMenuTrigger, inputs: ["cdkMenuTriggerFor", "llmMenuTriggerFor"] }], ngImport: i0 });
1991
+ }
1992
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmMenuTrigger, decorators: [{
1993
+ type: Directive,
1994
+ args: [{
1995
+ selector: '[llmMenuTriggerFor]',
1996
+ standalone: true,
1997
+ hostDirectives: [
1998
+ {
1999
+ directive: CdkMenuTrigger,
2000
+ inputs: ['cdkMenuTriggerFor: llmMenuTriggerFor'],
2001
+ },
2002
+ ],
2003
+ }]
2004
+ }] });
2005
+ /**
2006
+ * Accessible dropdown menu panel.
2007
+ * Uses `@angular/cdk/menu` for keyboard navigation, focus management, and ARIA.
2008
+ *
2009
+ * Usage:
2010
+ * ```html
2011
+ * <llm-button [llmMenuTriggerFor]="actions">Actions</llm-button>
2012
+ * <ng-template #actions>
2013
+ * <llm-menu>
2014
+ * <llm-menu-item (triggered)="onCopy()">Copy</llm-menu-item>
2015
+ * <llm-menu-separator />
2016
+ * <llm-menu-item [disabled]="true">Paste</llm-menu-item>
2017
+ * </llm-menu>
2018
+ * </ng-template>
2019
+ * ```
2020
+ */
2021
+ class LlmMenu {
2022
+ /** Visual variant. `compact` reduces font size and padding. */
2023
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
2024
+ /** @internal */
2025
+ hostClasses = computed(() => `llm-menu variant-${this.variant()}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
2026
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
2027
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmMenu, isStandalone: true, selector: "llm-menu", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, hostDirectives: [{ directive: i1$3.CdkMenu }], ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["llm-menu{display:block;min-width:10rem;padding:var(--ui-spacing-1) 0;background:var(--ui-color-surface-raised);border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-md);box-shadow:var(--ui-shadow-lg);font-family:var(--ui-font-family);font-size:var(--ui-font-size-md);color:var(--ui-color-text);outline:none;overflow:hidden;opacity:0;transform:translateY(-4px);animation:llm-menu-enter var(--ui-duration-normal) var(--ui-ease-out) forwards}llm-menu.variant-compact{font-size:var(--ui-font-size-sm)}llm-menu.variant-compact .llm-menu-item{padding:var(--ui-spacing-1) var(--ui-spacing-3)}@keyframes llm-menu-enter{to{opacity:1;transform:translateY(0)}}.llm-menu-item{display:flex;align-items:center;gap:var(--ui-spacing-2);padding:var(--ui-spacing-2) var(--ui-spacing-3);cursor:pointer;color:var(--ui-color-text);transition:background var(--ui-transition-fast);outline:none;border:none;background:none;font:inherit;width:100%;text-align:start}.llm-menu-item:hover,.llm-menu-item:focus-visible,.llm-menu-item.cdk-menu-item-highlighted{background:var(--ui-color-surface-sunken)}.llm-menu-item.is-disabled{opacity:var(--ui-opacity-disabled);cursor:not-allowed}.llm-menu-item-chevron{margin-inline-start:auto;font-size:var(--ui-font-size-lg);color:var(--ui-color-text-muted);line-height:1}.llm-menu-separator{display:block;height:1px;margin:var(--ui-spacing-1) 0;background:var(--ui-color-border)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2028
+ }
2029
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmMenu, decorators: [{
2030
+ type: Component,
2031
+ args: [{ selector: 'llm-menu', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, hostDirectives: [CdkMenu], template: `<ng-content />`, host: {
2032
+ '[class]': 'hostClasses()',
2033
+ }, styles: ["llm-menu{display:block;min-width:10rem;padding:var(--ui-spacing-1) 0;background:var(--ui-color-surface-raised);border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-md);box-shadow:var(--ui-shadow-lg);font-family:var(--ui-font-family);font-size:var(--ui-font-size-md);color:var(--ui-color-text);outline:none;overflow:hidden;opacity:0;transform:translateY(-4px);animation:llm-menu-enter var(--ui-duration-normal) var(--ui-ease-out) forwards}llm-menu.variant-compact{font-size:var(--ui-font-size-sm)}llm-menu.variant-compact .llm-menu-item{padding:var(--ui-spacing-1) var(--ui-spacing-3)}@keyframes llm-menu-enter{to{opacity:1;transform:translateY(0)}}.llm-menu-item{display:flex;align-items:center;gap:var(--ui-spacing-2);padding:var(--ui-spacing-2) var(--ui-spacing-3);cursor:pointer;color:var(--ui-color-text);transition:background var(--ui-transition-fast);outline:none;border:none;background:none;font:inherit;width:100%;text-align:start}.llm-menu-item:hover,.llm-menu-item:focus-visible,.llm-menu-item.cdk-menu-item-highlighted{background:var(--ui-color-surface-sunken)}.llm-menu-item.is-disabled{opacity:var(--ui-opacity-disabled);cursor:not-allowed}.llm-menu-item-chevron{margin-inline-start:auto;font-size:var(--ui-font-size-lg);color:var(--ui-color-text-muted);line-height:1}.llm-menu-separator{display:block;height:1px;margin:var(--ui-spacing-1) 0;background:var(--ui-color-border)}\n"] }]
2034
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }] } });
2035
+ /**
2036
+ * A single item inside an `<llm-menu>`.
2037
+ * Supports keyboard navigation, disabled state, and nested submenus via `[llmMenuTriggerFor]`.
2038
+ *
2039
+ * Usage:
2040
+ * ```html
2041
+ * <llm-menu-item (triggered)="doSomething()">Label</llm-menu-item>
2042
+ * <llm-menu-item [disabled]="true">Disabled</llm-menu-item>
2043
+ * ```
2044
+ */
2045
+ class LlmMenuItem {
2046
+ /** Whether this menu item is disabled. */
2047
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
2048
+ /** @internal — detect if this item also triggers a submenu */
2049
+ menuTrigger = inject(CdkMenuTrigger, { optional: true, self: true });
2050
+ /** @internal */
2051
+ hasSubmenu = computed(() => !!this.menuTrigger, ...(ngDevMode ? [{ debugName: "hasSubmenu" }] : /* istanbul ignore next */ []));
2052
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
2053
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmMenuItem, isStandalone: true, selector: "llm-menu-item", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.is-disabled": "disabled()" }, classAttribute: "llm-menu-item" }, hostDirectives: [{ directive: i1$3.CdkMenuItem, inputs: ["cdkMenuItemDisabled", "disabled"], outputs: ["cdkMenuItemTriggered", "triggered"] }], ngImport: i0, template: `
2054
+ <ng-content />
2055
+ @if (hasSubmenu()) {
2056
+ <span class="llm-menu-item-chevron" aria-hidden="true">&#x203A;</span>
2057
+ }
2058
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
2059
+ }
2060
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmMenuItem, decorators: [{
2061
+ type: Component,
2062
+ args: [{
2063
+ selector: 'llm-menu-item',
2064
+ standalone: true,
2065
+ changeDetection: ChangeDetectionStrategy.OnPush,
2066
+ hostDirectives: [
2067
+ {
2068
+ directive: CdkMenuItem,
2069
+ inputs: ['cdkMenuItemDisabled: disabled'],
2070
+ outputs: ['cdkMenuItemTriggered: triggered'],
2071
+ },
2072
+ ],
2073
+ template: `
2074
+ <ng-content />
2075
+ @if (hasSubmenu()) {
2076
+ <span class="llm-menu-item-chevron" aria-hidden="true">&#x203A;</span>
2077
+ }
2078
+ `,
2079
+ host: {
2080
+ class: 'llm-menu-item',
2081
+ '[class.is-disabled]': 'disabled()',
2082
+ },
2083
+ }]
2084
+ }], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
2085
+ /**
2086
+ * Visual separator between groups of menu items.
2087
+ *
2088
+ * Usage:
2089
+ * ```html
2090
+ * <llm-menu-item>Copy</llm-menu-item>
2091
+ * <llm-menu-separator />
2092
+ * <llm-menu-item>Delete</llm-menu-item>
2093
+ * ```
2094
+ */
2095
+ class LlmMenuSeparator {
2096
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmMenuSeparator, deps: [], target: i0.ɵɵFactoryTarget.Component });
2097
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmMenuSeparator, isStandalone: true, selector: "llm-menu-separator", host: { attributes: { "role": "separator" }, classAttribute: "llm-menu-separator" }, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
2098
+ }
2099
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmMenuSeparator, decorators: [{
2100
+ type: Component,
2101
+ args: [{
2102
+ selector: 'llm-menu-separator',
2103
+ standalone: true,
2104
+ changeDetection: ChangeDetectionStrategy.OnPush,
2105
+ template: ``,
2106
+ host: {
2107
+ class: 'llm-menu-separator',
2108
+ role: 'separator',
2109
+ },
2110
+ }]
2111
+ }] });
2112
+
2113
+ let nextTooltipId = 0;
2114
+ /** @internal — Rendered inside the CDK overlay when the tooltip is visible. */
2115
+ class LlmTooltipContent {
2116
+ /** @internal */
2117
+ text = input('', ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
2118
+ /** @internal */
2119
+ tooltipId = input('', ...(ngDevMode ? [{ debugName: "tooltipId" }] : /* istanbul ignore next */ []));
2120
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmTooltipContent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2121
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmTooltipContent, isStandalone: true, selector: "llm-tooltip-content", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, tooltipId: { classPropertyName: "tooltipId", publicName: "tooltipId", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "tooltip" }, properties: { "id": "tooltipId()" }, classAttribute: "llm-tooltip" }, ngImport: i0, template: `{{ text() }}`, isInline: true, styles: [".llm-tooltip{display:block;padding:var(--ui-spacing-1) var(--ui-spacing-2);background:var(--ui-color-text);color:var(--ui-color-surface);font-family:var(--ui-font-family);font-size:var(--ui-font-size-xs);line-height:var(--ui-line-height-normal);border-radius:var(--ui-radius-sm);box-shadow:var(--ui-shadow-md);max-width:20rem;word-wrap:break-word;pointer-events:none;animation:llm-tooltip-enter var(--ui-duration-fast) var(--ui-ease-out) forwards}@keyframes llm-tooltip-enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2122
+ }
2123
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmTooltipContent, decorators: [{
2124
+ type: Component,
2125
+ args: [{ selector: 'llm-tooltip-content', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `{{ text() }}`, host: {
2126
+ class: 'llm-tooltip',
2127
+ role: 'tooltip',
2128
+ '[id]': 'tooltipId()',
2129
+ }, styles: [".llm-tooltip{display:block;padding:var(--ui-spacing-1) var(--ui-spacing-2);background:var(--ui-color-text);color:var(--ui-color-surface);font-family:var(--ui-font-family);font-size:var(--ui-font-size-xs);line-height:var(--ui-line-height-normal);border-radius:var(--ui-radius-sm);box-shadow:var(--ui-shadow-md);max-width:20rem;word-wrap:break-word;pointer-events:none;animation:llm-tooltip-enter var(--ui-duration-fast) var(--ui-ease-out) forwards}@keyframes llm-tooltip-enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}\n"] }]
2130
+ }], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], tooltipId: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipId", required: false }] }] } });
2131
+ const POSITIONS = {
2132
+ above: [
2133
+ { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -8 },
2134
+ { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: 8 },
2135
+ ],
2136
+ below: [
2137
+ { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: 8 },
2138
+ { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -8 },
2139
+ ],
2140
+ left: [
2141
+ { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -8 },
2142
+ { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: 8 },
2143
+ ],
2144
+ right: [
2145
+ { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: 8 },
2146
+ { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -8 },
2147
+ ],
2148
+ };
2149
+ /**
2150
+ * Attribute directive that displays a text tooltip on hover or focus.
2151
+ * Uses `@angular/cdk/overlay` for viewport-aware positioning.
2152
+ *
2153
+ * Usage:
2154
+ * ```html
2155
+ * <llm-button llmTooltip="Save your changes">Save</llm-button>
2156
+ * <llm-button llmTooltip="Copy to clipboard" llmTooltipPosition="right">Copy</llm-button>
2157
+ * ```
2158
+ */
2159
+ class LlmTooltip {
2160
+ /** The tooltip text. */
2161
+ llmTooltip = input.required(...(ngDevMode ? [{ debugName: "llmTooltip" }] : /* istanbul ignore next */ []));
2162
+ /** Preferred tooltip placement. Falls back to the opposite side if clipped. */
2163
+ llmTooltipPosition = input('above', ...(ngDevMode ? [{ debugName: "llmTooltipPosition" }] : /* istanbul ignore next */ []));
2164
+ /** Disable the tooltip without removing the directive. */
2165
+ llmTooltipDisabled = input(false, ...(ngDevMode ? [{ debugName: "llmTooltipDisabled" }] : /* istanbul ignore next */ []));
2166
+ /** Delay in ms before the tooltip appears. */
2167
+ llmTooltipShowDelay = input(300, ...(ngDevMode ? [{ debugName: "llmTooltipShowDelay" }] : /* istanbul ignore next */ []));
2168
+ /** Delay in ms before the tooltip hides. */
2169
+ llmTooltipHideDelay = input(0, ...(ngDevMode ? [{ debugName: "llmTooltipHideDelay" }] : /* istanbul ignore next */ []));
2170
+ injector = inject(Injector);
2171
+ elementRef = inject(ElementRef);
2172
+ overlayRef = null;
2173
+ showTimer = null;
2174
+ hideTimer = null;
2175
+ /** @internal — links host aria-describedby to the tooltip element */
2176
+ activeTooltipId = signal(null, ...(ngDevMode ? [{ debugName: "activeTooltipId" }] : /* istanbul ignore next */ []));
2177
+ /** @internal */
2178
+ show() {
2179
+ if (this.llmTooltipDisabled() || !this.llmTooltip())
2180
+ return;
2181
+ this.clearHideTimer();
2182
+ if (this.overlayRef?.hasAttached())
2183
+ return;
2184
+ this.showTimer = setTimeout(() => {
2185
+ this.showTimer = null;
2186
+ this.attach();
2187
+ }, this.llmTooltipShowDelay());
2188
+ }
2189
+ /** @internal */
2190
+ hide() {
2191
+ this.clearShowTimer();
2192
+ if (!this.overlayRef?.hasAttached())
2193
+ return;
2194
+ this.hideTimer = setTimeout(() => {
2195
+ this.hideTimer = null;
2196
+ this.overlayRef?.detach();
2197
+ this.activeTooltipId.set(null);
2198
+ }, this.llmTooltipHideDelay());
2199
+ }
2200
+ ngOnDestroy() {
2201
+ this.clearShowTimer();
2202
+ this.clearHideTimer();
2203
+ this.overlayRef?.dispose();
2204
+ this.overlayRef = null;
2205
+ }
2206
+ attach() {
2207
+ if (!this.overlayRef) {
2208
+ this.overlayRef = this.createOverlay();
2209
+ }
2210
+ if (this.overlayRef.hasAttached())
2211
+ return;
2212
+ const id = `llm-tooltip-${nextTooltipId++}`;
2213
+ const portal = new ComponentPortal(LlmTooltipContent);
2214
+ const ref = this.overlayRef.attach(portal);
2215
+ ref.setInput('text', this.llmTooltip());
2216
+ ref.setInput('tooltipId', id);
2217
+ this.activeTooltipId.set(id);
2218
+ }
2219
+ createOverlay() {
2220
+ const positions = POSITIONS[this.llmTooltipPosition()] ?? POSITIONS['above'];
2221
+ const positionStrategy = createFlexibleConnectedPositionStrategy(this.injector, this.elementRef)
2222
+ .withPositions(positions)
2223
+ .withFlexibleDimensions(false)
2224
+ .withPush(true);
2225
+ const scrollStrategy = createRepositionScrollStrategy(this.injector);
2226
+ return createOverlayRef(this.injector, {
2227
+ positionStrategy,
2228
+ scrollStrategy,
2229
+ panelClass: 'llm-tooltip-panel',
2230
+ });
2231
+ }
2232
+ clearShowTimer() {
2233
+ if (this.showTimer !== null) {
2234
+ clearTimeout(this.showTimer);
2235
+ this.showTimer = null;
2236
+ }
2237
+ }
2238
+ clearHideTimer() {
2239
+ if (this.hideTimer !== null) {
2240
+ clearTimeout(this.hideTimer);
2241
+ this.hideTimer = null;
2242
+ }
2243
+ }
2244
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmTooltip, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2245
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.4", type: LlmTooltip, isStandalone: true, selector: "[llmTooltip]", inputs: { llmTooltip: { classPropertyName: "llmTooltip", publicName: "llmTooltip", isSignal: true, isRequired: true, transformFunction: null }, llmTooltipPosition: { classPropertyName: "llmTooltipPosition", publicName: "llmTooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, llmTooltipDisabled: { classPropertyName: "llmTooltipDisabled", publicName: "llmTooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, llmTooltipShowDelay: { classPropertyName: "llmTooltipShowDelay", publicName: "llmTooltipShowDelay", isSignal: true, isRequired: false, transformFunction: null }, llmTooltipHideDelay: { classPropertyName: "llmTooltipHideDelay", publicName: "llmTooltipHideDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "mouseleave": "hide()", "focusin": "show()", "focusout": "hide()", "keydown.escape": "hide()" }, properties: { "attr.aria-describedby": "activeTooltipId()" } }, ngImport: i0 });
2246
+ }
2247
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmTooltip, decorators: [{
2248
+ type: Directive,
2249
+ args: [{
2250
+ selector: '[llmTooltip]',
2251
+ standalone: true,
2252
+ host: {
2253
+ '(mouseenter)': 'show()',
2254
+ '(mouseleave)': 'hide()',
2255
+ '(focusin)': 'show()',
2256
+ '(focusout)': 'hide()',
2257
+ '(keydown.escape)': 'hide()',
2258
+ '[attr.aria-describedby]': 'activeTooltipId()',
2259
+ },
2260
+ }]
2261
+ }], propDecorators: { llmTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "llmTooltip", required: true }] }], llmTooltipPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "llmTooltipPosition", required: false }] }], llmTooltipDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "llmTooltipDisabled", required: false }] }], llmTooltipShowDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "llmTooltipShowDelay", required: false }] }], llmTooltipHideDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "llmTooltipHideDelay", required: false }] }] } });
2262
+
2263
+ /**
2264
+ * Loading placeholder that mimics the shape of content while it loads.
2265
+ *
2266
+ * Usage:
2267
+ * ```html
2268
+ * <llm-skeleton />
2269
+ * <llm-skeleton variant="circular" width="40px" />
2270
+ * <llm-skeleton variant="rectangular" height="200px" />
2271
+ * ```
2272
+ */
2273
+ class LlmSkeleton {
2274
+ /** Shape variant of the skeleton placeholder. */
2275
+ variant = input('text', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
2276
+ /** CSS width of the skeleton. */
2277
+ width = input('100%', ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
2278
+ /** CSS height — when empty, a sensible default is chosen per variant. */
2279
+ height = input('', ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
2280
+ /** Whether the shimmer animation is active. */
2281
+ animated = input(true, ...(ngDevMode ? [{ debugName: "animated" }] : /* istanbul ignore next */ []));
2282
+ computedHeight = computed(() => {
2283
+ if (this.height())
2284
+ return this.height();
2285
+ switch (this.variant()) {
2286
+ case 'text':
2287
+ return '1em';
2288
+ case 'circular':
2289
+ return this.width();
2290
+ case 'rectangular':
2291
+ return '100px';
2292
+ }
2293
+ }, ...(ngDevMode ? [{ debugName: "computedHeight" }] : /* istanbul ignore next */ []));
2294
+ hostClasses = computed(() => {
2295
+ const classes = [`variant-${this.variant()}`];
2296
+ if (this.animated())
2297
+ classes.push('is-animated');
2298
+ return classes.join(' ');
2299
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
2300
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component });
2301
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmSkeleton, isStandalone: true, selector: "llm-skeleton", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, animated: { classPropertyName: "animated", publicName: "animated", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, properties: { "class": "hostClasses()", "style.width": "width()", "style.height": "computedHeight()" } }, ngImport: i0, template: ``, isInline: true, styles: [":host{display:block;background:var(--ui-color-border);overflow:hidden;position:relative}:host(.variant-text){border-radius:var(--ui-radius-sm)}:host(.variant-circular){border-radius:var(--ui-radius-full, 9999px)}:host(.variant-rectangular){border-radius:var(--ui-radius-md)}:host(.is-animated):after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,transparent 0%,rgba(255,255,255,.3) 50%,transparent 100%);animation:shimmer 1.5s infinite}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}@media(prefers-reduced-motion:reduce){:host(.is-animated):after{animation:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2302
+ }
2303
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmSkeleton, decorators: [{
2304
+ type: Component,
2305
+ args: [{ selector: 'llm-skeleton', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: ``, host: {
2306
+ '[class]': 'hostClasses()',
2307
+ '[style.width]': 'width()',
2308
+ '[style.height]': 'computedHeight()',
2309
+ 'aria-hidden': 'true',
2310
+ }, styles: [":host{display:block;background:var(--ui-color-border);overflow:hidden;position:relative}:host(.variant-text){border-radius:var(--ui-radius-sm)}:host(.variant-circular){border-radius:var(--ui-radius-full, 9999px)}:host(.variant-rectangular){border-radius:var(--ui-radius-md)}:host(.is-animated):after{content:\"\";position:absolute;inset:0;background:linear-gradient(90deg,transparent 0%,rgba(255,255,255,.3) 50%,transparent 100%);animation:shimmer 1.5s infinite}@keyframes shimmer{0%{transform:translate(-100%)}to{transform:translate(100%)}}@media(prefers-reduced-motion:reduce){:host(.is-animated):after{animation:none}}\n"] }]
2311
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }] } });
2312
+
2313
+ let toastId = 0;
2314
+ /**
2315
+ * Service for showing transient toast notifications.
2316
+ *
2317
+ * Usage:
2318
+ * ```typescript
2319
+ * const toast = inject(LlmToastService);
2320
+ * toast.show('Saved successfully', { variant: 'success' });
2321
+ * ```
2322
+ */
2323
+ class LlmToastService {
2324
+ toasts = signal([], ...(ngDevMode ? [{ debugName: "toasts" }] : /* istanbul ignore next */ []));
2325
+ timers = new Map();
2326
+ /**
2327
+ * Show a toast notification.
2328
+ * @returns The unique id of the toast, which can be used with `dismiss()`.
2329
+ */
2330
+ show(message, options) {
2331
+ const id = `llm-toast-${toastId++}`;
2332
+ const toast = {
2333
+ id,
2334
+ message,
2335
+ variant: options?.variant ?? 'default',
2336
+ duration: options?.duration ?? 5000,
2337
+ dismissible: options?.dismissible ?? true,
2338
+ };
2339
+ this.toasts.update((list) => [...list, toast]);
2340
+ if (toast.duration > 0) {
2341
+ const timer = setTimeout(() => this.dismiss(id), toast.duration);
2342
+ this.timers.set(id, timer);
2343
+ }
2344
+ return id;
2345
+ }
2346
+ /** Dismiss a single toast by id. */
2347
+ dismiss(id) {
2348
+ const timer = this.timers.get(id);
2349
+ if (timer !== undefined) {
2350
+ clearTimeout(timer);
2351
+ this.timers.delete(id);
2352
+ }
2353
+ this.toasts.update((list) => list.filter((t) => t.id !== id));
2354
+ }
2355
+ /** Clear all active toasts. */
2356
+ clear() {
2357
+ for (const timer of this.timers.values()) {
2358
+ clearTimeout(timer);
2359
+ }
2360
+ this.timers.clear();
2361
+ this.toasts.set([]);
2362
+ }
2363
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2364
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmToastService, providedIn: 'root' });
2365
+ }
2366
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmToastService, decorators: [{
2367
+ type: Injectable,
2368
+ args: [{ providedIn: 'root' }]
2369
+ }] });
2370
+ /**
2371
+ * Individual toast notification.
2372
+ *
2373
+ * Typically rendered by `llm-toast-container`, but can also be used standalone.
2374
+ */
2375
+ class LlmToast {
2376
+ /** Semantic color variant. */
2377
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
2378
+ /** Whether to show a dismiss button. */
2379
+ dismissible = input(true, ...(ngDevMode ? [{ debugName: "dismissible" }] : /* istanbul ignore next */ []));
2380
+ /** The message to display. */
2381
+ message = input('', ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
2382
+ /** Unique identifier for this toast. */
2383
+ toastId = input('', ...(ngDevMode ? [{ debugName: "toastId" }] : /* istanbul ignore next */ []));
2384
+ /** Emitted when the toast is dismissed by the user. */
2385
+ dismissed = output();
2386
+ hostClasses = computed(() => `variant-${this.variant()}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
2387
+ onDismiss() {
2388
+ this.dismissed.emit(this.toastId());
2389
+ }
2390
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmToast, deps: [], target: i0.ɵɵFactoryTarget.Component });
2391
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmToast, isStandalone: true, selector: "llm-toast", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, toastId: { classPropertyName: "toastId", publicName: "toastId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, host: { attributes: { "role": "status" }, properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
2392
+ <span class="message">{{ message() }}</span>
2393
+ @if (dismissible()) {
2394
+ <button class="dismiss" type="button" aria-label="Dismiss" (click)="onDismiss()">
2395
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
2396
+ <line x1="18" y1="6" x2="6" y2="18" />
2397
+ <line x1="6" y1="6" x2="18" y2="18" />
2398
+ </svg>
2399
+ </button>
2400
+ }
2401
+ `, isInline: true, styles: [":host{display:flex;align-items:center;gap:var(--ui-spacing-3);padding:var(--ui-spacing-3) var(--ui-spacing-4);border-radius:var(--ui-radius-md);border-left:3px solid transparent;font-family:var(--ui-font-family);font-size:var(--ui-font-size-sm);line-height:var(--ui-line-height-normal);box-shadow:var(--ui-shadow-md);background-color:var(--ui-color-surface-raised, var(--ui-color-surface));color:var(--ui-color-text);pointer-events:auto;min-width:16rem;max-width:100%;box-sizing:border-box;animation:toast-enter .3s ease-out}:host(.variant-default){border-left-color:var(--ui-color-border)}:host(.variant-success){border-left-color:var(--ui-color-success);background-color:color-mix(in srgb,var(--ui-color-success) 8%,var(--ui-color-surface-raised, var(--ui-color-surface)))}:host(.variant-warning){border-left-color:var(--ui-color-warning);background-color:color-mix(in srgb,var(--ui-color-warning) 8%,var(--ui-color-surface-raised, var(--ui-color-surface)))}:host(.variant-danger){border-left-color:var(--ui-color-danger);background-color:color-mix(in srgb,var(--ui-color-danger) 8%,var(--ui-color-surface-raised, var(--ui-color-surface)))}:host(.variant-info){border-left-color:var(--ui-color-info);background-color:color-mix(in srgb,var(--ui-color-info) 8%,var(--ui-color-surface-raised, var(--ui-color-surface)))}.message{flex:1}.dismiss{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:.125rem;background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted, currentColor);opacity:.7;transition:opacity var(--ui-transition-fast, .15s),background-color var(--ui-transition-fast, .15s);line-height:1}.dismiss:hover{opacity:1;background-color:color-mix(in srgb,currentColor 10%,transparent)}.dismiss:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);opacity:1}@keyframes toast-enter{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}@media(prefers-reduced-motion:reduce){:host{animation:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2402
+ }
2403
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmToast, decorators: [{
2404
+ type: Component,
2405
+ args: [{ selector: 'llm-toast', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
2406
+ <span class="message">{{ message() }}</span>
2407
+ @if (dismissible()) {
2408
+ <button class="dismiss" type="button" aria-label="Dismiss" (click)="onDismiss()">
2409
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
2410
+ <line x1="18" y1="6" x2="6" y2="18" />
2411
+ <line x1="6" y1="6" x2="18" y2="18" />
2412
+ </svg>
2413
+ </button>
2414
+ }
2415
+ `, host: {
2416
+ '[class]': 'hostClasses()',
2417
+ role: 'status',
2418
+ }, styles: [":host{display:flex;align-items:center;gap:var(--ui-spacing-3);padding:var(--ui-spacing-3) var(--ui-spacing-4);border-radius:var(--ui-radius-md);border-left:3px solid transparent;font-family:var(--ui-font-family);font-size:var(--ui-font-size-sm);line-height:var(--ui-line-height-normal);box-shadow:var(--ui-shadow-md);background-color:var(--ui-color-surface-raised, var(--ui-color-surface));color:var(--ui-color-text);pointer-events:auto;min-width:16rem;max-width:100%;box-sizing:border-box;animation:toast-enter .3s ease-out}:host(.variant-default){border-left-color:var(--ui-color-border)}:host(.variant-success){border-left-color:var(--ui-color-success);background-color:color-mix(in srgb,var(--ui-color-success) 8%,var(--ui-color-surface-raised, var(--ui-color-surface)))}:host(.variant-warning){border-left-color:var(--ui-color-warning);background-color:color-mix(in srgb,var(--ui-color-warning) 8%,var(--ui-color-surface-raised, var(--ui-color-surface)))}:host(.variant-danger){border-left-color:var(--ui-color-danger);background-color:color-mix(in srgb,var(--ui-color-danger) 8%,var(--ui-color-surface-raised, var(--ui-color-surface)))}:host(.variant-info){border-left-color:var(--ui-color-info);background-color:color-mix(in srgb,var(--ui-color-info) 8%,var(--ui-color-surface-raised, var(--ui-color-surface)))}.message{flex:1}.dismiss{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:.125rem;background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted, currentColor);opacity:.7;transition:opacity var(--ui-transition-fast, .15s),background-color var(--ui-transition-fast, .15s);line-height:1}.dismiss:hover{opacity:1;background-color:color-mix(in srgb,currentColor 10%,transparent)}.dismiss:focus-visible{outline:none;box-shadow:var(--ui-focus-ring);opacity:1}@keyframes toast-enter{0%{opacity:0;transform:translateY(.5rem)}to{opacity:1;transform:translateY(0)}}@media(prefers-reduced-motion:reduce){:host{animation:none}}\n"] }]
2419
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], dismissible: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissible", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], toastId: [{ type: i0.Input, args: [{ isSignal: true, alias: "toastId", required: false }] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }] } });
2420
+ /**
2421
+ * Container that renders the toast stack at a fixed viewport position.
2422
+ * Place once in your app root or layout component.
2423
+ *
2424
+ * Usage:
2425
+ * ```html
2426
+ * <llm-toast-container position="bottom-right" />
2427
+ * ```
2428
+ */
2429
+ class LlmToastContainer {
2430
+ toastService = inject(LlmToastService);
2431
+ destroyRef = inject(DestroyRef);
2432
+ /** Position of the toast stack on the viewport. */
2433
+ position = input('bottom-right', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
2434
+ hostClasses = computed(() => `position-${this.position()}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
2435
+ constructor() {
2436
+ this.destroyRef.onDestroy(() => this.toastService.clear());
2437
+ }
2438
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmToastContainer, deps: [], target: i0.ɵɵFactoryTarget.Component });
2439
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmToastContainer, isStandalone: true, selector: "llm-toast-container", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-live": "polite", "role": "status" }, properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
2440
+ @for (toast of toastService.toasts(); track toast.id) {
2441
+ <llm-toast
2442
+ [variant]="toast.variant"
2443
+ [dismissible]="toast.dismissible"
2444
+ [message]="toast.message"
2445
+ [toastId]="toast.id"
2446
+ (dismissed)="toastService.dismiss($event)"
2447
+ />
2448
+ }
2449
+ `, isInline: true, styles: [":host{position:fixed;z-index:var(--ui-z-toast, 400);display:flex;flex-direction:column;gap:var(--ui-spacing-2);pointer-events:none;max-width:min(24rem,calc(100vw - 2rem));box-sizing:border-box}:host(.position-bottom-right){bottom:var(--ui-spacing-4);right:var(--ui-spacing-4);align-items:flex-end}:host(.position-bottom-center){bottom:var(--ui-spacing-4);left:50%;transform:translate(-50%);align-items:center}:host(.position-top-right){top:var(--ui-spacing-4);right:var(--ui-spacing-4);align-items:flex-end}:host(.position-top-center){top:var(--ui-spacing-4);left:50%;transform:translate(-50%);align-items:center}\n"], dependencies: [{ kind: "component", type: LlmToast, selector: "llm-toast", inputs: ["variant", "dismissible", "message", "toastId"], outputs: ["dismissed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2450
+ }
2451
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmToastContainer, decorators: [{
2452
+ type: Component,
2453
+ args: [{ selector: 'llm-toast-container', standalone: true, imports: [LlmToast], changeDetection: ChangeDetectionStrategy.OnPush, template: `
2454
+ @for (toast of toastService.toasts(); track toast.id) {
2455
+ <llm-toast
2456
+ [variant]="toast.variant"
2457
+ [dismissible]="toast.dismissible"
2458
+ [message]="toast.message"
2459
+ [toastId]="toast.id"
2460
+ (dismissed)="toastService.dismiss($event)"
2461
+ />
2462
+ }
2463
+ `, host: {
2464
+ '[class]': 'hostClasses()',
2465
+ 'aria-live': 'polite',
2466
+ role: 'status',
2467
+ }, styles: [":host{position:fixed;z-index:var(--ui-z-toast, 400);display:flex;flex-direction:column;gap:var(--ui-spacing-2);pointer-events:none;max-width:min(24rem,calc(100vw - 2rem));box-sizing:border-box}:host(.position-bottom-right){bottom:var(--ui-spacing-4);right:var(--ui-spacing-4);align-items:flex-end}:host(.position-bottom-center){bottom:var(--ui-spacing-4);left:50%;transform:translate(-50%);align-items:center}:host(.position-top-right){top:var(--ui-spacing-4);right:var(--ui-spacing-4);align-items:flex-end}:host(.position-top-center){top:var(--ui-spacing-4);left:50%;transform:translate(-50%);align-items:center}\n"] }]
2468
+ }], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }] } });
2469
+
2470
+ /**
2471
+ * Displays a user avatar with image, initials, or icon fallback.
2472
+ *
2473
+ * Fallback order: image → initials (from `name`) → generic icon.
2474
+ *
2475
+ * Usage:
2476
+ * ```html
2477
+ * <llm-avatar src="https://example.com/photo.jpg" name="Jane Doe" />
2478
+ * <llm-avatar name="John Smith" size="lg" status="online" />
2479
+ * <llm-avatar size="sm" shape="square" />
2480
+ * ```
2481
+ */
2482
+ class LlmAvatar {
2483
+ /** Image URL. Falls back to initials or icon if empty or fails to load. */
2484
+ src = input('', ...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []));
2485
+ /** Alt text for the image (also used as aria-label). */
2486
+ alt = input('', ...(ngDevMode ? [{ debugName: "alt" }] : /* istanbul ignore next */ []));
2487
+ /** Full name used to generate initials fallback and default aria-label. */
2488
+ name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
2489
+ /** Size of the avatar. */
2490
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
2491
+ /** Shape of the avatar. */
2492
+ shape = input('circle', ...(ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []));
2493
+ /** Presence status indicator dot. Empty string hides the dot. */
2494
+ status = input('', ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
2495
+ /** @internal — reset to true whenever src changes */
2496
+ showImage = signal(true, ...(ngDevMode ? [{ debugName: "showImage" }] : /* istanbul ignore next */ []));
2497
+ /** @internal */
2498
+ initials = computed(() => {
2499
+ const name = this.name();
2500
+ if (!name)
2501
+ return '';
2502
+ return name
2503
+ .split(' ')
2504
+ .filter(Boolean)
2505
+ .slice(0, 2)
2506
+ .map((w) => w[0].toUpperCase())
2507
+ .join('');
2508
+ }, ...(ngDevMode ? [{ debugName: "initials" }] : /* istanbul ignore next */ []));
2509
+ /** @internal */
2510
+ ariaLabel = computed(() => this.alt() || this.name() || 'Avatar', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
2511
+ /** @internal */
2512
+ hostClasses = computed(() => `size-${this.size()} shape-${this.shape()}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
2513
+ constructor() {
2514
+ effect(() => {
2515
+ this.src(); // track src changes
2516
+ untracked(() => this.showImage.set(true));
2517
+ });
2518
+ }
2519
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAvatar, deps: [], target: i0.ɵɵFactoryTarget.Component });
2520
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmAvatar, isStandalone: true, selector: "llm-avatar", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "img" }, properties: { "class": "hostClasses()", "attr.aria-label": "ariaLabel()" } }, ngImport: i0, template: `
2521
+ <!-- eslint-disable -->
2522
+ @if (src() && showImage()) {
2523
+ <img [src]="src()" [alt]="alt()" (error)="showImage.set(false)" />
2524
+ } @else if (initials()) {
2525
+ <span class="initials" aria-hidden="true">{{ initials() }}</span>
2526
+ } @else {
2527
+ <svg class="icon" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
2528
+ <path d="M12 12c2.761 0 5-2.239 5-5s-2.239-5-5-5-5 2.239-5 5 2.239 5 5 5zm0 2c-3.314 0-10 1.343-10 4v2h20v-2c0-2.657-6.686-4-10-4z" />
2529
+ </svg>
2530
+ }
2531
+ @if (status()) {
2532
+ <span [class]="'status-dot status-' + status()" aria-hidden="true"></span>
2533
+ }
2534
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;position:relative;overflow:hidden;flex-shrink:0;font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-semibold);background-color:color-mix(in srgb,var(--ui-color-primary) 12%,var(--ui-color-surface-sunken));color:var(--ui-color-primary);-webkit-user-select:none;user-select:none}:host(.size-xs){width:24px;height:24px;font-size:.625rem}:host(.size-sm){width:32px;height:32px;font-size:var(--ui-font-size-xs)}:host(.size-md){width:40px;height:40px;font-size:var(--ui-font-size-sm)}:host(.size-lg){width:48px;height:48px;font-size:var(--ui-font-size-md)}:host(.size-xl){width:64px;height:64px;font-size:var(--ui-font-size-lg)}:host(.shape-circle){border-radius:var(--ui-radius-full)}:host(.shape-square){border-radius:var(--ui-radius-md)}img{width:100%;height:100%;object-fit:cover;display:block}.initials{line-height:1;letter-spacing:.02em}.icon{width:55%;height:55%;opacity:.6}.status-dot{position:absolute;bottom:0;right:0;width:25%;height:25%;min-width:6px;min-height:6px;max-width:14px;max-height:14px;border-radius:var(--ui-radius-full);border:2px solid var(--ui-color-surface);box-sizing:content-box}.status-dot.status-online{background-color:var(--ui-color-success)}.status-dot.status-offline{background-color:var(--ui-color-text-muted)}.status-dot.status-away{background-color:var(--ui-color-warning)}.status-dot.status-busy{background-color:var(--ui-color-danger)}:host(.group){display:inline-flex;align-items:center;background:none;overflow:visible;padding-inline-start:4px}:host-context(llm-avatar-group){box-shadow:0 0 0 2px var(--ui-color-surface);margin-inline-start:-8px}.overflow-badge{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text-muted);border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-full);font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-semibold);box-shadow:0 0 0 2px var(--ui-color-surface);margin-inline-start:-8px}.overflow-badge.size-xs{width:24px;height:24px;font-size:.5625rem}.overflow-badge.size-sm{width:32px;height:32px;font-size:var(--ui-font-size-xs)}.overflow-badge.size-md{width:40px;height:40px;font-size:var(--ui-font-size-sm)}.overflow-badge.size-lg{width:48px;height:48px;font-size:var(--ui-font-size-sm)}.overflow-badge.size-xl{width:64px;height:64px;font-size:var(--ui-font-size-md)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2535
+ }
2536
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAvatar, decorators: [{
2537
+ type: Component,
2538
+ args: [{ selector: 'llm-avatar', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
2539
+ <!-- eslint-disable -->
2540
+ @if (src() && showImage()) {
2541
+ <img [src]="src()" [alt]="alt()" (error)="showImage.set(false)" />
2542
+ } @else if (initials()) {
2543
+ <span class="initials" aria-hidden="true">{{ initials() }}</span>
2544
+ } @else {
2545
+ <svg class="icon" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
2546
+ <path d="M12 12c2.761 0 5-2.239 5-5s-2.239-5-5-5-5 2.239-5 5 2.239 5 5 5zm0 2c-3.314 0-10 1.343-10 4v2h20v-2c0-2.657-6.686-4-10-4z" />
2547
+ </svg>
2548
+ }
2549
+ @if (status()) {
2550
+ <span [class]="'status-dot status-' + status()" aria-hidden="true"></span>
2551
+ }
2552
+ `, host: {
2553
+ '[class]': 'hostClasses()',
2554
+ role: 'img',
2555
+ '[attr.aria-label]': 'ariaLabel()',
2556
+ }, styles: [":host{display:inline-flex;align-items:center;justify-content:center;position:relative;overflow:hidden;flex-shrink:0;font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-semibold);background-color:color-mix(in srgb,var(--ui-color-primary) 12%,var(--ui-color-surface-sunken));color:var(--ui-color-primary);-webkit-user-select:none;user-select:none}:host(.size-xs){width:24px;height:24px;font-size:.625rem}:host(.size-sm){width:32px;height:32px;font-size:var(--ui-font-size-xs)}:host(.size-md){width:40px;height:40px;font-size:var(--ui-font-size-sm)}:host(.size-lg){width:48px;height:48px;font-size:var(--ui-font-size-md)}:host(.size-xl){width:64px;height:64px;font-size:var(--ui-font-size-lg)}:host(.shape-circle){border-radius:var(--ui-radius-full)}:host(.shape-square){border-radius:var(--ui-radius-md)}img{width:100%;height:100%;object-fit:cover;display:block}.initials{line-height:1;letter-spacing:.02em}.icon{width:55%;height:55%;opacity:.6}.status-dot{position:absolute;bottom:0;right:0;width:25%;height:25%;min-width:6px;min-height:6px;max-width:14px;max-height:14px;border-radius:var(--ui-radius-full);border:2px solid var(--ui-color-surface);box-sizing:content-box}.status-dot.status-online{background-color:var(--ui-color-success)}.status-dot.status-offline{background-color:var(--ui-color-text-muted)}.status-dot.status-away{background-color:var(--ui-color-warning)}.status-dot.status-busy{background-color:var(--ui-color-danger)}:host(.group){display:inline-flex;align-items:center;background:none;overflow:visible;padding-inline-start:4px}:host-context(llm-avatar-group){box-shadow:0 0 0 2px var(--ui-color-surface);margin-inline-start:-8px}.overflow-badge{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text-muted);border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-full);font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-semibold);box-shadow:0 0 0 2px var(--ui-color-surface);margin-inline-start:-8px}.overflow-badge.size-xs{width:24px;height:24px;font-size:.5625rem}.overflow-badge.size-sm{width:32px;height:32px;font-size:var(--ui-font-size-xs)}.overflow-badge.size-md{width:40px;height:40px;font-size:var(--ui-font-size-sm)}.overflow-badge.size-lg{width:48px;height:48px;font-size:var(--ui-font-size-sm)}.overflow-badge.size-xl{width:64px;height:64px;font-size:var(--ui-font-size-md)}\n"] }]
2557
+ }], ctorParameters: () => [], propDecorators: { src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], alt: [{ type: i0.Input, args: [{ isSignal: true, alias: "alt", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }] } });
2558
+ /**
2559
+ * Groups multiple avatars with overlap and an overflow count badge.
2560
+ *
2561
+ * Usage:
2562
+ * ```html
2563
+ * <llm-avatar-group [max]="3" size="md">
2564
+ * <llm-avatar name="Alice" />
2565
+ * <llm-avatar name="Bob" />
2566
+ * <llm-avatar name="Charlie" />
2567
+ * <llm-avatar name="Dave" />
2568
+ * </llm-avatar-group>
2569
+ * ```
2570
+ */
2571
+ class LlmAvatarGroup {
2572
+ /** Maximum visible avatars before showing an overflow count. */
2573
+ max = input(5, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
2574
+ /** Size applied to the overflow badge (match the size used on child avatars). */
2575
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
2576
+ avatarEls = contentChildren(LlmAvatar, { ...(ngDevMode ? { debugName: "avatarEls" } : /* istanbul ignore next */ {}), read: ElementRef });
2577
+ overflowCount = computed(() => Math.max(0, this.avatarEls().length - this.max()), ...(ngDevMode ? [{ debugName: "overflowCount" }] : /* istanbul ignore next */ []));
2578
+ constructor() {
2579
+ effect(() => {
2580
+ const max = this.max();
2581
+ this.avatarEls().forEach((el, i) => {
2582
+ el.nativeElement.style.display = i >= max ? 'none' : '';
2583
+ });
2584
+ });
2585
+ }
2586
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAvatarGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
2587
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmAvatarGroup, isStandalone: true, selector: "llm-avatar-group", inputs: { max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "\"group size-\" + size()" }, classAttribute: "group" }, queries: [{ propertyName: "avatarEls", predicate: LlmAvatar, read: ElementRef, isSignal: true }], ngImport: i0, template: `
2588
+ <ng-content />
2589
+ @if (overflowCount() > 0) {
2590
+ <span [class]="'overflow-badge size-' + size()">+{{ overflowCount() }}</span>
2591
+ }
2592
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;position:relative;overflow:hidden;flex-shrink:0;font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-semibold);background-color:color-mix(in srgb,var(--ui-color-primary) 12%,var(--ui-color-surface-sunken));color:var(--ui-color-primary);-webkit-user-select:none;user-select:none}:host(.size-xs){width:24px;height:24px;font-size:.625rem}:host(.size-sm){width:32px;height:32px;font-size:var(--ui-font-size-xs)}:host(.size-md){width:40px;height:40px;font-size:var(--ui-font-size-sm)}:host(.size-lg){width:48px;height:48px;font-size:var(--ui-font-size-md)}:host(.size-xl){width:64px;height:64px;font-size:var(--ui-font-size-lg)}:host(.shape-circle){border-radius:var(--ui-radius-full)}:host(.shape-square){border-radius:var(--ui-radius-md)}img{width:100%;height:100%;object-fit:cover;display:block}.initials{line-height:1;letter-spacing:.02em}.icon{width:55%;height:55%;opacity:.6}.status-dot{position:absolute;bottom:0;right:0;width:25%;height:25%;min-width:6px;min-height:6px;max-width:14px;max-height:14px;border-radius:var(--ui-radius-full);border:2px solid var(--ui-color-surface);box-sizing:content-box}.status-dot.status-online{background-color:var(--ui-color-success)}.status-dot.status-offline{background-color:var(--ui-color-text-muted)}.status-dot.status-away{background-color:var(--ui-color-warning)}.status-dot.status-busy{background-color:var(--ui-color-danger)}:host(.group){display:inline-flex;align-items:center;background:none;overflow:visible;padding-inline-start:4px}:host-context(llm-avatar-group){box-shadow:0 0 0 2px var(--ui-color-surface);margin-inline-start:-8px}.overflow-badge{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text-muted);border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-full);font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-semibold);box-shadow:0 0 0 2px var(--ui-color-surface);margin-inline-start:-8px}.overflow-badge.size-xs{width:24px;height:24px;font-size:.5625rem}.overflow-badge.size-sm{width:32px;height:32px;font-size:var(--ui-font-size-xs)}.overflow-badge.size-md{width:40px;height:40px;font-size:var(--ui-font-size-sm)}.overflow-badge.size-lg{width:48px;height:48px;font-size:var(--ui-font-size-sm)}.overflow-badge.size-xl{width:64px;height:64px;font-size:var(--ui-font-size-md)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2593
+ }
2594
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmAvatarGroup, decorators: [{
2595
+ type: Component,
2596
+ args: [{ selector: 'llm-avatar-group', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
2597
+ <ng-content />
2598
+ @if (overflowCount() > 0) {
2599
+ <span [class]="'overflow-badge size-' + size()">+{{ overflowCount() }}</span>
2600
+ }
2601
+ `, host: {
2602
+ class: 'group',
2603
+ '[class]': '"group size-" + size()',
2604
+ }, styles: [":host{display:inline-flex;align-items:center;justify-content:center;position:relative;overflow:hidden;flex-shrink:0;font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-semibold);background-color:color-mix(in srgb,var(--ui-color-primary) 12%,var(--ui-color-surface-sunken));color:var(--ui-color-primary);-webkit-user-select:none;user-select:none}:host(.size-xs){width:24px;height:24px;font-size:.625rem}:host(.size-sm){width:32px;height:32px;font-size:var(--ui-font-size-xs)}:host(.size-md){width:40px;height:40px;font-size:var(--ui-font-size-sm)}:host(.size-lg){width:48px;height:48px;font-size:var(--ui-font-size-md)}:host(.size-xl){width:64px;height:64px;font-size:var(--ui-font-size-lg)}:host(.shape-circle){border-radius:var(--ui-radius-full)}:host(.shape-square){border-radius:var(--ui-radius-md)}img{width:100%;height:100%;object-fit:cover;display:block}.initials{line-height:1;letter-spacing:.02em}.icon{width:55%;height:55%;opacity:.6}.status-dot{position:absolute;bottom:0;right:0;width:25%;height:25%;min-width:6px;min-height:6px;max-width:14px;max-height:14px;border-radius:var(--ui-radius-full);border:2px solid var(--ui-color-surface);box-sizing:content-box}.status-dot.status-online{background-color:var(--ui-color-success)}.status-dot.status-offline{background-color:var(--ui-color-text-muted)}.status-dot.status-away{background-color:var(--ui-color-warning)}.status-dot.status-busy{background-color:var(--ui-color-danger)}:host(.group){display:inline-flex;align-items:center;background:none;overflow:visible;padding-inline-start:4px}:host-context(llm-avatar-group){box-shadow:0 0 0 2px var(--ui-color-surface);margin-inline-start:-8px}.overflow-badge{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text-muted);border:1px solid var(--ui-color-border);border-radius:var(--ui-radius-full);font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-semibold);box-shadow:0 0 0 2px var(--ui-color-surface);margin-inline-start:-8px}.overflow-badge.size-xs{width:24px;height:24px;font-size:.5625rem}.overflow-badge.size-sm{width:32px;height:32px;font-size:var(--ui-font-size-xs)}.overflow-badge.size-md{width:40px;height:40px;font-size:var(--ui-font-size-sm)}.overflow-badge.size-lg{width:48px;height:48px;font-size:var(--ui-font-size-sm)}.overflow-badge.size-xl{width:64px;height:64px;font-size:var(--ui-font-size-md)}\n"] }]
2605
+ }], ctorParameters: () => [], propDecorators: { max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], avatarEls: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => LlmAvatar), { ...{ read: ElementRef }, isSignal: true }] }] } });
2606
+
2607
+ /**
2608
+ * Progress bar with determinate and indeterminate states.
2609
+ *
2610
+ * Usage:
2611
+ * ```html
2612
+ * <llm-progress [value]="75" />
2613
+ * <llm-progress variant="success" [value]="100" />
2614
+ * <llm-progress [indeterminate]="true" />
2615
+ * ```
2616
+ */
2617
+ class LlmProgress {
2618
+ /** Current value of the progress bar. */
2619
+ value = input(0, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
2620
+ /** Maximum value. */
2621
+ max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
2622
+ /** Semantic color variant. */
2623
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
2624
+ /** Height size of the track. */
2625
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
2626
+ /** Shows an animated indeterminate state (loading). */
2627
+ indeterminate = input(false, ...(ngDevMode ? [{ debugName: "indeterminate" }] : /* istanbul ignore next */ []));
2628
+ clampedValue = computed(() => Math.min(Math.max(this.value(), 0), this.max()), ...(ngDevMode ? [{ debugName: "clampedValue" }] : /* istanbul ignore next */ []));
2629
+ fillWidth = computed(() => this.indeterminate()
2630
+ ? '100%'
2631
+ : `${(this.clampedValue() / this.max()) * 100}%`, ...(ngDevMode ? [{ debugName: "fillWidth" }] : /* istanbul ignore next */ []));
2632
+ hostClasses = computed(() => `variant-${this.variant()} size-${this.size()}${this.indeterminate() ? ' is-indeterminate' : ''}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
2633
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmProgress, deps: [], target: i0.ɵɵFactoryTarget.Component });
2634
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmProgress, isStandalone: true, selector: "llm-progress", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "progressbar", "aria-valuemin": "0" }, properties: { "attr.aria-valuenow": "indeterminate() ? null : clampedValue()", "attr.aria-valuemax": "indeterminate() ? null : max()", "class": "hostClasses()" } }, ngImport: i0, template: `
2635
+ <div class="track">
2636
+ <div class="fill" [style.width]="fillWidth()"></div>
2637
+ </div>
2638
+ `, isInline: true, styles: [":host{display:block;width:100%;font-family:var(--ui-font-family)}.track{position:relative;width:100%;border-radius:var(--ui-radius-full);background-color:var(--ui-color-surface-sunken);overflow:hidden}:host(.size-sm) .track{height:4px}:host(.size-md) .track{height:8px}:host(.size-lg) .track{height:12px}.fill{height:100%;border-radius:var(--ui-radius-full);background-color:var(--ui-color-primary);transition:width var(--ui-transition-normal)}:host(.variant-success) .fill{background-color:var(--ui-color-success)}:host(.variant-warning) .fill{background-color:var(--ui-color-warning)}:host(.variant-danger) .fill{background-color:var(--ui-color-danger)}@keyframes progress-indeterminate{0%{transform:translate(-150%)}to{transform:translate(350%)}}:host(.is-indeterminate) .fill{width:40%!important;animation:progress-indeterminate 1.4s var(--ui-ease-in-out) infinite}@media(prefers-reduced-motion:reduce){:host(.is-indeterminate) .fill{animation:none;opacity:.5}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2639
+ }
2640
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmProgress, decorators: [{
2641
+ type: Component,
2642
+ args: [{ selector: 'llm-progress', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
2643
+ <div class="track">
2644
+ <div class="fill" [style.width]="fillWidth()"></div>
2645
+ </div>
2646
+ `, host: {
2647
+ role: 'progressbar',
2648
+ 'aria-valuemin': '0',
2649
+ '[attr.aria-valuenow]': 'indeterminate() ? null : clampedValue()',
2650
+ '[attr.aria-valuemax]': 'indeterminate() ? null : max()',
2651
+ '[class]': 'hostClasses()',
2652
+ }, styles: [":host{display:block;width:100%;font-family:var(--ui-font-family)}.track{position:relative;width:100%;border-radius:var(--ui-radius-full);background-color:var(--ui-color-surface-sunken);overflow:hidden}:host(.size-sm) .track{height:4px}:host(.size-md) .track{height:8px}:host(.size-lg) .track{height:12px}.fill{height:100%;border-radius:var(--ui-radius-full);background-color:var(--ui-color-primary);transition:width var(--ui-transition-normal)}:host(.variant-success) .fill{background-color:var(--ui-color-success)}:host(.variant-warning) .fill{background-color:var(--ui-color-warning)}:host(.variant-danger) .fill{background-color:var(--ui-color-danger)}@keyframes progress-indeterminate{0%{transform:translate(-150%)}to{transform:translate(350%)}}:host(.is-indeterminate) .fill{width:40%!important;animation:progress-indeterminate 1.4s var(--ui-ease-in-out) infinite}@media(prefers-reduced-motion:reduce){:host(.is-indeterminate) .fill{animation:none;opacity:.5}}\n"] }]
2653
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }] } });
2654
+
2655
+ const LLM_BREADCRUMBS = new InjectionToken('LLM_BREADCRUMBS');
2656
+
2657
+ /**
2658
+ * Accessible breadcrumb navigation. Wrap `llm-breadcrumb-item` elements inside.
2659
+ * The last item is automatically marked as the current page.
2660
+ *
2661
+ * Usage:
2662
+ * ```html
2663
+ * <llm-breadcrumbs>
2664
+ * <llm-breadcrumb-item href="/home">Home</llm-breadcrumb-item>
2665
+ * <llm-breadcrumb-item href="/products">Products</llm-breadcrumb-item>
2666
+ * <llm-breadcrumb-item>Widget X</llm-breadcrumb-item>
2667
+ * </llm-breadcrumbs>
2668
+ * ```
2669
+ */
2670
+ class LlmBreadcrumbs {
2671
+ _itemIds = signal([], ...(ngDevMode ? [{ debugName: "_itemIds" }] : /* istanbul ignore next */ []));
2672
+ _nextId = 0;
2673
+ /** @internal — used by LlmBreadcrumbItem via LLM_BREADCRUMBS token */
2674
+ lastItemId = computed(() => {
2675
+ const ids = this._itemIds();
2676
+ return ids.length > 0 ? ids[ids.length - 1] : -1;
2677
+ }, ...(ngDevMode ? [{ debugName: "lastItemId" }] : /* istanbul ignore next */ []));
2678
+ /** @internal */
2679
+ registerItem() {
2680
+ const id = this._nextId++;
2681
+ this._itemIds.update((ids) => [...ids, id]);
2682
+ return id;
2683
+ }
2684
+ /** @internal */
2685
+ unregisterItem(id) {
2686
+ this._itemIds.update((ids) => ids.filter((i) => i !== id));
2687
+ }
2688
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmBreadcrumbs, deps: [], target: i0.ɵɵFactoryTarget.Component });
2689
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmBreadcrumbs, isStandalone: true, selector: "llm-breadcrumbs", providers: [
2690
+ {
2691
+ provide: LLM_BREADCRUMBS,
2692
+ useFactory: (bc) => ({
2693
+ registerItem: () => bc.registerItem(),
2694
+ unregisterItem: (id) => bc.unregisterItem(id),
2695
+ lastItemId: bc.lastItemId,
2696
+ }),
2697
+ deps: [LlmBreadcrumbs],
2698
+ },
2699
+ ], ngImport: i0, template: `
2700
+ <nav aria-label="Breadcrumb">
2701
+ <ol role="list" class="list">
2702
+ <ng-content />
2703
+ </ol>
2704
+ </nav>
2705
+ `, isInline: true, styles: ["llm-breadcrumbs{display:block;font-family:var(--ui-font-family)}nav{display:block}.list{display:flex;flex-wrap:wrap;align-items:center;gap:0;list-style:none;margin:0;padding:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-text-muted)}llm-breadcrumb-item{display:contents}.item{display:flex;align-items:center}.item:after{content:\"\\203a\";margin:0 var(--ui-spacing-2);color:var(--ui-color-border-hover);font-size:var(--ui-font-size-md);line-height:1}:host(.is-current) .item:after{display:none}.item a[href]{color:var(--ui-color-text-muted);text-decoration:none;border-radius:var(--ui-radius-sm);padding:.125rem .25rem;margin:-.125rem -.25rem;transition:color var(--ui-transition-fast)}.item a[href]:hover{color:var(--ui-color-text);text-decoration:underline}.item a[href]:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}.item a:not([href]){color:var(--ui-color-text);font-weight:var(--ui-font-weight-semibold)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2706
+ }
2707
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmBreadcrumbs, decorators: [{
2708
+ type: Component,
2709
+ args: [{ selector: 'llm-breadcrumbs', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
2710
+ {
2711
+ provide: LLM_BREADCRUMBS,
2712
+ useFactory: (bc) => ({
2713
+ registerItem: () => bc.registerItem(),
2714
+ unregisterItem: (id) => bc.unregisterItem(id),
2715
+ lastItemId: bc.lastItemId,
2716
+ }),
2717
+ deps: [LlmBreadcrumbs],
2718
+ },
2719
+ ], template: `
2720
+ <nav aria-label="Breadcrumb">
2721
+ <ol role="list" class="list">
2722
+ <ng-content />
2723
+ </ol>
2724
+ </nav>
2725
+ `, styles: ["llm-breadcrumbs{display:block;font-family:var(--ui-font-family)}nav{display:block}.list{display:flex;flex-wrap:wrap;align-items:center;gap:0;list-style:none;margin:0;padding:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-text-muted)}llm-breadcrumb-item{display:contents}.item{display:flex;align-items:center}.item:after{content:\"\\203a\";margin:0 var(--ui-spacing-2);color:var(--ui-color-border-hover);font-size:var(--ui-font-size-md);line-height:1}:host(.is-current) .item:after{display:none}.item a[href]{color:var(--ui-color-text-muted);text-decoration:none;border-radius:var(--ui-radius-sm);padding:.125rem .25rem;margin:-.125rem -.25rem;transition:color var(--ui-transition-fast)}.item a[href]:hover{color:var(--ui-color-text);text-decoration:underline}.item a[href]:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}.item a:not([href]){color:var(--ui-color-text);font-weight:var(--ui-font-weight-semibold)}\n"] }]
2726
+ }] });
2727
+ /**
2728
+ * A single breadcrumb step. The last item is automatically treated as
2729
+ * `aria-current="page"` and rendered as plain text (no link).
2730
+ */
2731
+ class LlmBreadcrumbItem {
2732
+ /** Optional href for navigation. Ignored on the last (current) item. */
2733
+ href = input('', ...(ngDevMode ? [{ debugName: "href" }] : /* istanbul ignore next */ []));
2734
+ context = inject(LLM_BREADCRUMBS);
2735
+ myIndex = signal(-1, ...(ngDevMode ? [{ debugName: "myIndex" }] : /* istanbul ignore next */ []));
2736
+ isCurrent = computed(() => this.myIndex() >= 0 && this.myIndex() === this.context.lastItemId(), ...(ngDevMode ? [{ debugName: "isCurrent" }] : /* istanbul ignore next */ []));
2737
+ ngOnInit() {
2738
+ this.myIndex.set(this.context.registerItem());
2739
+ }
2740
+ ngOnDestroy() {
2741
+ if (this.myIndex() >= 0) {
2742
+ this.context.unregisterItem(this.myIndex());
2743
+ }
2744
+ }
2745
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmBreadcrumbItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
2746
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: LlmBreadcrumbItem, isStandalone: true, selector: "llm-breadcrumb-item", inputs: { href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.is-current": "isCurrent()" } }, ngImport: i0, template: `
2747
+ <li class="item">
2748
+ <a
2749
+ [attr.href]="href() && !isCurrent() ? href() : null"
2750
+ [attr.aria-current]="isCurrent() ? 'page' : null"
2751
+ ><ng-content /></a>
2752
+ </li>
2753
+ `, isInline: true, styles: ["llm-breadcrumbs{display:block;font-family:var(--ui-font-family)}nav{display:block}.list{display:flex;flex-wrap:wrap;align-items:center;gap:0;list-style:none;margin:0;padding:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-text-muted)}llm-breadcrumb-item{display:contents}.item{display:flex;align-items:center}.item:after{content:\"\\203a\";margin:0 var(--ui-spacing-2);color:var(--ui-color-border-hover);font-size:var(--ui-font-size-md);line-height:1}:host(.is-current) .item:after{display:none}.item a[href]{color:var(--ui-color-text-muted);text-decoration:none;border-radius:var(--ui-radius-sm);padding:.125rem .25rem;margin:-.125rem -.25rem;transition:color var(--ui-transition-fast)}.item a[href]:hover{color:var(--ui-color-text);text-decoration:underline}.item a[href]:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}.item a:not([href]){color:var(--ui-color-text);font-weight:var(--ui-font-weight-semibold)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2754
+ }
2755
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmBreadcrumbItem, decorators: [{
2756
+ type: Component,
2757
+ args: [{ selector: 'llm-breadcrumb-item', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
2758
+ <li class="item">
2759
+ <a
2760
+ [attr.href]="href() && !isCurrent() ? href() : null"
2761
+ [attr.aria-current]="isCurrent() ? 'page' : null"
2762
+ ><ng-content /></a>
2763
+ </li>
2764
+ `, host: {
2765
+ '[class.is-current]': 'isCurrent()',
2766
+ }, styles: ["llm-breadcrumbs{display:block;font-family:var(--ui-font-family)}nav{display:block}.list{display:flex;flex-wrap:wrap;align-items:center;gap:0;list-style:none;margin:0;padding:0;font-size:var(--ui-font-size-sm);color:var(--ui-color-text-muted)}llm-breadcrumb-item{display:contents}.item{display:flex;align-items:center}.item:after{content:\"\\203a\";margin:0 var(--ui-spacing-2);color:var(--ui-color-border-hover);font-size:var(--ui-font-size-md);line-height:1}:host(.is-current) .item:after{display:none}.item a[href]{color:var(--ui-color-text-muted);text-decoration:none;border-radius:var(--ui-radius-sm);padding:.125rem .25rem;margin:-.125rem -.25rem;transition:color var(--ui-transition-fast)}.item a[href]:hover{color:var(--ui-color-text);text-decoration:underline}.item a[href]:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}.item a:not([href]){color:var(--ui-color-text);font-weight:var(--ui-font-weight-semibold)}\n"] }]
2767
+ }], propDecorators: { href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: false }] }] } });
2768
+
2769
+ /**
2770
+ * Pagination control for navigating multi-page content.
2771
+ *
2772
+ * Usage:
2773
+ * ```html
2774
+ * <llm-pagination [(page)]="currentPage" [pageCount]="totalPages" />
2775
+ * ```
2776
+ */
2777
+ class LlmPagination {
2778
+ /** Current page (1-based). Supports two-way binding: [(page)]="currentPage". */
2779
+ page = model(1, ...(ngDevMode ? [{ debugName: "page" }] : /* istanbul ignore next */ []));
2780
+ /** Total number of pages. */
2781
+ pageCount = input(1, ...(ngDevMode ? [{ debugName: "pageCount" }] : /* istanbul ignore next */ []));
2782
+ /** Number of page buttons to show on each side of the current page. */
2783
+ siblingCount = input(1, ...(ngDevMode ? [{ debugName: "siblingCount" }] : /* istanbul ignore next */ []));
2784
+ /** Whether to show first/last page jump buttons. */
2785
+ showFirstLast = input(true, ...(ngDevMode ? [{ debugName: "showFirstLast" }] : /* istanbul ignore next */ []));
2786
+ pageItems = computed(() => {
2787
+ const total = this.pageCount();
2788
+ const current = this.page();
2789
+ const siblings = this.siblingCount();
2790
+ if (total <= 1)
2791
+ return [{ type: 'page', page: 1 }];
2792
+ const items = [];
2793
+ // Always include first page
2794
+ items.push({ type: 'page', page: 1 });
2795
+ const left = Math.max(2, current - siblings);
2796
+ const right = Math.min(total - 1, current + siblings);
2797
+ // Left ellipsis
2798
+ if (left > 2) {
2799
+ items.push({ type: 'ellipsis', key: 'ellipsis-start' });
2800
+ }
2801
+ // Middle pages
2802
+ for (let p = left; p <= right; p++) {
2803
+ items.push({ type: 'page', page: p });
2804
+ }
2805
+ // Right ellipsis
2806
+ if (right < total - 1) {
2807
+ items.push({ type: 'ellipsis', key: 'ellipsis-end' });
2808
+ }
2809
+ // Always include last page
2810
+ items.push({ type: 'page', page: total });
2811
+ return items;
2812
+ }, ...(ngDevMode ? [{ debugName: "pageItems" }] : /* istanbul ignore next */ []));
2813
+ goTo(p) {
2814
+ const clamped = Math.min(Math.max(p, 1), this.pageCount());
2815
+ this.page.set(clamped);
2816
+ }
2817
+ goPrev() {
2818
+ this.goTo(this.page() - 1);
2819
+ }
2820
+ goNext() {
2821
+ this.goTo(this.page() + 1);
2822
+ }
2823
+ goFirst() {
2824
+ this.goTo(1);
2825
+ }
2826
+ goLast() {
2827
+ this.goTo(this.pageCount());
2828
+ }
2829
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmPagination, deps: [], target: i0.ɵɵFactoryTarget.Component });
2830
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: LlmPagination, isStandalone: true, selector: "llm-pagination", inputs: { page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, pageCount: { classPropertyName: "pageCount", publicName: "pageCount", isSignal: true, isRequired: false, transformFunction: null }, siblingCount: { classPropertyName: "siblingCount", publicName: "siblingCount", isSignal: true, isRequired: false, transformFunction: null }, showFirstLast: { classPropertyName: "showFirstLast", publicName: "showFirstLast", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { page: "pageChange" }, ngImport: i0, template: `
2831
+ <nav aria-label="Pagination">
2832
+ <ul role="list" class="page-list">
2833
+ @if (showFirstLast()) {
2834
+ <li>
2835
+ <button
2836
+ class="page-btn"
2837
+ [class.is-disabled]="page() <= 1"
2838
+ [disabled]="page() <= 1"
2839
+ aria-label="First page"
2840
+ (click)="goFirst()"
2841
+ >«</button>
2842
+ </li>
2843
+ }
2844
+ <li>
2845
+ <button
2846
+ class="page-btn"
2847
+ [class.is-disabled]="page() <= 1"
2848
+ [disabled]="page() <= 1"
2849
+ aria-label="Previous page"
2850
+ (click)="goPrev()"
2851
+ >‹</button>
2852
+ </li>
2853
+
2854
+ @for (item of pageItems(); track $index) {
2855
+ @if (item.type === 'page') {
2856
+ <li>
2857
+ <button
2858
+ class="page-btn"
2859
+ [class.is-active]="item.page === page()"
2860
+ [attr.aria-current]="item.page === page() ? 'page' : null"
2861
+ [attr.aria-label]="'Page ' + item.page"
2862
+ (click)="goTo(item.page)"
2863
+ >{{ item.page }}</button>
2864
+ </li>
2865
+ } @else {
2866
+ <li>
2867
+ <span class="ellipsis" aria-hidden="true">…</span>
2868
+ </li>
2869
+ }
2870
+ }
2871
+
2872
+ <li>
2873
+ <button
2874
+ class="page-btn"
2875
+ [class.is-disabled]="page() >= pageCount()"
2876
+ [disabled]="page() >= pageCount()"
2877
+ aria-label="Next page"
2878
+ (click)="goNext()"
2879
+ >›</button>
2880
+ </li>
2881
+ @if (showFirstLast()) {
2882
+ <li>
2883
+ <button
2884
+ class="page-btn"
2885
+ [class.is-disabled]="page() >= pageCount()"
2886
+ [disabled]="page() >= pageCount()"
2887
+ aria-label="Last page"
2888
+ (click)="goLast()"
2889
+ >»</button>
2890
+ </li>
2891
+ }
2892
+ </ul>
2893
+ </nav>
2894
+ `, isInline: true, styles: [":host{display:block;font-family:var(--ui-font-family)}nav{display:block}.page-list{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-spacing-1);list-style:none;margin:0;padding:0}.page-btn{all:unset;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:var(--ui-radius-md);border:1px solid var(--ui-color-border);background:var(--ui-color-surface);color:var(--ui-color-text);font-size:var(--ui-font-size-sm);font-weight:var(--ui-font-weight-medium);cursor:pointer;-webkit-user-select:none;user-select:none;transition:background-color var(--ui-transition-fast),border-color var(--ui-transition-fast),color var(--ui-transition-fast)}.page-btn:hover:not(:disabled){background-color:var(--ui-color-surface-sunken);border-color:var(--ui-color-border-hover)}.page-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}.page-btn.is-active{background-color:var(--ui-color-primary);border-color:var(--ui-color-primary);color:var(--ui-color-text-on-primary)}.page-btn.is-active:hover{background-color:var(--ui-color-primary-hover);border-color:var(--ui-color-primary-hover)}.page-btn.is-disabled,.page-btn:disabled{opacity:.4;pointer-events:none;cursor:default}.ellipsis{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;color:var(--ui-color-text-muted);font-size:var(--ui-font-size-sm);-webkit-user-select:none;user-select:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2895
+ }
2896
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmPagination, decorators: [{
2897
+ type: Component,
2898
+ args: [{ selector: 'llm-pagination', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
2899
+ <nav aria-label="Pagination">
2900
+ <ul role="list" class="page-list">
2901
+ @if (showFirstLast()) {
2902
+ <li>
2903
+ <button
2904
+ class="page-btn"
2905
+ [class.is-disabled]="page() <= 1"
2906
+ [disabled]="page() <= 1"
2907
+ aria-label="First page"
2908
+ (click)="goFirst()"
2909
+ >«</button>
2910
+ </li>
2911
+ }
2912
+ <li>
2913
+ <button
2914
+ class="page-btn"
2915
+ [class.is-disabled]="page() <= 1"
2916
+ [disabled]="page() <= 1"
2917
+ aria-label="Previous page"
2918
+ (click)="goPrev()"
2919
+ >‹</button>
2920
+ </li>
2921
+
2922
+ @for (item of pageItems(); track $index) {
2923
+ @if (item.type === 'page') {
2924
+ <li>
2925
+ <button
2926
+ class="page-btn"
2927
+ [class.is-active]="item.page === page()"
2928
+ [attr.aria-current]="item.page === page() ? 'page' : null"
2929
+ [attr.aria-label]="'Page ' + item.page"
2930
+ (click)="goTo(item.page)"
2931
+ >{{ item.page }}</button>
2932
+ </li>
2933
+ } @else {
2934
+ <li>
2935
+ <span class="ellipsis" aria-hidden="true">…</span>
2936
+ </li>
2937
+ }
2938
+ }
2939
+
2940
+ <li>
2941
+ <button
2942
+ class="page-btn"
2943
+ [class.is-disabled]="page() >= pageCount()"
2944
+ [disabled]="page() >= pageCount()"
2945
+ aria-label="Next page"
2946
+ (click)="goNext()"
2947
+ >›</button>
2948
+ </li>
2949
+ @if (showFirstLast()) {
2950
+ <li>
2951
+ <button
2952
+ class="page-btn"
2953
+ [class.is-disabled]="page() >= pageCount()"
2954
+ [disabled]="page() >= pageCount()"
2955
+ aria-label="Last page"
2956
+ (click)="goLast()"
2957
+ >»</button>
2958
+ </li>
2959
+ }
2960
+ </ul>
2961
+ </nav>
2962
+ `, styles: [":host{display:block;font-family:var(--ui-font-family)}nav{display:block}.page-list{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-spacing-1);list-style:none;margin:0;padding:0}.page-btn{all:unset;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border-radius:var(--ui-radius-md);border:1px solid var(--ui-color-border);background:var(--ui-color-surface);color:var(--ui-color-text);font-size:var(--ui-font-size-sm);font-weight:var(--ui-font-weight-medium);cursor:pointer;-webkit-user-select:none;user-select:none;transition:background-color var(--ui-transition-fast),border-color var(--ui-transition-fast),color var(--ui-transition-fast)}.page-btn:hover:not(:disabled){background-color:var(--ui-color-surface-sunken);border-color:var(--ui-color-border-hover)}.page-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}.page-btn.is-active{background-color:var(--ui-color-primary);border-color:var(--ui-color-primary);color:var(--ui-color-text-on-primary)}.page-btn.is-active:hover{background-color:var(--ui-color-primary-hover);border-color:var(--ui-color-primary-hover)}.page-btn.is-disabled,.page-btn:disabled{opacity:.4;pointer-events:none;cursor:default}.ellipsis{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;color:var(--ui-color-text-muted);font-size:var(--ui-font-size-sm);-webkit-user-select:none;user-select:none}\n"] }]
2963
+ }], propDecorators: { page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }, { type: i0.Output, args: ["pageChange"] }], pageCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageCount", required: false }] }], siblingCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "siblingCount", required: false }] }], showFirstLast: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFirstLast", required: false }] }] } });
2964
+
2965
+ const LLM_DRAWER = new InjectionToken('LLM_DRAWER');
2966
+
2967
+ let nextId = 0;
2968
+ /**
2969
+ * Slide-in drawer panel using the native `<dialog>` element.
2970
+ * Supports left, right, top, and bottom positions with focus trap,
2971
+ * Escape to close, and backdrop click to close.
2972
+ * Compose with `llm-drawer-header`, `llm-drawer-content`, and `llm-drawer-footer`.
2973
+ *
2974
+ * Usage:
2975
+ * ```html
2976
+ * <llm-button (click)="isOpen = true">Open</llm-button>
2977
+ * <llm-drawer [(open)]="isOpen" position="right">
2978
+ * <llm-drawer-header>Settings</llm-drawer-header>
2979
+ * <llm-drawer-content>Content here.</llm-drawer-content>
2980
+ * <llm-drawer-footer>
2981
+ * <llm-button variant="primary" (click)="isOpen = false">Save</llm-button>
2982
+ * </llm-drawer-footer>
2983
+ * </llm-drawer>
2984
+ * ```
2985
+ */
2986
+ class LlmDrawer {
2987
+ /** Whether the drawer is open. Supports two-way binding: [(open)]="isOpen". */
2988
+ open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
2989
+ /** Which edge the drawer slides in from. */
2990
+ position = input('right', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
2991
+ /** Width (for left/right) or height (for top/bottom) of the panel. */
2992
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
2993
+ /** Whether clicking the backdrop closes the drawer. */
2994
+ closeOnBackdrop = input(true, ...(ngDevMode ? [{ debugName: "closeOnBackdrop" }] : /* istanbul ignore next */ []));
2995
+ /** @internal — referenced by LlmDrawerHeader via LLM_DRAWER token */
2996
+ headerId = `llm-drawer-header-${nextId}`;
2997
+ drawerId = `llm-drawer-${nextId++}`;
2998
+ dialogRef = viewChild('dialogEl', ...(ngDevMode ? [{ debugName: "dialogRef" }] : /* istanbul ignore next */ []));
2999
+ triggerEl = signal(null, ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
3000
+ hostClasses = computed(() => `position-${this.position()} size-${this.size()}${this.open() ? ' is-open' : ''}`, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
3001
+ constructor() {
3002
+ effect(() => {
3003
+ const dialog = this.dialogRef()?.nativeElement;
3004
+ if (!dialog)
3005
+ return;
3006
+ if (this.open()) {
3007
+ this.triggerEl.set(document.activeElement);
3008
+ dialog.showModal();
3009
+ }
3010
+ else {
3011
+ if (dialog.open)
3012
+ dialog.close();
3013
+ this.triggerEl()?.focus();
3014
+ this.triggerEl.set(null);
3015
+ }
3016
+ });
3017
+ }
3018
+ onCancel(event) {
3019
+ event.preventDefault();
3020
+ this.open.set(false);
3021
+ }
3022
+ onBackdropClick(event) {
3023
+ if (this.closeOnBackdrop() && event.target === this.dialogRef()?.nativeElement) {
3024
+ this.open.set(false);
3025
+ }
3026
+ }
3027
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDrawer, deps: [], target: i0.ɵɵFactoryTarget.Component });
3028
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.4", type: LlmDrawer, isStandalone: true, selector: "llm-drawer", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdrop: { classPropertyName: "closeOnBackdrop", publicName: "closeOnBackdrop", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { properties: { "class": "hostClasses()" } }, providers: [
3029
+ {
3030
+ provide: LLM_DRAWER,
3031
+ useFactory: (drawer) => ({
3032
+ headerId: drawer.headerId,
3033
+ close: () => drawer.open.set(false),
3034
+ }),
3035
+ deps: [LlmDrawer],
3036
+ },
3037
+ ], viewQueries: [{ propertyName: "dialogRef", first: true, predicate: ["dialogEl"], descendants: true, isSignal: true }], ngImport: i0, template: `
3038
+ <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
3039
+ <dialog
3040
+ #dialogEl
3041
+ [attr.aria-labelledby]="headerId"
3042
+ aria-modal="true"
3043
+ [cdkTrapFocus]="open()"
3044
+ (cancel)="onCancel($event)"
3045
+ (close)="open.set(false)"
3046
+ (click)="onBackdropClick($event)"
3047
+ >
3048
+ <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
3049
+ <div class="panel" (click)="$event.stopPropagation()">
3050
+ <ng-content />
3051
+ </div>
3052
+ </dialog>
3053
+ `, isInline: true, styles: ["llm-drawer{display:contents}dialog{all:unset;position:fixed;display:none;flex-direction:column;background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;transition:transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;transform:translate(0)!important}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden}:host(.position-right) dialog{inset:0 0 0 auto;height:100dvh;transform:translate(100%)}@starting-style{:host(.position-right) dialog[open]{transform:translate(100%)}}:host(.position-left) dialog{inset:0 auto 0 0;height:100dvh;transform:translate(-100%)}@starting-style{:host(.position-left) dialog[open]{transform:translate(-100%)}}:host(.position-top) dialog{inset:0 0 auto;width:100vw;transform:translateY(-100%)}@starting-style{:host(.position-top) dialog[open]{transform:translateY(-100%)}}:host(.position-bottom) dialog{inset:auto 0 0;width:100vw;transform:translateY(100%)}@starting-style{:host(.position-bottom) dialog[open]{transform:translateY(100%)}}:host(.position-right.size-sm) dialog,:host(.position-left.size-sm) dialog{width:20rem}:host(.position-right.size-md) dialog,:host(.position-left.size-md) dialog{width:28rem}:host(.position-right.size-lg) dialog,:host(.position-left.size-lg) dialog{width:40rem}:host(.position-right.size-full) dialog,:host(.position-left.size-full) dialog{width:100vw}:host(.position-top.size-sm) dialog,:host(.position-bottom.size-sm) dialog{height:12rem}:host(.position-top.size-md) dialog,:host(.position-bottom.size-md) dialog{height:20rem}:host(.position-top.size-lg) dialog,:host(.position-bottom.size-lg) dialog{height:32rem}:host(.position-top.size-full) dialog,:host(.position-bottom.size-full) dialog{height:100dvh}llm-drawer-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-drawer-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-drawer-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"], dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i1$1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3054
+ }
3055
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDrawer, decorators: [{
3056
+ type: Component,
3057
+ args: [{ selector: 'llm-drawer', standalone: true, imports: [A11yModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
3058
+ {
3059
+ provide: LLM_DRAWER,
3060
+ useFactory: (drawer) => ({
3061
+ headerId: drawer.headerId,
3062
+ close: () => drawer.open.set(false),
3063
+ }),
3064
+ deps: [LlmDrawer],
3065
+ },
3066
+ ], template: `
3067
+ <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
3068
+ <dialog
3069
+ #dialogEl
3070
+ [attr.aria-labelledby]="headerId"
3071
+ aria-modal="true"
3072
+ [cdkTrapFocus]="open()"
3073
+ (cancel)="onCancel($event)"
3074
+ (close)="open.set(false)"
3075
+ (click)="onBackdropClick($event)"
3076
+ >
3077
+ <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
3078
+ <div class="panel" (click)="$event.stopPropagation()">
3079
+ <ng-content />
3080
+ </div>
3081
+ </dialog>
3082
+ `, host: {
3083
+ '[class]': 'hostClasses()',
3084
+ }, styles: ["llm-drawer{display:contents}dialog{all:unset;position:fixed;display:none;flex-direction:column;background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;transition:transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;transform:translate(0)!important}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden}:host(.position-right) dialog{inset:0 0 0 auto;height:100dvh;transform:translate(100%)}@starting-style{:host(.position-right) dialog[open]{transform:translate(100%)}}:host(.position-left) dialog{inset:0 auto 0 0;height:100dvh;transform:translate(-100%)}@starting-style{:host(.position-left) dialog[open]{transform:translate(-100%)}}:host(.position-top) dialog{inset:0 0 auto;width:100vw;transform:translateY(-100%)}@starting-style{:host(.position-top) dialog[open]{transform:translateY(-100%)}}:host(.position-bottom) dialog{inset:auto 0 0;width:100vw;transform:translateY(100%)}@starting-style{:host(.position-bottom) dialog[open]{transform:translateY(100%)}}:host(.position-right.size-sm) dialog,:host(.position-left.size-sm) dialog{width:20rem}:host(.position-right.size-md) dialog,:host(.position-left.size-md) dialog{width:28rem}:host(.position-right.size-lg) dialog,:host(.position-left.size-lg) dialog{width:40rem}:host(.position-right.size-full) dialog,:host(.position-left.size-full) dialog{width:100vw}:host(.position-top.size-sm) dialog,:host(.position-bottom.size-sm) dialog{height:12rem}:host(.position-top.size-md) dialog,:host(.position-bottom.size-md) dialog{height:20rem}:host(.position-top.size-lg) dialog,:host(.position-bottom.size-lg) dialog{height:32rem}:host(.position-top.size-full) dialog,:host(.position-bottom.size-full) dialog{height:100dvh}llm-drawer-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-drawer-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-drawer-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"] }]
3085
+ }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], closeOnBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdrop", required: false }] }], dialogRef: [{ type: i0.ViewChild, args: ['dialogEl', { isSignal: true }] }] } });
3086
+ /**
3087
+ * Header slot for `llm-drawer`. Contains the title and a close button.
3088
+ * Automatically receives the correct `id` for `aria-labelledby` association.
3089
+ */
3090
+ class LlmDrawerHeader {
3091
+ context = inject(LLM_DRAWER);
3092
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDrawerHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
3093
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmDrawerHeader, isStandalone: true, selector: "llm-drawer-header", host: { properties: { "attr.id": "context.headerId" } }, ngImport: i0, template: `
3094
+ <ng-content />
3095
+ <button
3096
+ class="close-btn"
3097
+ type="button"
3098
+ aria-label="Close drawer"
3099
+ (click)="context.close()"
3100
+ >
3101
+ <svg
3102
+ xmlns="http://www.w3.org/2000/svg"
3103
+ width="14"
3104
+ height="14"
3105
+ viewBox="0 0 24 24"
3106
+ fill="none"
3107
+ stroke="currentColor"
3108
+ stroke-width="2.5"
3109
+ stroke-linecap="round"
3110
+ stroke-linejoin="round"
3111
+ aria-hidden="true"
3112
+ focusable="false"
3113
+ >
3114
+ <line x1="18" y1="6" x2="6" y2="18" />
3115
+ <line x1="6" y1="6" x2="18" y2="18" />
3116
+ </svg>
3117
+ </button>
3118
+ `, isInline: true, styles: ["llm-drawer{display:contents}dialog{all:unset;position:fixed;display:none;flex-direction:column;background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;transition:transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;transform:translate(0)!important}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden}:host(.position-right) dialog{inset:0 0 0 auto;height:100dvh;transform:translate(100%)}@starting-style{:host(.position-right) dialog[open]{transform:translate(100%)}}:host(.position-left) dialog{inset:0 auto 0 0;height:100dvh;transform:translate(-100%)}@starting-style{:host(.position-left) dialog[open]{transform:translate(-100%)}}:host(.position-top) dialog{inset:0 0 auto;width:100vw;transform:translateY(-100%)}@starting-style{:host(.position-top) dialog[open]{transform:translateY(-100%)}}:host(.position-bottom) dialog{inset:auto 0 0;width:100vw;transform:translateY(100%)}@starting-style{:host(.position-bottom) dialog[open]{transform:translateY(100%)}}:host(.position-right.size-sm) dialog,:host(.position-left.size-sm) dialog{width:20rem}:host(.position-right.size-md) dialog,:host(.position-left.size-md) dialog{width:28rem}:host(.position-right.size-lg) dialog,:host(.position-left.size-lg) dialog{width:40rem}:host(.position-right.size-full) dialog,:host(.position-left.size-full) dialog{width:100vw}:host(.position-top.size-sm) dialog,:host(.position-bottom.size-sm) dialog{height:12rem}:host(.position-top.size-md) dialog,:host(.position-bottom.size-md) dialog{height:20rem}:host(.position-top.size-lg) dialog,:host(.position-bottom.size-lg) dialog{height:32rem}:host(.position-top.size-full) dialog,:host(.position-bottom.size-full) dialog{height:100dvh}llm-drawer-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-drawer-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-drawer-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3119
+ }
3120
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDrawerHeader, decorators: [{
3121
+ type: Component,
3122
+ args: [{ selector: 'llm-drawer-header', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
3123
+ <ng-content />
3124
+ <button
3125
+ class="close-btn"
3126
+ type="button"
3127
+ aria-label="Close drawer"
3128
+ (click)="context.close()"
3129
+ >
3130
+ <svg
3131
+ xmlns="http://www.w3.org/2000/svg"
3132
+ width="14"
3133
+ height="14"
3134
+ viewBox="0 0 24 24"
3135
+ fill="none"
3136
+ stroke="currentColor"
3137
+ stroke-width="2.5"
3138
+ stroke-linecap="round"
3139
+ stroke-linejoin="round"
3140
+ aria-hidden="true"
3141
+ focusable="false"
3142
+ >
3143
+ <line x1="18" y1="6" x2="6" y2="18" />
3144
+ <line x1="6" y1="6" x2="18" y2="18" />
3145
+ </svg>
3146
+ </button>
3147
+ `, host: {
3148
+ '[attr.id]': 'context.headerId',
3149
+ }, styles: ["llm-drawer{display:contents}dialog{all:unset;position:fixed;display:none;flex-direction:column;background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;transition:transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;transform:translate(0)!important}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden}:host(.position-right) dialog{inset:0 0 0 auto;height:100dvh;transform:translate(100%)}@starting-style{:host(.position-right) dialog[open]{transform:translate(100%)}}:host(.position-left) dialog{inset:0 auto 0 0;height:100dvh;transform:translate(-100%)}@starting-style{:host(.position-left) dialog[open]{transform:translate(-100%)}}:host(.position-top) dialog{inset:0 0 auto;width:100vw;transform:translateY(-100%)}@starting-style{:host(.position-top) dialog[open]{transform:translateY(-100%)}}:host(.position-bottom) dialog{inset:auto 0 0;width:100vw;transform:translateY(100%)}@starting-style{:host(.position-bottom) dialog[open]{transform:translateY(100%)}}:host(.position-right.size-sm) dialog,:host(.position-left.size-sm) dialog{width:20rem}:host(.position-right.size-md) dialog,:host(.position-left.size-md) dialog{width:28rem}:host(.position-right.size-lg) dialog,:host(.position-left.size-lg) dialog{width:40rem}:host(.position-right.size-full) dialog,:host(.position-left.size-full) dialog{width:100vw}:host(.position-top.size-sm) dialog,:host(.position-bottom.size-sm) dialog{height:12rem}:host(.position-top.size-md) dialog,:host(.position-bottom.size-md) dialog{height:20rem}:host(.position-top.size-lg) dialog,:host(.position-bottom.size-lg) dialog{height:32rem}:host(.position-top.size-full) dialog,:host(.position-bottom.size-full) dialog{height:100dvh}llm-drawer-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-drawer-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-drawer-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"] }]
3150
+ }] });
3151
+ /**
3152
+ * Content slot for `llm-drawer`. Scrollable primary content area.
3153
+ */
3154
+ class LlmDrawerContent {
3155
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDrawerContent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3156
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmDrawerContent, isStandalone: true, selector: "llm-drawer-content", ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["llm-drawer{display:contents}dialog{all:unset;position:fixed;display:none;flex-direction:column;background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;transition:transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;transform:translate(0)!important}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden}:host(.position-right) dialog{inset:0 0 0 auto;height:100dvh;transform:translate(100%)}@starting-style{:host(.position-right) dialog[open]{transform:translate(100%)}}:host(.position-left) dialog{inset:0 auto 0 0;height:100dvh;transform:translate(-100%)}@starting-style{:host(.position-left) dialog[open]{transform:translate(-100%)}}:host(.position-top) dialog{inset:0 0 auto;width:100vw;transform:translateY(-100%)}@starting-style{:host(.position-top) dialog[open]{transform:translateY(-100%)}}:host(.position-bottom) dialog{inset:auto 0 0;width:100vw;transform:translateY(100%)}@starting-style{:host(.position-bottom) dialog[open]{transform:translateY(100%)}}:host(.position-right.size-sm) dialog,:host(.position-left.size-sm) dialog{width:20rem}:host(.position-right.size-md) dialog,:host(.position-left.size-md) dialog{width:28rem}:host(.position-right.size-lg) dialog,:host(.position-left.size-lg) dialog{width:40rem}:host(.position-right.size-full) dialog,:host(.position-left.size-full) dialog{width:100vw}:host(.position-top.size-sm) dialog,:host(.position-bottom.size-sm) dialog{height:12rem}:host(.position-top.size-md) dialog,:host(.position-bottom.size-md) dialog{height:20rem}:host(.position-top.size-lg) dialog,:host(.position-bottom.size-lg) dialog{height:32rem}:host(.position-top.size-full) dialog,:host(.position-bottom.size-full) dialog{height:100dvh}llm-drawer-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-drawer-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-drawer-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3157
+ }
3158
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDrawerContent, decorators: [{
3159
+ type: Component,
3160
+ args: [{ selector: 'llm-drawer-content', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, styles: ["llm-drawer{display:contents}dialog{all:unset;position:fixed;display:none;flex-direction:column;background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;transition:transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;transform:translate(0)!important}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden}:host(.position-right) dialog{inset:0 0 0 auto;height:100dvh;transform:translate(100%)}@starting-style{:host(.position-right) dialog[open]{transform:translate(100%)}}:host(.position-left) dialog{inset:0 auto 0 0;height:100dvh;transform:translate(-100%)}@starting-style{:host(.position-left) dialog[open]{transform:translate(-100%)}}:host(.position-top) dialog{inset:0 0 auto;width:100vw;transform:translateY(-100%)}@starting-style{:host(.position-top) dialog[open]{transform:translateY(-100%)}}:host(.position-bottom) dialog{inset:auto 0 0;width:100vw;transform:translateY(100%)}@starting-style{:host(.position-bottom) dialog[open]{transform:translateY(100%)}}:host(.position-right.size-sm) dialog,:host(.position-left.size-sm) dialog{width:20rem}:host(.position-right.size-md) dialog,:host(.position-left.size-md) dialog{width:28rem}:host(.position-right.size-lg) dialog,:host(.position-left.size-lg) dialog{width:40rem}:host(.position-right.size-full) dialog,:host(.position-left.size-full) dialog{width:100vw}:host(.position-top.size-sm) dialog,:host(.position-bottom.size-sm) dialog{height:12rem}:host(.position-top.size-md) dialog,:host(.position-bottom.size-md) dialog{height:20rem}:host(.position-top.size-lg) dialog,:host(.position-bottom.size-lg) dialog{height:32rem}:host(.position-top.size-full) dialog,:host(.position-bottom.size-full) dialog{height:100dvh}llm-drawer-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-drawer-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-drawer-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"] }]
3161
+ }] });
3162
+ /**
3163
+ * Footer slot for `llm-drawer`. Renders at the bottom with action buttons.
3164
+ */
3165
+ class LlmDrawerFooter {
3166
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDrawerFooter, deps: [], target: i0.ɵɵFactoryTarget.Component });
3167
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: LlmDrawerFooter, isStandalone: true, selector: "llm-drawer-footer", ngImport: i0, template: `<ng-content />`, isInline: true, styles: ["llm-drawer{display:contents}dialog{all:unset;position:fixed;display:none;flex-direction:column;background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;transition:transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;transform:translate(0)!important}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden}:host(.position-right) dialog{inset:0 0 0 auto;height:100dvh;transform:translate(100%)}@starting-style{:host(.position-right) dialog[open]{transform:translate(100%)}}:host(.position-left) dialog{inset:0 auto 0 0;height:100dvh;transform:translate(-100%)}@starting-style{:host(.position-left) dialog[open]{transform:translate(-100%)}}:host(.position-top) dialog{inset:0 0 auto;width:100vw;transform:translateY(-100%)}@starting-style{:host(.position-top) dialog[open]{transform:translateY(-100%)}}:host(.position-bottom) dialog{inset:auto 0 0;width:100vw;transform:translateY(100%)}@starting-style{:host(.position-bottom) dialog[open]{transform:translateY(100%)}}:host(.position-right.size-sm) dialog,:host(.position-left.size-sm) dialog{width:20rem}:host(.position-right.size-md) dialog,:host(.position-left.size-md) dialog{width:28rem}:host(.position-right.size-lg) dialog,:host(.position-left.size-lg) dialog{width:40rem}:host(.position-right.size-full) dialog,:host(.position-left.size-full) dialog{width:100vw}:host(.position-top.size-sm) dialog,:host(.position-bottom.size-sm) dialog{height:12rem}:host(.position-top.size-md) dialog,:host(.position-bottom.size-md) dialog{height:20rem}:host(.position-top.size-lg) dialog,:host(.position-bottom.size-lg) dialog{height:32rem}:host(.position-top.size-full) dialog,:host(.position-bottom.size-full) dialog{height:100dvh}llm-drawer-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-drawer-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-drawer-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3168
+ }
3169
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: LlmDrawerFooter, decorators: [{
3170
+ type: Component,
3171
+ args: [{ selector: 'llm-drawer-footer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<ng-content />`, styles: ["llm-drawer{display:contents}dialog{all:unset;position:fixed;display:none;flex-direction:column;background:var(--ui-color-surface);box-shadow:var(--ui-shadow-xl, 0 20px 60px rgba(0, 0, 0, .3));color:var(--ui-color-text);overflow:hidden;transition:transform var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}dialog[open]{display:flex;transform:translate(0)!important}dialog::backdrop{background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);transition:opacity var(--ui-duration-slow) var(--ui-ease-out, ease-out),display var(--ui-duration-slow) allow-discrete,overlay var(--ui-duration-slow) allow-discrete}@starting-style{dialog[open]::backdrop{opacity:0}}@media(prefers-color-scheme:dark){dialog::backdrop{background:#000000b3}}[data-theme=dark] dialog::backdrop{background:#000000b3}.panel{display:flex;flex-direction:column;width:100%;height:100%;overflow:hidden}:host(.position-right) dialog{inset:0 0 0 auto;height:100dvh;transform:translate(100%)}@starting-style{:host(.position-right) dialog[open]{transform:translate(100%)}}:host(.position-left) dialog{inset:0 auto 0 0;height:100dvh;transform:translate(-100%)}@starting-style{:host(.position-left) dialog[open]{transform:translate(-100%)}}:host(.position-top) dialog{inset:0 0 auto;width:100vw;transform:translateY(-100%)}@starting-style{:host(.position-top) dialog[open]{transform:translateY(-100%)}}:host(.position-bottom) dialog{inset:auto 0 0;width:100vw;transform:translateY(100%)}@starting-style{:host(.position-bottom) dialog[open]{transform:translateY(100%)}}:host(.position-right.size-sm) dialog,:host(.position-left.size-sm) dialog{width:20rem}:host(.position-right.size-md) dialog,:host(.position-left.size-md) dialog{width:28rem}:host(.position-right.size-lg) dialog,:host(.position-left.size-lg) dialog{width:40rem}:host(.position-right.size-full) dialog,:host(.position-left.size-full) dialog{width:100vw}:host(.position-top.size-sm) dialog,:host(.position-bottom.size-sm) dialog{height:12rem}:host(.position-top.size-md) dialog,:host(.position-bottom.size-md) dialog{height:20rem}:host(.position-top.size-lg) dialog,:host(.position-bottom.size-lg) dialog{height:32rem}:host(.position-top.size-full) dialog,:host(.position-bottom.size-full) dialog{height:100dvh}llm-drawer-header{display:flex;align-items:center;justify-content:space-between;padding:var(--ui-spacing-4) var(--ui-spacing-5);border-bottom:1px solid var(--ui-color-border);font-size:var(--ui-font-size-xl);font-weight:600;letter-spacing:var(--ui-letter-spacing-tight);color:var(--ui-color-text);flex-shrink:0}llm-drawer-content{display:block;padding:var(--ui-spacing-5);overflow-y:auto;flex:1;color:var(--ui-color-text)}llm-drawer-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--ui-spacing-2);padding:var(--ui-spacing-4) var(--ui-spacing-5);border-top:1px solid var(--ui-color-border);flex-shrink:0}.close-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;margin-left:var(--ui-spacing-3);background:transparent;border:none;border-radius:var(--ui-radius-sm);cursor:pointer;color:var(--ui-color-text-muted);transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast);line-height:1}.close-btn:hover{background-color:var(--ui-color-surface-sunken);color:var(--ui-color-text)}.close-btn:focus-visible{outline:none;box-shadow:var(--ui-focus-ring)}\n"] }]
3172
+ }] });
3173
+
3174
+ // Design tokens stylesheet — consumers should import:
3175
+ // @import '@atelier-ui/angular/styles/tokens.css';
3176
+
3177
+ /**
3178
+ * Generated bundle index. Do not edit.
3179
+ */
3180
+
3181
+ export { LLM_ACCORDION_GROUP, LLM_BREADCRUMBS, LLM_DIALOG, LLM_DRAWER, LLM_RADIO_GROUP, LLM_SELECT, LLM_TAB_GROUP, LlmAccordionGroup, LlmAccordionHeader, LlmAccordionItem, LlmAlert, LlmAvatar, LlmAvatarGroup, LlmBadge, LlmBreadcrumbItem, LlmBreadcrumbs, LlmButton, LlmCard, LlmCardContent, LlmCardFooter, LlmCardHeader, LlmCheckbox, LlmDialog, LlmDialogContent, LlmDialogFooter, LlmDialogHeader, LlmDrawer, LlmDrawerContent, LlmDrawerFooter, LlmDrawerHeader, LlmInput, LlmMenu, LlmMenuItem, LlmMenuSeparator, LlmMenuTrigger, LlmOption, LlmPagination, LlmProgress, LlmRadio, LlmRadioGroup, LlmSelect, LlmSkeleton, LlmTab, LlmTabGroup, LlmTextarea, LlmToast, LlmToastContainer, LlmToastService, LlmToggle, LlmTooltip };
3182
+ //# sourceMappingURL=atelier-ui-angular.mjs.map