@magicx-eng/ai-autocomplete-angular 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +1 -0
  2. package/esm2020/lib/ai-autocomplete/ai-autocomplete.component.mjs +75 -29
  3. package/esm2020/lib/ai-autocomplete-dropdown/ai-autocomplete-dropdown.component.mjs +46 -12
  4. package/esm2020/lib/controller/ai-autocomplete.controller.mjs +89 -7
  5. package/esm2020/lib/input/ai-autocomplete-input.directive.mjs +85 -6
  6. package/esm2020/lib/internal/editor-host/editor-host.directive.mjs +4 -2
  7. package/esm2020/lib/internal/layout/cluster.component.mjs +45 -0
  8. package/esm2020/lib/internal/layout/grid.component.mjs +95 -0
  9. package/esm2020/lib/internal/layout/stack.component.mjs +29 -0
  10. package/esm2020/lib/internal/pill-list/pill-list.component.mjs +8 -8
  11. package/esm2020/lib/internal/submit-button/submit-button.component.mjs +29 -0
  12. package/esm2020/lib/internal/suggestion-grid/suggestion-grid.component.mjs +10 -62
  13. package/esm2020/lib/internal/suggestion-item/suggestion-item.component.mjs +3 -3
  14. package/esm2020/lib/shared/types.mjs +1 -1
  15. package/fesm2015/magicx-eng-ai-autocomplete-angular.mjs +503 -125
  16. package/fesm2015/magicx-eng-ai-autocomplete-angular.mjs.map +1 -1
  17. package/fesm2020/magicx-eng-ai-autocomplete-angular.mjs +495 -120
  18. package/fesm2020/magicx-eng-ai-autocomplete-angular.mjs.map +1 -1
  19. package/lib/ai-autocomplete/ai-autocomplete.component.d.ts +11 -3
  20. package/lib/ai-autocomplete/ai-autocomplete.component.d.ts.map +1 -1
  21. package/lib/ai-autocomplete-dropdown/ai-autocomplete-dropdown.component.d.ts +29 -12
  22. package/lib/ai-autocomplete-dropdown/ai-autocomplete-dropdown.component.d.ts.map +1 -1
  23. package/lib/controller/ai-autocomplete.controller.d.ts.map +1 -1
  24. package/lib/input/ai-autocomplete-input.directive.d.ts +15 -0
  25. package/lib/input/ai-autocomplete-input.directive.d.ts.map +1 -1
  26. package/lib/internal/editor-host/editor-host.directive.d.ts.map +1 -1
  27. package/lib/internal/layout/cluster.component.d.ts +23 -0
  28. package/lib/internal/layout/cluster.component.d.ts.map +1 -0
  29. package/lib/internal/layout/grid.component.d.ts +43 -0
  30. package/lib/internal/layout/grid.component.d.ts.map +1 -0
  31. package/lib/internal/layout/stack.component.d.ts +16 -0
  32. package/lib/internal/layout/stack.component.d.ts.map +1 -0
  33. package/lib/internal/pill-list/pill-list.component.d.ts +2 -2
  34. package/lib/internal/pill-list/pill-list.component.d.ts.map +1 -1
  35. package/lib/internal/submit-button/submit-button.component.d.ts +17 -0
  36. package/lib/internal/submit-button/submit-button.component.d.ts.map +1 -0
  37. package/lib/internal/suggestion-grid/suggestion-grid.component.d.ts +7 -20
  38. package/lib/internal/suggestion-grid/suggestion-grid.component.d.ts.map +1 -1
  39. package/lib/shared/types.d.ts +2 -0
  40. package/lib/shared/types.d.ts.map +1 -1
  41. package/package.json +5 -5
@@ -1,16 +1,86 @@
1
1
  import * as i1 from '@angular/common';
2
2
  import { CommonModule, isPlatformBrowser } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { EventEmitter, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, Output, inject, ChangeDetectorRef, NgZone, ViewChild, ElementRef, Renderer2, Directive, PLATFORM_ID, forwardRef, NgModule } from '@angular/core';
4
+ import { Component, ChangeDetectionStrategy, ViewEncapsulation, Input, EventEmitter, Output, inject, NgZone, ChangeDetectorRef, ViewChild, ElementRef, Renderer2, Directive, PLATFORM_ID, forwardRef, NgModule } from '@angular/core';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
- import { AIAutocomplete, getCursorOffset, extractPlainText, renderEditableContent, plainTextLength, setCursorOffset, ModeController, buildQuery } from '@magicx-eng/ai-autocomplete-vanilla';
6
+ import { getFooterHint, AIAutocomplete, getCursorOffset, extractPlainText, renderEditableContent, plainTextLength, setCursorOffset, ModeController, buildQuery } from '@magicx-eng/ai-autocomplete-vanilla';
7
+ import { BehaviorSubject, combineLatest, map as map$1, distinctUntilChanged, shareReplay, Subject, takeUntil } from 'rxjs';
7
8
  import { map } from 'rxjs/operators';
8
- import { map as map$1, distinctUntilChanged, shareReplay, BehaviorSubject, Subject, takeUntil } from 'rxjs';
9
+
10
+ /**
11
+ * Horizontal layout primitive — children sit in a row and wrap when out of
12
+ * room. Mirrors the React `<Cluster>` component / vanilla `.aia-cluster` CSS
13
+ * primitive. `noWrap` keeps a single row; `inline` makes it inline-level.
14
+ *
15
+ * @internal
16
+ */
17
+ class ClusterComponent {
18
+ constructor() {
19
+ /** Cross-axis alignment. Defaults to `center`. */
20
+ this.align = "center";
21
+ /** Main-axis distribution. Defaults to `start`. */
22
+ this.justify = "start";
23
+ /** When true, the cluster does NOT flex-wrap (single-row clusters). */
24
+ this.noWrap = false;
25
+ /** Render inline-level (inline-flex) instead of block. */
26
+ this.inline = false;
27
+ }
28
+ }
29
+ ClusterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ClusterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
30
+ ClusterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: ClusterComponent, isStandalone: true, selector: "aia-cluster", inputs: { gap: "gap", align: "align", justify: "justify", noWrap: "noWrap", inline: "inline" }, host: { properties: { "attr.data-align": "align", "attr.data-justify": "justify", "attr.data-nowrap": "noWrap ? '' : null", "attr.data-inline": "inline ? '' : null", "style.--aia-cluster-gap": "gap" }, classAttribute: "aia-cluster" }, ngImport: i0, template: "<ng-content></ng-content>", isInline: true, styles: ["@layer layout{.aia-cluster{display:flex;flex-wrap:wrap;gap:var(--aia-cluster-gap, .5rem)}.aia-cluster[data-inline]{display:inline-flex}.aia-cluster[data-nowrap]{flex-wrap:nowrap}.aia-cluster[data-align=start]{align-items:start}.aia-cluster[data-align=center]{align-items:center}.aia-cluster[data-align=end]{align-items:end}.aia-cluster[data-align=baseline]{align-items:baseline}.aia-cluster[data-justify=start]{justify-content:start}.aia-cluster[data-justify=center]{justify-content:center}.aia-cluster[data-justify=end]{justify-content:end}.aia-cluster[data-justify=between]{justify-content:space-between}.aia-cluster[data-justify=around]{justify-content:space-around}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
31
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ClusterComponent, decorators: [{
32
+ type: Component,
33
+ args: [{ selector: "aia-cluster", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<ng-content></ng-content>", host: {
34
+ class: "aia-cluster",
35
+ "[attr.data-align]": "align",
36
+ "[attr.data-justify]": "justify",
37
+ "[attr.data-nowrap]": "noWrap ? '' : null",
38
+ "[attr.data-inline]": "inline ? '' : null",
39
+ "[style.--aia-cluster-gap]": "gap",
40
+ }, styles: ["@layer layout{.aia-cluster{display:flex;flex-wrap:wrap;gap:var(--aia-cluster-gap, .5rem)}.aia-cluster[data-inline]{display:inline-flex}.aia-cluster[data-nowrap]{flex-wrap:nowrap}.aia-cluster[data-align=start]{align-items:start}.aia-cluster[data-align=center]{align-items:center}.aia-cluster[data-align=end]{align-items:end}.aia-cluster[data-align=baseline]{align-items:baseline}.aia-cluster[data-justify=start]{justify-content:start}.aia-cluster[data-justify=center]{justify-content:center}.aia-cluster[data-justify=end]{justify-content:end}.aia-cluster[data-justify=between]{justify-content:space-between}.aia-cluster[data-justify=around]{justify-content:space-around}}\n"] }]
41
+ }], propDecorators: { gap: [{
42
+ type: Input
43
+ }], align: [{
44
+ type: Input
45
+ }], justify: [{
46
+ type: Input
47
+ }], noWrap: [{
48
+ type: Input
49
+ }], inline: [{
50
+ type: Input
51
+ }] } });
52
+
53
+ /**
54
+ * Vertical layout primitive — children stack top-to-bottom with `space` gap.
55
+ * Mirrors the React `<Stack>` component / vanilla `.aia-stack` CSS primitive.
56
+ *
57
+ * @internal
58
+ */
59
+ class StackComponent {
60
+ constructor() {
61
+ /** Cross-axis alignment of children. Defaults to `stretch` (full width). */
62
+ this.align = "stretch";
63
+ }
64
+ }
65
+ StackComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: StackComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
66
+ StackComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: StackComponent, isStandalone: true, selector: "aia-stack", inputs: { space: "space", align: "align" }, host: { properties: { "attr.data-align": "align", "style.--aia-stack-space": "space" }, classAttribute: "aia-stack" }, ngImport: i0, template: "<ng-content></ng-content>", isInline: true, styles: ["@layer layout{.aia-stack{display:flex;flex-direction:column;gap:var(--aia-stack-space, .5rem)}.aia-stack[data-align=start]{align-items:start}.aia-stack[data-align=center]{align-items:center}.aia-stack[data-align=end]{align-items:end}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
67
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: StackComponent, decorators: [{
68
+ type: Component,
69
+ args: [{ selector: "aia-stack", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<ng-content></ng-content>", host: {
70
+ class: "aia-stack",
71
+ "[attr.data-align]": "align",
72
+ "[style.--aia-stack-space]": "space",
73
+ }, styles: ["@layer layout{.aia-stack{display:flex;flex-direction:column;gap:var(--aia-stack-space, .5rem)}.aia-stack[data-align=start]{align-items:start}.aia-stack[data-align=center]{align-items:center}.aia-stack[data-align=end]{align-items:end}}\n"] }]
74
+ }], propDecorators: { space: [{
75
+ type: Input
76
+ }], align: [{
77
+ type: Input
78
+ }] } });
9
79
 
10
80
  /**
11
81
  * Internal pill list used by both the dropdown and Tier 1's inline pillbar.
12
82
  * Mirrors `packages/react/src/components/PillList.tsx` one-for-one — including
13
- * the per-index opacity ramp (0.4 / 0.3 / 0.15) and the skeleton-loading
83
+ * the per-index opacity ramp (1 / 0.4 / 0.2) and the skeleton-loading
14
84
  * fallback that preserves layout while the next fetch is in flight.
15
85
  *
16
86
  * @internal
@@ -33,13 +103,13 @@ class PillListComponent {
33
103
  this.trackByType = (_, pill) => pill.type;
34
104
  this.trackByWidth = (_, w) => w;
35
105
  }
36
- /** Per-index opacity ramp — mirrors PillList.tsx `getPillOpacity`. */
106
+ /** Per-index opacity ramp — mirrors PillList.tsx `PILL_OPACITY`. */
37
107
  pillOpacity(index) {
38
108
  if (index === 0)
39
- return 0.4;
109
+ return 1;
40
110
  if (index === 1)
41
- return 0.3;
42
- return 0.15;
111
+ return 0.4;
112
+ return 0.2;
43
113
  }
44
114
  onPillClick(index) {
45
115
  if (this.loading)
@@ -52,10 +122,10 @@ class PillListComponent {
52
122
  }
53
123
  }
54
124
  PillListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PillListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
55
- PillListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: PillListComponent, isStandalone: true, selector: "aia-pill-list", inputs: { pills: "pills", activePillIndex: "activePillIndex", rounded: "rounded", loading: "loading" }, outputs: { selectPill: "selectPill" }, ngImport: i0, template: "<ng-container *ngIf=\"loading && pills.length === 0; else realPills\">\n <span class=\"aia-pill-list\" data-aia-pill-list-loading=\"\">\n <span\n *ngFor=\"let w of fallbackSkeletonWidths; trackBy: trackByWidth; let i = index\"\n data-aia-pill-skeleton=\"\"\n class=\"aia-pill aia-pill-skeleton\"\n [class.aia-pill-rounded]=\"rounded\"\n [style.width.px]=\"w\"\n [style.opacity]=\"pillOpacity(i)\"\n ></span>\n </span>\n</ng-container>\n\n<ng-template #realPills>\n <span\n class=\"aia-pill-list\"\n [attr.data-aia-pill-list-loading]=\"loading ? '' : null\"\n >\n <button\n *ngFor=\"let pill of pills; trackBy: trackByType; let i = index\"\n type=\"button\"\n data-aia-pill=\"\"\n [attr.data-aia-loading]=\"loading ? '' : null\"\n tabindex=\"-1\"\n class=\"aia-pill\"\n [class.aia-pill-rounded]=\"rounded\"\n [class.aia-pill-active]=\"i === activePillIndex && !loading\"\n [class.aia-pill-skeleton]=\"loading\"\n [style.opacity]=\"pillOpacity(i)\"\n [disabled]=\"loading\"\n (mousedown)=\"onPillMouseDown($event)\"\n (click)=\"onPillClick(i)\"\n >\n {{ pill.text }}\n </button>\n </span>\n</ng-template>\n", styles: [".aia-pill-list{position:relative;z-index:1;pointer-events:auto;display:inline-flex;gap:5px;align-items:center;vertical-align:middle}.aia-pill{display:inline-flex;align-items:center;justify-content:center;height:36px;padding:13px;border:none;border-radius:999px;background:rgba(49,50,85,.25);background:color-mix(in srgb,var(--aia-pill-bg, var(--aia-color-background-supportive, #313255)) 25%,transparent);color:var(--aia-pill-color, var(--aia-color-text-muted, #c1c4cb));font-family:inherit;font-size:var(--aia-pill-font-size, 19px);line-height:30px;cursor:pointer;white-space:nowrap;animation:aiaPillFadeIn .4s cubic-bezier(.4,0,.2,1) forwards;box-shadow:#fff -3.2px -3.2px 3.2px -3.2px inset,#fff 6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset,#ffffff26 -1.6px 0 0 -1.6px inset,#ffffff26 0 -1.6px 0 -1.6px inset,#ffffff4d 0 1.6px inset,#ffffff4d 1.6px 0 inset,inset 0 0 30px 5px #0000000d,#00000014 0 0 30px 2px;backdrop-filter:blur(30px)}.aia-pill-rounded{border-radius:999px}.aia-pill-skeleton{pointer-events:none;cursor:default;color:transparent;animation:aiaPillSkeletonPulse 1.4s ease-in-out infinite}.aia-pill:hover{filter:brightness(1.2)}.aia-pill-active{outline:1px solid #5a5b8a}@keyframes aiaPillFadeIn{0%{opacity:0}}@keyframes aiaPillSkeletonPulse{0%,to{filter:brightness(1)}50%{filter:brightness(.55)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
125
+ PillListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: PillListComponent, isStandalone: true, selector: "aia-pill-list", inputs: { pills: "pills", activePillIndex: "activePillIndex", rounded: "rounded", loading: "loading" }, outputs: { selectPill: "selectPill" }, ngImport: i0, template: "<ng-container *ngIf=\"loading && pills.length === 0; else realPills\">\n <span class=\"aia-pill-list\" data-aia-pill-list-loading=\"\">\n <span\n *ngFor=\"let w of fallbackSkeletonWidths; trackBy: trackByWidth; let i = index\"\n data-aia-pill-skeleton=\"\"\n class=\"aia-pill aia-pill-skeleton\"\n [class.aia-pill-rounded]=\"rounded\"\n [style.width.px]=\"w\"\n [style.opacity]=\"pillOpacity(i)\"\n ></span>\n </span>\n</ng-container>\n\n<ng-template #realPills>\n <span\n class=\"aia-pill-list\"\n [attr.data-aia-pill-list-loading]=\"loading ? '' : null\"\n >\n <button\n *ngFor=\"let pill of pills; trackBy: trackByType; let i = index\"\n type=\"button\"\n data-aia-pill=\"\"\n [attr.data-aia-loading]=\"loading ? '' : null\"\n tabindex=\"-1\"\n class=\"aia-pill\"\n [class.aia-pill-rounded]=\"rounded\"\n [class.aia-pill-active]=\"i === activePillIndex && !loading\"\n [class.aia-pill-skeleton]=\"loading\"\n [style.opacity]=\"pillOpacity(i)\"\n [disabled]=\"loading\"\n (mousedown)=\"onPillMouseDown($event)\"\n (click)=\"onPillClick(i)\"\n >\n {{ pill.text }}\n </button>\n </span>\n</ng-template>\n", styles: [".aia-pill-list{position:relative;z-index:1;pointer-events:auto;display:inline-flex;gap:7px;align-items:center;vertical-align:middle}.aia-pill{display:inline-flex;align-items:center;justify-content:center;height:38px;padding:10px 12px;border:none;border-radius:999px;background:rgba(49,50,85,.25);background:color-mix(in srgb,var(--aia-pill-bg, var(--aia-color-background-supportive, #313255)) 30%,transparent);color:var(--aia-pill-color, var(--aia-color-text-muted, #c1c4cb));font-family:inherit;font-size:var(--aia-pill-font-size, 19px);line-height:30px;cursor:pointer;white-space:nowrap;animation:aiaPillFadeIn .4s cubic-bezier(.4,0,.2,1) forwards}.aia-pill-rounded{border-radius:999px}.aia-pill-skeleton{pointer-events:none;cursor:default;color:transparent;animation:aiaPillSkeletonPulse 1.4s ease-in-out infinite}@keyframes aiaPillFadeIn{0%{opacity:0}}@keyframes aiaPillSkeletonPulse{0%,to{filter:brightness(1)}50%{filter:brightness(.55)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
56
126
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PillListComponent, decorators: [{
57
127
  type: Component,
58
- args: [{ selector: "aia-pill-list", standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<ng-container *ngIf=\"loading && pills.length === 0; else realPills\">\n <span class=\"aia-pill-list\" data-aia-pill-list-loading=\"\">\n <span\n *ngFor=\"let w of fallbackSkeletonWidths; trackBy: trackByWidth; let i = index\"\n data-aia-pill-skeleton=\"\"\n class=\"aia-pill aia-pill-skeleton\"\n [class.aia-pill-rounded]=\"rounded\"\n [style.width.px]=\"w\"\n [style.opacity]=\"pillOpacity(i)\"\n ></span>\n </span>\n</ng-container>\n\n<ng-template #realPills>\n <span\n class=\"aia-pill-list\"\n [attr.data-aia-pill-list-loading]=\"loading ? '' : null\"\n >\n <button\n *ngFor=\"let pill of pills; trackBy: trackByType; let i = index\"\n type=\"button\"\n data-aia-pill=\"\"\n [attr.data-aia-loading]=\"loading ? '' : null\"\n tabindex=\"-1\"\n class=\"aia-pill\"\n [class.aia-pill-rounded]=\"rounded\"\n [class.aia-pill-active]=\"i === activePillIndex && !loading\"\n [class.aia-pill-skeleton]=\"loading\"\n [style.opacity]=\"pillOpacity(i)\"\n [disabled]=\"loading\"\n (mousedown)=\"onPillMouseDown($event)\"\n (click)=\"onPillClick(i)\"\n >\n {{ pill.text }}\n </button>\n </span>\n</ng-template>\n", styles: [".aia-pill-list{position:relative;z-index:1;pointer-events:auto;display:inline-flex;gap:5px;align-items:center;vertical-align:middle}.aia-pill{display:inline-flex;align-items:center;justify-content:center;height:36px;padding:13px;border:none;border-radius:999px;background:rgba(49,50,85,.25);background:color-mix(in srgb,var(--aia-pill-bg, var(--aia-color-background-supportive, #313255)) 25%,transparent);color:var(--aia-pill-color, var(--aia-color-text-muted, #c1c4cb));font-family:inherit;font-size:var(--aia-pill-font-size, 19px);line-height:30px;cursor:pointer;white-space:nowrap;animation:aiaPillFadeIn .4s cubic-bezier(.4,0,.2,1) forwards;box-shadow:#fff -3.2px -3.2px 3.2px -3.2px inset,#fff 6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset,#ffffff26 -1.6px 0 0 -1.6px inset,#ffffff26 0 -1.6px 0 -1.6px inset,#ffffff4d 0 1.6px inset,#ffffff4d 1.6px 0 inset,inset 0 0 30px 5px #0000000d,#00000014 0 0 30px 2px;backdrop-filter:blur(30px)}.aia-pill-rounded{border-radius:999px}.aia-pill-skeleton{pointer-events:none;cursor:default;color:transparent;animation:aiaPillSkeletonPulse 1.4s ease-in-out infinite}.aia-pill:hover{filter:brightness(1.2)}.aia-pill-active{outline:1px solid #5a5b8a}@keyframes aiaPillFadeIn{0%{opacity:0}}@keyframes aiaPillSkeletonPulse{0%,to{filter:brightness(1)}50%{filter:brightness(.55)}}\n"] }]
128
+ args: [{ selector: "aia-pill-list", standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<ng-container *ngIf=\"loading && pills.length === 0; else realPills\">\n <span class=\"aia-pill-list\" data-aia-pill-list-loading=\"\">\n <span\n *ngFor=\"let w of fallbackSkeletonWidths; trackBy: trackByWidth; let i = index\"\n data-aia-pill-skeleton=\"\"\n class=\"aia-pill aia-pill-skeleton\"\n [class.aia-pill-rounded]=\"rounded\"\n [style.width.px]=\"w\"\n [style.opacity]=\"pillOpacity(i)\"\n ></span>\n </span>\n</ng-container>\n\n<ng-template #realPills>\n <span\n class=\"aia-pill-list\"\n [attr.data-aia-pill-list-loading]=\"loading ? '' : null\"\n >\n <button\n *ngFor=\"let pill of pills; trackBy: trackByType; let i = index\"\n type=\"button\"\n data-aia-pill=\"\"\n [attr.data-aia-loading]=\"loading ? '' : null\"\n tabindex=\"-1\"\n class=\"aia-pill\"\n [class.aia-pill-rounded]=\"rounded\"\n [class.aia-pill-active]=\"i === activePillIndex && !loading\"\n [class.aia-pill-skeleton]=\"loading\"\n [style.opacity]=\"pillOpacity(i)\"\n [disabled]=\"loading\"\n (mousedown)=\"onPillMouseDown($event)\"\n (click)=\"onPillClick(i)\"\n >\n {{ pill.text }}\n </button>\n </span>\n</ng-template>\n", styles: [".aia-pill-list{position:relative;z-index:1;pointer-events:auto;display:inline-flex;gap:7px;align-items:center;vertical-align:middle}.aia-pill{display:inline-flex;align-items:center;justify-content:center;height:38px;padding:10px 12px;border:none;border-radius:999px;background:rgba(49,50,85,.25);background:color-mix(in srgb,var(--aia-pill-bg, var(--aia-color-background-supportive, #313255)) 30%,transparent);color:var(--aia-pill-color, var(--aia-color-text-muted, #c1c4cb));font-family:inherit;font-size:var(--aia-pill-font-size, 19px);line-height:30px;cursor:pointer;white-space:nowrap;animation:aiaPillFadeIn .4s cubic-bezier(.4,0,.2,1) forwards}.aia-pill-rounded{border-radius:999px}.aia-pill-skeleton{pointer-events:none;cursor:default;color:transparent;animation:aiaPillSkeletonPulse 1.4s ease-in-out infinite}@keyframes aiaPillFadeIn{0%{opacity:0}}@keyframes aiaPillSkeletonPulse{0%,to{filter:brightness(1)}50%{filter:brightness(.55)}}\n"] }]
59
129
  }], propDecorators: { pills: [{
60
130
  type: Input
61
131
  }], activePillIndex: [{
@@ -68,6 +138,102 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
68
138
  type: Output
69
139
  }] } });
70
140
 
141
+ /**
142
+ * Intrinsic grid layout primitive — auto-fits as many columns as fit between
143
+ * `min` and `max` wide, wrapping to new rows when there's no more horizontal
144
+ * room. Mirrors the React `<Grid>` component / vanilla `.aia-grid` primitive.
145
+ *
146
+ * Optionally scrolls (`scroll`, capped height) with a bottom fade overlay
147
+ * (`fade`) that appears while there's hidden overflow below. The fade is driven
148
+ * by a ResizeObserver + scroll listener + MutationObserver (for projected
149
+ * content changes) — all run outside Angular's zone so high-frequency layout
150
+ * events don't trip change detection (mirrors the former SuggestionGrid).
151
+ *
152
+ * @internal
153
+ */
154
+ class GridComponent {
155
+ constructor() {
156
+ /** Minimum cell width. CSS length, e.g. "16rem". Columns auto-fit at runtime. */
157
+ this.min = "16rem";
158
+ /** Cap the height and scroll vertically when content overflows. */
159
+ this.scroll = false;
160
+ /** Show a bottom fade overlay while the grid has hidden overflow below. */
161
+ this.fade = false;
162
+ this.hasBottomOverflow = false;
163
+ this.zone = inject(NgZone);
164
+ this.cdr = inject(ChangeDetectorRef);
165
+ }
166
+ ngAfterViewInit() {
167
+ if (!this.fade)
168
+ return;
169
+ this.bindOverflowTracking();
170
+ this.measureOverflow();
171
+ }
172
+ ngOnDestroy() {
173
+ var _a, _b;
174
+ (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
175
+ (_b = this.mutationObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
176
+ if (this.scrollListener && this.gridRef) {
177
+ this.gridRef.nativeElement.removeEventListener("scroll", this.scrollListener);
178
+ }
179
+ }
180
+ bindOverflowTracking() {
181
+ var _a;
182
+ const grid = (_a = this.gridRef) === null || _a === void 0 ? void 0 : _a.nativeElement;
183
+ if (!grid)
184
+ return;
185
+ this.zone.runOutsideAngular(() => {
186
+ this.scrollListener = () => this.measureOverflow();
187
+ grid.addEventListener("scroll", this.scrollListener, { passive: true });
188
+ if (typeof ResizeObserver !== "undefined") {
189
+ this.resizeObserver = new ResizeObserver(() => this.measureOverflow());
190
+ this.resizeObserver.observe(grid);
191
+ }
192
+ // Projected option count changes don't resize the capped grid box, so
193
+ // ResizeObserver misses them — watch the child list directly to match
194
+ // React's useLayoutEffect-on-options re-measure.
195
+ if (typeof MutationObserver !== "undefined") {
196
+ this.mutationObserver = new MutationObserver(() => this.measureOverflow());
197
+ this.mutationObserver.observe(grid, { childList: true, subtree: true });
198
+ }
199
+ });
200
+ }
201
+ measureOverflow() {
202
+ var _a;
203
+ const grid = (_a = this.gridRef) === null || _a === void 0 ? void 0 : _a.nativeElement;
204
+ if (!grid)
205
+ return;
206
+ const next = grid.scrollHeight - grid.scrollTop - grid.clientHeight > 1;
207
+ if (next !== this.hasBottomOverflow) {
208
+ this.zone.run(() => {
209
+ this.hasBottomOverflow = next;
210
+ this.cdr.markForCheck();
211
+ });
212
+ }
213
+ }
214
+ }
215
+ GridComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: GridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
216
+ GridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: GridComponent, isStandalone: true, selector: "aia-grid", inputs: { min: "min", max: "max", gap: "gap", scroll: "scroll", maxHeight: "maxHeight", fade: "fade" }, viewQueries: [{ propertyName: "gridRef", first: true, predicate: ["grid"], descendants: true }], ngImport: i0, template: "<div [class.aia-grid-fade]=\"fade\" [attr.data-fade]=\"fade && hasBottomOverflow ? '' : null\">\n <div\n #grid\n class=\"aia-grid\"\n [attr.data-scroll]=\"scroll ? '' : null\"\n [style.--aia-grid-min]=\"min\"\n [style.--aia-grid-max]=\"max\"\n [style.--aia-grid-gap]=\"gap\"\n [style.--aia-grid-max-height]=\"maxHeight\"\n >\n <ng-content></ng-content>\n </div>\n</div>\n", styles: ["aia-grid{display:contents}@layer layout{.aia-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(var(--aia-grid-min),100%),var(--aia-grid-max, 1fr)));gap:var(--aia-grid-gap, 0)}.aia-grid[data-scroll]{grid-auto-rows:min-content;align-content:start;justify-content:start;padding:var(--aia-grid-scroll-pad, 0);max-height:var(--aia-grid-max-height, 200px);overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--aia-scrollbar-thumb, rgba(0, 0, 0, .3)) transparent}.aia-grid[data-scroll]::-webkit-scrollbar{width:6px}.aia-grid[data-scroll]::-webkit-scrollbar-track{background:transparent}.aia-grid[data-scroll]::-webkit-scrollbar-thumb{background:var(--aia-scrollbar-thumb, rgba(0, 0, 0, .3));border-radius:3px}.aia-grid-fade{position:relative}.aia-grid-fade:after{content:\"\";position:absolute;left:0;right:0;bottom:0;height:50%;pointer-events:none;opacity:0;transition:opacity .15s ease-out;backdrop-filter:blur(12px);mask-image:linear-gradient(to bottom,transparent,white)}.aia-grid-fade[data-fade]:after{opacity:1}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
217
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: GridComponent, decorators: [{
218
+ type: Component,
219
+ args: [{ selector: "aia-grid", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div [class.aia-grid-fade]=\"fade\" [attr.data-fade]=\"fade && hasBottomOverflow ? '' : null\">\n <div\n #grid\n class=\"aia-grid\"\n [attr.data-scroll]=\"scroll ? '' : null\"\n [style.--aia-grid-min]=\"min\"\n [style.--aia-grid-max]=\"max\"\n [style.--aia-grid-gap]=\"gap\"\n [style.--aia-grid-max-height]=\"maxHeight\"\n >\n <ng-content></ng-content>\n </div>\n</div>\n", styles: ["aia-grid{display:contents}@layer layout{.aia-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(var(--aia-grid-min),100%),var(--aia-grid-max, 1fr)));gap:var(--aia-grid-gap, 0)}.aia-grid[data-scroll]{grid-auto-rows:min-content;align-content:start;justify-content:start;padding:var(--aia-grid-scroll-pad, 0);max-height:var(--aia-grid-max-height, 200px);overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--aia-scrollbar-thumb, rgba(0, 0, 0, .3)) transparent}.aia-grid[data-scroll]::-webkit-scrollbar{width:6px}.aia-grid[data-scroll]::-webkit-scrollbar-track{background:transparent}.aia-grid[data-scroll]::-webkit-scrollbar-thumb{background:var(--aia-scrollbar-thumb, rgba(0, 0, 0, .3));border-radius:3px}.aia-grid-fade{position:relative}.aia-grid-fade:after{content:\"\";position:absolute;left:0;right:0;bottom:0;height:50%;pointer-events:none;opacity:0;transition:opacity .15s ease-out;backdrop-filter:blur(12px);mask-image:linear-gradient(to bottom,transparent,white)}.aia-grid-fade[data-fade]:after{opacity:1}}\n"] }]
220
+ }], propDecorators: { min: [{
221
+ type: Input
222
+ }], max: [{
223
+ type: Input
224
+ }], gap: [{
225
+ type: Input
226
+ }], scroll: [{
227
+ type: Input
228
+ }], maxHeight: [{
229
+ type: Input
230
+ }], fade: [{
231
+ type: Input
232
+ }], gridRef: [{
233
+ type: ViewChild,
234
+ args: ["grid", { static: false }]
235
+ }] } });
236
+
71
237
  /**
72
238
  * Internal single-option cell used inside the suggestion grid. Mirrors
73
239
  * `packages/react/src/components/SuggestionItem.tsx`. Handles:
@@ -122,10 +288,10 @@ class SuggestionItemComponent {
122
288
  }
123
289
  }
124
290
  SuggestionItemComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SuggestionItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
125
- SuggestionItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: SuggestionItemComponent, isStandalone: true, selector: "aia-suggestion-item", inputs: { option: "option", isHighlighted: "isHighlighted", id: "id", loading: "loading" }, outputs: { select: "select", highlight: "highlight" }, ngImport: i0, template: "<div\n [id]=\"id\"\n role=\"option\"\n data-aia-option=\"\"\n [attr.data-aia-loading]=\"loading ? '' : null\"\n [attr.aria-selected]=\"isHighlighted\"\n class=\"aia-suggestion-item\"\n [class.aia-suggestion-item-highlighted]=\"isHighlighted && !loading\"\n [class.aia-suggestion-item-tappable]=\"option.is_tappable\"\n [class.aia-suggestion-item-non-tappable]=\"!option.is_tappable\"\n [class.aia-suggestion-item-pressed]=\"pressed\"\n [attr.tabindex]=\"loading || !option.is_tappable ? -1 : 0\"\n (click)=\"onSelect()\"\n (keydown)=\"onKeyDown($event)\"\n (mouseenter)=\"onMouseEnter()\"\n>\n <div class=\"aia-suggestion-streaks\"></div>\n <div class=\"aia-suggestion-streaks-vert\"></div>\n <span class=\"aia-suggestion-content\">\n <span class=\"aia-suggestion-text\">\n <ng-container *ngIf=\"option.icon; else noIcon\"\n >{{ option.icon }} {{ option.text }}</ng-container\n >\n <ng-template #noIcon>{{ option.text }}</ng-template>\n </span>\n <span *ngIf=\"option.tag\" class=\"aia-suggestion-tag\">{{ option.tag }}</span>\n </span>\n</div>\n", styles: [".aia-suggestion-item{position:relative;overflow:visible;display:flex;align-items:flex-start;font-family:inherit;font-size:var(--aia-option-font-size, 19px);font-weight:250;line-height:24px;color:var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));white-space:normal;word-break:break-word;border-radius:12px;padding:13px;animation:aiaSuggestionFadeIn .5s cubic-bezier(.4,0,.2,1) forwards}@keyframes aiaSuggestionFadeIn{0%{opacity:0}}.aia-suggestion-content{position:relative;z-index:2}.aia-suggestion-item-tappable{cursor:pointer}.aia-suggestion-item-tappable:hover{color:var(--aia-option-color-selected, var(--aia-color-text-default, #fff))}.aia-suggestion-item-non-tappable{cursor:default}.aia-suggestion-item-highlighted{color:var(--aia-option-color-selected, var(--aia-color-text-default, #fff));background:var(--aia-option-bg, transparent)}.aia-suggestion-tag{font-size:11px;margin-left:6px;opacity:.5}.aia-suggestion-item-pressed{opacity:.8;color:var(--aia-color-text-default, #fff);background:rgba(var(--aia-streak-rgb, 255, 255, 255),.06);animation:aiaGlassFade .5s ease forwards,aiaTapDown .5s ease forwards}@keyframes aiaTapDown{0%{transform:scale(1)}30%{transform:scale(.97)}to{transform:scale(1)}}@keyframes aiaGlassFade{0%{background:var(--aia-streak-glass-bg, rgba(255, 255, 255, .1))}to{background:transparent}}.aia-suggestion-streaks{position:absolute;inset:0;z-index:1;pointer-events:none;border-radius:inherit;overflow:hidden}.aia-suggestion-streaks:before{content:\"\";position:absolute;bottom:-3px;left:60%;width:0;height:6px;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.5) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.2) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.2);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks:after{content:\"\";position:absolute;top:-3px;right:60%;width:0;height:6px;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.5) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.2) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.2);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks-vert{position:absolute;inset:0;z-index:1;pointer-events:none;border-radius:inherit;overflow:hidden}.aia-suggestion-streaks-vert:before{content:\"\";position:absolute;bottom:0;right:-3px;width:6px;height:0;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.4) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.15) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.15);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks-vert:after{content:\"\";position:absolute;top:0;left:-3px;width:6px;height:0;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.4) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.15) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.15);filter:blur(1px);border-radius:50%}.aia-suggestion-item-pressed .aia-suggestion-streaks:before{animation:aiaStreakHorizRight .5s cubic-bezier(.4,0,.2,1) forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks:after{animation:aiaStreakHorizLeft .5s cubic-bezier(.4,0,.2,1) forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks-vert:before{animation:aiaStreakVertUp .3s cubic-bezier(.3,0,.2,1) .2s forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks-vert:after{animation:aiaStreakVertDown .3s cubic-bezier(.3,0,.2,1) .2s forwards}@keyframes aiaStreakHorizRight{0%{width:0;height:4px;opacity:0;filter:blur(1px);box-shadow:0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}15%{height:4px;opacity:1;filter:blur(1px);box-shadow:0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}80%{width:50%;height:10px;opacity:.8;filter:blur(3px);box-shadow:0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255),.1)}to{width:50%;height:12px;opacity:0;filter:blur(5px);box-shadow:0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.03)}}@keyframes aiaStreakHorizLeft{0%{width:0;height:4px;opacity:0;filter:blur(1px);box-shadow:0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}15%{height:4px;opacity:1;filter:blur(1px);box-shadow:0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}80%{width:50%;height:10px;opacity:.8;filter:blur(3px);box-shadow:0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255),.1)}to{width:50%;height:12px;opacity:0;filter:blur(5px);box-shadow:0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.03)}}@keyframes aiaStreakVertUp{0%{height:0;width:6px;opacity:.9;filter:blur(1.8px);box-shadow:0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255),.25)}75%{height:100%;width:10px;opacity:.4;filter:blur(3px);box-shadow:0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.06)}to{height:100%;width:14px;opacity:0;filter:blur(5px);box-shadow:0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255),.02)}}@keyframes aiaStreakVertDown{0%{height:0;width:6px;opacity:.9;filter:blur(1.8px);box-shadow:0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255),.25)}75%{height:100%;width:10px;opacity:.4;filter:blur(3px);box-shadow:0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.06)}to{height:100%;width:14px;opacity:0;filter:blur(5px);box-shadow:0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255),.02)}}.aia-suggestion-item[data-aia-loading]{cursor:default;animation:aiaSuggestionSkeletonPulse 1.4s ease-in-out infinite}.aia-suggestion-item[data-aia-loading] .aia-suggestion-text{color:transparent;background:var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, .51)));border-radius:999px;-webkit-box-decoration-break:clone;box-decoration-break:clone}.aia-suggestion-item[data-aia-loading] .aia-suggestion-tag{display:none}@keyframes aiaSuggestionSkeletonPulse{0%,to{filter:brightness(1)}50%{filter:brightness(.55)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
291
+ SuggestionItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: SuggestionItemComponent, isStandalone: true, selector: "aia-suggestion-item", inputs: { option: "option", isHighlighted: "isHighlighted", id: "id", loading: "loading" }, outputs: { select: "select", highlight: "highlight" }, ngImport: i0, template: "<div\n [id]=\"id\"\n role=\"option\"\n data-aia-option=\"\"\n [attr.data-aia-loading]=\"loading ? '' : null\"\n [attr.aria-selected]=\"isHighlighted\"\n class=\"aia-suggestion-item\"\n [class.aia-suggestion-item-highlighted]=\"isHighlighted && !loading\"\n [class.aia-suggestion-item-tappable]=\"option.is_tappable\"\n [class.aia-suggestion-item-non-tappable]=\"!option.is_tappable\"\n [class.aia-suggestion-item-pressed]=\"pressed\"\n [attr.tabindex]=\"loading || !option.is_tappable ? -1 : 0\"\n (click)=\"onSelect()\"\n (keydown)=\"onKeyDown($event)\"\n (mouseenter)=\"onMouseEnter()\"\n>\n <div class=\"aia-suggestion-streaks\"></div>\n <div class=\"aia-suggestion-streaks-vert\"></div>\n <span class=\"aia-suggestion-content\">\n <span class=\"aia-suggestion-text\">\n <ng-container *ngIf=\"option.icon; else noIcon\"\n >{{ option.icon }} {{ option.text }}</ng-container\n >\n <ng-template #noIcon>{{ option.text }}</ng-template>\n </span>\n <span *ngIf=\"option.tag\" class=\"aia-suggestion-tag\">{{ option.tag }}</span>\n </span>\n</div>\n", styles: [".aia-suggestion-item{position:relative;overflow:visible;display:flex;align-items:flex-start;font-family:inherit;font-size:var(--aia-option-font-size, 19px);font-weight:250;line-height:24px;color:var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));white-space:normal;word-break:break-word;border-radius:12px;padding:10px 15px;animation:aiaSuggestionFadeIn .5s cubic-bezier(.4,0,.2,1) forwards}@keyframes aiaSuggestionFadeIn{0%{opacity:0}}.aia-suggestion-content{position:relative;z-index:2}.aia-suggestion-item-tappable{cursor:pointer}.aia-suggestion-item-tappable:hover{color:var(--aia-option-color-selected, var(--aia-color-text-default, #fff))}.aia-suggestion-item-non-tappable{cursor:default}.aia-suggestion-item-highlighted{color:var(--aia-option-color-selected, var(--aia-color-text-default, #fff));background:var(--aia-option-bg, transparent)}.aia-suggestion-tag{font-size:11px;margin-left:6px;opacity:.5}.aia-suggestion-item-pressed{opacity:.8;color:var(--aia-color-text-default, #fff);background:rgba(var(--aia-streak-rgb, 255, 255, 255),.06);animation:aiaGlassFade .5s ease forwards,aiaTapDown .5s ease forwards}@keyframes aiaTapDown{0%{transform:scale(1)}30%{transform:scale(.97)}to{transform:scale(1)}}@keyframes aiaGlassFade{0%{background:var(--aia-streak-glass-bg, rgba(255, 255, 255, .1))}to{background:transparent}}.aia-suggestion-streaks{position:absolute;inset:0;z-index:1;pointer-events:none;border-radius:inherit;overflow:hidden}.aia-suggestion-streaks:before{content:\"\";position:absolute;bottom:-3px;left:60%;width:0;height:6px;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.5) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.2) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.2);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks:after{content:\"\";position:absolute;top:-3px;right:60%;width:0;height:6px;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.5) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.2) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.2);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks-vert{position:absolute;inset:0;z-index:1;pointer-events:none;border-radius:inherit;overflow:hidden}.aia-suggestion-streaks-vert:before{content:\"\";position:absolute;bottom:0;right:-3px;width:6px;height:0;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.4) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.15) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.15);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks-vert:after{content:\"\";position:absolute;top:0;left:-3px;width:6px;height:0;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.4) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.15) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.15);filter:blur(1px);border-radius:50%}.aia-suggestion-item-pressed .aia-suggestion-streaks:before{animation:aiaStreakHorizRight .5s cubic-bezier(.4,0,.2,1) forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks:after{animation:aiaStreakHorizLeft .5s cubic-bezier(.4,0,.2,1) forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks-vert:before{animation:aiaStreakVertUp .3s cubic-bezier(.3,0,.2,1) .2s forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks-vert:after{animation:aiaStreakVertDown .3s cubic-bezier(.3,0,.2,1) .2s forwards}@keyframes aiaStreakHorizRight{0%{width:0;height:4px;opacity:0;filter:blur(1px);box-shadow:0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}15%{height:4px;opacity:1;filter:blur(1px);box-shadow:0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}80%{width:50%;height:10px;opacity:.8;filter:blur(3px);box-shadow:0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255),.1)}to{width:50%;height:12px;opacity:0;filter:blur(5px);box-shadow:0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.03)}}@keyframes aiaStreakHorizLeft{0%{width:0;height:4px;opacity:0;filter:blur(1px);box-shadow:0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}15%{height:4px;opacity:1;filter:blur(1px);box-shadow:0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}80%{width:50%;height:10px;opacity:.8;filter:blur(3px);box-shadow:0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255),.1)}to{width:50%;height:12px;opacity:0;filter:blur(5px);box-shadow:0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.03)}}@keyframes aiaStreakVertUp{0%{height:0;width:6px;opacity:.9;filter:blur(1.8px);box-shadow:0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255),.25)}75%{height:100%;width:10px;opacity:.4;filter:blur(3px);box-shadow:0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.06)}to{height:100%;width:14px;opacity:0;filter:blur(5px);box-shadow:0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255),.02)}}@keyframes aiaStreakVertDown{0%{height:0;width:6px;opacity:.9;filter:blur(1.8px);box-shadow:0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255),.25)}75%{height:100%;width:10px;opacity:.4;filter:blur(3px);box-shadow:0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.06)}to{height:100%;width:14px;opacity:0;filter:blur(5px);box-shadow:0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255),.02)}}.aia-suggestion-item[data-aia-loading]{cursor:default;animation:aiaSuggestionSkeletonPulse 1.4s ease-in-out infinite}.aia-suggestion-item[data-aia-loading] .aia-suggestion-text{color:transparent;background:var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, .51)));border-radius:999px;-webkit-box-decoration-break:clone;box-decoration-break:clone}.aia-suggestion-item[data-aia-loading] .aia-suggestion-tag{display:none}@keyframes aiaSuggestionSkeletonPulse{0%,to{filter:brightness(1)}50%{filter:brightness(.55)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
126
292
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SuggestionItemComponent, decorators: [{
127
293
  type: Component,
128
- args: [{ selector: "aia-suggestion-item", standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n [id]=\"id\"\n role=\"option\"\n data-aia-option=\"\"\n [attr.data-aia-loading]=\"loading ? '' : null\"\n [attr.aria-selected]=\"isHighlighted\"\n class=\"aia-suggestion-item\"\n [class.aia-suggestion-item-highlighted]=\"isHighlighted && !loading\"\n [class.aia-suggestion-item-tappable]=\"option.is_tappable\"\n [class.aia-suggestion-item-non-tappable]=\"!option.is_tappable\"\n [class.aia-suggestion-item-pressed]=\"pressed\"\n [attr.tabindex]=\"loading || !option.is_tappable ? -1 : 0\"\n (click)=\"onSelect()\"\n (keydown)=\"onKeyDown($event)\"\n (mouseenter)=\"onMouseEnter()\"\n>\n <div class=\"aia-suggestion-streaks\"></div>\n <div class=\"aia-suggestion-streaks-vert\"></div>\n <span class=\"aia-suggestion-content\">\n <span class=\"aia-suggestion-text\">\n <ng-container *ngIf=\"option.icon; else noIcon\"\n >{{ option.icon }} {{ option.text }}</ng-container\n >\n <ng-template #noIcon>{{ option.text }}</ng-template>\n </span>\n <span *ngIf=\"option.tag\" class=\"aia-suggestion-tag\">{{ option.tag }}</span>\n </span>\n</div>\n", styles: [".aia-suggestion-item{position:relative;overflow:visible;display:flex;align-items:flex-start;font-family:inherit;font-size:var(--aia-option-font-size, 19px);font-weight:250;line-height:24px;color:var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));white-space:normal;word-break:break-word;border-radius:12px;padding:13px;animation:aiaSuggestionFadeIn .5s cubic-bezier(.4,0,.2,1) forwards}@keyframes aiaSuggestionFadeIn{0%{opacity:0}}.aia-suggestion-content{position:relative;z-index:2}.aia-suggestion-item-tappable{cursor:pointer}.aia-suggestion-item-tappable:hover{color:var(--aia-option-color-selected, var(--aia-color-text-default, #fff))}.aia-suggestion-item-non-tappable{cursor:default}.aia-suggestion-item-highlighted{color:var(--aia-option-color-selected, var(--aia-color-text-default, #fff));background:var(--aia-option-bg, transparent)}.aia-suggestion-tag{font-size:11px;margin-left:6px;opacity:.5}.aia-suggestion-item-pressed{opacity:.8;color:var(--aia-color-text-default, #fff);background:rgba(var(--aia-streak-rgb, 255, 255, 255),.06);animation:aiaGlassFade .5s ease forwards,aiaTapDown .5s ease forwards}@keyframes aiaTapDown{0%{transform:scale(1)}30%{transform:scale(.97)}to{transform:scale(1)}}@keyframes aiaGlassFade{0%{background:var(--aia-streak-glass-bg, rgba(255, 255, 255, .1))}to{background:transparent}}.aia-suggestion-streaks{position:absolute;inset:0;z-index:1;pointer-events:none;border-radius:inherit;overflow:hidden}.aia-suggestion-streaks:before{content:\"\";position:absolute;bottom:-3px;left:60%;width:0;height:6px;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.5) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.2) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.2);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks:after{content:\"\";position:absolute;top:-3px;right:60%;width:0;height:6px;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.5) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.2) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.2);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks-vert{position:absolute;inset:0;z-index:1;pointer-events:none;border-radius:inherit;overflow:hidden}.aia-suggestion-streaks-vert:before{content:\"\";position:absolute;bottom:0;right:-3px;width:6px;height:0;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.4) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.15) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.15);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks-vert:after{content:\"\";position:absolute;top:0;left:-3px;width:6px;height:0;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.4) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.15) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.15);filter:blur(1px);border-radius:50%}.aia-suggestion-item-pressed .aia-suggestion-streaks:before{animation:aiaStreakHorizRight .5s cubic-bezier(.4,0,.2,1) forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks:after{animation:aiaStreakHorizLeft .5s cubic-bezier(.4,0,.2,1) forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks-vert:before{animation:aiaStreakVertUp .3s cubic-bezier(.3,0,.2,1) .2s forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks-vert:after{animation:aiaStreakVertDown .3s cubic-bezier(.3,0,.2,1) .2s forwards}@keyframes aiaStreakHorizRight{0%{width:0;height:4px;opacity:0;filter:blur(1px);box-shadow:0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}15%{height:4px;opacity:1;filter:blur(1px);box-shadow:0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}80%{width:50%;height:10px;opacity:.8;filter:blur(3px);box-shadow:0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255),.1)}to{width:50%;height:12px;opacity:0;filter:blur(5px);box-shadow:0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.03)}}@keyframes aiaStreakHorizLeft{0%{width:0;height:4px;opacity:0;filter:blur(1px);box-shadow:0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}15%{height:4px;opacity:1;filter:blur(1px);box-shadow:0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}80%{width:50%;height:10px;opacity:.8;filter:blur(3px);box-shadow:0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255),.1)}to{width:50%;height:12px;opacity:0;filter:blur(5px);box-shadow:0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.03)}}@keyframes aiaStreakVertUp{0%{height:0;width:6px;opacity:.9;filter:blur(1.8px);box-shadow:0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255),.25)}75%{height:100%;width:10px;opacity:.4;filter:blur(3px);box-shadow:0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.06)}to{height:100%;width:14px;opacity:0;filter:blur(5px);box-shadow:0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255),.02)}}@keyframes aiaStreakVertDown{0%{height:0;width:6px;opacity:.9;filter:blur(1.8px);box-shadow:0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255),.25)}75%{height:100%;width:10px;opacity:.4;filter:blur(3px);box-shadow:0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.06)}to{height:100%;width:14px;opacity:0;filter:blur(5px);box-shadow:0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255),.02)}}.aia-suggestion-item[data-aia-loading]{cursor:default;animation:aiaSuggestionSkeletonPulse 1.4s ease-in-out infinite}.aia-suggestion-item[data-aia-loading] .aia-suggestion-text{color:transparent;background:var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, .51)));border-radius:999px;-webkit-box-decoration-break:clone;box-decoration-break:clone}.aia-suggestion-item[data-aia-loading] .aia-suggestion-tag{display:none}@keyframes aiaSuggestionSkeletonPulse{0%,to{filter:brightness(1)}50%{filter:brightness(.55)}}\n"] }]
294
+ args: [{ selector: "aia-suggestion-item", standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n [id]=\"id\"\n role=\"option\"\n data-aia-option=\"\"\n [attr.data-aia-loading]=\"loading ? '' : null\"\n [attr.aria-selected]=\"isHighlighted\"\n class=\"aia-suggestion-item\"\n [class.aia-suggestion-item-highlighted]=\"isHighlighted && !loading\"\n [class.aia-suggestion-item-tappable]=\"option.is_tappable\"\n [class.aia-suggestion-item-non-tappable]=\"!option.is_tappable\"\n [class.aia-suggestion-item-pressed]=\"pressed\"\n [attr.tabindex]=\"loading || !option.is_tappable ? -1 : 0\"\n (click)=\"onSelect()\"\n (keydown)=\"onKeyDown($event)\"\n (mouseenter)=\"onMouseEnter()\"\n>\n <div class=\"aia-suggestion-streaks\"></div>\n <div class=\"aia-suggestion-streaks-vert\"></div>\n <span class=\"aia-suggestion-content\">\n <span class=\"aia-suggestion-text\">\n <ng-container *ngIf=\"option.icon; else noIcon\"\n >{{ option.icon }} {{ option.text }}</ng-container\n >\n <ng-template #noIcon>{{ option.text }}</ng-template>\n </span>\n <span *ngIf=\"option.tag\" class=\"aia-suggestion-tag\">{{ option.tag }}</span>\n </span>\n</div>\n", styles: [".aia-suggestion-item{position:relative;overflow:visible;display:flex;align-items:flex-start;font-family:inherit;font-size:var(--aia-option-font-size, 19px);font-weight:250;line-height:24px;color:var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));white-space:normal;word-break:break-word;border-radius:12px;padding:10px 15px;animation:aiaSuggestionFadeIn .5s cubic-bezier(.4,0,.2,1) forwards}@keyframes aiaSuggestionFadeIn{0%{opacity:0}}.aia-suggestion-content{position:relative;z-index:2}.aia-suggestion-item-tappable{cursor:pointer}.aia-suggestion-item-tappable:hover{color:var(--aia-option-color-selected, var(--aia-color-text-default, #fff))}.aia-suggestion-item-non-tappable{cursor:default}.aia-suggestion-item-highlighted{color:var(--aia-option-color-selected, var(--aia-color-text-default, #fff));background:var(--aia-option-bg, transparent)}.aia-suggestion-tag{font-size:11px;margin-left:6px;opacity:.5}.aia-suggestion-item-pressed{opacity:.8;color:var(--aia-color-text-default, #fff);background:rgba(var(--aia-streak-rgb, 255, 255, 255),.06);animation:aiaGlassFade .5s ease forwards,aiaTapDown .5s ease forwards}@keyframes aiaTapDown{0%{transform:scale(1)}30%{transform:scale(.97)}to{transform:scale(1)}}@keyframes aiaGlassFade{0%{background:var(--aia-streak-glass-bg, rgba(255, 255, 255, .1))}to{background:transparent}}.aia-suggestion-streaks{position:absolute;inset:0;z-index:1;pointer-events:none;border-radius:inherit;overflow:hidden}.aia-suggestion-streaks:before{content:\"\";position:absolute;bottom:-3px;left:60%;width:0;height:6px;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.5) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.2) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.2);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks:after{content:\"\";position:absolute;top:-3px;right:60%;width:0;height:6px;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.5) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.2) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.2);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks-vert{position:absolute;inset:0;z-index:1;pointer-events:none;border-radius:inherit;overflow:hidden}.aia-suggestion-streaks-vert:before{content:\"\";position:absolute;bottom:0;right:-3px;width:6px;height:0;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.4) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.15) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.15);filter:blur(1px);border-radius:50%}.aia-suggestion-streaks-vert:after{content:\"\";position:absolute;top:0;left:-3px;width:6px;height:0;opacity:0;background:radial-gradient(ellipse at center,rgba(var(--aia-streak-rgb, 255, 255, 255),.4) 0%,rgba(var(--aia-streak-rgb, 255, 255, 255),.15) 40%,transparent 70%);box-shadow:0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.15);filter:blur(1px);border-radius:50%}.aia-suggestion-item-pressed .aia-suggestion-streaks:before{animation:aiaStreakHorizRight .5s cubic-bezier(.4,0,.2,1) forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks:after{animation:aiaStreakHorizLeft .5s cubic-bezier(.4,0,.2,1) forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks-vert:before{animation:aiaStreakVertUp .3s cubic-bezier(.3,0,.2,1) .2s forwards}.aia-suggestion-item-pressed .aia-suggestion-streaks-vert:after{animation:aiaStreakVertDown .3s cubic-bezier(.3,0,.2,1) .2s forwards}@keyframes aiaStreakHorizRight{0%{width:0;height:4px;opacity:0;filter:blur(1px);box-shadow:0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}15%{height:4px;opacity:1;filter:blur(1px);box-shadow:0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}80%{width:50%;height:10px;opacity:.8;filter:blur(3px);box-shadow:0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255),.1)}to{width:50%;height:12px;opacity:0;filter:blur(5px);box-shadow:0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.03)}}@keyframes aiaStreakHorizLeft{0%{width:0;height:4px;opacity:0;filter:blur(1px);box-shadow:0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}15%{height:4px;opacity:1;filter:blur(1px);box-shadow:0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255),.3)}80%{width:50%;height:10px;opacity:.8;filter:blur(3px);box-shadow:0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255),.1)}to{width:50%;height:12px;opacity:0;filter:blur(5px);box-shadow:0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.03)}}@keyframes aiaStreakVertUp{0%{height:0;width:6px;opacity:.9;filter:blur(1.8px);box-shadow:0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255),.25)}75%{height:100%;width:10px;opacity:.4;filter:blur(3px);box-shadow:0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.06)}to{height:100%;width:14px;opacity:0;filter:blur(5px);box-shadow:0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255),.02)}}@keyframes aiaStreakVertDown{0%{height:0;width:6px;opacity:.9;filter:blur(1.8px);box-shadow:0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255),.25)}75%{height:100%;width:10px;opacity:.4;filter:blur(3px);box-shadow:0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255),.06)}to{height:100%;width:14px;opacity:0;filter:blur(5px);box-shadow:0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255),.02)}}.aia-suggestion-item[data-aia-loading]{cursor:default;animation:aiaSuggestionSkeletonPulse 1.4s ease-in-out infinite}.aia-suggestion-item[data-aia-loading] .aia-suggestion-text{color:transparent;background:var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, .51)));border-radius:999px;-webkit-box-decoration-break:clone;box-decoration-break:clone}.aia-suggestion-item[data-aia-loading] .aia-suggestion-tag{display:none}@keyframes aiaSuggestionSkeletonPulse{0%,to{filter:brightness(1)}50%{filter:brightness(.55)}}\n"] }]
129
295
  }], propDecorators: { option: [{
130
296
  type: Input
131
297
  }], isHighlighted: [{
@@ -141,11 +307,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
141
307
  }] } });
142
308
 
143
309
  /**
144
- * Internal scrollable grid of suggestion options. Mirrors
145
- * `packages/react/src/components/SuggestionGrid.tsx` — including the bottom
146
- * fade overlay that appears when there's vertical overflow, driven by a
147
- * ResizeObserver + scroll listener. ResizeObserver runs outside Angular's
148
- * zone (§16.1) so high-frequency layout events don't trip change detection.
310
+ * Internal grid of suggestion options. Mirrors
311
+ * `packages/react/src/components/SuggestionGrid.tsx` — a thin wrapper over the
312
+ * `Grid` layout primitive (which owns the auto-fit columns and the
313
+ * capped-height scroll + bottom-fade). It only wires each option to its
314
+ * select/highlight handlers and listbox-scoped id.
149
315
  *
150
316
  * @internal
151
317
  */
@@ -157,67 +323,14 @@ class SuggestionGridComponent {
157
323
  this.loading = false;
158
324
  this.select = new EventEmitter();
159
325
  this.highlight = new EventEmitter();
160
- this.hasBottomOverflow = false;
161
- this.zone = inject(NgZone);
162
- this.cdr = inject(ChangeDetectorRef);
163
326
  this.trackByOptionText = (_, opt) => opt.text;
164
327
  }
165
- ngAfterViewInit() {
166
- this.bindOverflowTracking();
167
- this.measureOverflow();
168
- }
169
- ngOnChanges() {
170
- // Synchronously re-measure when options change — matches React's
171
- // useLayoutEffect on [options]. ResizeObserver alone misses this case
172
- // because the observed box doesn't grow when the grid hits max-height.
173
- queueMicrotask(() => this.measureOverflow());
174
- }
175
- ngOnDestroy() {
176
- var _a;
177
- (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
178
- if (this.scrollListener && this.gridRef) {
179
- this.gridRef.nativeElement.removeEventListener("scroll", this.scrollListener);
180
- }
181
- }
182
- onSelectItem(option) {
183
- this.select.emit(option);
184
- }
185
- onHighlightItem(index) {
186
- this.highlight.emit(index);
187
- }
188
- bindOverflowTracking() {
189
- var _a;
190
- const grid = (_a = this.gridRef) === null || _a === void 0 ? void 0 : _a.nativeElement;
191
- if (!grid)
192
- return;
193
- this.zone.runOutsideAngular(() => {
194
- this.scrollListener = () => this.measureOverflow();
195
- grid.addEventListener("scroll", this.scrollListener, { passive: true });
196
- if (typeof ResizeObserver !== "undefined") {
197
- this.resizeObserver = new ResizeObserver(() => this.measureOverflow());
198
- this.resizeObserver.observe(grid);
199
- }
200
- });
201
- }
202
- measureOverflow() {
203
- var _a;
204
- const grid = (_a = this.gridRef) === null || _a === void 0 ? void 0 : _a.nativeElement;
205
- if (!grid)
206
- return;
207
- const next = grid.scrollHeight - grid.scrollTop - grid.clientHeight > 1;
208
- if (next !== this.hasBottomOverflow) {
209
- this.zone.run(() => {
210
- this.hasBottomOverflow = next;
211
- this.cdr.markForCheck();
212
- });
213
- }
214
- }
215
328
  }
216
329
  SuggestionGridComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SuggestionGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
217
- SuggestionGridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: SuggestionGridComponent, isStandalone: true, selector: "aia-suggestion-grid", inputs: { options: "options", activeIndex: "activeIndex", listboxId: "listboxId", loading: "loading" }, outputs: { select: "select", highlight: "highlight" }, viewQueries: [{ propertyName: "gridRef", first: true, predicate: ["grid"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"aia-suggestion-grid-scroll\"\n [attr.data-fade]=\"hasBottomOverflow ? '' : null\"\n>\n <div #grid class=\"aia-suggestion-grid\">\n <aia-suggestion-item\n *ngFor=\"let option of options; trackBy: trackByOptionText; let i = index\"\n [option]=\"option\"\n [isHighlighted]=\"i === activeIndex\"\n [id]=\"listboxId + '-option-' + i\"\n [loading]=\"loading\"\n (select)=\"onSelectItem($event)\"\n (highlight)=\"onHighlightItem(i)\"\n >\n </aia-suggestion-item>\n </div>\n</div>\n", styles: [".aia-suggestion-grid-scroll{position:relative}.aia-suggestion-grid-scroll:after{content:\"\";position:absolute;left:0;right:0;bottom:0;height:50%;pointer-events:none;opacity:0;transition:opacity .15s ease-out;backdrop-filter:blur(12px);mask-image:linear-gradient(to bottom,transparent,white)}.aia-suggestion-grid-scroll[data-fade]:after{opacity:1}.aia-suggestion-grid{display:grid;grid-template-columns:minmax(0,250px);grid-auto-rows:min-content;align-content:start;max-width:100cqi;padding:8px;max-height:200px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--aia-scrollbar-thumb, rgba(0, 0, 0, .3)) transparent}@container (min-width: 516px){.aia-suggestion-grid{grid-template-columns:repeat(2,minmax(0,250px));justify-content:start}}.aia-suggestion-grid::-webkit-scrollbar{width:6px}.aia-suggestion-grid::-webkit-scrollbar-track{background:transparent}.aia-suggestion-grid::-webkit-scrollbar-thumb{background:var(--aia-scrollbar-thumb, rgba(0, 0, 0, .3));border-radius:3px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: SuggestionItemComponent, selector: "aia-suggestion-item", inputs: ["option", "isHighlighted", "id", "loading"], outputs: ["select", "highlight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
330
+ SuggestionGridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: SuggestionGridComponent, isStandalone: true, selector: "aia-suggestion-grid", inputs: { options: "options", activeIndex: "activeIndex", listboxId: "listboxId", loading: "loading" }, outputs: { select: "select", highlight: "highlight" }, ngImport: i0, template: "<aia-grid min=\"250px\" max=\"250px\" gap=\"0\" [scroll]=\"true\" [fade]=\"true\">\n <aia-suggestion-item\n *ngFor=\"let option of options; trackBy: trackByOptionText; let i = index\"\n [option]=\"option\"\n [isHighlighted]=\"i === activeIndex\"\n [id]=\"listboxId + '-option-' + i\"\n [loading]=\"loading\"\n (select)=\"select.emit($event)\"\n (highlight)=\"highlight.emit(i)\"\n ></aia-suggestion-item>\n</aia-grid>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: GridComponent, selector: "aia-grid", inputs: ["min", "max", "gap", "scroll", "maxHeight", "fade"] }, { kind: "component", type: SuggestionItemComponent, selector: "aia-suggestion-item", inputs: ["option", "isHighlighted", "id", "loading"], outputs: ["select", "highlight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
218
331
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SuggestionGridComponent, decorators: [{
219
332
  type: Component,
220
- args: [{ selector: "aia-suggestion-grid", standalone: true, imports: [CommonModule, SuggestionItemComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n class=\"aia-suggestion-grid-scroll\"\n [attr.data-fade]=\"hasBottomOverflow ? '' : null\"\n>\n <div #grid class=\"aia-suggestion-grid\">\n <aia-suggestion-item\n *ngFor=\"let option of options; trackBy: trackByOptionText; let i = index\"\n [option]=\"option\"\n [isHighlighted]=\"i === activeIndex\"\n [id]=\"listboxId + '-option-' + i\"\n [loading]=\"loading\"\n (select)=\"onSelectItem($event)\"\n (highlight)=\"onHighlightItem(i)\"\n >\n </aia-suggestion-item>\n </div>\n</div>\n", styles: [".aia-suggestion-grid-scroll{position:relative}.aia-suggestion-grid-scroll:after{content:\"\";position:absolute;left:0;right:0;bottom:0;height:50%;pointer-events:none;opacity:0;transition:opacity .15s ease-out;backdrop-filter:blur(12px);mask-image:linear-gradient(to bottom,transparent,white)}.aia-suggestion-grid-scroll[data-fade]:after{opacity:1}.aia-suggestion-grid{display:grid;grid-template-columns:minmax(0,250px);grid-auto-rows:min-content;align-content:start;max-width:100cqi;padding:8px;max-height:200px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--aia-scrollbar-thumb, rgba(0, 0, 0, .3)) transparent}@container (min-width: 516px){.aia-suggestion-grid{grid-template-columns:repeat(2,minmax(0,250px));justify-content:start}}.aia-suggestion-grid::-webkit-scrollbar{width:6px}.aia-suggestion-grid::-webkit-scrollbar-track{background:transparent}.aia-suggestion-grid::-webkit-scrollbar-thumb{background:var(--aia-scrollbar-thumb, rgba(0, 0, 0, .3));border-radius:3px}\n"] }]
333
+ args: [{ selector: "aia-suggestion-grid", standalone: true, imports: [CommonModule, GridComponent, SuggestionItemComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<aia-grid min=\"250px\" max=\"250px\" gap=\"0\" [scroll]=\"true\" [fade]=\"true\">\n <aia-suggestion-item\n *ngFor=\"let option of options; trackBy: trackByOptionText; let i = index\"\n [option]=\"option\"\n [isHighlighted]=\"i === activeIndex\"\n [id]=\"listboxId + '-option-' + i\"\n [loading]=\"loading\"\n (select)=\"select.emit($event)\"\n (highlight)=\"highlight.emit(i)\"\n ></aia-suggestion-item>\n</aia-grid>\n" }]
221
334
  }], propDecorators: { options: [{
222
335
  type: Input
223
336
  }], activeIndex: [{
@@ -230,9 +343,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
230
343
  type: Output
231
344
  }], highlight: [{
232
345
  type: Output
233
- }], gridRef: [{
234
- type: ViewChild,
235
- args: ["grid", { static: false }]
236
346
  }] } });
237
347
 
238
348
  /**
@@ -256,21 +366,43 @@ class AIAutocompleteDropdownComponent {
256
366
  this.showPills = true;
257
367
  /** Fallback skeleton-bar widths used when loading with zero cached options. */
258
368
  this.fallbackSkeletonBarWidths = [159, 119, 164];
369
+ // Bridge for the @Input `showPills` into the reactive pipeline. Without this,
370
+ // changing the input after init wouldn't trigger a new vm emission until the
371
+ // next controller.dropdown$ tick — and we'd lose the showPills update entirely
372
+ // if the controller is idle. Updated from ngOnChanges below.
373
+ this.showPills$ = new BehaviorSubject(true);
259
374
  this.trackByWidth = (_, w) => w;
260
375
  }
261
- /**
262
- * View-model derived from the controller's `dropdown$`. Adds three booleans
263
- * (`showsPills`, `showsOptions`, `showsFallbackSkeleton`, `isVisible`) that
264
- * keep template-level logic to a property read per §19.6.
265
- */
266
- get vm$() {
267
- return this.controller.dropdown$.pipe(map((dd) => {
268
- var _a, _b;
376
+ ngOnInit() {
377
+ // Seed showPills$ from the input's resolved value at init time.
378
+ this.showPills$.next(this.showPills);
379
+ this.initVm();
380
+ }
381
+ ngOnChanges(changes) {
382
+ if (changes["showPills"]) {
383
+ this.showPills$.next(this.showPills);
384
+ }
385
+ // Re-bind vm$ when the controller @Input is swapped (e.g. a multi-step form
386
+ // toggling between controllers). Without this, vm$ stays subscribed to the
387
+ // previous controller's dropdown$ — rendering stale options, or, if that
388
+ // controller was destroy()-ed, receiving a completion that collapses the
389
+ // dropdown permanently. Skip the first change: ngOnChanges fires before
390
+ // ngOnInit, which owns the initial creation.
391
+ if (changes["controller"] && !changes["controller"].firstChange && this.controller) {
392
+ this.initVm();
393
+ }
394
+ }
395
+ /** Build the view-model stream from the current controller + showPills$. */
396
+ initVm() {
397
+ this.vm$ = combineLatest([this.controller.dropdown$, this.showPills$]).pipe(map(([dd, showPills]) => {
398
+ var _a, _b, _c;
269
399
  const options = (_b = (_a = dd.suggestions[0]) === null || _a === void 0 ? void 0 : _a.options) !== null && _b !== void 0 ? _b : [];
270
- const showsPills = this.showPills && (dd.pills.length > 0 || dd.isLoading);
400
+ const showsPills = showPills && (dd.pills.length > 0 || dd.isLoading);
271
401
  const showsOptions = options.length > 0;
272
402
  const showsFallbackSkeleton = dd.isLoading && !showsOptions;
273
403
  const isVisible = dd.isOpen && (showsOptions || showsPills || dd.isLoading);
404
+ const optionHighlighted = dd.activeIndex >= 0 && Boolean((_c = options[dd.activeIndex]) === null || _c === void 0 ? void 0 : _c.is_tappable);
405
+ const { key: footerKey, hint: footerHint } = getFooterHint(dd.hasTabbedToHighlight, optionHighlighted);
274
406
  return {
275
407
  pills: dd.pills,
276
408
  options,
@@ -280,6 +412,8 @@ class AIAutocompleteDropdownComponent {
280
412
  showsOptions,
281
413
  showsFallbackSkeleton,
282
414
  isVisible,
415
+ footerKey,
416
+ footerHint,
283
417
  };
284
418
  }));
285
419
  }
@@ -298,10 +432,16 @@ class AIAutocompleteDropdownComponent {
298
432
  }
299
433
  }
300
434
  AIAutocompleteDropdownComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: AIAutocompleteDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
301
- AIAutocompleteDropdownComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: AIAutocompleteDropdownComponent, isStandalone: true, selector: "ai-autocomplete-dropdown", inputs: { controller: "controller", showPills: "showPills", className: "className" }, ngImport: i0, template: "<div\n *ngIf=\"vm$ | async as vm\"\n [id]=\"controller.listboxId\"\n role=\"listbox\"\n data-aia-dropdown=\"\"\n [attr.data-aia-loading]=\"vm.isLoading ? '' : null\"\n class=\"magicx-aia-dropdown\"\n [class.magicx-aia-dropdown-visible]=\"vm.isVisible\"\n [class]=\"className ? 'magicx-aia-dropdown ' + className : 'magicx-aia-dropdown'\"\n (mousedown)=\"preventBlur($event)\"\n>\n <div\n *ngIf=\"vm.showsPills\"\n class=\"magicx-aia-dropdown-pillbar\"\n data-aia-pillbar=\"\"\n >\n <aia-pill-list\n [pills]=\"vm.pills\"\n [activePillIndex]=\"0\"\n [rounded]=\"true\"\n [loading]=\"vm.isLoading\"\n (selectPill)=\"onPillClick($event)\"\n ></aia-pill-list>\n </div>\n\n <aia-suggestion-grid\n *ngIf=\"vm.showsOptions\"\n [options]=\"vm.options\"\n [activeIndex]=\"vm.activeIndex\"\n [listboxId]=\"controller.listboxId\"\n [loading]=\"vm.isLoading\"\n (select)=\"onSelect($event)\"\n (highlight)=\"onHighlight($event)\"\n ></aia-suggestion-grid>\n\n <div\n *ngIf=\"vm.showsFallbackSkeleton\"\n class=\"magicx-aia-dropdown-skeleton-bars\"\n data-aia-skeleton-bars=\"\"\n >\n <span\n *ngFor=\"let w of fallbackSkeletonBarWidths; trackBy: trackByWidth\"\n class=\"magicx-aia-dropdown-skeleton-bar\"\n [style.width.px]=\"w\"\n ></span>\n </div>\n</div>\n", styles: [".magicx-aia-dropdown{position:absolute;left:0;right:0;top:100%;max-width:516px;margin-top:6px;display:flex;flex-direction:column;overflow:hidden;container-type:inline-size;z-index:10;opacity:0;pointer-events:none;transition:opacity .4s cubic-bezier(.4,0,.2,1);box-shadow:#fff -3.2px -3.2px 3.2px -3.2px inset,#fff 6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset,#ffffff26 -1.6px 0 0 -1.6px inset,#ffffff26 0 -1.6px 0 -1.6px inset,#ffffff4d 0 1.6px inset,#ffffff4d 1.6px 0 inset,inset 0 0 30px 5px #0000000d,#00000014 0 0 30px 2px;backdrop-filter:blur(30px);border-radius:28px}.magicx-aia-dropdown-visible{opacity:1;pointer-events:auto}.magicx-aia-dropdown-pillbar{padding:27px 27px 3px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 48px),transparent 100%);-webkit-mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 48px),transparent 100%)}.magicx-aia-dropdown-pillbar::-webkit-scrollbar{display:none}.magicx-aia-dropdown-skeleton-bars{display:flex;flex-direction:column;gap:20px;padding:25px}.magicx-aia-dropdown-skeleton-bar{display:block;height:19px;border-radius:999px;background:var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, .51)));opacity:.5;animation:aiaDropdownSkeletonPulse 1.4s ease-in-out infinite}.magicx-aia-dropdown-skeleton-bar:nth-child(2){animation-delay:.15s}.magicx-aia-dropdown-skeleton-bar:nth-child(3){animation-delay:.3s}@keyframes aiaDropdownSkeletonPulse{0%,to{opacity:.5}50%{opacity:.25}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "component", type: PillListComponent, selector: "aia-pill-list", inputs: ["pills", "activePillIndex", "rounded", "loading"], outputs: ["selectPill"] }, { kind: "component", type: SuggestionGridComponent, selector: "aia-suggestion-grid", inputs: ["options", "activeIndex", "listboxId", "loading"], outputs: ["select", "highlight"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
435
+ AIAutocompleteDropdownComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: AIAutocompleteDropdownComponent, isStandalone: true, selector: "ai-autocomplete-dropdown", inputs: { controller: "controller", showPills: "showPills", className: "className" }, usesOnChanges: true, ngImport: i0, template: "<div\n *ngIf=\"vm$ | async as vm\"\n [id]=\"controller.listboxId\"\n role=\"listbox\"\n data-aia-dropdown=\"\"\n [attr.data-aia-loading]=\"vm.isLoading ? '' : null\"\n [class]=\"className ? 'magicx-aia-dropdown ' + className : 'magicx-aia-dropdown'\"\n [class.magicx-aia-dropdown-visible]=\"vm.isVisible\"\n (mousedown)=\"preventBlur($event)\"\n>\n <aia-stack space=\"14px\">\n <aia-cluster\n *ngIf=\"vm.showsPills\"\n class=\"magicx-aia-dropdown-pillbar\"\n data-aia-pillbar=\"\"\n [noWrap]=\"true\"\n >\n <aia-pill-list\n [pills]=\"vm.pills\"\n [activePillIndex]=\"0\"\n [rounded]=\"true\"\n [loading]=\"vm.isLoading\"\n (selectPill)=\"onPillClick($event)\"\n ></aia-pill-list>\n </aia-cluster>\n\n <aia-suggestion-grid\n *ngIf=\"vm.showsOptions\"\n [options]=\"vm.options\"\n [activeIndex]=\"vm.activeIndex\"\n [listboxId]=\"controller.listboxId\"\n [loading]=\"vm.isLoading\"\n (select)=\"onSelect($event)\"\n (highlight)=\"onHighlight($event)\"\n ></aia-suggestion-grid>\n\n <div\n *ngIf=\"vm.showsFallbackSkeleton\"\n class=\"magicx-aia-dropdown-skeleton-bars\"\n data-aia-skeleton-bars=\"\"\n >\n <span\n *ngFor=\"let w of fallbackSkeletonBarWidths; trackBy: trackByWidth\"\n class=\"magicx-aia-dropdown-skeleton-bar\"\n [style.width.px]=\"w\"\n ></span>\n </div>\n\n <footer class=\"magicx-aia-footer\" data-aia-footer=\"\">\n <div class=\"magicx-aia-footer-divider\"></div>\n <div class=\"magicx-aia-footer-row\">\n <span class=\"magicx-aia-footer-hint-group\">\n <kbd class=\"magicx-aia-footer-key\">{{ vm.footerKey }}</kbd>\n <span class=\"magicx-aia-footer-hint\">{{ vm.footerHint }}</span>\n </span>\n <a\n class=\"magicx-aia-footer-brand-link\"\n href=\"https://ai-autocomplete.com\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <span class=\"magicx-aia-footer-brand\">AI</span>\n <span class=\"magicx-aia-footer-badge\">Autocomplete</span>\n </a>\n </div>\n </footer>\n </aia-stack>\n</div>\n", styles: [".magicx-aia-dropdown{position:absolute;left:0;right:0;top:100%;max-width:516px;margin-top:6px;display:flex;flex-direction:column;box-sizing:border-box;padding:15px 0;overflow:hidden;container-type:inline-size;z-index:10;opacity:0;pointer-events:none;transition:opacity .4s cubic-bezier(.4,0,.2,1);background:var(--aia-surface, #ffffff);border:1px solid var(--aia-border, #b0b0b0);border-radius:25px}.magicx-aia-dropdown[data-aia-surface=glass]{background:transparent;border-color:transparent;box-shadow:#fff -3.2px -3.2px 3.2px -3.2px inset,#fff 6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset,#ffffff26 -1.6px 0 0 -1.6px inset,#ffffff26 0 -1.6px 0 -1.6px inset,#ffffff4d 0 1.6px inset,#ffffff4d 1.6px 0 inset,inset 0 0 30px 5px #0000000d,#00000014 0 0 30px 2px;backdrop-filter:blur(30px)}.magicx-aia-dropdown-visible{opacity:1;pointer-events:auto}.magicx-aia-dropdown-pillbar{padding:0 15px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 48px),transparent 100%);-webkit-mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 48px),transparent 100%)}.magicx-aia-dropdown-pillbar::-webkit-scrollbar{display:none}.magicx-aia-footer{display:flex;flex-direction:column;gap:12px;padding:0 15px}.magicx-aia-footer-divider{border-top:.5px solid var(--aia-footer-divider, rgba(176, 176, 176, .4))}.magicx-aia-footer-row{display:flex;align-items:center;justify-content:space-between}.magicx-aia-footer-hint-group{display:inline-flex;align-items:center;gap:5px}.magicx-aia-footer-brand-link{display:inline-flex;align-items:center;gap:2px;text-decoration:none;cursor:pointer;transition:opacity .15s ease-out}.magicx-aia-footer-brand-link:hover{opacity:.7}.magicx-aia-footer-key{display:inline-flex;align-items:center;justify-content:center;min-width:30px;height:22px;padding:2px 6px;border:.5px solid var(--aia-footer-hint-color, #505050);border-radius:5px;font-family:inherit;font-size:12px;line-height:18px;color:var(--aia-footer-hint-color, #505050)}.magicx-aia-footer-hint{font-family:inherit;font-size:12px;line-height:18px;color:var(--aia-footer-hint-color, #505050)}.magicx-aia-footer-brand{font-family:inherit;font-size:10px;line-height:18px;color:var(--aia-footer-brand-color, #b0b0b0)}.magicx-aia-footer-badge{display:inline-flex;align-items:center;height:23px;padding:2.5px 5.5px;border:.36px solid var(--aia-footer-badge-border, rgba(189, 189, 189, .51));border-radius:999px;font-family:inherit;font-size:10px;line-height:18px;color:var(--aia-footer-brand-color, #b0b0b0)}.magicx-aia-dropdown-skeleton-bars{display:flex;flex-direction:column;gap:20px;padding:10px 15px}.magicx-aia-dropdown-skeleton-bar{display:block;height:19px;border-radius:999px;background:var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, .51)));opacity:.5;animation:aiaDropdownSkeletonPulse 1.4s ease-in-out infinite}.magicx-aia-dropdown-skeleton-bar:nth-child(2){animation-delay:.15s}.magicx-aia-dropdown-skeleton-bar:nth-child(3){animation-delay:.3s}@keyframes aiaDropdownSkeletonPulse{0%,to{opacity:.5}50%{opacity:.25}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "component", type: PillListComponent, selector: "aia-pill-list", inputs: ["pills", "activePillIndex", "rounded", "loading"], outputs: ["selectPill"] }, { kind: "component", type: SuggestionGridComponent, selector: "aia-suggestion-grid", inputs: ["options", "activeIndex", "listboxId", "loading"], outputs: ["select", "highlight"] }, { kind: "component", type: StackComponent, selector: "aia-stack", inputs: ["space", "align"] }, { kind: "component", type: ClusterComponent, selector: "aia-cluster", inputs: ["gap", "align", "justify", "noWrap", "inline"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
302
436
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: AIAutocompleteDropdownComponent, decorators: [{
303
437
  type: Component,
304
- args: [{ selector: "ai-autocomplete-dropdown", standalone: true, imports: [CommonModule, PillListComponent, SuggestionGridComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n *ngIf=\"vm$ | async as vm\"\n [id]=\"controller.listboxId\"\n role=\"listbox\"\n data-aia-dropdown=\"\"\n [attr.data-aia-loading]=\"vm.isLoading ? '' : null\"\n class=\"magicx-aia-dropdown\"\n [class.magicx-aia-dropdown-visible]=\"vm.isVisible\"\n [class]=\"className ? 'magicx-aia-dropdown ' + className : 'magicx-aia-dropdown'\"\n (mousedown)=\"preventBlur($event)\"\n>\n <div\n *ngIf=\"vm.showsPills\"\n class=\"magicx-aia-dropdown-pillbar\"\n data-aia-pillbar=\"\"\n >\n <aia-pill-list\n [pills]=\"vm.pills\"\n [activePillIndex]=\"0\"\n [rounded]=\"true\"\n [loading]=\"vm.isLoading\"\n (selectPill)=\"onPillClick($event)\"\n ></aia-pill-list>\n </div>\n\n <aia-suggestion-grid\n *ngIf=\"vm.showsOptions\"\n [options]=\"vm.options\"\n [activeIndex]=\"vm.activeIndex\"\n [listboxId]=\"controller.listboxId\"\n [loading]=\"vm.isLoading\"\n (select)=\"onSelect($event)\"\n (highlight)=\"onHighlight($event)\"\n ></aia-suggestion-grid>\n\n <div\n *ngIf=\"vm.showsFallbackSkeleton\"\n class=\"magicx-aia-dropdown-skeleton-bars\"\n data-aia-skeleton-bars=\"\"\n >\n <span\n *ngFor=\"let w of fallbackSkeletonBarWidths; trackBy: trackByWidth\"\n class=\"magicx-aia-dropdown-skeleton-bar\"\n [style.width.px]=\"w\"\n ></span>\n </div>\n</div>\n", styles: [".magicx-aia-dropdown{position:absolute;left:0;right:0;top:100%;max-width:516px;margin-top:6px;display:flex;flex-direction:column;overflow:hidden;container-type:inline-size;z-index:10;opacity:0;pointer-events:none;transition:opacity .4s cubic-bezier(.4,0,.2,1);box-shadow:#fff -3.2px -3.2px 3.2px -3.2px inset,#fff 6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset,#ffffff26 -1.6px 0 0 -1.6px inset,#ffffff26 0 -1.6px 0 -1.6px inset,#ffffff4d 0 1.6px inset,#ffffff4d 1.6px 0 inset,inset 0 0 30px 5px #0000000d,#00000014 0 0 30px 2px;backdrop-filter:blur(30px);border-radius:28px}.magicx-aia-dropdown-visible{opacity:1;pointer-events:auto}.magicx-aia-dropdown-pillbar{padding:27px 27px 3px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 48px),transparent 100%);-webkit-mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 48px),transparent 100%)}.magicx-aia-dropdown-pillbar::-webkit-scrollbar{display:none}.magicx-aia-dropdown-skeleton-bars{display:flex;flex-direction:column;gap:20px;padding:25px}.magicx-aia-dropdown-skeleton-bar{display:block;height:19px;border-radius:999px;background:var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, .51)));opacity:.5;animation:aiaDropdownSkeletonPulse 1.4s ease-in-out infinite}.magicx-aia-dropdown-skeleton-bar:nth-child(2){animation-delay:.15s}.magicx-aia-dropdown-skeleton-bar:nth-child(3){animation-delay:.3s}@keyframes aiaDropdownSkeletonPulse{0%,to{opacity:.5}50%{opacity:.25}}\n"] }]
438
+ args: [{ selector: "ai-autocomplete-dropdown", standalone: true, imports: [
439
+ CommonModule,
440
+ PillListComponent,
441
+ SuggestionGridComponent,
442
+ StackComponent,
443
+ ClusterComponent,
444
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n *ngIf=\"vm$ | async as vm\"\n [id]=\"controller.listboxId\"\n role=\"listbox\"\n data-aia-dropdown=\"\"\n [attr.data-aia-loading]=\"vm.isLoading ? '' : null\"\n [class]=\"className ? 'magicx-aia-dropdown ' + className : 'magicx-aia-dropdown'\"\n [class.magicx-aia-dropdown-visible]=\"vm.isVisible\"\n (mousedown)=\"preventBlur($event)\"\n>\n <aia-stack space=\"14px\">\n <aia-cluster\n *ngIf=\"vm.showsPills\"\n class=\"magicx-aia-dropdown-pillbar\"\n data-aia-pillbar=\"\"\n [noWrap]=\"true\"\n >\n <aia-pill-list\n [pills]=\"vm.pills\"\n [activePillIndex]=\"0\"\n [rounded]=\"true\"\n [loading]=\"vm.isLoading\"\n (selectPill)=\"onPillClick($event)\"\n ></aia-pill-list>\n </aia-cluster>\n\n <aia-suggestion-grid\n *ngIf=\"vm.showsOptions\"\n [options]=\"vm.options\"\n [activeIndex]=\"vm.activeIndex\"\n [listboxId]=\"controller.listboxId\"\n [loading]=\"vm.isLoading\"\n (select)=\"onSelect($event)\"\n (highlight)=\"onHighlight($event)\"\n ></aia-suggestion-grid>\n\n <div\n *ngIf=\"vm.showsFallbackSkeleton\"\n class=\"magicx-aia-dropdown-skeleton-bars\"\n data-aia-skeleton-bars=\"\"\n >\n <span\n *ngFor=\"let w of fallbackSkeletonBarWidths; trackBy: trackByWidth\"\n class=\"magicx-aia-dropdown-skeleton-bar\"\n [style.width.px]=\"w\"\n ></span>\n </div>\n\n <footer class=\"magicx-aia-footer\" data-aia-footer=\"\">\n <div class=\"magicx-aia-footer-divider\"></div>\n <div class=\"magicx-aia-footer-row\">\n <span class=\"magicx-aia-footer-hint-group\">\n <kbd class=\"magicx-aia-footer-key\">{{ vm.footerKey }}</kbd>\n <span class=\"magicx-aia-footer-hint\">{{ vm.footerHint }}</span>\n </span>\n <a\n class=\"magicx-aia-footer-brand-link\"\n href=\"https://ai-autocomplete.com\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <span class=\"magicx-aia-footer-brand\">AI</span>\n <span class=\"magicx-aia-footer-badge\">Autocomplete</span>\n </a>\n </div>\n </footer>\n </aia-stack>\n</div>\n", styles: [".magicx-aia-dropdown{position:absolute;left:0;right:0;top:100%;max-width:516px;margin-top:6px;display:flex;flex-direction:column;box-sizing:border-box;padding:15px 0;overflow:hidden;container-type:inline-size;z-index:10;opacity:0;pointer-events:none;transition:opacity .4s cubic-bezier(.4,0,.2,1);background:var(--aia-surface, #ffffff);border:1px solid var(--aia-border, #b0b0b0);border-radius:25px}.magicx-aia-dropdown[data-aia-surface=glass]{background:transparent;border-color:transparent;box-shadow:#fff -3.2px -3.2px 3.2px -3.2px inset,#fff 6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset,var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset,#ffffff26 -1.6px 0 0 -1.6px inset,#ffffff26 0 -1.6px 0 -1.6px inset,#ffffff4d 0 1.6px inset,#ffffff4d 1.6px 0 inset,inset 0 0 30px 5px #0000000d,#00000014 0 0 30px 2px;backdrop-filter:blur(30px)}.magicx-aia-dropdown-visible{opacity:1;pointer-events:auto}.magicx-aia-dropdown-pillbar{padding:0 15px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 48px),transparent 100%);-webkit-mask-image:linear-gradient(to right,#000 0,#000 calc(100% - 48px),transparent 100%)}.magicx-aia-dropdown-pillbar::-webkit-scrollbar{display:none}.magicx-aia-footer{display:flex;flex-direction:column;gap:12px;padding:0 15px}.magicx-aia-footer-divider{border-top:.5px solid var(--aia-footer-divider, rgba(176, 176, 176, .4))}.magicx-aia-footer-row{display:flex;align-items:center;justify-content:space-between}.magicx-aia-footer-hint-group{display:inline-flex;align-items:center;gap:5px}.magicx-aia-footer-brand-link{display:inline-flex;align-items:center;gap:2px;text-decoration:none;cursor:pointer;transition:opacity .15s ease-out}.magicx-aia-footer-brand-link:hover{opacity:.7}.magicx-aia-footer-key{display:inline-flex;align-items:center;justify-content:center;min-width:30px;height:22px;padding:2px 6px;border:.5px solid var(--aia-footer-hint-color, #505050);border-radius:5px;font-family:inherit;font-size:12px;line-height:18px;color:var(--aia-footer-hint-color, #505050)}.magicx-aia-footer-hint{font-family:inherit;font-size:12px;line-height:18px;color:var(--aia-footer-hint-color, #505050)}.magicx-aia-footer-brand{font-family:inherit;font-size:10px;line-height:18px;color:var(--aia-footer-brand-color, #b0b0b0)}.magicx-aia-footer-badge{display:inline-flex;align-items:center;height:23px;padding:2.5px 5.5px;border:.36px solid var(--aia-footer-badge-border, rgba(189, 189, 189, .51));border-radius:999px;font-family:inherit;font-size:10px;line-height:18px;color:var(--aia-footer-brand-color, #b0b0b0)}.magicx-aia-dropdown-skeleton-bars{display:flex;flex-direction:column;gap:20px;padding:10px 15px}.magicx-aia-dropdown-skeleton-bar{display:block;height:19px;border-radius:999px;background:var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, .51)));opacity:.5;animation:aiaDropdownSkeletonPulse 1.4s ease-in-out infinite}.magicx-aia-dropdown-skeleton-bar:nth-child(2){animation-delay:.15s}.magicx-aia-dropdown-skeleton-bar:nth-child(3){animation-delay:.3s}@keyframes aiaDropdownSkeletonPulse{0%,to{opacity:.5}50%{opacity:.25}}\n"] }]
305
445
  }], propDecorators: { controller: [{
306
446
  type: Input
307
447
  }], showPills: [{
@@ -367,17 +507,37 @@ class AIAutocompleteController {
367
507
  // arrow opens the dropdown from the input.
368
508
  optionsPosition: (_b = opts.optionsPosition) !== null && _b !== void 0 ? _b : "below" }));
369
509
  this.rawState$ = new BehaviorSubject(this.core.getState());
370
- this.unsubscribeCore = this.core.subscribe((state) => {
510
+ // Push the store's *current* state, not the snapshot the listener was
511
+ // handed. The core notifies listeners synchronously, and some actions
512
+ // trigger reentrant `store.set` calls (e.g. typing a non-matching char
513
+ // during re-edit makes the core synchronously exit re-edit and kick off a
514
+ // fetch). Reentrancy makes the outer set's listener loop continue with a
515
+ // now-stale snapshot, so the listener can fire *out of order* — delivering
516
+ // an older state (still in re-edit) after a newer one (re-edit exited).
517
+ // Reading `getState()` at emission time collapses every notification onto
518
+ // the true latest state, so a stale `editingParam` can't resurrect and
519
+ // retrigger the editor's re-edit caret-park (which would yank the caret
520
+ // back to where re-editing started). distinctUntilChanged downstream drops
521
+ // the resulting duplicate emissions. React avoids this because it batches
522
+ // renders and its caret effects are dependency-gated; our subscription is
523
+ // synchronous, so we coalesce here instead.
524
+ this.unsubscribeCore = this.core.subscribe(() => {
371
525
  if (!this.isDestroyed)
372
- this.rawState$.next(state);
526
+ this.rawState$.next(this.core.getState());
373
527
  });
374
528
  // === Per-field observables ===
529
+ // Array-valued fields use shallow equality. The vanilla store spreads on
530
+ // every write (`store.set({ completedParams: [...] })`), so reference
531
+ // equality would re-fire downstream subscribers on every state tick even
532
+ // when the array's contents are unchanged. The other fields are
533
+ // primitives or stable object references, so default identity equality
534
+ // works fine.
375
535
  this.text$ = deriveField(this.rawState$, (s) => s.text);
376
- this.completedParams$ = deriveField(this.rawState$, (s) => s.completedParams);
377
- this.suggestionPills$ = deriveField(this.rawState$, (s) => s.actionableSuggestions);
378
- this.segments$ = deriveField(this.rawState$, (s) => s.segments);
536
+ this.completedParams$ = deriveField(this.rawState$, (s) => s.completedParams, arrEq);
537
+ this.suggestionPills$ = deriveField(this.rawState$, (s) => s.actionableSuggestions, arrEq);
538
+ this.segments$ = deriveField(this.rawState$, (s) => s.segments, arrEq);
379
539
  this.newParamId$ = deriveField(this.rawState$, (s) => s.newParamId);
380
- this.suggestions$ = deriveField(this.rawState$, (s) => s.suggestions);
540
+ this.suggestions$ = deriveField(this.rawState$, (s) => s.suggestions, arrEq);
381
541
  this.activeIndex$ = deriveField(this.rawState$, (s) => s.activeDropdownIndex);
382
542
  this.isLoading$ = deriveField(this.rawState$, computeUiLoading);
383
543
  this.isReady$ = deriveField(this.rawState$, (s) => s.isReady);
@@ -418,68 +578,109 @@ class AIAutocompleteController {
418
578
  return computeState(this.rawState$.value);
419
579
  }
420
580
  // === Action methods (pass-through to the core) ===
581
+ //
582
+ // Every action method begins with an `isDestroyed` guard so that callers
583
+ // who hold a stale reference after `destroy()` don't accidentally trigger
584
+ // work on a torn-down core. The vanilla core does not gate its own methods
585
+ // post-dispose — `reset()`, `handleTextChange()`, and friends would still
586
+ // schedule fetches or fire HTTP requests against an aborted controller,
587
+ // and the responses would have nowhere to surface (rawState$ is already
588
+ // complete). The guard makes the JSDoc-promised "no-op silently"
589
+ // semantics actually true.
421
590
  /** Clear all state, rotate `session_id`, and re-fetch. Call after submit. */
422
591
  reset() {
592
+ if (this.isDestroyed)
593
+ return;
423
594
  this.core.reset();
424
595
  }
425
596
  /** Pick a dropdown option (or replace the re-edited param if in re-edit mode). */
426
597
  selectOption(option) {
598
+ if (this.isDestroyed)
599
+ return;
427
600
  this.core.selectOption(option);
428
601
  }
429
602
  /** Promote the pill at `index` to active (front of the list). */
430
603
  setActivePill(index) {
604
+ if (this.isDestroyed)
605
+ return;
431
606
  this.core.setActivePill(index);
432
607
  }
433
608
  /** Drop the last completed param's "completed" status. Text stays as plain text. */
434
609
  removeLastParam() {
610
+ if (this.isDestroyed)
611
+ return;
435
612
  this.core.removeLastParam();
436
613
  }
437
614
  /** Clear the shimmer animation state for the most-recently-added param. */
438
615
  clearNewParamId() {
616
+ if (this.isDestroyed)
617
+ return;
439
618
  this.core.clearNewParamId();
440
619
  }
441
620
  /** Controlled-mode setter for editor text. */
442
621
  setValue(text) {
622
+ if (this.isDestroyed)
623
+ return;
443
624
  this.core.setValue(text);
444
625
  }
445
626
  /** Controlled-mode setter for completed params. */
446
627
  setCompletedParams(params) {
628
+ if (this.isDestroyed)
629
+ return;
447
630
  this.core.setCompletedParams(params);
448
631
  }
449
632
  /** Forward plain-text input from the consumer's `<textarea>` to the core. */
450
633
  handleTextChange(value) {
634
+ if (this.isDestroyed)
635
+ return;
451
636
  this.core.handleTextChange(value);
452
637
  }
453
638
  /** Forward keyboard events from the consumer's `<textarea>` to the core. */
454
639
  handleKeyDown(event) {
640
+ if (this.isDestroyed)
641
+ return;
455
642
  this.core.handleKeyDown(event);
456
643
  }
457
644
  /** Notify the core of focus state. */
458
645
  setFocused(focused) {
646
+ if (this.isDestroyed)
647
+ return;
459
648
  this.core.setFocused(focused);
460
649
  }
461
650
  /** Enter re-edit mode for the bold param with the given id. */
462
651
  startEditingParam(paramId) {
652
+ if (this.isDestroyed)
653
+ return;
463
654
  this.core.startEditingParam(paramId);
464
655
  }
465
656
  /** Exit re-edit mode without changing the bold param. */
466
657
  exitEditMode() {
658
+ if (this.isDestroyed)
659
+ return;
467
660
  this.core.exitEditMode();
468
661
  }
469
662
  /** Forward post-input caret position (extends the edit tail). */
470
663
  handleCaretAfterInput(offset) {
664
+ if (this.isDestroyed)
665
+ return;
471
666
  this.core.handleCaretAfterInput(offset);
472
667
  }
473
668
  /** Forward selection-only caret moves (may exit re-edit). */
474
669
  handleCaretMove(offset) {
670
+ if (this.isDestroyed)
671
+ return;
475
672
  this.core.handleCaretMove(offset);
476
673
  }
477
674
  /** Replace the bold param being re-edited. Returns true when applied. */
478
675
  replaceEditingRange(replacement) {
676
+ if (this.isDestroyed)
677
+ return false;
479
678
  return this.core.replaceEditingRange(replacement);
480
679
  }
481
680
  /** Set the highlighted option index (typically driven by hover). */
482
681
  setActiveDropdownIndex(index) {
682
+ if (this.isDestroyed)
683
+ return;
483
684
  this.core.setActiveDropdownIndex(index);
484
685
  }
485
686
  // === Lifecycle ===
@@ -491,6 +692,8 @@ class AIAutocompleteController {
491
692
  * (e.g. `text$` instead of `onChange`).
492
693
  */
493
694
  update(opts) {
695
+ if (this.isDestroyed)
696
+ return;
494
697
  this.core.update(opts);
495
698
  }
496
699
  /**
@@ -508,6 +711,24 @@ class AIAutocompleteController {
508
711
  }
509
712
  }
510
713
  // ===== Pure helpers — not part of the public surface =====
714
+ /**
715
+ * Shallow array equality. The vanilla store reassigns array fields on every
716
+ * write (`store.set({ completedParams: [...prev, x] })`), so reference
717
+ * equality alone would re-emit downstream even when the contents are
718
+ * identical. Used for `completedParams$`, `suggestions$`, `suggestionPills$`,
719
+ * and `segments$`.
720
+ */
721
+ function arrEq(a, b) {
722
+ if (a === b)
723
+ return true;
724
+ if (a.length !== b.length)
725
+ return false;
726
+ for (let i = 0; i < a.length; i++) {
727
+ if (a[i] !== b[i])
728
+ return false;
729
+ }
730
+ return true;
731
+ }
511
732
  function computeUiLoading(s) {
512
733
  return s.isLoading && !s.editingParam && !s.inSelectionAnimation;
513
734
  }
@@ -550,6 +771,7 @@ function computeDropdown(s) {
550
771
  isOpen: s.isDropdownOpen,
551
772
  pills: dropdownPills,
552
773
  isLoading: computeUiLoading(s),
774
+ hasTabbedToHighlight: s.hasTabbedToHighlight,
553
775
  };
554
776
  }
555
777
 
@@ -704,7 +926,9 @@ class AIAutocompleteEditorHostDirective {
704
926
  const anchor = sel.anchorNode;
705
927
  const startEl = anchor.nodeType === Node.ELEMENT_NODE ? anchor : anchor.parentElement;
706
928
  const strong = startEl === null || startEl === void 0 ? void 0 : startEl.closest('strong[data-seg="completed"][data-param-id]');
707
- const enclosing = (_a = strong === null || strong === void 0 ? void 0 : strong.dataset.paramId) !== null && _a !== void 0 ? _a : null;
929
+ // `DOMStringMap` is an index signature; bracket notation is required
930
+ // by `noPropertyAccessFromIndexSignature`.
931
+ const enclosing = (_a = strong === null || strong === void 0 ? void 0 : strong.dataset["paramId"]) !== null && _a !== void 0 ? _a : null;
708
932
  if (enclosing && enclosing !== this.editingParamId) {
709
933
  this.zone.run(() => this.controller.startEditingParam(enclosing));
710
934
  return;
@@ -806,13 +1030,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
806
1030
  type: Input
807
1031
  }] } });
808
1032
 
809
- function resolveInitialMode(mode) {
810
- if (mode !== "auto")
811
- return mode;
812
- if (typeof window === "undefined")
813
- return "dark";
814
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1033
+ /**
1034
+ * Internal default submit button (up-arrow). Angular analogue of React's
1035
+ * `SubmitButton`. The default/custom/hidden branching stays in the parent
1036
+ * (`AIAutocompleteComponent`); this is only the built-in button.
1037
+ *
1038
+ * @internal
1039
+ */
1040
+ class SubmitButtonComponent {
1041
+ constructor() {
1042
+ this.disabled = false;
1043
+ this.submit = new EventEmitter();
1044
+ }
1045
+ onClick(event) {
1046
+ this.submit.emit(event);
1047
+ }
815
1048
  }
1049
+ SubmitButtonComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SubmitButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1050
+ SubmitButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: SubmitButtonComponent, isStandalone: true, selector: "aia-submit-button", inputs: { disabled: "disabled" }, outputs: { submit: "submit" }, ngImport: i0, template: "<button\n type=\"button\"\n data-aia-submit=\"\"\n class=\"magicx-aia-submit-button\"\n [disabled]=\"disabled\"\n aria-label=\"Submit\"\n (click)=\"onClick($event)\"\n>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" role=\"img\" aria-label=\"Submit\">\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n</button>\n", styles: [".magicx-aia-submit-button{flex-shrink:0;width:36px;height:36px;border-radius:50%;border:none;background:var(--aia-submit-bg, var(--aia-color-text-default, #fff));color:var(--aia-submit-color, var(--aia-color-bg-default, #000));cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;transition:opacity .2s ease}.magicx-aia-submit-button:hover{opacity:.85}.magicx-aia-submit-button:disabled{opacity:.4;cursor:default}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1051
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SubmitButtonComponent, decorators: [{
1052
+ type: Component,
1053
+ args: [{ selector: "aia-submit-button", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<button\n type=\"button\"\n data-aia-submit=\"\"\n class=\"magicx-aia-submit-button\"\n [disabled]=\"disabled\"\n aria-label=\"Submit\"\n (click)=\"onClick($event)\"\n>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" role=\"img\" aria-label=\"Submit\">\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n</button>\n", styles: [".magicx-aia-submit-button{flex-shrink:0;width:36px;height:36px;border-radius:50%;border:none;background:var(--aia-submit-bg, var(--aia-color-text-default, #fff));color:var(--aia-submit-color, var(--aia-color-bg-default, #000));cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;transition:opacity .2s ease}.magicx-aia-submit-button:hover{opacity:.85}.magicx-aia-submit-button:disabled{opacity:.4;cursor:default}\n"] }]
1054
+ }], propDecorators: { disabled: [{
1055
+ type: Input
1056
+ }], submit: [{
1057
+ type: Output
1058
+ }] } });
1059
+
816
1060
  /**
817
1061
  * Tier 1 component — `<ai-autocomplete>`. The Angular equivalent of React's
818
1062
  * `<AIAutocomplete />`. Owns the contentEditable editor, inline pills, mode
@@ -840,19 +1084,26 @@ class AIAutocompleteComponent {
840
1084
  this.completedParamsChange = new EventEmitter();
841
1085
  this.focused = new EventEmitter();
842
1086
  this.blurred = new EventEmitter();
1087
+ /**
1088
+ * Concrete light/dark value bound to `[attr.data-mode]`. Seeded in ngOnInit
1089
+ * so the attribute is present during SSR (where ModeController, gated behind
1090
+ * isPlatformBrowser in ngAfterViewInit, never runs). On the browser the
1091
+ * ModeController's resolve callback keeps this in sync — so its runtime
1092
+ * prefers-color-scheme updates and this binding always agree (no clobber).
1093
+ */
843
1094
  this.resolvedMode = "dark";
844
1095
  this.onChangeFn = noop$1;
845
1096
  this.onTouchedFn = noop$1;
846
1097
  // §16.9: prefer `inject()` over constructor-parameter DI for components.
847
1098
  this.platformId = inject(PLATFORM_ID);
848
- this.el = inject(ElementRef);
849
- this.cdr = inject(ChangeDetectorRef);
850
1099
  this.zone = inject(NgZone);
1100
+ this.cdr = inject(ChangeDetectorRef);
851
1101
  }
852
1102
  ngOnInit() {
1103
+ // Seed before the browser guard so SSR renders a concrete data-mode.
1104
+ this.resolvedMode = resolveInitialMode(this.mode);
853
1105
  if (!isPlatformBrowser(this.platformId))
854
1106
  return;
855
- this.resolvedMode = resolveInitialMode(this.mode);
856
1107
  this.controller = new AIAutocompleteController({
857
1108
  apiConfig: this.apiConfig,
858
1109
  optionOverrides: this.optionOverrides,
@@ -886,12 +1137,26 @@ class AIAutocompleteComponent {
886
1137
  setCursorOffset(editor, offset);
887
1138
  },
888
1139
  });
1140
+ if (this.pendingWriteValue !== undefined) {
1141
+ this.controller.setValue(this.pendingWriteValue);
1142
+ this.pendingWriteValue = undefined;
1143
+ }
889
1144
  }
890
1145
  ngAfterViewInit() {
891
1146
  if (!isPlatformBrowser(this.platformId))
892
1147
  return;
893
- const container = this.el.nativeElement;
894
- this.modeController = new ModeController(container, this.mode);
1148
+ // ModeController writes `data-mode` to the element it's given. The CSS
1149
+ // selectors are scoped to `.magicx-aia[data-mode="..."]` — which lives on
1150
+ // the inner `<div class="magicx-aia magicx-aia-container" #container>`,
1151
+ // NOT the host `<ai-autocomplete>` element. The resolve callback mirrors
1152
+ // the value into `resolvedMode` so the `[attr.data-mode]` binding stays in
1153
+ // lockstep with ModeController — the binding handles SSR, ModeController
1154
+ // handles runtime prefers-color-scheme switches, and because they always
1155
+ // agree neither clobbers the other.
1156
+ this.modeController = new ModeController(this.containerRef.nativeElement, this.mode, (resolved) => {
1157
+ this.resolvedMode = resolved;
1158
+ this.cdr.markForCheck();
1159
+ });
895
1160
  // Pill-wrap detection — when the pill list wraps below the editor's last
896
1161
  // line, drop its 8px left margin via a data attribute the CSS keys off.
897
1162
  // Mirrors the React component's useLayoutEffect.
@@ -910,20 +1175,24 @@ class AIAutocompleteComponent {
910
1175
  var _a;
911
1176
  if (!this.controller)
912
1177
  return;
1178
+ // `SimpleChanges` is `{ [key: string]: SimpleChange }`, so per
1179
+ // `noPropertyAccessFromIndexSignature` each key lookup uses bracket
1180
+ // notation — this keeps the strictness contract that the rest of the
1181
+ // workspace enforces.
913
1182
  // Controlled-mode propagation
914
- if (changes.value && this.value !== undefined) {
1183
+ if (changes["value"] && this.value !== undefined) {
915
1184
  this.controller.setValue(this.value);
916
1185
  }
917
- if (changes.completedParams && this.completedParams !== undefined) {
1186
+ if (changes["completedParams"] && this.completedParams !== undefined) {
918
1187
  this.controller.setCompletedParams(this.completedParams);
919
1188
  }
920
1189
  // Reactive options
921
- if (changes.apiConfig ||
922
- changes.optionOverrides ||
923
- changes.dropdownTrigger ||
924
- changes.optionsPosition ||
925
- changes.closeDropdownOnBlur ||
926
- changes.showNonTappableOptions) {
1190
+ if (changes["apiConfig"] ||
1191
+ changes["optionOverrides"] ||
1192
+ changes["dropdownTrigger"] ||
1193
+ changes["optionsPosition"] ||
1194
+ changes["closeDropdownOnBlur"] ||
1195
+ changes["showNonTappableOptions"]) {
927
1196
  this.controller.update({
928
1197
  apiConfig: this.apiConfig,
929
1198
  optionOverrides: this.optionOverrides,
@@ -933,9 +1202,12 @@ class AIAutocompleteComponent {
933
1202
  showNonTappableOptions: this.showNonTappableOptions,
934
1203
  });
935
1204
  }
936
- if (changes.mode) {
937
- (_a = this.modeController) === null || _a === void 0 ? void 0 : _a.setMode(this.mode);
1205
+ if (changes["mode"]) {
1206
+ // Keep the binding correct even when ModeController doesn't exist yet
1207
+ // (SSR / pre-ngAfterViewInit). On the browser, setMode triggers the
1208
+ // resolve callback which sets the same value.
938
1209
  this.resolvedMode = resolveInitialMode(this.mode);
1210
+ (_a = this.modeController) === null || _a === void 0 ? void 0 : _a.setMode(this.mode);
939
1211
  }
940
1212
  }
941
1213
  ngOnDestroy() {
@@ -964,8 +1236,8 @@ class AIAutocompleteComponent {
964
1236
  setMode(mode) {
965
1237
  var _a;
966
1238
  this.mode = mode;
967
- (_a = this.modeController) === null || _a === void 0 ? void 0 : _a.setMode(mode);
968
1239
  this.resolvedMode = resolveInitialMode(mode);
1240
+ (_a = this.modeController) === null || _a === void 0 ? void 0 : _a.setMode(mode);
969
1241
  this.cdr.markForCheck();
970
1242
  }
971
1243
  // === Template helpers ===
@@ -1019,9 +1291,16 @@ class AIAutocompleteComponent {
1019
1291
  }
1020
1292
  // === ControlValueAccessor ===
1021
1293
  writeValue(value) {
1022
- if (!this.controller)
1294
+ const next = value !== null && value !== void 0 ? value : "";
1295
+ if (!this.controller) {
1296
+ // Reactive Forms can call writeValue() before ngOnInit creates the
1297
+ // controller (dynamic form construction, or a FormControl that already
1298
+ // had a value at directive-creation time). Buffer the value; ngOnInit
1299
+ // flushes it as soon as the controller exists.
1300
+ this.pendingWriteValue = next;
1023
1301
  return;
1024
- this.controller.setValue(value !== null && value !== void 0 ? value : "");
1302
+ }
1303
+ this.controller.setValue(next);
1025
1304
  }
1026
1305
  registerOnChange(fn) {
1027
1306
  this.onChangeFn = fn;
@@ -1103,7 +1382,7 @@ AIAutocompleteComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0"
1103
1382
  useExisting: forwardRef(() => AIAutocompleteComponent),
1104
1383
  multi: true,
1105
1384
  },
1106
- ], viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true }, { propertyName: "pillContainerRef", first: true, predicate: ["pillContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"magicx-aia magicx-aia-container\"\n [attr.data-pill-placement]=\"pillPlacement\"\n [attr.data-options-position]=\"optionsPosition\"\n [attr.data-animations]=\"animations ? 'on' : 'off'\"\n [attr.data-mode]=\"resolvedMode\"\n>\n <ai-autocomplete-dropdown\n *ngIf=\"controller\"\n [controller]=\"controller\"\n [showPills]=\"showDropdownPills\"\n ></ai-autocomplete-dropdown>\n\n <div\n class=\"magicx-aia-input-wrapper\"\n (click)=\"onWrapperClick($event)\"\n (keyup)=\"$event.stopPropagation()\"\n >\n <div class=\"magicx-aia-editor-area\" data-aia-editor=\"\">\n <div\n #editor\n *ngIf=\"controller\"\n [aiaEditorHost]=\"controller\"\n [autoFocus]=\"autoFocus\"\n class=\"magicx-aia-input\"\n data-aia-input=\"\"\n ></div>\n\n <ng-container *ngIf=\"controller && showInlinePills\">\n <span\n #pillContainer\n class=\"magicx-aia-pill-list-container\"\n data-aia-pill-list-container=\"\"\n *ngIf=\"\n (controller.isLoading$ | async) ||\n ((controller.suggestionPills$ | async)?.length ?? 0) > 0\n \"\n >\n <aia-pill-list\n [pills]=\"(controller.suggestionPills$ | async) ?? []\"\n [activePillIndex]=\"0\"\n [loading]=\"(controller.isLoading$ | async) ?? false\"\n (selectPill)=\"onSelectPill($event)\"\n ></aia-pill-list>\n </span>\n </ng-container>\n </div>\n\n <ng-container [ngSwitch]=\"submitButtonState\">\n <button\n *ngSwitchCase=\"'default'\"\n type=\"button\"\n data-aia-submit=\"\"\n class=\"magicx-aia-submit-button\"\n [disabled]=\"\n !(\n controller &&\n canSubmit({\n segments: (controller.segments$ | async) ?? [],\n completedParams: (controller.completedParams$ | async) ?? []\n })\n )\n \"\n aria-label=\"Submit\"\n (click)=\"onSubmitButtonClick($event)\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Submit\"\n >\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n\n <span\n *ngSwitchCase=\"'custom'\"\n data-aia-submit=\"\"\n class=\"magicx-aia-submit-slot\"\n (click)=\"onSubmitSlotClick($event)\"\n >\n <ng-container *ngTemplateOutlet=\"customSubmitTemplate\"></ng-container>\n </span>\n </ng-container>\n </div>\n</div>\n", styles: [":where(.magicx-aia,.magicx-aia *,.magicx-aia *::before,.magicx-aia *::after){box-sizing:border-box}:where(.magicx-aia),:where(.magicx-aia[data-mode=\"light\"]){--aia-pill-bg: #bdbdbd;--aia-pill-color: #000000;--aia-pill-font-size: 19px;--aia-option-bg: transparent;--aia-option-color: #4f4f4f;--aia-option-color-selected: #000000;--aia-option-font-size: 19px;--aia-written-text-color: #000000;--aia-written-text-font-size: 19px;--aia-caret-color: var(--aia-written-text-color, #000000);--aia-submit-bg: #000000;--aia-submit-color: #ffffff;--aia-color-text-muted: #6b7280;--aia-skeleton-bg: rgba(189, 189, 189, .51);--aia-streak-rgb: 99, 102, 241;--aia-streak-glass-bg: rgba(99, 102, 241, .1)}:where(.magicx-aia[data-mode=\"dark\"]){--aia-pill-bg: #bdbdbd;--aia-pill-color: #ffffff;--aia-pill-font-size: 19px;--aia-option-bg: transparent;--aia-option-color: #b0b0b0;--aia-option-color-selected: #ffffff;--aia-option-font-size: 19px;--aia-written-text-color: #ffffff;--aia-written-text-font-size: 19px;--aia-caret-color: var(--aia-written-text-color, #ffffff);--aia-submit-bg: #ffffff;--aia-submit-color: #000000;--aia-color-text-muted: #c1c4cb;--aia-skeleton-bg: #333539;--aia-streak-rgb: 255, 255, 255;--aia-streak-glass-bg: rgba(255, 255, 255, .1)}:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown]{top:auto;bottom:100%;margin-top:0;margin-bottom:6px;flex-direction:column-reverse}:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-pillbar]{padding:0 27px 27px}:where(.magicx-aia[data-animations=\"off\"]) *,:where(.magicx-aia[data-animations=\"off\"]) *:before,:where(.magicx-aia[data-animations=\"off\"]) *:after{animation-duration:0s!important;transition-duration:0s!important}.magicx-aia-container{position:relative;font-family:var(--aia-font-family, inherit);container-type:inline-size}.magicx-aia-input-wrapper{padding:20px;border:1px solid var(--aia-color-border-default, #9ea5b2);border-radius:23px;background:transparent;overflow:hidden;display:flex;align-items:center;gap:4px}.magicx-aia-editor-area{position:relative;flex:1;min-width:0;min-height:26.6px;line-height:26.6px;font-family:inherit;font-size:var(--aia-written-text-font-size, 19px);white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere}.magicx-aia-input{display:inline;outline:none;background:transparent;color:var(--aia-written-text-color, var(--aia-color-text-default, #fff));caret-color:var( --aia-caret-color, var(--aia-written-text-color, var(--aia-color-text-default, #fff)) );font-weight:250;vertical-align:middle}:where(.magicx-aia-input) strong{font-weight:500;letter-spacing:-.01em}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]{background-color:color-mix(in srgb,var(--aia-edit-outline, currentColor) 20%,transparent);border-radius:6px;padding:2px 3px;margin:0 -1.5px;caret-color:transparent}.magicx-aia-input:has(strong[class~=\"magicx-aia-segment--editing\"]){caret-color:transparent}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]::selection{background:transparent;color:inherit}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]::-moz-selection{background:transparent;color:inherit}.magicx-aia-input[data-aia-empty=true][data-placeholder]:before{content:attr(data-placeholder);color:var(--aia-color-text-muted, #c1c4cb);opacity:.7;pointer-events:none}.magicx-aia-input[data-aia-empty=true]{display:inline-block;min-width:1px}.magicx-aia-pill-list-container{display:inline;margin-left:8px}.magicx-aia-pill-list-container:empty,.magicx-aia-pill-list-container[data-aia-pill-wrapped]{margin-left:0}.magicx-aia-submit-button{flex-shrink:0;width:36px;height:36px;border-radius:50%;border:none;background:var(--aia-submit-bg, var(--aia-color-text-default, #fff));color:var(--aia-submit-color, var(--aia-color-bg-default, #000));cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;transition:opacity .2s ease}.magicx-aia-submit-button:hover{opacity:.85}.magicx-aia-submit-slot{display:contents}:where(.magicx-aia-input) strong[class~=magicx-aia-shimmer-revealed]{color:transparent;background:linear-gradient(120deg,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 0%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 44%,#b0b0b0 48%,#b0b0b0 52%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 56%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 100%);background-size:200% 100%;-webkit-background-clip:text;background-clip:text}:where(.magicx-aia-input) strong[class~=magicx-aia-shimmer-sweep]{animation:aiaTextShimmer .65s ease-out forwards}@keyframes aiaTextShimmer{0%{background-position:100% 0}to{background-position:-50% 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "component", type: AIAutocompleteDropdownComponent, selector: "ai-autocomplete-dropdown", inputs: ["controller", "showPills", "className"] }, { kind: "directive", type: AIAutocompleteEditorHostDirective, selector: "[aiaEditorHost]", inputs: ["aiaEditorHost", "autoFocus"] }, { kind: "component", type: PillListComponent, selector: "aia-pill-list", inputs: ["pills", "activePillIndex", "rounded", "loading"], outputs: ["selectPill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1385
+ ], viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true, static: true }, { propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true }, { propertyName: "pillContainerRef", first: true, predicate: ["pillContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #container\n class=\"magicx-aia magicx-aia-container\"\n [attr.data-pill-placement]=\"pillPlacement\"\n [attr.data-options-position]=\"optionsPosition\"\n [attr.data-animations]=\"animations ? 'on' : 'off'\"\n [attr.data-mode]=\"resolvedMode\"\n>\n <ai-autocomplete-dropdown\n *ngIf=\"controller\"\n [controller]=\"controller\"\n [showPills]=\"showDropdownPills\"\n ></ai-autocomplete-dropdown>\n\n <div\n class=\"magicx-aia-input-wrapper\"\n (click)=\"onWrapperClick($event)\"\n (keyup)=\"$event.stopPropagation()\"\n >\n <div class=\"magicx-aia-editor-area\" data-aia-editor=\"\">\n <div\n #editor\n *ngIf=\"controller\"\n [aiaEditorHost]=\"controller\"\n [autoFocus]=\"autoFocus\"\n class=\"magicx-aia-input\"\n data-aia-input=\"\"\n ></div>\n\n <ng-container *ngIf=\"controller && showInlinePills\">\n <span\n #pillContainer\n class=\"magicx-aia-pill-list-container\"\n data-aia-pill-list-container=\"\"\n *ngIf=\"\n (controller.isLoading$ | async) ||\n ((controller.suggestionPills$ | async)?.length ?? 0) > 0\n \"\n >\n <aia-pill-list\n [pills]=\"(controller.suggestionPills$ | async) ?? []\"\n [activePillIndex]=\"0\"\n [loading]=\"(controller.isLoading$ | async) ?? false\"\n (selectPill)=\"onSelectPill($event)\"\n ></aia-pill-list>\n </span>\n </ng-container>\n </div>\n\n <ng-container [ngSwitch]=\"submitButtonState\">\n <aia-submit-button\n *ngSwitchCase=\"'default'\"\n [disabled]=\"\n !(\n controller &&\n canSubmit({\n segments: (controller.segments$ | async) ?? [],\n completedParams: (controller.completedParams$ | async) ?? []\n })\n )\n \"\n (submit)=\"onSubmitButtonClick($event)\"\n ></aia-submit-button>\n\n <span\n *ngSwitchCase=\"'custom'\"\n data-aia-submit=\"\"\n class=\"magicx-aia-submit-slot\"\n (click)=\"onSubmitSlotClick($event)\"\n >\n <ng-container *ngTemplateOutlet=\"customSubmitTemplate\"></ng-container>\n </span>\n </ng-container>\n </div>\n</div>\n", styles: [":where(.magicx-aia,.magicx-aia *,.magicx-aia *::before,.magicx-aia *::after){box-sizing:border-box}:where(.magicx-aia),:where(.magicx-aia[data-mode=\"light\"]){--aia-surface: #ffffff;--aia-border: #b0b0b0;--aia-pill-bg: #bdbdbd;--aia-pill-color: #333539;--aia-pill-font-size: 18px;--aia-option-bg: transparent;--aia-option-color: #505050;--aia-option-color-selected: #000000;--aia-option-font-size: 18px;--aia-written-text-color: #000000;--aia-written-text-font-size: 20px;--aia-caret-color: var(--aia-written-text-color, #000000);--aia-submit-bg: #000000;--aia-submit-color: #ffffff;--aia-color-text-muted: #6b7280;--aia-skeleton-bg: rgba(189, 189, 189, .51);--aia-streak-rgb: 99, 102, 241;--aia-streak-glass-bg: rgba(99, 102, 241, .1);--aia-footer-divider: rgba(176, 176, 176, .4);--aia-footer-hint-color: #505050;--aia-footer-brand-color: #b0b0b0;--aia-footer-badge-border: rgba(189, 189, 189, .51)}:where(.magicx-aia[data-mode=\"dark\"]){--aia-surface: #000000;--aia-border: #505050;--aia-pill-bg: #bdbdbd;--aia-pill-color: #b0b0b0;--aia-pill-font-size: 18px;--aia-option-bg: transparent;--aia-option-color: #b0b0b0;--aia-option-color-selected: #ffffff;--aia-option-font-size: 18px;--aia-written-text-color: #ffffff;--aia-written-text-font-size: 20px;--aia-caret-color: var(--aia-written-text-color, #ffffff);--aia-submit-bg: #ffffff;--aia-submit-color: #000000;--aia-color-text-muted: #c1c4cb;--aia-skeleton-bg: #333539;--aia-streak-rgb: 255, 255, 255;--aia-streak-glass-bg: rgba(255, 255, 255, .1);--aia-footer-divider: rgba(255, 255, 255, .15);--aia-footer-hint-color: #b0b0b0;--aia-footer-brand-color: #505050;--aia-footer-badge-border: #505050}:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown]{top:auto;bottom:100%;margin-top:0;margin-bottom:6px}:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] .aia-stack{flex-direction:column-reverse}:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] .magicx-aia-footer{flex-direction:column-reverse}:where(.magicx-aia[data-animations=\"off\"]) *,:where(.magicx-aia[data-animations=\"off\"]) *:before,:where(.magicx-aia[data-animations=\"off\"]) *:after{animation-duration:0s!important;transition-duration:0s!important}.magicx-aia-container{position:relative;font-family:var(--aia-font-family, inherit);container-type:inline-size}.magicx-aia-input-wrapper{padding:19px 15px 20px 25px;border:1px solid var(--aia-border, #b0b0b0);border-radius:30px;background:var(--aia-surface, #ffffff);overflow:hidden;display:flex;align-items:center;gap:4px}.magicx-aia-editor-area{position:relative;flex:1;min-width:0;min-height:26.6px;line-height:26.6px;font-family:inherit;font-size:var(--aia-written-text-font-size, 19px);white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere}.magicx-aia-input{display:inline;outline:none;background:transparent;color:var(--aia-written-text-color, var(--aia-color-text-default, #fff));caret-color:var( --aia-caret-color, var(--aia-written-text-color, var(--aia-color-text-default, #fff)) );font-weight:250;vertical-align:middle}:where(.magicx-aia-input) strong{font-weight:500;letter-spacing:-.01em}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]{background-color:color-mix(in srgb,var(--aia-edit-outline, currentColor) 20%,transparent);border-radius:6px;padding:2px 3px;margin:0 -1.5px;caret-color:transparent}.magicx-aia-input:has(strong[class~=\"magicx-aia-segment--editing\"]){caret-color:transparent}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]::selection{background:transparent;color:inherit}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]::-moz-selection{background:transparent;color:inherit}.magicx-aia-input[data-aia-empty=true][data-placeholder]:before{content:attr(data-placeholder);color:var(--aia-color-text-muted, #c1c4cb);opacity:.7;pointer-events:none}.magicx-aia-input[data-aia-empty=true]{display:inline-block;min-width:1px}.magicx-aia-pill-list-container{display:inline;margin-left:8px}.magicx-aia-pill-list-container:empty,.magicx-aia-pill-list-container[data-aia-pill-wrapped]{margin-left:0}.magicx-aia-submit-slot{display:contents}:where(.magicx-aia-input) strong[class~=magicx-aia-shimmer-revealed]{color:transparent;background:linear-gradient(120deg,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 0%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 44%,#b0b0b0 48%,#b0b0b0 52%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 56%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 100%);background-size:200% 100%;-webkit-background-clip:text;background-clip:text}:where(.magicx-aia-input) strong[class~=magicx-aia-shimmer-sweep]{animation:aiaTextShimmer .65s ease-out forwards}@keyframes aiaTextShimmer{0%{background-position:100% 0}to{background-position:-50% 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "component", type: AIAutocompleteDropdownComponent, selector: "ai-autocomplete-dropdown", inputs: ["controller", "showPills", "className"] }, { kind: "directive", type: AIAutocompleteEditorHostDirective, selector: "[aiaEditorHost]", inputs: ["aiaEditorHost", "autoFocus"] }, { kind: "component", type: PillListComponent, selector: "aia-pill-list", inputs: ["pills", "activePillIndex", "rounded", "loading"], outputs: ["selectPill"] }, { kind: "component", type: SubmitButtonComponent, selector: "aia-submit-button", inputs: ["disabled"], outputs: ["submit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1107
1386
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: AIAutocompleteComponent, decorators: [{
1108
1387
  type: Component,
1109
1388
  args: [{ selector: "ai-autocomplete", standalone: true, imports: [
@@ -1111,6 +1390,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
1111
1390
  AIAutocompleteDropdownComponent,
1112
1391
  AIAutocompleteEditorHostDirective,
1113
1392
  PillListComponent,
1393
+ SubmitButtonComponent,
1114
1394
  ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
1115
1395
  {
1116
1396
  provide: NG_VALUE_ACCESSOR,
@@ -1118,7 +1398,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
1118
1398
  useExisting: forwardRef(() => AIAutocompleteComponent),
1119
1399
  multi: true,
1120
1400
  },
1121
- ], template: "<div\n class=\"magicx-aia magicx-aia-container\"\n [attr.data-pill-placement]=\"pillPlacement\"\n [attr.data-options-position]=\"optionsPosition\"\n [attr.data-animations]=\"animations ? 'on' : 'off'\"\n [attr.data-mode]=\"resolvedMode\"\n>\n <ai-autocomplete-dropdown\n *ngIf=\"controller\"\n [controller]=\"controller\"\n [showPills]=\"showDropdownPills\"\n ></ai-autocomplete-dropdown>\n\n <div\n class=\"magicx-aia-input-wrapper\"\n (click)=\"onWrapperClick($event)\"\n (keyup)=\"$event.stopPropagation()\"\n >\n <div class=\"magicx-aia-editor-area\" data-aia-editor=\"\">\n <div\n #editor\n *ngIf=\"controller\"\n [aiaEditorHost]=\"controller\"\n [autoFocus]=\"autoFocus\"\n class=\"magicx-aia-input\"\n data-aia-input=\"\"\n ></div>\n\n <ng-container *ngIf=\"controller && showInlinePills\">\n <span\n #pillContainer\n class=\"magicx-aia-pill-list-container\"\n data-aia-pill-list-container=\"\"\n *ngIf=\"\n (controller.isLoading$ | async) ||\n ((controller.suggestionPills$ | async)?.length ?? 0) > 0\n \"\n >\n <aia-pill-list\n [pills]=\"(controller.suggestionPills$ | async) ?? []\"\n [activePillIndex]=\"0\"\n [loading]=\"(controller.isLoading$ | async) ?? false\"\n (selectPill)=\"onSelectPill($event)\"\n ></aia-pill-list>\n </span>\n </ng-container>\n </div>\n\n <ng-container [ngSwitch]=\"submitButtonState\">\n <button\n *ngSwitchCase=\"'default'\"\n type=\"button\"\n data-aia-submit=\"\"\n class=\"magicx-aia-submit-button\"\n [disabled]=\"\n !(\n controller &&\n canSubmit({\n segments: (controller.segments$ | async) ?? [],\n completedParams: (controller.completedParams$ | async) ?? []\n })\n )\n \"\n aria-label=\"Submit\"\n (click)=\"onSubmitButtonClick($event)\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Submit\"\n >\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n\n <span\n *ngSwitchCase=\"'custom'\"\n data-aia-submit=\"\"\n class=\"magicx-aia-submit-slot\"\n (click)=\"onSubmitSlotClick($event)\"\n >\n <ng-container *ngTemplateOutlet=\"customSubmitTemplate\"></ng-container>\n </span>\n </ng-container>\n </div>\n</div>\n", styles: [":where(.magicx-aia,.magicx-aia *,.magicx-aia *::before,.magicx-aia *::after){box-sizing:border-box}:where(.magicx-aia),:where(.magicx-aia[data-mode=\"light\"]){--aia-pill-bg: #bdbdbd;--aia-pill-color: #000000;--aia-pill-font-size: 19px;--aia-option-bg: transparent;--aia-option-color: #4f4f4f;--aia-option-color-selected: #000000;--aia-option-font-size: 19px;--aia-written-text-color: #000000;--aia-written-text-font-size: 19px;--aia-caret-color: var(--aia-written-text-color, #000000);--aia-submit-bg: #000000;--aia-submit-color: #ffffff;--aia-color-text-muted: #6b7280;--aia-skeleton-bg: rgba(189, 189, 189, .51);--aia-streak-rgb: 99, 102, 241;--aia-streak-glass-bg: rgba(99, 102, 241, .1)}:where(.magicx-aia[data-mode=\"dark\"]){--aia-pill-bg: #bdbdbd;--aia-pill-color: #ffffff;--aia-pill-font-size: 19px;--aia-option-bg: transparent;--aia-option-color: #b0b0b0;--aia-option-color-selected: #ffffff;--aia-option-font-size: 19px;--aia-written-text-color: #ffffff;--aia-written-text-font-size: 19px;--aia-caret-color: var(--aia-written-text-color, #ffffff);--aia-submit-bg: #ffffff;--aia-submit-color: #000000;--aia-color-text-muted: #c1c4cb;--aia-skeleton-bg: #333539;--aia-streak-rgb: 255, 255, 255;--aia-streak-glass-bg: rgba(255, 255, 255, .1)}:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown]{top:auto;bottom:100%;margin-top:0;margin-bottom:6px;flex-direction:column-reverse}:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-pillbar]{padding:0 27px 27px}:where(.magicx-aia[data-animations=\"off\"]) *,:where(.magicx-aia[data-animations=\"off\"]) *:before,:where(.magicx-aia[data-animations=\"off\"]) *:after{animation-duration:0s!important;transition-duration:0s!important}.magicx-aia-container{position:relative;font-family:var(--aia-font-family, inherit);container-type:inline-size}.magicx-aia-input-wrapper{padding:20px;border:1px solid var(--aia-color-border-default, #9ea5b2);border-radius:23px;background:transparent;overflow:hidden;display:flex;align-items:center;gap:4px}.magicx-aia-editor-area{position:relative;flex:1;min-width:0;min-height:26.6px;line-height:26.6px;font-family:inherit;font-size:var(--aia-written-text-font-size, 19px);white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere}.magicx-aia-input{display:inline;outline:none;background:transparent;color:var(--aia-written-text-color, var(--aia-color-text-default, #fff));caret-color:var( --aia-caret-color, var(--aia-written-text-color, var(--aia-color-text-default, #fff)) );font-weight:250;vertical-align:middle}:where(.magicx-aia-input) strong{font-weight:500;letter-spacing:-.01em}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]{background-color:color-mix(in srgb,var(--aia-edit-outline, currentColor) 20%,transparent);border-radius:6px;padding:2px 3px;margin:0 -1.5px;caret-color:transparent}.magicx-aia-input:has(strong[class~=\"magicx-aia-segment--editing\"]){caret-color:transparent}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]::selection{background:transparent;color:inherit}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]::-moz-selection{background:transparent;color:inherit}.magicx-aia-input[data-aia-empty=true][data-placeholder]:before{content:attr(data-placeholder);color:var(--aia-color-text-muted, #c1c4cb);opacity:.7;pointer-events:none}.magicx-aia-input[data-aia-empty=true]{display:inline-block;min-width:1px}.magicx-aia-pill-list-container{display:inline;margin-left:8px}.magicx-aia-pill-list-container:empty,.magicx-aia-pill-list-container[data-aia-pill-wrapped]{margin-left:0}.magicx-aia-submit-button{flex-shrink:0;width:36px;height:36px;border-radius:50%;border:none;background:var(--aia-submit-bg, var(--aia-color-text-default, #fff));color:var(--aia-submit-color, var(--aia-color-bg-default, #000));cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;transition:opacity .2s ease}.magicx-aia-submit-button:hover{opacity:.85}.magicx-aia-submit-slot{display:contents}:where(.magicx-aia-input) strong[class~=magicx-aia-shimmer-revealed]{color:transparent;background:linear-gradient(120deg,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 0%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 44%,#b0b0b0 48%,#b0b0b0 52%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 56%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 100%);background-size:200% 100%;-webkit-background-clip:text;background-clip:text}:where(.magicx-aia-input) strong[class~=magicx-aia-shimmer-sweep]{animation:aiaTextShimmer .65s ease-out forwards}@keyframes aiaTextShimmer{0%{background-position:100% 0}to{background-position:-50% 0}}\n"] }]
1401
+ ], template: "<div\n #container\n class=\"magicx-aia magicx-aia-container\"\n [attr.data-pill-placement]=\"pillPlacement\"\n [attr.data-options-position]=\"optionsPosition\"\n [attr.data-animations]=\"animations ? 'on' : 'off'\"\n [attr.data-mode]=\"resolvedMode\"\n>\n <ai-autocomplete-dropdown\n *ngIf=\"controller\"\n [controller]=\"controller\"\n [showPills]=\"showDropdownPills\"\n ></ai-autocomplete-dropdown>\n\n <div\n class=\"magicx-aia-input-wrapper\"\n (click)=\"onWrapperClick($event)\"\n (keyup)=\"$event.stopPropagation()\"\n >\n <div class=\"magicx-aia-editor-area\" data-aia-editor=\"\">\n <div\n #editor\n *ngIf=\"controller\"\n [aiaEditorHost]=\"controller\"\n [autoFocus]=\"autoFocus\"\n class=\"magicx-aia-input\"\n data-aia-input=\"\"\n ></div>\n\n <ng-container *ngIf=\"controller && showInlinePills\">\n <span\n #pillContainer\n class=\"magicx-aia-pill-list-container\"\n data-aia-pill-list-container=\"\"\n *ngIf=\"\n (controller.isLoading$ | async) ||\n ((controller.suggestionPills$ | async)?.length ?? 0) > 0\n \"\n >\n <aia-pill-list\n [pills]=\"(controller.suggestionPills$ | async) ?? []\"\n [activePillIndex]=\"0\"\n [loading]=\"(controller.isLoading$ | async) ?? false\"\n (selectPill)=\"onSelectPill($event)\"\n ></aia-pill-list>\n </span>\n </ng-container>\n </div>\n\n <ng-container [ngSwitch]=\"submitButtonState\">\n <aia-submit-button\n *ngSwitchCase=\"'default'\"\n [disabled]=\"\n !(\n controller &&\n canSubmit({\n segments: (controller.segments$ | async) ?? [],\n completedParams: (controller.completedParams$ | async) ?? []\n })\n )\n \"\n (submit)=\"onSubmitButtonClick($event)\"\n ></aia-submit-button>\n\n <span\n *ngSwitchCase=\"'custom'\"\n data-aia-submit=\"\"\n class=\"magicx-aia-submit-slot\"\n (click)=\"onSubmitSlotClick($event)\"\n >\n <ng-container *ngTemplateOutlet=\"customSubmitTemplate\"></ng-container>\n </span>\n </ng-container>\n </div>\n</div>\n", styles: [":where(.magicx-aia,.magicx-aia *,.magicx-aia *::before,.magicx-aia *::after){box-sizing:border-box}:where(.magicx-aia),:where(.magicx-aia[data-mode=\"light\"]){--aia-surface: #ffffff;--aia-border: #b0b0b0;--aia-pill-bg: #bdbdbd;--aia-pill-color: #333539;--aia-pill-font-size: 18px;--aia-option-bg: transparent;--aia-option-color: #505050;--aia-option-color-selected: #000000;--aia-option-font-size: 18px;--aia-written-text-color: #000000;--aia-written-text-font-size: 20px;--aia-caret-color: var(--aia-written-text-color, #000000);--aia-submit-bg: #000000;--aia-submit-color: #ffffff;--aia-color-text-muted: #6b7280;--aia-skeleton-bg: rgba(189, 189, 189, .51);--aia-streak-rgb: 99, 102, 241;--aia-streak-glass-bg: rgba(99, 102, 241, .1);--aia-footer-divider: rgba(176, 176, 176, .4);--aia-footer-hint-color: #505050;--aia-footer-brand-color: #b0b0b0;--aia-footer-badge-border: rgba(189, 189, 189, .51)}:where(.magicx-aia[data-mode=\"dark\"]){--aia-surface: #000000;--aia-border: #505050;--aia-pill-bg: #bdbdbd;--aia-pill-color: #b0b0b0;--aia-pill-font-size: 18px;--aia-option-bg: transparent;--aia-option-color: #b0b0b0;--aia-option-color-selected: #ffffff;--aia-option-font-size: 18px;--aia-written-text-color: #ffffff;--aia-written-text-font-size: 20px;--aia-caret-color: var(--aia-written-text-color, #ffffff);--aia-submit-bg: #ffffff;--aia-submit-color: #000000;--aia-color-text-muted: #c1c4cb;--aia-skeleton-bg: #333539;--aia-streak-rgb: 255, 255, 255;--aia-streak-glass-bg: rgba(255, 255, 255, .1);--aia-footer-divider: rgba(255, 255, 255, .15);--aia-footer-hint-color: #b0b0b0;--aia-footer-brand-color: #505050;--aia-footer-badge-border: #505050}:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown]{top:auto;bottom:100%;margin-top:0;margin-bottom:6px}:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] .aia-stack{flex-direction:column-reverse}:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] .magicx-aia-footer{flex-direction:column-reverse}:where(.magicx-aia[data-animations=\"off\"]) *,:where(.magicx-aia[data-animations=\"off\"]) *:before,:where(.magicx-aia[data-animations=\"off\"]) *:after{animation-duration:0s!important;transition-duration:0s!important}.magicx-aia-container{position:relative;font-family:var(--aia-font-family, inherit);container-type:inline-size}.magicx-aia-input-wrapper{padding:19px 15px 20px 25px;border:1px solid var(--aia-border, #b0b0b0);border-radius:30px;background:var(--aia-surface, #ffffff);overflow:hidden;display:flex;align-items:center;gap:4px}.magicx-aia-editor-area{position:relative;flex:1;min-width:0;min-height:26.6px;line-height:26.6px;font-family:inherit;font-size:var(--aia-written-text-font-size, 19px);white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere}.magicx-aia-input{display:inline;outline:none;background:transparent;color:var(--aia-written-text-color, var(--aia-color-text-default, #fff));caret-color:var( --aia-caret-color, var(--aia-written-text-color, var(--aia-color-text-default, #fff)) );font-weight:250;vertical-align:middle}:where(.magicx-aia-input) strong{font-weight:500;letter-spacing:-.01em}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]{background-color:color-mix(in srgb,var(--aia-edit-outline, currentColor) 20%,transparent);border-radius:6px;padding:2px 3px;margin:0 -1.5px;caret-color:transparent}.magicx-aia-input:has(strong[class~=\"magicx-aia-segment--editing\"]){caret-color:transparent}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]::selection{background:transparent;color:inherit}:where(.magicx-aia-input) strong[class~=magicx-aia-segment--editing]::-moz-selection{background:transparent;color:inherit}.magicx-aia-input[data-aia-empty=true][data-placeholder]:before{content:attr(data-placeholder);color:var(--aia-color-text-muted, #c1c4cb);opacity:.7;pointer-events:none}.magicx-aia-input[data-aia-empty=true]{display:inline-block;min-width:1px}.magicx-aia-pill-list-container{display:inline;margin-left:8px}.magicx-aia-pill-list-container:empty,.magicx-aia-pill-list-container[data-aia-pill-wrapped]{margin-left:0}.magicx-aia-submit-slot{display:contents}:where(.magicx-aia-input) strong[class~=magicx-aia-shimmer-revealed]{color:transparent;background:linear-gradient(120deg,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 0%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 44%,#b0b0b0 48%,#b0b0b0 52%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 56%,var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 100%);background-size:200% 100%;-webkit-background-clip:text;background-clip:text}:where(.magicx-aia-input) strong[class~=magicx-aia-shimmer-sweep]{animation:aiaTextShimmer .65s ease-out forwards}@keyframes aiaTextShimmer{0%{background-position:100% 0}to{background-position:-50% 0}}\n"] }]
1122
1402
  }], propDecorators: { apiConfig: [{
1123
1403
  type: Input
1124
1404
  }], optionOverrides: [{
@@ -1161,6 +1441,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
1161
1441
  type: Output
1162
1442
  }], blurred: [{
1163
1443
  type: Output
1444
+ }], containerRef: [{
1445
+ type: ViewChild,
1446
+ args: ["container", { static: true }]
1164
1447
  }], editorRef: [{
1165
1448
  type: ViewChild,
1166
1449
  args: ["editor", { static: false }]
@@ -1171,6 +1454,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
1171
1454
  function noop$1() {
1172
1455
  // Default no-op for CVA callbacks.
1173
1456
  }
1457
+ /**
1458
+ * Resolve a concrete light/dark value from the configured mode. Used to seed
1459
+ * the `data-mode` attribute synchronously (including during SSR, where
1460
+ * ModeController never runs). On the server `window` is undefined → defaults
1461
+ * to "dark" (matches the vanilla/React behavior).
1462
+ */
1463
+ function resolveInitialMode(mode) {
1464
+ if (mode !== "auto")
1465
+ return mode;
1466
+ if (typeof window === "undefined")
1467
+ return "dark";
1468
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1469
+ }
1174
1470
 
1175
1471
  /**
1176
1472
  * Tier 2 input binder. Attach to a `<textarea>` or `<input>` and pass an
@@ -1204,11 +1500,23 @@ class AIAutocompleteInputDirective {
1204
1500
  this.destroy$ = new Subject();
1205
1501
  this.onChangeFn = noop;
1206
1502
  this.onTouchedFn = noop;
1503
+ // Timestamp of the last `input` event. A `keyup`/`select` that fires within
1504
+ // this window is the tail of a keystroke, not a deliberate caret move, so we
1505
+ // skip the caret-move handler there (mirrors the editor host's selectionchange
1506
+ // guard). performance.now() is monotonic; 0 means "no input yet".
1507
+ this.lastInputAt = 0;
1508
+ // Tracks the most-recently-promoted param so we only reposition the caret
1509
+ // once per option selection (mirrors the editor host's post-promote refocus).
1510
+ this.lastSeenParamId = "";
1207
1511
  }
1208
1512
  ngOnInit() {
1209
1513
  if (!this.controller) {
1210
1514
  throw new Error('[aiaInput] requires a controller — use `[aiaInput]="myController"`.');
1211
1515
  }
1516
+ if (this.pendingWriteValue !== undefined) {
1517
+ this.controller.setValue(this.pendingWriteValue);
1518
+ this.pendingWriteValue = undefined;
1519
+ }
1212
1520
  const el = this.el.nativeElement;
1213
1521
  this.renderer.setAttribute(el, "aria-controls", this.controller.listboxId);
1214
1522
  // Sync editor text → DOM. Skips the write when values already match, so
@@ -1244,6 +1552,36 @@ class AIAutocompleteInputDirective {
1244
1552
  this.renderer.removeAttribute(el, "aria-activedescendant");
1245
1553
  }
1246
1554
  });
1555
+ // After an option selection promotes a param, the core appends its text and
1556
+ // stamps `caretOffset` at the end of the inserted text. The text$ subscriber
1557
+ // above writes the new value but *restores the pre-write caret* (correct for
1558
+ // typing echoes, wrong here), so we move the caret to the promoted position.
1559
+ // Keyed on newParamId so it fires once per selection, not on every tick.
1560
+ // Registered after text$ so the new value is in the DOM before we seek.
1561
+ this.controller.newParamId$.pipe(takeUntil(this.destroy$)).subscribe((id) => {
1562
+ var _a;
1563
+ const current = id !== null && id !== void 0 ? id : "";
1564
+ if (current && current !== this.lastSeenParamId) {
1565
+ this.lastSeenParamId = current;
1566
+ const offset = (_a = this.controller.getState().caretOffset) !== null && _a !== void 0 ? _a : el.value.length;
1567
+ const clamped = Math.min(Math.max(offset, 0), el.value.length);
1568
+ // Only grab focus if we don't already have it — don't yank focus back
1569
+ // from wherever the user moved it after selecting (e.g. a host-app
1570
+ // button). setSelectionRange still positions the caret regardless.
1571
+ if (typeof document !== "undefined" && document.activeElement !== el) {
1572
+ el.focus();
1573
+ }
1574
+ try {
1575
+ el.setSelectionRange(clamped, clamped);
1576
+ }
1577
+ catch (_b) {
1578
+ // Some input types (e.g. "number") don't support setSelectionRange.
1579
+ }
1580
+ }
1581
+ else if (!current) {
1582
+ this.lastSeenParamId = "";
1583
+ }
1584
+ });
1247
1585
  }
1248
1586
  ngOnDestroy() {
1249
1587
  this.destroy$.next();
@@ -1257,6 +1595,12 @@ class AIAutocompleteInputDirective {
1257
1595
  * we don't disrupt multi-keystroke input methods (Pinyin, Hangul, etc.).
1258
1596
  */
1259
1597
  onInput(event) {
1598
+ var _a;
1599
+ // Stamp the input time before anything else. The autocapitalize path below
1600
+ // calls setSelectionRange, which can synchronously fire a `select` event →
1601
+ // onCaretMove; stamping first ensures that event falls inside the guard
1602
+ // window and is treated as part of this keystroke, not a caret move.
1603
+ this.lastInputAt = performance.now();
1260
1604
  const target = event.target;
1261
1605
  const raw = target.value;
1262
1606
  const isComposing = event.isComposing === true;
@@ -1271,17 +1615,43 @@ class AIAutocompleteInputDirective {
1271
1615
  try {
1272
1616
  target.setSelectionRange(start, end);
1273
1617
  }
1274
- catch (_a) {
1618
+ catch (_b) {
1275
1619
  // See note in ngOnInit's text$ subscriber.
1276
1620
  }
1277
1621
  }
1278
1622
  }
1279
1623
  this.controller.handleTextChange(next);
1624
+ // Sync the real caret into the core. The dropdown's auto-trigger gate only
1625
+ // opens when the caret is at the end of the text; without this, the core's
1626
+ // `caretOffset` stays pinned at whatever a prior promote/select set it to
1627
+ // and goes stale as the user keeps typing, wedging the dropdown closed.
1628
+ // selectionStart is null on some input types (number/email/color); treat
1629
+ // that as "caret at end" rather than feeding null into the core.
1630
+ this.controller.handleCaretAfterInput((_a = target.selectionStart) !== null && _a !== void 0 ? _a : target.value.length);
1280
1631
  this.onChangeFn(next);
1281
1632
  }
1282
1633
  onKeyDown(event) {
1283
1634
  this.controller.handleKeyDown(event);
1284
1635
  }
1636
+ /**
1637
+ * Caret moved by something other than typing — arrow keys, Home/End, or a
1638
+ * mouse click/drag (keyup + mouseup). Forward the new offset so the core can
1639
+ * re-evaluate the caret-at-end dropdown gate (and exit re-edit if the caret
1640
+ * left the region). We deliberately do NOT listen for the `select` event:
1641
+ * programmatic `setSelectionRange` calls (the text$ writeback, the post-select
1642
+ * caret reposition) fire it in jsdom/some browsers, which would re-enter here
1643
+ * and clobber `caretOffset`. `keyup`/`mouseup` only fire for real user input.
1644
+ * Skipped right after an `input` event, where the caret is already handled by
1645
+ * `handleCaretAfterInput` above.
1646
+ */
1647
+ onCaretMove() {
1648
+ var _a;
1649
+ if (performance.now() - this.lastInputAt < 50)
1650
+ return;
1651
+ const el = this.el.nativeElement;
1652
+ // selectionStart is null on some input types — treat as caret at end.
1653
+ this.controller.handleCaretMove((_a = el.selectionStart) !== null && _a !== void 0 ? _a : el.value.length);
1654
+ }
1285
1655
  onFocus() {
1286
1656
  this.controller.setFocused(true);
1287
1657
  }
@@ -1293,11 +1663,17 @@ class AIAutocompleteInputDirective {
1293
1663
  writeValue(value) {
1294
1664
  const next = value !== null && value !== void 0 ? value : "";
1295
1665
  this.renderer.setProperty(this.el.nativeElement, "value", next);
1296
- // The controller may be undefined transiently if Angular calls
1297
- // writeValue() before ngOnInit (rare but possible during dynamic form
1298
- // construction). Guard so we don't throw in that window.
1299
- if (this.controller)
1666
+ // If Angular calls writeValue() before ngOnInit (possible during dynamic
1667
+ // form construction), queue the value and let ngOnInit flush it. We
1668
+ // can't push it into the controller now because either the controller
1669
+ // binding hasn't resolved yet, or text$'s initial subscription would
1670
+ // overwrite it moments later.
1671
+ if (this.controller) {
1300
1672
  this.controller.setValue(next);
1673
+ }
1674
+ else {
1675
+ this.pendingWriteValue = next;
1676
+ }
1301
1677
  }
1302
1678
  registerOnChange(fn) {
1303
1679
  this.onChangeFn = fn;
@@ -1310,7 +1686,7 @@ class AIAutocompleteInputDirective {
1310
1686
  }
1311
1687
  }
1312
1688
  AIAutocompleteInputDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: AIAutocompleteInputDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1313
- AIAutocompleteInputDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: AIAutocompleteInputDirective, isStandalone: true, selector: "[aiaInput]", inputs: { controller: ["aiaInput", "controller"] }, host: { attributes: { "role": "combobox", "aria-autocomplete": "list" }, listeners: { "input": "onInput($event)", "keydown": "onKeyDown($event)", "focus": "onFocus()", "blur": "onBlur()" } }, providers: [
1689
+ AIAutocompleteInputDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: AIAutocompleteInputDirective, isStandalone: true, selector: "[aiaInput]", inputs: { controller: ["aiaInput", "controller"] }, host: { attributes: { "role": "combobox", "aria-autocomplete": "list" }, listeners: { "input": "onInput($event)", "keydown": "onKeyDown($event)", "keyup": "onCaretMove()", "mouseup": "onCaretMove()", "focus": "onFocus()", "blur": "onBlur()" } }, providers: [
1314
1690
  {
1315
1691
  provide: NG_VALUE_ACCESSOR,
1316
1692
  // eslint-disable-next-line @typescript-eslint/no-use-before-define
@@ -1328,6 +1704,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
1328
1704
  "aria-autocomplete": "list",
1329
1705
  "(input)": "onInput($event)",
1330
1706
  "(keydown)": "onKeyDown($event)",
1707
+ "(keyup)": "onCaretMove()",
1708
+ "(mouseup)": "onCaretMove()",
1331
1709
  "(focus)": "onFocus()",
1332
1710
  "(blur)": "onBlur()",
1333
1711
  },