@akcelik/strct 4.21.0 → 4.23.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.
@@ -23261,6 +23261,795 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
23261
23261
  }, styles: [".strct-mf{position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden;border:1px solid var(--b2);border-radius:var(--radius-md);background:var(--bg-3);min-width:0}.strct-mf>img,.strct-mf>video,.strct-mf>canvas{width:100%;height:100%;object-fit:cover;display:block}.strct-mf[data-state=off]{background:#000}.strct-mf__placeholder{display:flex;flex-direction:column;align-items:center;gap:6px;padding:var(--space-2);color:var(--t3);text-align:center}.strct-mf[data-state=off] .strct-mf__placeholder{color:#fff9}.strct-mf[data-state=error] .strct-mf__placeholder{color:var(--critical)}.strct-mf__msg{font-size:var(--text-sm);line-height:1.35}.strct-mf__hit{position:absolute;inset:-1px;padding:0;border:0;background:none;cursor:pointer}.strct-mf__hit:focus-visible{outline:2px solid var(--acc50);outline-offset:2px}.strct-mf--interactive:hover{border-color:var(--b3)}\n"] }]
23262
23262
  }], propDecorators: { ratio: [{ type: i0.Input, args: [{ isSignal: true, alias: "ratio", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], activateLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "activateLabel", required: false }] }], activated: [{ type: i0.Output, args: ["activated"] }] } });
23263
23263
 
23264
+ const WINDOW_LABELS = {
23265
+ minimize: 'Minimize',
23266
+ maximize: 'Maximize',
23267
+ restore: 'Restore',
23268
+ close: 'Close',
23269
+ dock: 'Minimized windows',
23270
+ };
23271
+ let windowCounter = 0;
23272
+ /**
23273
+ * Knows which windows exist, which is on top, and which are minimised — so the
23274
+ * dock can list them and a click can raise one.
23275
+ */
23276
+ class StrctWindowService {
23277
+ topZ = 0;
23278
+ windows = signal([], /* @ts-ignore */
23279
+ ...(ngDevMode ? [{ debugName: "windows" }] : /* istanbul ignore next */ []));
23280
+ /** The minimised ones, in the order they were opened. */
23281
+ minimized = computed(() => this.windows().filter((w) => w.minimized()), /* @ts-ignore */
23282
+ ...(ngDevMode ? [{ debugName: "minimized" }] : /* istanbul ignore next */ []));
23283
+ register(w) {
23284
+ this.windows.update((ws) => [...ws, w]);
23285
+ }
23286
+ unregister(w) {
23287
+ this.windows.update((ws) => ws.filter((x) => x !== w));
23288
+ }
23289
+ /** Raise a window above the others; returns its new stacking offset. */
23290
+ raise() {
23291
+ return ++this.topZ;
23292
+ }
23293
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctWindowService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
23294
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctWindowService, providedIn: 'root' });
23295
+ }
23296
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctWindowService, decorators: [{
23297
+ type: Injectable,
23298
+ args: [{ providedIn: 'root' }]
23299
+ }] });
23300
+ /**
23301
+ * Some work lives in a window beside the page: a VM console stays open while
23302
+ * the operator browses. It can be moved, resized and minimised, and it comes
23303
+ * back from the dock. A modal blocks the page and a drawer is pinned to an
23304
+ * edge — neither is a window.
23305
+ *
23306
+ * <strct-window [(open)]="open" [(minimized)]="min" heading="APP01" palette="dark">
23307
+ * <ng-container strctWindowTitleMeta><strct-badge status="success">Running</strct-badge></ng-container>
23308
+ * <ng-container strctWindowActions>…</ng-container>
23309
+ * …content…
23310
+ * <ng-container strctWindowStatus>…</ng-container>
23311
+ * </strct-window>
23312
+ * <strct-window-dock />
23313
+ */
23314
+ class StrctWindow {
23315
+ /** Whether the window exists on screen (two-way). */
23316
+ open = model(false, /* @ts-ignore */
23317
+ ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
23318
+ /** Minimised to the dock (two-way). */
23319
+ minimized = model(false, /* @ts-ignore */
23320
+ ...(ngDevMode ? [{ debugName: "minimized" }] : /* istanbul ignore next */ []));
23321
+ /** Filling the viewport — not browser fullscreen (two-way). */
23322
+ maximized = model(false, /* @ts-ignore */
23323
+ ...(ngDevMode ? [{ debugName: "maximized" }] : /* istanbul ignore next */ []));
23324
+ /** Position and size in px (two-way); null lets the window place itself. */
23325
+ bounds = model(null, /* @ts-ignore */
23326
+ ...(ngDevMode ? [{ debugName: "bounds" }] : /* istanbul ignore next */ []));
23327
+ /** The title-bar heading, and the window's accessible name. */
23328
+ heading = input('', /* @ts-ignore */
23329
+ ...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
23330
+ /** Corner resize grips. */
23331
+ resizable = input(true, { ...(ngDevMode ? { debugName: "resizable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
23332
+ minWidth = input(480, /* @ts-ignore */
23333
+ ...(ngDevMode ? [{ debugName: "minWidth" }] : /* istanbul ignore next */ []));
23334
+ minHeight = input(320, /* @ts-ignore */
23335
+ ...(ngDevMode ? [{ debugName: "minHeight" }] : /* istanbul ignore next */ []));
23336
+ /** `dark` / `light` force that scheme inside the window (a console is dark). */
23337
+ palette = input('inherit', /* @ts-ignore */
23338
+ ...(ngDevMode ? [{ debugName: "palette" }] : /* istanbul ignore next */ []));
23339
+ /** What a click outside does. A window is not dismissed like a modal. */
23340
+ closeOnOutside = input('none', /* @ts-ignore */
23341
+ ...(ngDevMode ? [{ debugName: "closeOnOutside" }] : /* istanbul ignore next */ []));
23342
+ /** The window's own strings. */
23343
+ labels = input({}, /* @ts-ignore */
23344
+ ...(ngDevMode ? [{ debugName: "labels" }] : /* istanbul ignore next */ []));
23345
+ /** The accessible name of each resize grip. */
23346
+ resizeLabel = input((corner) => `Resize (${corner})`, /* @ts-ignore */
23347
+ ...(ngDevMode ? [{ debugName: "resizeLabel" }] : /* istanbul ignore next */ []));
23348
+ /** The window was closed. */
23349
+ closed = output();
23350
+ CORNERS = ['nw', 'ne', 'sw', 'se'];
23351
+ titleId = `strct-window-${++windowCounter}`;
23352
+ L = computed(() => ({
23353
+ ...WINDOW_LABELS,
23354
+ ...this.labels(),
23355
+ }), /* @ts-ignore */
23356
+ ...(ngDevMode ? [{ debugName: "L" }] : /* istanbul ignore next */ []));
23357
+ service = inject(StrctWindowService);
23358
+ doc = inject(DOCUMENT$1);
23359
+ host = inject(ElementRef);
23360
+ zOffset = signal(0, /* @ts-ignore */
23361
+ ...(ngDevMode ? [{ debugName: "zOffset" }] : /* istanbul ignore next */ []));
23362
+ zIndex = computed(() => `calc(var(--z-window) + ${this.zOffset()})`, /* @ts-ignore */
23363
+ ...(ngDevMode ? [{ debugName: "zIndex" }] : /* istanbul ignore next */ []));
23364
+ /** The palette in force outside, so `palette` only swaps the scheme. */
23365
+ hostPalette = computed(() => this.doc.documentElement.getAttribute('data-palette') ?? 'arctic', /* @ts-ignore */
23366
+ ...(ngDevMode ? [{ debugName: "hostPalette" }] : /* istanbul ignore next */ []));
23367
+ /** Where the window is. Defaults to a slightly offset, comfortable box. */
23368
+ fallback = signal({ x: 80, y: 80, width: 720, height: 460 }, /* @ts-ignore */
23369
+ ...(ngDevMode ? [{ debugName: "fallback" }] : /* istanbul ignore next */ []));
23370
+ rect = computed(() => this.bounds() ?? this.fallback(), /* @ts-ignore */
23371
+ ...(ngDevMode ? [{ debugName: "rect" }] : /* istanbul ignore next */ []));
23372
+ restoreTo = null;
23373
+ constructor() {
23374
+ this.service.register(this);
23375
+ effect(() => {
23376
+ if (this.open() && !this.minimized()) {
23377
+ this.restoreTo ??= saveFocusedElement();
23378
+ this.zOffset.set(this.service.raise());
23379
+ queueMicrotask(() => this.focusTitle());
23380
+ }
23381
+ });
23382
+ }
23383
+ /** Raise this window above the others when it is clicked. */
23384
+ focusWindow() {
23385
+ this.zOffset.set(this.service.raise());
23386
+ }
23387
+ focusTitle() {
23388
+ this.host.nativeElement.querySelector('.strct-window__title')?.focus();
23389
+ }
23390
+ minimize() {
23391
+ if (!this.open())
23392
+ return;
23393
+ this.minimized.set(true);
23394
+ restoreFocus(this.restoreTo);
23395
+ }
23396
+ /** Bring a minimised window back and raise it. */
23397
+ restore() {
23398
+ this.minimized.set(false);
23399
+ this.open.set(true);
23400
+ }
23401
+ close() {
23402
+ this.open.set(false);
23403
+ this.minimized.set(false);
23404
+ this.closed.emit();
23405
+ restoreFocus(this.restoreTo);
23406
+ this.restoreTo = null;
23407
+ }
23408
+ // ── Moving ───────────────────────────────────────────────────────────────
23409
+ dragFrom = null;
23410
+ onMove = (e) => this.dragMove(e);
23411
+ onUp = () => this.dragEnd();
23412
+ onDragStart(event) {
23413
+ if (event.target.closest('button'))
23414
+ return;
23415
+ if (this.maximized())
23416
+ return;
23417
+ event.preventDefault();
23418
+ this.dragFrom = { x: event.clientX, y: event.clientY, rect: this.rect() };
23419
+ this.doc.addEventListener('pointermove', this.onMove);
23420
+ this.doc.addEventListener('pointerup', this.onUp);
23421
+ this.doc.addEventListener('pointercancel', this.onUp);
23422
+ }
23423
+ dragMove(event) {
23424
+ const from = this.dragFrom;
23425
+ if (!from)
23426
+ return;
23427
+ this.setRect({
23428
+ ...from.rect,
23429
+ x: from.rect.x + (event.clientX - from.x),
23430
+ y: from.rect.y + (event.clientY - from.y),
23431
+ });
23432
+ }
23433
+ dragEnd() {
23434
+ this.dragFrom = null;
23435
+ this.doc.removeEventListener('pointermove', this.onMove);
23436
+ this.doc.removeEventListener('pointerup', this.onUp);
23437
+ this.doc.removeEventListener('pointercancel', this.onUp);
23438
+ }
23439
+ /** Alt+arrows move the window; Escape minimises it. */
23440
+ onTitleKeydown(event) {
23441
+ if (!event.altKey)
23442
+ return;
23443
+ const step = event.shiftKey ? 64 : 16;
23444
+ const r = this.rect();
23445
+ const moves = {
23446
+ ArrowLeft: { x: r.x - step },
23447
+ ArrowRight: { x: r.x + step },
23448
+ ArrowUp: { y: r.y - step },
23449
+ ArrowDown: { y: r.y + step },
23450
+ };
23451
+ const move = moves[event.key];
23452
+ if (!move)
23453
+ return;
23454
+ event.preventDefault();
23455
+ this.setRect({ ...r, ...move });
23456
+ }
23457
+ // ── Resizing ─────────────────────────────────────────────────────────────
23458
+ resizeFrom = null;
23459
+ onResizeMove = (e) => this.resizeMove(e);
23460
+ onResizeUp = () => this.resizeEnd();
23461
+ onResizeStart(event, corner) {
23462
+ event.preventDefault();
23463
+ event.stopPropagation();
23464
+ this.resizeFrom = { x: event.clientX, y: event.clientY, rect: this.rect(), corner };
23465
+ this.doc.addEventListener('pointermove', this.onResizeMove);
23466
+ this.doc.addEventListener('pointerup', this.onResizeUp);
23467
+ this.doc.addEventListener('pointercancel', this.onResizeUp);
23468
+ }
23469
+ resizeMove(event) {
23470
+ const from = this.resizeFrom;
23471
+ if (!from)
23472
+ return;
23473
+ this.setRect(this.resized(from.rect, from.corner, event.clientX - from.x, event.clientY - from.y));
23474
+ }
23475
+ resizeEnd() {
23476
+ this.resizeFrom = null;
23477
+ this.doc.removeEventListener('pointermove', this.onResizeMove);
23478
+ this.doc.removeEventListener('pointerup', this.onResizeUp);
23479
+ this.doc.removeEventListener('pointercancel', this.onResizeUp);
23480
+ }
23481
+ /** Arrows resize by 16px, Shift+arrows by 64px. */
23482
+ onResizeKeydown(event, corner) {
23483
+ const step = event.shiftKey ? 64 : 16;
23484
+ const deltas = {
23485
+ ArrowLeft: [-step, 0],
23486
+ ArrowRight: [step, 0],
23487
+ ArrowUp: [0, -step],
23488
+ ArrowDown: [0, step],
23489
+ };
23490
+ const delta = deltas[event.key];
23491
+ if (!delta)
23492
+ return;
23493
+ event.preventDefault();
23494
+ this.setRect(this.resized(this.rect(), corner, delta[0], delta[1]));
23495
+ }
23496
+ /**
23497
+ * A corner drag moves the two edges it touches: the west and north edges move
23498
+ * the window's origin as well as its size, so the opposite corner stays put.
23499
+ */
23500
+ resized(rect, corner, dx, dy) {
23501
+ const west = corner.includes('w');
23502
+ const north = corner.includes('n');
23503
+ const width = Math.max(this.minWidth(), rect.width + (west ? -dx : dx));
23504
+ const height = Math.max(this.minHeight(), rect.height + (north ? -dy : dy));
23505
+ return {
23506
+ x: west ? rect.x + (rect.width - width) : rect.x,
23507
+ y: north ? rect.y + (rect.height - height) : rect.y,
23508
+ width,
23509
+ height,
23510
+ };
23511
+ }
23512
+ setRect(next) {
23513
+ if (this.bounds())
23514
+ this.bounds.set(next);
23515
+ else
23516
+ this.fallback.set(next);
23517
+ }
23518
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctWindow, deps: [], target: i0.ɵɵFactoryTarget.Component });
23519
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctWindow, isStandalone: true, selector: "strct-window", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, minimized: { classPropertyName: "minimized", publicName: "minimized", isSignal: true, isRequired: false, transformFunction: null }, maximized: { classPropertyName: "maximized", publicName: "maximized", isSignal: true, isRequired: false, transformFunction: null }, bounds: { classPropertyName: "bounds", publicName: "bounds", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, palette: { classPropertyName: "palette", publicName: "palette", isSignal: true, isRequired: false, transformFunction: null }, closeOnOutside: { classPropertyName: "closeOnOutside", publicName: "closeOnOutside", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, resizeLabel: { classPropertyName: "resizeLabel", publicName: "resizeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", minimized: "minimizedChange", maximized: "maximizedChange", bounds: "boundsChange", closed: "closed" }, host: { classAttribute: "strct-window" }, ngImport: i0, template: `
23520
+ @if (open() && !minimized()) {
23521
+ <div
23522
+ class="strct-window__frame"
23523
+ role="dialog"
23524
+ aria-modal="false"
23525
+ [attr.aria-labelledby]="titleId"
23526
+ [attr.data-palette]="palette() === 'inherit' ? null : hostPalette()"
23527
+ [attr.data-theme]="palette() === 'inherit' ? null : palette()"
23528
+ [style.z-index]="zIndex()"
23529
+ [style.left.px]="maximized() ? null : rect().x"
23530
+ [style.top.px]="maximized() ? null : rect().y"
23531
+ [style.width.px]="maximized() ? null : rect().width"
23532
+ [style.height.px]="maximized() ? null : rect().height"
23533
+ [class.strct-window__frame--max]="maximized()"
23534
+ (pointerdown)="focusWindow()"
23535
+ (keydown.escape)="minimize()"
23536
+ >
23537
+ <!-- The title bar moves the window: by pointer, or with Alt+arrows. -->
23538
+ <div
23539
+ class="strct-window__title"
23540
+ tabindex="0"
23541
+ [attr.aria-label]="heading()"
23542
+ (pointerdown)="onDragStart($event)"
23543
+ (keydown)="onTitleKeydown($event)"
23544
+ (dblclick)="maximized.set(!maximized())"
23545
+ >
23546
+ <span class="strct-window__heading" [id]="titleId">{{ heading() }}</span>
23547
+ <span class="strct-window__meta"><ng-content select="[strctWindowTitleMeta]" /></span>
23548
+ <span class="strct-window__actions"><ng-content select="[strctWindowActions]" /></span>
23549
+ <span class="strct-window__controls">
23550
+ <button
23551
+ type="button"
23552
+ class="strct-window__btn"
23553
+ [attr.aria-label]="L().minimize"
23554
+ (click)="minimize()"
23555
+ >
23556
+ <strct-icon strictName="minus" [size]="14" />
23557
+ </button>
23558
+ <button
23559
+ type="button"
23560
+ class="strct-window__btn"
23561
+ [attr.aria-label]="maximized() ? L().restore : L().maximize"
23562
+ (click)="maximized.set(!maximized())"
23563
+ >
23564
+ <strct-icon
23565
+ [strictName]="maximized() ? 'exitFullscreen' : 'fullscreen'"
23566
+ [size]="13"
23567
+ />
23568
+ </button>
23569
+ <button
23570
+ type="button"
23571
+ class="strct-window__btn strct-window__btn--close"
23572
+ [attr.aria-label]="L().close"
23573
+ (click)="close()"
23574
+ >
23575
+ <strct-icon strictName="close" [size]="14" />
23576
+ </button>
23577
+ </span>
23578
+ </div>
23579
+
23580
+ <div class="strct-window__body"><ng-content /></div>
23581
+ <div class="strct-window__status"><ng-content select="[strctWindowStatus]" /></div>
23582
+
23583
+ @if (resizable() && !maximized()) {
23584
+ <!-- Focusable, so a window can be resized without a pointer. -->
23585
+ @for (corner of CORNERS; track corner) {
23586
+ <button
23587
+ type="button"
23588
+ class="strct-window__rz strct-window__rz--{{ corner }}"
23589
+ [attr.aria-label]="resizeLabel()(corner)"
23590
+ (pointerdown)="onResizeStart($event, corner)"
23591
+ (keydown)="onResizeKeydown($event, corner)"
23592
+ ></button>
23593
+ }
23594
+ }
23595
+ </div>
23596
+ }
23597
+ `, isInline: true, styles: [".strct-window{display:contents}.strct-window__frame{position:fixed;display:flex;flex-direction:column;min-width:0;border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-1);color:var(--t1);box-shadow:var(--shadow-overlay, 0 12px 40px rgba(0, 0, 0, .32));overflow:hidden}.strct-window__frame--max{inset:var(--space-3);width:auto;height:auto}.strct-window__title{display:flex;align-items:center;gap:var(--space-2);padding:6px 6px 6px var(--space-3);border-block-end:1px solid var(--b1);background:var(--bg-2);cursor:move;-webkit-user-select:none;user-select:none;touch-action:none}.strct-window__title:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-window__heading{font-size:var(--text-sm);font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.strct-window__meta,.strct-window__actions{display:inline-flex;align-items:center;gap:6px}.strct-window__actions{margin-inline-start:auto}.strct-window__controls{display:inline-flex;align-items:center;gap:2px;flex:none}.strct-window__btn{display:inline-flex;padding:4px;border:0;border-radius:var(--radius-sm);background:transparent;color:var(--t2);cursor:pointer}.strct-window__btn:hover{background:var(--bg-3);color:var(--t1)}.strct-window__btn--close:hover{background:var(--critical-bg);color:var(--critical)}.strct-window__body{flex:1;min-height:0;overflow:auto}.strct-window__status:empty{display:none}.strct-window__status{border-block-start:1px solid var(--b1);padding:4px var(--space-3);font-size:var(--text-sm);color:var(--t3);background:var(--bg-2)}.strct-window__rz{position:absolute;width:14px;height:14px;padding:0;border:0;background:transparent}.strct-window__rz:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-window__rz--nw{inset-block-start:0;inset-inline-start:0;cursor:nwse-resize}.strct-window__rz--ne{inset-block-start:0;inset-inline-end:0;cursor:nesw-resize}.strct-window__rz--sw{inset-block-end:0;inset-inline-start:0;cursor:nesw-resize}.strct-window__rz--se{inset-block-end:0;inset-inline-end:0;cursor:nwse-resize}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23598
+ }
23599
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctWindow, decorators: [{
23600
+ type: Component,
23601
+ args: [{ selector: 'strct-window', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon], template: `
23602
+ @if (open() && !minimized()) {
23603
+ <div
23604
+ class="strct-window__frame"
23605
+ role="dialog"
23606
+ aria-modal="false"
23607
+ [attr.aria-labelledby]="titleId"
23608
+ [attr.data-palette]="palette() === 'inherit' ? null : hostPalette()"
23609
+ [attr.data-theme]="palette() === 'inherit' ? null : palette()"
23610
+ [style.z-index]="zIndex()"
23611
+ [style.left.px]="maximized() ? null : rect().x"
23612
+ [style.top.px]="maximized() ? null : rect().y"
23613
+ [style.width.px]="maximized() ? null : rect().width"
23614
+ [style.height.px]="maximized() ? null : rect().height"
23615
+ [class.strct-window__frame--max]="maximized()"
23616
+ (pointerdown)="focusWindow()"
23617
+ (keydown.escape)="minimize()"
23618
+ >
23619
+ <!-- The title bar moves the window: by pointer, or with Alt+arrows. -->
23620
+ <div
23621
+ class="strct-window__title"
23622
+ tabindex="0"
23623
+ [attr.aria-label]="heading()"
23624
+ (pointerdown)="onDragStart($event)"
23625
+ (keydown)="onTitleKeydown($event)"
23626
+ (dblclick)="maximized.set(!maximized())"
23627
+ >
23628
+ <span class="strct-window__heading" [id]="titleId">{{ heading() }}</span>
23629
+ <span class="strct-window__meta"><ng-content select="[strctWindowTitleMeta]" /></span>
23630
+ <span class="strct-window__actions"><ng-content select="[strctWindowActions]" /></span>
23631
+ <span class="strct-window__controls">
23632
+ <button
23633
+ type="button"
23634
+ class="strct-window__btn"
23635
+ [attr.aria-label]="L().minimize"
23636
+ (click)="minimize()"
23637
+ >
23638
+ <strct-icon strictName="minus" [size]="14" />
23639
+ </button>
23640
+ <button
23641
+ type="button"
23642
+ class="strct-window__btn"
23643
+ [attr.aria-label]="maximized() ? L().restore : L().maximize"
23644
+ (click)="maximized.set(!maximized())"
23645
+ >
23646
+ <strct-icon
23647
+ [strictName]="maximized() ? 'exitFullscreen' : 'fullscreen'"
23648
+ [size]="13"
23649
+ />
23650
+ </button>
23651
+ <button
23652
+ type="button"
23653
+ class="strct-window__btn strct-window__btn--close"
23654
+ [attr.aria-label]="L().close"
23655
+ (click)="close()"
23656
+ >
23657
+ <strct-icon strictName="close" [size]="14" />
23658
+ </button>
23659
+ </span>
23660
+ </div>
23661
+
23662
+ <div class="strct-window__body"><ng-content /></div>
23663
+ <div class="strct-window__status"><ng-content select="[strctWindowStatus]" /></div>
23664
+
23665
+ @if (resizable() && !maximized()) {
23666
+ <!-- Focusable, so a window can be resized without a pointer. -->
23667
+ @for (corner of CORNERS; track corner) {
23668
+ <button
23669
+ type="button"
23670
+ class="strct-window__rz strct-window__rz--{{ corner }}"
23671
+ [attr.aria-label]="resizeLabel()(corner)"
23672
+ (pointerdown)="onResizeStart($event, corner)"
23673
+ (keydown)="onResizeKeydown($event, corner)"
23674
+ ></button>
23675
+ }
23676
+ }
23677
+ </div>
23678
+ }
23679
+ `, host: { class: 'strct-window' }, styles: [".strct-window{display:contents}.strct-window__frame{position:fixed;display:flex;flex-direction:column;min-width:0;border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-1);color:var(--t1);box-shadow:var(--shadow-overlay, 0 12px 40px rgba(0, 0, 0, .32));overflow:hidden}.strct-window__frame--max{inset:var(--space-3);width:auto;height:auto}.strct-window__title{display:flex;align-items:center;gap:var(--space-2);padding:6px 6px 6px var(--space-3);border-block-end:1px solid var(--b1);background:var(--bg-2);cursor:move;-webkit-user-select:none;user-select:none;touch-action:none}.strct-window__title:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-window__heading{font-size:var(--text-sm);font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.strct-window__meta,.strct-window__actions{display:inline-flex;align-items:center;gap:6px}.strct-window__actions{margin-inline-start:auto}.strct-window__controls{display:inline-flex;align-items:center;gap:2px;flex:none}.strct-window__btn{display:inline-flex;padding:4px;border:0;border-radius:var(--radius-sm);background:transparent;color:var(--t2);cursor:pointer}.strct-window__btn:hover{background:var(--bg-3);color:var(--t1)}.strct-window__btn--close:hover{background:var(--critical-bg);color:var(--critical)}.strct-window__body{flex:1;min-height:0;overflow:auto}.strct-window__status:empty{display:none}.strct-window__status{border-block-start:1px solid var(--b1);padding:4px var(--space-3);font-size:var(--text-sm);color:var(--t3);background:var(--bg-2)}.strct-window__rz{position:absolute;width:14px;height:14px;padding:0;border:0;background:transparent}.strct-window__rz:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-window__rz--nw{inset-block-start:0;inset-inline-start:0;cursor:nwse-resize}.strct-window__rz--ne{inset-block-start:0;inset-inline-end:0;cursor:nesw-resize}.strct-window__rz--sw{inset-block-end:0;inset-inline-start:0;cursor:nesw-resize}.strct-window__rz--se{inset-block-end:0;inset-inline-end:0;cursor:nwse-resize}\n"] }]
23680
+ }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], minimized: [{ type: i0.Input, args: [{ isSignal: true, alias: "minimized", required: false }] }, { type: i0.Output, args: ["minimizedChange"] }], maximized: [{ type: i0.Input, args: [{ isSignal: true, alias: "maximized", required: false }] }, { type: i0.Output, args: ["maximizedChange"] }], bounds: [{ type: i0.Input, args: [{ isSignal: true, alias: "bounds", required: false }] }, { type: i0.Output, args: ["boundsChange"] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], minHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "minHeight", required: false }] }], palette: [{ type: i0.Input, args: [{ isSignal: true, alias: "palette", required: false }] }], closeOnOutside: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnOutside", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], resizeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizeLabel", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
23681
+ /**
23682
+ * Where minimised windows wait. Put it in a toolbar or a status bar; each entry
23683
+ * restores its window, and its × closes it.
23684
+ */
23685
+ class StrctWindowDock {
23686
+ service = inject(StrctWindowService);
23687
+ /** The dock's accessible name. */
23688
+ label = input('Minimized windows', /* @ts-ignore */
23689
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
23690
+ /** The name of each chip's close button. */
23691
+ closeLabel = input((heading) => `Close ${heading}`, /* @ts-ignore */
23692
+ ...(ngDevMode ? [{ debugName: "closeLabel" }] : /* istanbul ignore next */ []));
23693
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctWindowDock, deps: [], target: i0.ɵɵFactoryTarget.Component });
23694
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctWindowDock, isStandalone: true, selector: "strct-window-dock", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "group" }, properties: { "attr.aria-label": "label()" }, classAttribute: "strct-windock" }, ngImport: i0, template: `
23695
+ @for (w of service.minimized(); track w) {
23696
+ <span class="strct-windock__chip">
23697
+ <button type="button" class="strct-windock__open" (click)="w.restore()">
23698
+ {{ w.heading() }}
23699
+ </button>
23700
+ <button
23701
+ type="button"
23702
+ class="strct-windock__close"
23703
+ [attr.aria-label]="closeLabel()(w.heading())"
23704
+ (click)="w.close()"
23705
+ >
23706
+ <strct-icon strictName="close" [size]="11" />
23707
+ </button>
23708
+ </span>
23709
+ }
23710
+ `, isInline: true, styles: [".strct-windock{display:inline-flex;align-items:center;gap:6px}.strct-windock__chip{display:inline-flex;align-items:center;gap:2px;padding-inline:8px 4px;border:1px solid var(--b2);border-radius:var(--radius-full, 999px);background:var(--bg-1);font-size:12px}.strct-windock__open,.strct-windock__close{border:0;background:none;color:inherit;font:inherit;cursor:pointer;padding:3px 2px;border-radius:var(--radius-sm)}.strct-windock__open:hover{color:var(--acc)}.strct-windock__close{display:inline-flex;color:var(--t3)}.strct-windock__close:hover{color:var(--critical)}.strct-windock__open:focus-visible,.strct-windock__close:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23711
+ }
23712
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctWindowDock, decorators: [{
23713
+ type: Component,
23714
+ args: [{ selector: 'strct-window-dock', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon], template: `
23715
+ @for (w of service.minimized(); track w) {
23716
+ <span class="strct-windock__chip">
23717
+ <button type="button" class="strct-windock__open" (click)="w.restore()">
23718
+ {{ w.heading() }}
23719
+ </button>
23720
+ <button
23721
+ type="button"
23722
+ class="strct-windock__close"
23723
+ [attr.aria-label]="closeLabel()(w.heading())"
23724
+ (click)="w.close()"
23725
+ >
23726
+ <strct-icon strictName="close" [size]="11" />
23727
+ </button>
23728
+ </span>
23729
+ }
23730
+ `, host: {
23731
+ class: 'strct-windock',
23732
+ role: 'group',
23733
+ '[attr.aria-label]': 'label()',
23734
+ }, styles: [".strct-windock{display:inline-flex;align-items:center;gap:6px}.strct-windock__chip{display:inline-flex;align-items:center;gap:2px;padding-inline:8px 4px;border:1px solid var(--b2);border-radius:var(--radius-full, 999px);background:var(--bg-1);font-size:12px}.strct-windock__open,.strct-windock__close{border:0;background:none;color:inherit;font:inherit;cursor:pointer;padding:3px 2px;border-radius:var(--radius-sm)}.strct-windock__open:hover{color:var(--acc)}.strct-windock__close{display:inline-flex;color:var(--t3)}.strct-windock__close:hover{color:var(--critical)}.strct-windock__open:focus-visible,.strct-windock__close:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}\n"] }]
23735
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }] } });
23736
+
23737
+ /** A card the message carries — an action to approve, a result to read. */
23738
+ class StrctChatAttachment {
23739
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctChatAttachment, deps: [], target: i0.ɵɵFactoryTarget.Directive });
23740
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctChatAttachment, isStandalone: true, selector: "[strctChatAttachment]", host: { classAttribute: "strct-chat__attachment" }, ngImport: i0 });
23741
+ }
23742
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctChatAttachment, decorators: [{
23743
+ type: Directive,
23744
+ args: [{ selector: '[strctChatAttachment]', host: { class: 'strct-chat__attachment' } }]
23745
+ }] });
23746
+ /**
23747
+ * A conversation is a thread of messages from two or more authors, and an
23748
+ * assistant panel is built from the library like every other panel.
23749
+ *
23750
+ * <strct-chat-thread [busy]="thinking()" label="Assistant conversation">
23751
+ * …<strct-chat-message author="user">…</strct-chat-message>…
23752
+ * </strct-chat-thread>
23753
+ *
23754
+ * The thread is a `role="log"` with `aria-live="polite"`: a streaming reply is
23755
+ * announced once, when it finishes, rather than token by token.
23756
+ */
23757
+ class StrctChatThread {
23758
+ /** The assistant is composing: shows the typing indicator after the last message. */
23759
+ busy = input(false, { ...(ngDevMode ? { debugName: "busy" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
23760
+ /** The thread's accessible name. */
23761
+ label = input('Conversation', /* @ts-ignore */
23762
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
23763
+ /** What the typing indicator says to assistive tech. */
23764
+ typingLabel = input('Assistant is typing', /* @ts-ignore */
23765
+ ...(ngDevMode ? [{ debugName: "typingLabel" }] : /* istanbul ignore next */ []));
23766
+ /** Keep the latest message in view — unless the reader scrolled up. */
23767
+ autoScroll = input(true, { ...(ngDevMode ? { debugName: "autoScroll" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
23768
+ host = inject(ElementRef);
23769
+ /** False once the reader scrolls away from the end; true again at the end. */
23770
+ atEnd = signal(true, /* @ts-ignore */
23771
+ ...(ngDevMode ? [{ debugName: "atEnd" }] : /* istanbul ignore next */ []));
23772
+ constructor() {
23773
+ afterNextRender(() => this.scrollToEnd());
23774
+ effect(() => {
23775
+ this.busy();
23776
+ if (this.autoScroll() && this.atEnd())
23777
+ queueMicrotask(() => this.scrollToEnd());
23778
+ });
23779
+ }
23780
+ onScroll() {
23781
+ const el = this.host.nativeElement;
23782
+ this.atEnd.set(el.scrollHeight - el.scrollTop - el.clientHeight < 24);
23783
+ }
23784
+ /** Jump to the newest message. */
23785
+ scrollToEnd() {
23786
+ const el = this.host.nativeElement;
23787
+ el.scrollTop = el.scrollHeight;
23788
+ }
23789
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctChatThread, deps: [], target: i0.ɵɵFactoryTarget.Component });
23790
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctChatThread, isStandalone: true, selector: "strct-chat-thread", inputs: { busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, typingLabel: { classPropertyName: "typingLabel", publicName: "typingLabel", isSignal: true, isRequired: false, transformFunction: null }, autoScroll: { classPropertyName: "autoScroll", publicName: "autoScroll", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "log", "aria-live": "polite", "aria-relevant": "additions" }, listeners: { "scroll": "onScroll()" }, properties: { "attr.aria-label": "label()", "attr.aria-busy": "busy() ? \"true\" : null" }, classAttribute: "strct-chat" }, ngImport: i0, template: `
23791
+ <div class="strct-chat__list" #list><ng-content /></div>
23792
+ @if (busy()) {
23793
+ <div class="strct-chat__typing" [attr.aria-label]="typingLabel()" role="status">
23794
+ <span class="strct-chat__dot"></span>
23795
+ <span class="strct-chat__dot"></span>
23796
+ <span class="strct-chat__dot"></span>
23797
+ </div>
23798
+ }
23799
+ `, isInline: true, styles: [".strct-chat{display:flex;flex-direction:column;gap:var(--space-3);min-height:0;overflow:auto;padding:var(--space-3)}.strct-chat__list{display:flex;flex-direction:column;gap:var(--space-3)}.strct-chat__typing{display:inline-flex;align-items:center;gap:4px;padding-inline-start:38px}.strct-chat__dot{width:6px;height:6px;border-radius:50%;background:var(--t3);animation:strct-chat-bounce 1.1s ease-in-out infinite}.strct-chat__dot:nth-child(2){animation-delay:.15s}.strct-chat__dot:nth-child(3){animation-delay:.3s}@keyframes strct-chat-bounce{0%,70%,to{opacity:.35;transform:translateY(0)}35%{opacity:1;transform:translateY(-3px)}}@media(prefers-reduced-motion:reduce){.strct-chat__dot{animation:none;opacity:.55}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23800
+ }
23801
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctChatThread, decorators: [{
23802
+ type: Component,
23803
+ args: [{ selector: 'strct-chat-thread', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `
23804
+ <div class="strct-chat__list" #list><ng-content /></div>
23805
+ @if (busy()) {
23806
+ <div class="strct-chat__typing" [attr.aria-label]="typingLabel()" role="status">
23807
+ <span class="strct-chat__dot"></span>
23808
+ <span class="strct-chat__dot"></span>
23809
+ <span class="strct-chat__dot"></span>
23810
+ </div>
23811
+ }
23812
+ `, host: {
23813
+ class: 'strct-chat',
23814
+ role: 'log',
23815
+ 'aria-live': 'polite',
23816
+ 'aria-relevant': 'additions',
23817
+ '[attr.aria-label]': 'label()',
23818
+ '[attr.aria-busy]': 'busy() ? "true" : null',
23819
+ '(scroll)': 'onScroll()',
23820
+ }, styles: [".strct-chat{display:flex;flex-direction:column;gap:var(--space-3);min-height:0;overflow:auto;padding:var(--space-3)}.strct-chat__list{display:flex;flex-direction:column;gap:var(--space-3)}.strct-chat__typing{display:inline-flex;align-items:center;gap:4px;padding-inline-start:38px}.strct-chat__dot{width:6px;height:6px;border-radius:50%;background:var(--t3);animation:strct-chat-bounce 1.1s ease-in-out infinite}.strct-chat__dot:nth-child(2){animation-delay:.15s}.strct-chat__dot:nth-child(3){animation-delay:.3s}@keyframes strct-chat-bounce{0%,70%,to{opacity:.35;transform:translateY(0)}35%{opacity:1;transform:translateY(-3px)}}@media(prefers-reduced-motion:reduce){.strct-chat__dot{animation:none;opacity:.55}}\n"] }]
23821
+ }], ctorParameters: () => [], propDecorators: { busy: [{ type: i0.Input, args: [{ isSignal: true, alias: "busy", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], typingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "typingLabel", required: false }] }], autoScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoScroll", required: false }] }] } });
23822
+ /**
23823
+ * One message in a {@link StrctChatThread}: an `article` labelled by its
23824
+ * author, with the author's avatar, its content, and any attachment card.
23825
+ */
23826
+ class StrctChatMessage {
23827
+ /** Who wrote it. */
23828
+ author = input('assistant', /* @ts-ignore */
23829
+ ...(ngDevMode ? [{ debugName: "author" }] : /* istanbul ignore next */ []));
23830
+ /** The author's name, shown above the bubble. */
23831
+ name = input('', /* @ts-ignore */
23832
+ ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
23833
+ /** An icon avatar instead of initials — an assistant is an icon. */
23834
+ avatarIcon = input('', /* @ts-ignore */
23835
+ ...(ngDevMode ? [{ debugName: "avatarIcon" }] : /* istanbul ignore next */ []));
23836
+ /** The reply is still arriving: a caret follows the content. */
23837
+ streaming = input(false, { ...(ngDevMode ? { debugName: "streaming" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
23838
+ /** When it was sent. */
23839
+ time = input(null, /* @ts-ignore */
23840
+ ...(ngDevMode ? [{ debugName: "time" }] : /* istanbul ignore next */ []));
23841
+ /** How the time reads (localisable). */
23842
+ timeFormat = input((d) => d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' }), /* @ts-ignore */
23843
+ ...(ngDevMode ? [{ debugName: "timeFormat" }] : /* istanbul ignore next */ []));
23844
+ /** Default names per author, overridable with `name` (and localisable). */
23845
+ authorNames = input({
23846
+ user: 'You',
23847
+ assistant: 'Assistant',
23848
+ system: 'System',
23849
+ }, /* @ts-ignore */
23850
+ ...(ngDevMode ? [{ debugName: "authorNames" }] : /* istanbul ignore next */ []));
23851
+ displayName = computed(() => this.name() || this.authorNames()[this.author()], /* @ts-ignore */
23852
+ ...(ngDevMode ? [{ debugName: "displayName" }] : /* istanbul ignore next */ []));
23853
+ shortTime = computed(() => {
23854
+ const t = this.time();
23855
+ return t ? this.timeFormat()(t) : '';
23856
+ }, /* @ts-ignore */
23857
+ ...(ngDevMode ? [{ debugName: "shortTime" }] : /* istanbul ignore next */ []));
23858
+ isoTime = computed(() => this.time()?.toISOString() ?? null, /* @ts-ignore */
23859
+ ...(ngDevMode ? [{ debugName: "isoTime" }] : /* istanbul ignore next */ []));
23860
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctChatMessage, deps: [], target: i0.ɵɵFactoryTarget.Component });
23861
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctChatMessage, isStandalone: true, selector: "strct-chat-message", inputs: { author: { classPropertyName: "author", publicName: "author", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, avatarIcon: { classPropertyName: "avatarIcon", publicName: "avatarIcon", isSignal: true, isRequired: false, transformFunction: null }, streaming: { classPropertyName: "streaming", publicName: "streaming", isSignal: true, isRequired: false, transformFunction: null }, time: { classPropertyName: "time", publicName: "time", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, authorNames: { classPropertyName: "authorNames", publicName: "authorNames", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "article" }, properties: { "attr.data-author": "author()", "attr.aria-label": "displayName()", "attr.aria-busy": "streaming() ? \"true\" : null" }, classAttribute: "strct-msg" }, ngImport: i0, template: `
23862
+ @if (author() !== 'system') {
23863
+ <strct-avatar
23864
+ class="strct-msg__avatar"
23865
+ size="sm"
23866
+ [name]="displayName()"
23867
+ [icon]="avatarIcon()"
23868
+ [tone]="author() === 'user' ? 'neutral' : 'accent-soft'"
23869
+ />
23870
+ }
23871
+ <div class="strct-msg__body">
23872
+ @if (author() !== 'system' && (name() || time())) {
23873
+ <div class="strct-msg__meta">
23874
+ @if (name()) {
23875
+ <span class="strct-msg__name">{{ name() }}</span>
23876
+ }
23877
+ @if (time()) {
23878
+ <time class="strct-msg__time" [attr.datetime]="isoTime()">{{ shortTime() }}</time>
23879
+ }
23880
+ </div>
23881
+ }
23882
+ <div class="strct-msg__bubble">
23883
+ <ng-content />
23884
+ @if (streaming()) {
23885
+ <span class="strct-msg__caret" aria-hidden="true"></span>
23886
+ }
23887
+ </div>
23888
+ <ng-content select="[strctChatAttachment]" />
23889
+ </div>
23890
+ `, isInline: true, styles: [".strct-msg{display:flex;align-items:flex-start;gap:var(--space-2);min-width:0}.strct-msg[data-author=user]{flex-direction:row-reverse}.strct-msg[data-author=system]{justify-content:center}.strct-msg__avatar{flex:none}.strct-msg__body{display:flex;flex-direction:column;gap:4px;min-width:0;max-width:80%}.strct-msg[data-author=user] .strct-msg__body{align-items:flex-end}.strct-msg__meta{display:flex;align-items:baseline;gap:6px;font-size:var(--text-sm);color:var(--t3)}.strct-msg__name{font-weight:600}.strct-msg__bubble{padding:var(--space-2) var(--space-3);border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);color:var(--t1);font-size:13px;line-height:1.5;min-width:0;overflow-wrap:anywhere}.strct-msg[data-author=user] .strct-msg__bubble{background:var(--acc-s);border-color:var(--acc30)}.strct-msg[data-author=system] .strct-msg__bubble{border:0;background:none;color:var(--t3);font-size:var(--text-sm);text-align:center}.strct-msg__caret{display:inline-block;width:2px;height:1em;margin-inline-start:2px;vertical-align:text-bottom;background:var(--acc);animation:strct-chat-caret 1s steps(2,start) infinite}@keyframes strct-chat-caret{to{opacity:0}}@media(prefers-reduced-motion:reduce){.strct-msg__caret{animation:none}}.strct-chat__attachment{display:block;margin-block-start:4px}\n"], dependencies: [{ kind: "component", type: StrctAvatar, selector: "strct-avatar", inputs: ["icon", "shape", "tone", "src", "name", "size", "status"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
23891
+ }
23892
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctChatMessage, decorators: [{
23893
+ type: Component,
23894
+ args: [{ selector: 'strct-chat-message', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctAvatar], template: `
23895
+ @if (author() !== 'system') {
23896
+ <strct-avatar
23897
+ class="strct-msg__avatar"
23898
+ size="sm"
23899
+ [name]="displayName()"
23900
+ [icon]="avatarIcon()"
23901
+ [tone]="author() === 'user' ? 'neutral' : 'accent-soft'"
23902
+ />
23903
+ }
23904
+ <div class="strct-msg__body">
23905
+ @if (author() !== 'system' && (name() || time())) {
23906
+ <div class="strct-msg__meta">
23907
+ @if (name()) {
23908
+ <span class="strct-msg__name">{{ name() }}</span>
23909
+ }
23910
+ @if (time()) {
23911
+ <time class="strct-msg__time" [attr.datetime]="isoTime()">{{ shortTime() }}</time>
23912
+ }
23913
+ </div>
23914
+ }
23915
+ <div class="strct-msg__bubble">
23916
+ <ng-content />
23917
+ @if (streaming()) {
23918
+ <span class="strct-msg__caret" aria-hidden="true"></span>
23919
+ }
23920
+ </div>
23921
+ <ng-content select="[strctChatAttachment]" />
23922
+ </div>
23923
+ `, host: {
23924
+ class: 'strct-msg',
23925
+ role: 'article',
23926
+ '[attr.data-author]': 'author()',
23927
+ '[attr.aria-label]': 'displayName()',
23928
+ // A streaming reply is announced when it finishes, not token by token.
23929
+ '[attr.aria-busy]': 'streaming() ? "true" : null',
23930
+ }, styles: [".strct-msg{display:flex;align-items:flex-start;gap:var(--space-2);min-width:0}.strct-msg[data-author=user]{flex-direction:row-reverse}.strct-msg[data-author=system]{justify-content:center}.strct-msg__avatar{flex:none}.strct-msg__body{display:flex;flex-direction:column;gap:4px;min-width:0;max-width:80%}.strct-msg[data-author=user] .strct-msg__body{align-items:flex-end}.strct-msg__meta{display:flex;align-items:baseline;gap:6px;font-size:var(--text-sm);color:var(--t3)}.strct-msg__name{font-weight:600}.strct-msg__bubble{padding:var(--space-2) var(--space-3);border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);color:var(--t1);font-size:13px;line-height:1.5;min-width:0;overflow-wrap:anywhere}.strct-msg[data-author=user] .strct-msg__bubble{background:var(--acc-s);border-color:var(--acc30)}.strct-msg[data-author=system] .strct-msg__bubble{border:0;background:none;color:var(--t3);font-size:var(--text-sm);text-align:center}.strct-msg__caret{display:inline-block;width:2px;height:1em;margin-inline-start:2px;vertical-align:text-bottom;background:var(--acc);animation:strct-chat-caret 1s steps(2,start) infinite}@keyframes strct-chat-caret{to{opacity:0}}@media(prefers-reduced-motion:reduce){.strct-msg__caret{animation:none}}.strct-chat__attachment{display:block;margin-block-start:4px}\n"] }]
23931
+ }], propDecorators: { author: [{ type: i0.Input, args: [{ isSignal: true, alias: "author", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], avatarIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarIcon", required: false }] }], streaming: [{ type: i0.Input, args: [{ isSignal: true, alias: "streaming", required: false }] }], time: [{ type: i0.Input, args: [{ isSignal: true, alias: "time", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], authorNames: [{ type: i0.Input, args: [{ isSignal: true, alias: "authorNames", required: false }] }] } });
23932
+ /**
23933
+ * The box the user writes in: it grows with the text up to `maxRows`, sends on
23934
+ * Enter and breaks a line on Shift+Enter — and never sends mid-composition, so
23935
+ * an IME's Enter commits the candidate instead of the message.
23936
+ */
23937
+ class StrctChatComposer {
23938
+ /** The draft (two-way). */
23939
+ value = model('', /* @ts-ignore */
23940
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
23941
+ /** Placeholder text. */
23942
+ placeholder = input('', /* @ts-ignore */
23943
+ ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
23944
+ /** The field's accessible name (visually hidden). */
23945
+ label = input('Message', /* @ts-ignore */
23946
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
23947
+ /** Disabled while the assistant is busy, say. */
23948
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
23949
+ /** How tall the box grows before it scrolls. */
23950
+ maxRows = input(8, /* @ts-ignore */
23951
+ ...(ngDevMode ? [{ debugName: "maxRows" }] : /* istanbul ignore next */ []));
23952
+ /** The send button's accessible name. */
23953
+ sendLabel = input('Send', /* @ts-ignore */
23954
+ ...(ngDevMode ? [{ debugName: "sendLabel" }] : /* istanbul ignore next */ []));
23955
+ /** The user sent the draft. */
23956
+ send = output();
23957
+ inputId = `strct-composer-${++composerCounter}`;
23958
+ /** True while an IME is composing — Enter must commit, not send. */
23959
+ composing = signal(false, /* @ts-ignore */
23960
+ ...(ngDevMode ? [{ debugName: "composing" }] : /* istanbul ignore next */ []));
23961
+ host = inject(ElementRef);
23962
+ onInput(event) {
23963
+ const el = event.target;
23964
+ this.value.set(el.value);
23965
+ this.grow(el);
23966
+ }
23967
+ /** Grow with the text: reset first, so deleting a line shrinks it again. */
23968
+ grow(el) {
23969
+ el.style.height = 'auto';
23970
+ el.style.height = `${el.scrollHeight}px`;
23971
+ }
23972
+ onEnter(event) {
23973
+ const e = event;
23974
+ if (e.shiftKey || this.composing() || e.isComposing)
23975
+ return;
23976
+ e.preventDefault();
23977
+ this.submit();
23978
+ }
23979
+ submit() {
23980
+ const text = this.value().trim();
23981
+ if (!text || this.disabled())
23982
+ return;
23983
+ this.send.emit(text);
23984
+ this.value.set('');
23985
+ const el = this.host.nativeElement.querySelector('textarea');
23986
+ if (el) {
23987
+ el.value = '';
23988
+ this.grow(el);
23989
+ el.focus();
23990
+ }
23991
+ }
23992
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctChatComposer, deps: [], target: i0.ɵɵFactoryTarget.Component });
23993
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: StrctChatComposer, isStandalone: true, selector: "strct-chat-composer", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, maxRows: { classPropertyName: "maxRows", publicName: "maxRows", isSignal: true, isRequired: false, transformFunction: null }, sendLabel: { classPropertyName: "sendLabel", publicName: "sendLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", send: "send" }, host: { classAttribute: "strct-composer" }, ngImport: i0, template: `
23994
+ <label class="strct-composer__label" [attr.for]="inputId">{{ label() }}</label>
23995
+ <div class="strct-composer__box">
23996
+ <textarea
23997
+ class="strct-composer__input"
23998
+ [id]="inputId"
23999
+ rows="1"
24000
+ [placeholder]="placeholder()"
24001
+ [disabled]="disabled()"
24002
+ [value]="value()"
24003
+ [style.max-height.px]="maxRows() * 20"
24004
+ (input)="onInput($event)"
24005
+ (compositionstart)="composing.set(true)"
24006
+ (compositionend)="composing.set(false)"
24007
+ (keydown.enter)="onEnter($event)"
24008
+ ></textarea>
24009
+ <button
24010
+ type="button"
24011
+ class="strct-composer__send"
24012
+ [attr.aria-label]="sendLabel()"
24013
+ [disabled]="disabled() || !value().trim()"
24014
+ (click)="submit()"
24015
+ >
24016
+ <strct-icon strictName="arrowUp" [size]="15" [strokeWidth]="1.8" />
24017
+ </button>
24018
+ </div>
24019
+ `, isInline: true, styles: [".strct-composer{display:block}.strct-composer__label{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.strct-composer__box{display:flex;align-items:flex-end;gap:4px;padding:4px 4px 4px var(--space-3);border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);transition:border-color .14s ease,box-shadow .14s ease}.strct-composer__box:focus-within{border-color:var(--acc50);box-shadow:0 0 0 3px var(--acc18);background:var(--bg-1)}.strct-composer__input{flex:1;min-width:0;border:0;background:none;resize:none;padding:6px 0;font-family:var(--font);font-size:13px;line-height:20px;color:var(--t1);overflow-y:auto}.strct-composer__input:focus{outline:none}.strct-composer__input::placeholder{color:var(--t3)}.strct-composer__send{display:inline-flex;align-items:center;justify-content:center;flex:none;width:28px;height:28px;border:0;border-radius:var(--radius-md);background:var(--acc);color:var(--inv);cursor:pointer}.strct-composer__send:disabled{opacity:var(--disabled-opacity);cursor:not-allowed}.strct-composer__send:focus-visible{outline:2px solid var(--acc50);outline-offset:2px}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel", "count", "countMax", "countStatus", "countLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
24020
+ }
24021
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctChatComposer, decorators: [{
24022
+ type: Component,
24023
+ args: [{ selector: 'strct-chat-composer', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon], template: `
24024
+ <label class="strct-composer__label" [attr.for]="inputId">{{ label() }}</label>
24025
+ <div class="strct-composer__box">
24026
+ <textarea
24027
+ class="strct-composer__input"
24028
+ [id]="inputId"
24029
+ rows="1"
24030
+ [placeholder]="placeholder()"
24031
+ [disabled]="disabled()"
24032
+ [value]="value()"
24033
+ [style.max-height.px]="maxRows() * 20"
24034
+ (input)="onInput($event)"
24035
+ (compositionstart)="composing.set(true)"
24036
+ (compositionend)="composing.set(false)"
24037
+ (keydown.enter)="onEnter($event)"
24038
+ ></textarea>
24039
+ <button
24040
+ type="button"
24041
+ class="strct-composer__send"
24042
+ [attr.aria-label]="sendLabel()"
24043
+ [disabled]="disabled() || !value().trim()"
24044
+ (click)="submit()"
24045
+ >
24046
+ <strct-icon strictName="arrowUp" [size]="15" [strokeWidth]="1.8" />
24047
+ </button>
24048
+ </div>
24049
+ `, host: { class: 'strct-composer' }, styles: [".strct-composer{display:block}.strct-composer__label{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.strct-composer__box{display:flex;align-items:flex-end;gap:4px;padding:4px 4px 4px var(--space-3);border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);transition:border-color .14s ease,box-shadow .14s ease}.strct-composer__box:focus-within{border-color:var(--acc50);box-shadow:0 0 0 3px var(--acc18);background:var(--bg-1)}.strct-composer__input{flex:1;min-width:0;border:0;background:none;resize:none;padding:6px 0;font-family:var(--font);font-size:13px;line-height:20px;color:var(--t1);overflow-y:auto}.strct-composer__input:focus{outline:none}.strct-composer__input::placeholder{color:var(--t3)}.strct-composer__send{display:inline-flex;align-items:center;justify-content:center;flex:none;width:28px;height:28px;border:0;border-radius:var(--radius-md);background:var(--acc);color:var(--inv);cursor:pointer}.strct-composer__send:disabled{opacity:var(--disabled-opacity);cursor:not-allowed}.strct-composer__send:focus-visible{outline:2px solid var(--acc50);outline-offset:2px}\n"] }]
24050
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], maxRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRows", required: false }] }], sendLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sendLabel", required: false }] }], send: [{ type: i0.Output, args: ["send"] }] } });
24051
+ let composerCounter = 0;
24052
+
23264
24053
  /**
23265
24054
  * A value change, as one phrase: "v10.27 → v10.28". The old value is muted, the
23266
24055
  * arrow is the library's, the new one is emphasised — and assistive tech hears
@@ -25177,5 +25966,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
25177
25966
  * Generated bundle index. Do not edit.
25178
25967
  */
25179
25968
 
25180
- export { FOCUSABLE_SELECTOR, STRCT_DP_DOW, STRCT_DP_DOW_FULL, STRCT_DP_MONTHS, STRCT_ICONS, STRCT_ICON_GROUPS, STRCT_ICON_NAMES, STRCT_MASKS, STRCT_NOTIFICATION_HISTORY_LIMIT, STRCT_PALETTES, STRCT_RAW_ICONS, STRCT_TIME_RANGE_PRESETS, STRCT_WIZARD_DEFAULTS, StrctAccordion, StrctAccordionPanel, StrctAlert, StrctAnnouncer, StrctAvatar, StrctBadge, StrctBreadcrumb, StrctBreadcrumbItem, StrctButton, StrctButtonGroup, StrctBytesPipe, StrctCard, StrctCardBlock, StrctCardFooter, StrctCardHeader, StrctCardHeaderActions, StrctCardHeaderMeta, StrctCardHeaderNote, StrctCascadeColumn, StrctCascadeHost, StrctCascadeSelect, StrctCellDef, StrctCellStatus, StrctChange, StrctChart, StrctCheckbox, StrctChips, StrctCode, StrctCodeInline, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctConfirmOutlet, StrctConfirmService, StrctContextMenu, StrctContextMenuTrigger, StrctControlDescription, StrctCopy, StrctDatagrid, StrctDatagridActionBar, StrctDatagridActionBarCaption, StrctDatepicker, StrctDatetimePicker, StrctDesc, StrctDescriptionList, StrctDiff, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownItem, StrctDropdownItemAction, StrctDropdownTrigger, StrctDurationPipe, StrctEmptyState, StrctField, StrctFieldGroup, StrctFieldHint, StrctFieldPrefix, StrctFieldSuffix, StrctFile, StrctFilterBar, StrctFlow, StrctFlowNodeTemplate, StrctFooter, StrctGauge, StrctHeader, StrctHeatmap, StrctHero, StrctHotkeysHelp, StrctHotkeysService, StrctIcon, StrctInlineEdit, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctLegend, StrctList, StrctListItem, StrctListItemDescription, StrctListItemLeading, StrctListItemMeta, StrctListItemTrailing, StrctLiveIndicator, StrctLogViewer, StrctLogin, StrctMediaFrame, StrctMenuPanel, StrctMenuService, StrctMenubar, StrctMetricTile, StrctModal, StrctModalContent, StrctNav, StrctNavItem, StrctNotificationCenter, StrctNumber, StrctOverlay, StrctPageHeader, StrctPageHeaderActions, StrctPageHeaderCrumbs, StrctPageHeaderTitleMeta, StrctPagination, StrctPassword, StrctPopover, StrctPopoverTrigger, StrctProgress, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRatePipe, StrctRating, StrctReorder, StrctReorderGroup, StrctReorderHandle, StrctReorderItem, StrctResizeHandle, StrctRowDetailDef, StrctSearchbox, StrctSectionHeader, StrctSectionHeaderActions, StrctSectionHeaderMeta, StrctSectionMenu, StrctSegmented, StrctSelect, StrctShell, StrctShellService, StrctSiPipe, StrctSignpost, StrctSignpostTrigger, StrctSkeleton, StrctSparkline, StrctSpeedDial, StrctSpinner, StrctSplitButton, StrctSplitter, StrctStack, StrctStackItem, StrctStatusDot, StrctStep, StrctStepAction, StrctSteps, StrctSubmenu, StrctTab, StrctTable, StrctTabs, StrctTag, StrctTagLeading, StrctThemeService, StrctThemeSwitcher, StrctTimeRangePicker, StrctTimeline, StrctTimelineItem, StrctToastOutlet, StrctToastService, StrctToggle, StrctToolbar, StrctToolbarCaption, StrctToolbarSpacer, StrctTooltip, StrctTour, StrctTransfer, StrctTree, StrctTreeNode, StrctTreeSelect, StrctVerticalNav, StrctWatermark, StrctWizard, StrctWizardAside, focusFirstIn, keepTabInside, lockBodyScroll, parseAnsi, provideStrctWizardDefaults, registerStrctIcon, restoreFocus, saveFocusedElement, strctComputeDiff, strctDpPad, strctFormatBytes, strctFormatDuration, strctFormatRate, strctFormatSi, strctValidationIcon, strctValidationTone, unlockBodyScroll };
25969
+ export { FOCUSABLE_SELECTOR, STRCT_DP_DOW, STRCT_DP_DOW_FULL, STRCT_DP_MONTHS, STRCT_ICONS, STRCT_ICON_GROUPS, STRCT_ICON_NAMES, STRCT_MASKS, STRCT_NOTIFICATION_HISTORY_LIMIT, STRCT_PALETTES, STRCT_RAW_ICONS, STRCT_TIME_RANGE_PRESETS, STRCT_WIZARD_DEFAULTS, StrctAccordion, StrctAccordionPanel, StrctAlert, StrctAnnouncer, StrctAvatar, StrctBadge, StrctBreadcrumb, StrctBreadcrumbItem, StrctButton, StrctButtonGroup, StrctBytesPipe, StrctCard, StrctCardBlock, StrctCardFooter, StrctCardHeader, StrctCardHeaderActions, StrctCardHeaderMeta, StrctCardHeaderNote, StrctCascadeColumn, StrctCascadeHost, StrctCascadeSelect, StrctCellDef, StrctCellStatus, StrctChange, StrctChart, StrctChatAttachment, StrctChatComposer, StrctChatMessage, StrctChatThread, StrctCheckbox, StrctChips, StrctCode, StrctCodeInline, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctConfirmOutlet, StrctConfirmService, StrctContextMenu, StrctContextMenuTrigger, StrctControlDescription, StrctCopy, StrctDatagrid, StrctDatagridActionBar, StrctDatagridActionBarCaption, StrctDatepicker, StrctDatetimePicker, StrctDesc, StrctDescriptionList, StrctDiff, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownItem, StrctDropdownItemAction, StrctDropdownTrigger, StrctDurationPipe, StrctEmptyState, StrctField, StrctFieldGroup, StrctFieldHint, StrctFieldPrefix, StrctFieldSuffix, StrctFile, StrctFilterBar, StrctFlow, StrctFlowNodeTemplate, StrctFooter, StrctGauge, StrctHeader, StrctHeatmap, StrctHero, StrctHotkeysHelp, StrctHotkeysService, StrctIcon, StrctInlineEdit, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctLegend, StrctList, StrctListItem, StrctListItemDescription, StrctListItemLeading, StrctListItemMeta, StrctListItemTrailing, StrctLiveIndicator, StrctLogViewer, StrctLogin, StrctMediaFrame, StrctMenuPanel, StrctMenuService, StrctMenubar, StrctMetricTile, StrctModal, StrctModalContent, StrctNav, StrctNavItem, StrctNotificationCenter, StrctNumber, StrctOverlay, StrctPageHeader, StrctPageHeaderActions, StrctPageHeaderCrumbs, StrctPageHeaderTitleMeta, StrctPagination, StrctPassword, StrctPopover, StrctPopoverTrigger, StrctProgress, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRatePipe, StrctRating, StrctReorder, StrctReorderGroup, StrctReorderHandle, StrctReorderItem, StrctResizeHandle, StrctRowDetailDef, StrctSearchbox, StrctSectionHeader, StrctSectionHeaderActions, StrctSectionHeaderMeta, StrctSectionMenu, StrctSegmented, StrctSelect, StrctShell, StrctShellService, StrctSiPipe, StrctSignpost, StrctSignpostTrigger, StrctSkeleton, StrctSparkline, StrctSpeedDial, StrctSpinner, StrctSplitButton, StrctSplitter, StrctStack, StrctStackItem, StrctStatusDot, StrctStep, StrctStepAction, StrctSteps, StrctSubmenu, StrctTab, StrctTable, StrctTabs, StrctTag, StrctTagLeading, StrctThemeService, StrctThemeSwitcher, StrctTimeRangePicker, StrctTimeline, StrctTimelineItem, StrctToastOutlet, StrctToastService, StrctToggle, StrctToolbar, StrctToolbarCaption, StrctToolbarSpacer, StrctTooltip, StrctTour, StrctTransfer, StrctTree, StrctTreeNode, StrctTreeSelect, StrctVerticalNav, StrctWatermark, StrctWindow, StrctWindowDock, StrctWindowService, StrctWizard, StrctWizardAside, focusFirstIn, keepTabInside, lockBodyScroll, parseAnsi, provideStrctWizardDefaults, registerStrctIcon, restoreFocus, saveFocusedElement, strctComputeDiff, strctDpPad, strctFormatBytes, strctFormatDuration, strctFormatRate, strctFormatSi, strctValidationIcon, strctValidationTone, unlockBodyScroll };
25181
25970
  //# sourceMappingURL=akcelik-strct.mjs.map