@akcelik/strct 1.5.0 → 1.6.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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, DOCUMENT, signal, computed, Injectable, input, ViewEncapsulation, ChangeDetectionStrategy, Component, ElementRef, NgZone, afterNextRender, Directive, model, output, booleanAttribute, HostListener, contentChildren, effect, ApplicationRef, EnvironmentInjector, createComponent, forwardRef, DestroyRef, contentChild, viewChild, viewChildren, untracked, TemplateRef, Renderer2 } from '@angular/core';
2
+ import { inject, DOCUMENT, signal, computed, Injectable, input, isDevMode, ViewEncapsulation, ChangeDetectionStrategy, Component, ElementRef, NgZone, afterNextRender, Directive, model, output, booleanAttribute, HostListener, contentChildren, effect, ApplicationRef, EnvironmentInjector, createComponent, forwardRef, DestroyRef, contentChild, viewChild, viewChildren, untracked, TemplateRef, Renderer2 } from '@angular/core';
3
3
  import { DomSanitizer } from '@angular/platform-browser';
4
4
  import { NgTemplateOutlet, DOCUMENT as DOCUMENT$1 } from '@angular/common';
5
5
  import { RouterLink, RouterLinkActive } from '@angular/router';
@@ -135,7 +135,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
135
135
  * storage, VMs …). Object state — running / stopped / maintenance — is layered
136
136
  * on with the `badge` input rather than a separate icon per state.
137
137
  */
138
- const STRCT_ICONS = {
138
+ // Built-in stroke glyphs. Keys stay inferred so \`StrctIconName\` below is a
139
+ // compile-time union of every name.
140
+ const STRCT_ICON_DEFS = {
139
141
  // ── General UI ───────────────────────────────────────────────
140
142
  hexagon: '<path d="M8 1.6l5.5 3.2v6.4L8 14.4 2.5 11.2V4.8L8 1.6z"/>',
141
143
  chevronRight: '<path d="M6 3.5L10.5 8 6 12.5"/>',
@@ -254,6 +256,7 @@ const STRCT_ICONS = {
254
256
  megaphone: '<path d="M3 7.3v1.6l7 3V4.3zM10 5.7 12.5 4.2v7.6L10 10.3M4 9.6l.9 3.1h1.6l-.7-2.9"/>',
255
257
  flag: '<path d="M4 13.5V3M4 3.6h7.4L9.8 6.2l1.6 2.6H4"/>',
256
258
  shieldAlert: '<path d="M8 2.3l5.2 1.9v3.3c0 3.1-2.3 5.1-5.2 6.4C5.1 12.6 2.8 10.6 2.8 7.5V4.2z"/><path d="M8 5.5v3.1M8 10.6v.2"/>',
259
+ shieldCheck: '<path d="M8 2.3l5.2 1.9v3.3c0 3.1-2.3 5.1-5.2 6.4C5.1 12.6 2.8 10.6 2.8 7.5V4.2z"/><path d="M5.9 7.9l1.5 1.5 2.8-2.9"/>',
257
260
  // ── State / action (also usable as badges via the icon `badge` input) ─
258
261
  running: '<path d="M5.5 4l6 4-6 4z"/>',
259
262
  stopped: '<rect x="4.5" y="4.5" width="7" height="7" rx="1"/>',
@@ -365,15 +368,26 @@ const STRCT_ICONS = {
365
368
  // Printer — paper feed, body, output sheet and an LED.
366
369
  printer: '<path d="M5 6.4V3.2h6v3.2"/><rect x="2.8" y="6.4" width="10.4" height="4.8" rx="1"/><path d="M5 9.2h6v3.6H5z"/><circle cx="11" cy="8.4" r=".5" fill="currentColor" stroke="none"/>',
367
370
  };
368
- // Composite "off" variants — re-use base glyph + diagonal slash.
369
- STRCT_ICONS['eyeOff'] = `${STRCT_ICONS['eye']}<path d="M2.5 2.5l11 11"/>`;
370
- STRCT_ICONS['bellOff'] = `${STRCT_ICONS['bell']}<path d="M2.6 2.6l10.8 10.8"/>`;
371
- STRCT_ICONS['wifiOff'] = `${STRCT_ICONS['wifi']}<path d="M2.5 2.5l11 11"/>`;
372
- STRCT_ICONS['cloudOff'] = `${STRCT_ICONS['cloud']}<path d="M2.5 2.5l11 11"/>`;
373
- STRCT_ICONS['linkOff'] = `${STRCT_ICONS['link']}<path d="M2.5 2.5l11 11"/>`;
374
- // Semantic aliases.
375
- STRCT_ICONS['unlink'] = STRCT_ICONS['linkOff'];
376
- STRCT_ICONS['webhook'] = STRCT_ICONS['bolt'];
371
+ // Composite "off" variants — re-use base glyph + diagonal slash — and aliases.
372
+ const STRCT_ICON_DERIVED_DEFS = {
373
+ eyeOff: `${STRCT_ICON_DEFS.eye}<path d="M2.5 2.5l11 11"/>`,
374
+ bellOff: `${STRCT_ICON_DEFS.bell}<path d="M2.6 2.6l10.8 10.8"/>`,
375
+ wifiOff: `${STRCT_ICON_DEFS.wifi}<path d="M2.5 2.5l11 11"/>`,
376
+ cloudOff: `${STRCT_ICON_DEFS.cloud}<path d="M2.5 2.5l11 11"/>`,
377
+ linkOff: `${STRCT_ICON_DEFS.link}<path d="M2.5 2.5l11 11"/>`,
378
+ unlink: `${STRCT_ICON_DEFS.link}<path d="M2.5 2.5l11 11"/>`,
379
+ webhook: STRCT_ICON_DEFS.bolt,
380
+ };
381
+ /**
382
+ * Icon name → glyph markup. Open (`Record<string, string>`) on purpose so
383
+ * `registerStrctIcon` can add app-specific names at runtime.
384
+ */
385
+ const STRCT_ICONS = {
386
+ ...STRCT_ICON_DEFS,
387
+ ...STRCT_ICON_DERIVED_DEFS,
388
+ };
389
+ /** All built-in icon names — greppable, iterable (galleries, docs, tests). */
390
+ const STRCT_ICON_NAMES = Object.keys(STRCT_ICONS).sort();
377
391
  /** Icon names grouped for galleries / documentation. */
378
392
  const STRCT_ICON_GROUPS = [
379
393
  {
@@ -514,6 +528,7 @@ const STRCT_ICON_GROUPS = [
514
528
  'container',
515
529
  'firewall',
516
530
  'shield',
531
+ 'shieldCheck',
517
532
  'certificate',
518
533
  'key',
519
534
  'metrics',
@@ -585,9 +600,15 @@ function registerStrctIcon(name, content, options = {}) {
585
600
  * glyph with a green status dot (a "running host"). Unknown names render
586
601
  * nothing rather than throwing.
587
602
  */
603
+ // One warning per unknown name per app run — enough to surface the bug
604
+ // without flooding the console from a list render.
605
+ const warnedUnknownIcons = new Set();
588
606
  class StrctIcon {
589
607
  sanitizer = inject(DomSanitizer);
590
- /** Icon name from the STRCT_ICONS registry. */
608
+ /**
609
+ * Icon name. Typed to autocomplete the built-in set while still accepting
610
+ * any string, since `registerStrctIcon` can add names at runtime.
611
+ */
591
612
  name = input.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
592
613
  /** Icon size in pixels. */
593
614
  size = input(16, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
@@ -599,7 +620,17 @@ class StrctIcon {
599
620
  ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
600
621
  /** True when the named icon is a full-SVG (raw) icon registered by the app. */
601
622
  isRaw = computed(() => Object.prototype.hasOwnProperty.call(STRCT_RAW_ICONS, this.name()), ...(ngDevMode ? [{ debugName: "isRaw" }] : /* istanbul ignore next */ []));
602
- svg = computed(() => this.sanitizer.bypassSecurityTrustHtml(STRCT_ICONS[this.name()] ?? ''), ...(ngDevMode ? [{ debugName: "svg" }] : /* istanbul ignore next */ []));
623
+ svg = computed(() => {
624
+ const name = this.name();
625
+ const glyph = STRCT_ICONS[name];
626
+ if (glyph === undefined && !this.isRaw() && isDevMode() && !warnedUnknownIcons.has(name)) {
627
+ warnedUnknownIcons.add(name);
628
+ console.warn(`[strct-icon] Unknown icon name "${name}" — it will render empty. ` +
629
+ `Built-in names are exported as STRCT_ICON_NAMES (type StrctIconName); ` +
630
+ `custom icons must be added with registerStrctIcon().`);
631
+ }
632
+ return this.sanitizer.bypassSecurityTrustHtml(glyph ?? '');
633
+ }, ...(ngDevMode ? [{ debugName: "svg" }] : /* istanbul ignore next */ []));
603
634
  rawSvg = computed(() => this.sanitizer.bypassSecurityTrustHtml(STRCT_RAW_ICONS[this.name()] ?? ''), ...(ngDevMode ? [{ debugName: "rawSvg" }] : /* istanbul ignore next */ []));
604
635
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctIcon, deps: [], target: i0.ɵɵFactoryTarget.Component });
605
636
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctIcon, isStandalone: true, selector: "strct-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "strct-icon" }, ngImport: i0, template: `@if (isRaw()) {
@@ -3326,11 +3357,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
3326
3357
  * <strct-dropdown-item>Rename</strct-dropdown-item>
3327
3358
  * <strct-dropdown-item critical>Delete</strct-dropdown-item>
3328
3359
  * </strct-dropdown>
3360
+ *
3361
+ * With `popover`, the panel holds *form controls* instead of menu items: an
3362
+ * inner click no longer closes it (only outside click / Escape do), and the
3363
+ * semantics switch from `role="menu"` to a labeled `role="dialog"` — a panel
3364
+ * of selects is not a menu to a screen reader either:
3365
+ *
3366
+ * <strct-dropdown popover popoverLabel="Filters">
3367
+ * <button strct-button strctDropdownTrigger>Filters</button>
3368
+ * <strct-field label="Severity">…</strct-field>
3369
+ * </strct-dropdown>
3329
3370
  */
3330
3371
  class StrctDropdown {
3331
3372
  host = inject((ElementRef));
3332
3373
  /** Horizontal alignment of the menu. */
3333
3374
  align = input('start', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
3375
+ /**
3376
+ * Popover mode for panels holding form controls (filter/settings panels):
3377
+ * inner clicks never close the panel — only outside click / Escape do —
3378
+ * and it renders as a labeled `role="dialog"` instead of a menu.
3379
+ */
3380
+ popover = input(false, { ...(ngDevMode ? { debugName: "popover" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
3381
+ /** Accessible name of the popover dialog (localizable). */
3382
+ popoverLabel = input('Filters', ...(ngDevMode ? [{ debugName: "popoverLabel" }] : /* istanbul ignore next */ []));
3334
3383
  open = signal(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
3335
3384
  toggle() {
3336
3385
  this.open.update((v) => !v);
@@ -3338,6 +3387,11 @@ class StrctDropdown {
3338
3387
  close() {
3339
3388
  this.open.set(false);
3340
3389
  }
3390
+ /** Menu items close on activation; popover form controls never do. */
3391
+ onInnerActivate() {
3392
+ if (!this.popover())
3393
+ this.close();
3394
+ }
3341
3395
  onDocClick(event) {
3342
3396
  if (this.open() && !this.host.nativeElement.contains(event.target)) {
3343
3397
  this.close();
@@ -3347,33 +3401,41 @@ class StrctDropdown {
3347
3401
  this.close();
3348
3402
  }
3349
3403
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctDropdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
3350
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctDropdown, isStandalone: true, selector: "strct-dropdown", inputs: { align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:click": "onDocClick($event)", "document:keydown.escape": "onEscape()" }, classAttribute: "strct-dd" }, ngImport: i0, template: `
3404
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctDropdown, isStandalone: true, selector: "strct-dropdown", inputs: { align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, popover: { classPropertyName: "popover", publicName: "popover", isSignal: true, isRequired: false, transformFunction: null }, popoverLabel: { classPropertyName: "popoverLabel", publicName: "popoverLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:click": "onDocClick($event)", "document:keydown.escape": "onEscape()" }, classAttribute: "strct-dd" }, ngImport: i0, template: `
3351
3405
  <div
3352
3406
  #trigger
3353
3407
  class="strct-dd__trigger"
3354
3408
  role="button"
3355
3409
  tabindex="0"
3410
+ [attr.aria-haspopup]="popover() ? 'dialog' : 'menu'"
3411
+ [attr.aria-expanded]="open()"
3356
3412
  (click)="toggle()"
3357
3413
  (keydown.enter)="toggle()"
3358
3414
  (keydown.space)="toggle()"
3359
3415
  >
3360
3416
  <ng-content select="[strctDropdownTrigger]" />
3361
3417
  </div>
3418
+ <!--
3419
+ One panel for both modes (a default ng-content per @if branch would strand
3420
+ the projected content in the inactive branch) — mode picks the semantics.
3421
+ -->
3362
3422
  @if (open()) {
3363
3423
  <div
3364
3424
  class="strct-dd__menu"
3425
+ [class.strct-dd__menu--popover]="popover()"
3365
3426
  [strctOverlay]="trigger"
3366
3427
  [strctOverlayPlacement]="align() === 'end' ? 'bottom-end' : 'bottom-start'"
3367
- role="menu"
3368
- tabindex="0"
3369
- (click)="close()"
3370
- (keydown.enter)="close()"
3371
- (keydown.space)="close()"
3428
+ [attr.role]="popover() ? 'dialog' : 'menu'"
3429
+ [attr.aria-label]="popover() ? popoverLabel() : null"
3430
+ [attr.tabindex]="popover() ? -1 : 0"
3431
+ (click)="onInnerActivate()"
3432
+ (keydown.enter)="onInnerActivate()"
3433
+ (keydown.space)="onInnerActivate()"
3372
3434
  >
3373
3435
  <ng-content />
3374
3436
  </div>
3375
3437
  }
3376
- `, isInline: true, styles: [".strct-dd{position:relative;display:inline-block}.strct-dd__trigger{display:inline-flex}.strct-dd__menu{position:absolute;top:calc(100% + 4px);left:0;z-index:200;min-width:170px;max-width:calc(100vw - 24px);padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:7px;box-shadow:var(--shh);animation:strct-dd-in .1s ease}.strct-dd__menu--end{left:auto;right:0}@keyframes strct-dd-in{0%{opacity:0;transform:translateY(-4px)}}\n"], dependencies: [{ kind: "directive", type: StrctOverlay, selector: "[strctOverlay]", inputs: ["strctOverlay", "strctOverlayPlacement", "strctOverlayMatchWidth", "strctOverlayGap"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3438
+ `, isInline: true, styles: [".strct-dd{position:relative;display:inline-block}.strct-dd__trigger{display:inline-flex}.strct-dd__menu{position:absolute;top:calc(100% + 4px);left:0;z-index:200;min-width:170px;max-width:calc(100vw - 24px);padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:7px;box-shadow:var(--shh);animation:strct-dd-in .1s ease}.strct-dd__menu--end{left:auto;right:0}.strct-dd__menu--popover{min-width:240px;padding:12px 14px}@keyframes strct-dd-in{0%{opacity:0;transform:translateY(-4px)}}\n"], dependencies: [{ kind: "directive", type: StrctOverlay, selector: "[strctOverlay]", inputs: ["strctOverlay", "strctOverlayPlacement", "strctOverlayMatchWidth", "strctOverlayGap"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3377
3439
  }
3378
3440
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctDropdown, decorators: [{
3379
3441
  type: Component,
@@ -3383,28 +3445,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
3383
3445
  class="strct-dd__trigger"
3384
3446
  role="button"
3385
3447
  tabindex="0"
3448
+ [attr.aria-haspopup]="popover() ? 'dialog' : 'menu'"
3449
+ [attr.aria-expanded]="open()"
3386
3450
  (click)="toggle()"
3387
3451
  (keydown.enter)="toggle()"
3388
3452
  (keydown.space)="toggle()"
3389
3453
  >
3390
3454
  <ng-content select="[strctDropdownTrigger]" />
3391
3455
  </div>
3456
+ <!--
3457
+ One panel for both modes (a default ng-content per @if branch would strand
3458
+ the projected content in the inactive branch) — mode picks the semantics.
3459
+ -->
3392
3460
  @if (open()) {
3393
3461
  <div
3394
3462
  class="strct-dd__menu"
3463
+ [class.strct-dd__menu--popover]="popover()"
3395
3464
  [strctOverlay]="trigger"
3396
3465
  [strctOverlayPlacement]="align() === 'end' ? 'bottom-end' : 'bottom-start'"
3397
- role="menu"
3398
- tabindex="0"
3399
- (click)="close()"
3400
- (keydown.enter)="close()"
3401
- (keydown.space)="close()"
3466
+ [attr.role]="popover() ? 'dialog' : 'menu'"
3467
+ [attr.aria-label]="popover() ? popoverLabel() : null"
3468
+ [attr.tabindex]="popover() ? -1 : 0"
3469
+ (click)="onInnerActivate()"
3470
+ (keydown.enter)="onInnerActivate()"
3471
+ (keydown.space)="onInnerActivate()"
3402
3472
  >
3403
3473
  <ng-content />
3404
3474
  </div>
3405
3475
  }
3406
- `, host: { class: 'strct-dd' }, styles: [".strct-dd{position:relative;display:inline-block}.strct-dd__trigger{display:inline-flex}.strct-dd__menu{position:absolute;top:calc(100% + 4px);left:0;z-index:200;min-width:170px;max-width:calc(100vw - 24px);padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:7px;box-shadow:var(--shh);animation:strct-dd-in .1s ease}.strct-dd__menu--end{left:auto;right:0}@keyframes strct-dd-in{0%{opacity:0;transform:translateY(-4px)}}\n"] }]
3407
- }], propDecorators: { align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], onDocClick: [{
3476
+ `, host: { class: 'strct-dd' }, styles: [".strct-dd{position:relative;display:inline-block}.strct-dd__trigger{display:inline-flex}.strct-dd__menu{position:absolute;top:calc(100% + 4px);left:0;z-index:200;min-width:170px;max-width:calc(100vw - 24px);padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:7px;box-shadow:var(--shh);animation:strct-dd-in .1s ease}.strct-dd__menu--end{left:auto;right:0}.strct-dd__menu--popover{min-width:240px;padding:12px 14px}@keyframes strct-dd-in{0%{opacity:0;transform:translateY(-4px)}}\n"] }]
3477
+ }], propDecorators: { align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], popover: [{ type: i0.Input, args: [{ isSignal: true, alias: "popover", required: false }] }], popoverLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "popoverLabel", required: false }] }], onDocClick: [{
3408
3478
  type: HostListener,
3409
3479
  args: ['document:click', ['$event']]
3410
3480
  }], onEscape: [{
@@ -4209,9 +4279,24 @@ class StrctCommandPalette {
4209
4279
  emptyText = input('No matches for', ...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
4210
4280
  /** Maximum rendered results. */
4211
4281
  maxResults = input(50, ...(ngDevMode ? [{ debugName: "maxResults" }] : /* istanbul ignore next */ []));
4282
+ /**
4283
+ * Internal ranked filtering. Set `false` for a **server-backed** palette:
4284
+ * items render in the order given (you already filtered them) and the query
4285
+ * reaches you through the two-way `query` model. `maxResults` still caps
4286
+ * rendering.
4287
+ */
4288
+ filter = input(true, { ...(ngDevMode ? { debugName: "filter" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4289
+ /** Show a "searching" row while server results are in flight. */
4290
+ loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4291
+ /** Localizable text of the loading row. */
4292
+ loadingText = input('Searching…', ...(ngDevMode ? [{ debugName: "loadingText" }] : /* istanbul ignore next */ []));
4212
4293
  /** Emitted when a command is chosen (Enter or click); the palette closes. */
4213
4294
  picked = output();
4214
- query = signal('', ...(ngDevMode ? [{ debugName: "query" }] : /* istanbul ignore next */ []));
4295
+ /**
4296
+ * The typed query (two-way). The palette still owns typing and keyboard
4297
+ * behaviour; consumers observe it to serve results asynchronously.
4298
+ */
4299
+ query = model('', ...(ngDevMode ? [{ debugName: "query" }] : /* istanbul ignore next */ []));
4215
4300
  activeIndex = signal(0, ...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
4216
4301
  listId = `strct-cmdp-list-${++paletteCounter}`;
4217
4302
  previousActive = null;
@@ -4220,8 +4305,11 @@ class StrctCommandPalette {
4220
4305
  }
4221
4306
  /** Rank: label prefix > word-start > substring; group/keyword matches last. */
4222
4307
  filtered = computed(() => {
4223
- const q = this.query().trim().toLowerCase();
4224
4308
  const items = this.items();
4309
+ // Server-backed mode: the caller already filtered — render as given.
4310
+ if (!this.filter())
4311
+ return items.slice(0, this.maxResults());
4312
+ const q = this.query().trim().toLowerCase();
4225
4313
  if (!q)
4226
4314
  return items.slice(0, this.maxResults());
4227
4315
  const scored = [];
@@ -4246,6 +4334,12 @@ class StrctCommandPalette {
4246
4334
  .map((s) => s.item);
4247
4335
  }, ...(ngDevMode ? [{ debugName: "filtered" }] : /* istanbul ignore next */ []));
4248
4336
  constructor() {
4337
+ // Async results can shrink under the cursor — keep the active option in range.
4338
+ effect(() => {
4339
+ const len = this.filtered().length;
4340
+ if (this.activeIndex() >= len)
4341
+ this.activeIndex.set(Math.max(0, len - 1));
4342
+ });
4249
4343
  // Focus the input on open; restore focus on close.
4250
4344
  effect(() => {
4251
4345
  if (this.open()) {
@@ -4317,7 +4411,7 @@ class StrctCommandPalette {
4317
4411
  this.open.set(false);
4318
4412
  }
4319
4413
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctCommandPalette, deps: [], target: i0.ɵɵFactoryTarget.Component });
4320
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctCommandPalette, isStandalone: true, selector: "strct-command-palette", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, hotkey: { classPropertyName: "hotkey", publicName: "hotkey", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, maxResults: { classPropertyName: "maxResults", publicName: "maxResults", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", picked: "picked" }, host: { listeners: { "document:keydown": "onGlobalKey($event)" } }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0, template: `
4414
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctCommandPalette, isStandalone: true, selector: "strct-command-palette", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, hotkey: { classPropertyName: "hotkey", publicName: "hotkey", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, maxResults: { classPropertyName: "maxResults", publicName: "maxResults", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, query: { classPropertyName: "query", publicName: "query", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", picked: "picked", query: "queryChange" }, host: { listeners: { "document:keydown": "onGlobalKey($event)" } }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0, template: `
4321
4415
  @if (open()) {
4322
4416
  <!-- Backdrop: pointer-only dismiss (Escape covers keyboard). -->
4323
4417
  <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->
@@ -4348,6 +4442,11 @@ class StrctCommandPalette {
4348
4442
  <strct-kbd>Esc</strct-kbd>
4349
4443
  </div>
4350
4444
  <div class="strct-cmdp__list" role="listbox" [id]="listId">
4445
+ @if (loading()) {
4446
+ <div class="strct-cmdp__loading" aria-live="polite">
4447
+ <span class="strct-cmdp__spin" aria-hidden="true"></span>{{ loadingText() }}
4448
+ </div>
4449
+ }
4351
4450
  @for (item of filtered(); track item.id; let i = $index) {
4352
4451
  <button
4353
4452
  type="button"
@@ -4377,13 +4476,15 @@ class StrctCommandPalette {
4377
4476
  }
4378
4477
  </button>
4379
4478
  } @empty {
4380
- <div class="strct-cmdp__empty">{{ emptyText() }} “{{ query() }}”</div>
4479
+ @if (!loading()) {
4480
+ <div class="strct-cmdp__empty">{{ emptyText() }} “{{ query() }}”</div>
4481
+ }
4381
4482
  }
4382
4483
  </div>
4383
4484
  </div>
4384
4485
  </div>
4385
4486
  }
4386
- `, isInline: true, styles: [".strct-cmdp__backdrop{position:fixed;inset:0;z-index:1200;display:flex;justify-content:center;align-items:flex-start;padding:14vh 16px 16px;background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);animation:strct-cmdp-fade .12s ease}.strct-cmdp{width:100%;max-width:560px;max-height:60vh;display:flex;flex-direction:column;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-xl);box-shadow:var(--shadow-floating);overflow:hidden;animation:strct-cmdp-rise .14s ease}.strct-cmdp__search{display:flex;align-items:center;gap:10px;padding:13px 16px;border-bottom:1px solid var(--b1);color:var(--t3)}.strct-cmdp__input{flex:1;min-width:0;border:0;background:transparent;color:var(--t1);font-size:15px;font-family:var(--font);outline:none}.strct-cmdp__list{overflow-y:auto;padding:6px}.strct-cmdp__item{display:flex;align-items:center;gap:11px;width:100%;padding:9px 11px;border:0;border-radius:var(--radius-md);background:transparent;cursor:pointer;text-align:start;font-family:var(--font)}.strct-cmdp__item.is-active{background:var(--acc-m)}.strct-cmdp__icon{color:var(--t2);flex-shrink:0}.strct-cmdp__item.is-active .strct-cmdp__icon{color:var(--acc)}.strct-cmdp__label{flex:1;min-width:0;font-size:var(--text-lg);color:var(--t1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-cmdp__group{font-size:var(--text-sm);color:var(--t3);flex-shrink:0}.strct-cmdp__empty{padding:20px;text-align:center;font-size:var(--text-md);color:var(--t3)}@keyframes strct-cmdp-fade{0%{opacity:0}}@keyframes strct-cmdp-rise{0%{opacity:0;transform:translateY(-8px)}}@media(prefers-reduced-motion:reduce){.strct-cmdp__backdrop,.strct-cmdp{animation:none}}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctKbd, selector: "strct-kbd" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4487
+ `, isInline: true, styles: [".strct-cmdp__backdrop{position:fixed;inset:0;z-index:1200;display:flex;justify-content:center;align-items:flex-start;padding:14vh 16px 16px;background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);animation:strct-cmdp-fade .12s ease}.strct-cmdp{width:100%;max-width:560px;max-height:60vh;display:flex;flex-direction:column;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-xl);box-shadow:var(--shadow-floating);overflow:hidden;animation:strct-cmdp-rise .14s ease}.strct-cmdp__search{display:flex;align-items:center;gap:10px;padding:13px 16px;border-bottom:1px solid var(--b1);color:var(--t3)}.strct-cmdp__input{flex:1;min-width:0;border:0;background:transparent;color:var(--t1);font-size:15px;font-family:var(--font);outline:none}.strct-cmdp__list{overflow-y:auto;padding:6px}.strct-cmdp__item{display:flex;align-items:center;gap:11px;width:100%;padding:9px 11px;border:0;border-radius:var(--radius-md);background:transparent;cursor:pointer;text-align:start;font-family:var(--font)}.strct-cmdp__item.is-active{background:var(--acc-m)}.strct-cmdp__icon{color:var(--t2);flex-shrink:0}.strct-cmdp__item.is-active .strct-cmdp__icon{color:var(--acc)}.strct-cmdp__label{flex:1;min-width:0;font-size:var(--text-lg);color:var(--t1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-cmdp__group{font-size:var(--text-sm);color:var(--t3);flex-shrink:0}.strct-cmdp__loading{display:flex;align-items:center;gap:9px;padding:10px 12px;font-size:var(--text-md);color:var(--t3)}.strct-cmdp__spin{width:13px;height:13px;border:2px solid var(--acc30);border-top-color:var(--acc);border-radius:50%;flex-shrink:0}@media(prefers-reduced-motion:no-preference){.strct-cmdp__spin{animation:strct-cmdp-spin .8s linear infinite}}@keyframes strct-cmdp-spin{to{transform:rotate(360deg)}}.strct-cmdp__empty{padding:20px;text-align:center;font-size:var(--text-md);color:var(--t3)}@keyframes strct-cmdp-fade{0%{opacity:0}}@keyframes strct-cmdp-rise{0%{opacity:0;transform:translateY(-8px)}}@media(prefers-reduced-motion:reduce){.strct-cmdp__backdrop,.strct-cmdp{animation:none}}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctKbd, selector: "strct-kbd" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4387
4488
  }
4388
4489
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctCommandPalette, decorators: [{
4389
4490
  type: Component,
@@ -4418,6 +4519,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
4418
4519
  <strct-kbd>Esc</strct-kbd>
4419
4520
  </div>
4420
4521
  <div class="strct-cmdp__list" role="listbox" [id]="listId">
4522
+ @if (loading()) {
4523
+ <div class="strct-cmdp__loading" aria-live="polite">
4524
+ <span class="strct-cmdp__spin" aria-hidden="true"></span>{{ loadingText() }}
4525
+ </div>
4526
+ }
4421
4527
  @for (item of filtered(); track item.id; let i = $index) {
4422
4528
  <button
4423
4529
  type="button"
@@ -4447,14 +4553,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
4447
4553
  }
4448
4554
  </button>
4449
4555
  } @empty {
4450
- <div class="strct-cmdp__empty">{{ emptyText() }} “{{ query() }}”</div>
4556
+ @if (!loading()) {
4557
+ <div class="strct-cmdp__empty">{{ emptyText() }} “{{ query() }}”</div>
4558
+ }
4451
4559
  }
4452
4560
  </div>
4453
4561
  </div>
4454
4562
  </div>
4455
4563
  }
4456
- `, styles: [".strct-cmdp__backdrop{position:fixed;inset:0;z-index:1200;display:flex;justify-content:center;align-items:flex-start;padding:14vh 16px 16px;background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);animation:strct-cmdp-fade .12s ease}.strct-cmdp{width:100%;max-width:560px;max-height:60vh;display:flex;flex-direction:column;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-xl);box-shadow:var(--shadow-floating);overflow:hidden;animation:strct-cmdp-rise .14s ease}.strct-cmdp__search{display:flex;align-items:center;gap:10px;padding:13px 16px;border-bottom:1px solid var(--b1);color:var(--t3)}.strct-cmdp__input{flex:1;min-width:0;border:0;background:transparent;color:var(--t1);font-size:15px;font-family:var(--font);outline:none}.strct-cmdp__list{overflow-y:auto;padding:6px}.strct-cmdp__item{display:flex;align-items:center;gap:11px;width:100%;padding:9px 11px;border:0;border-radius:var(--radius-md);background:transparent;cursor:pointer;text-align:start;font-family:var(--font)}.strct-cmdp__item.is-active{background:var(--acc-m)}.strct-cmdp__icon{color:var(--t2);flex-shrink:0}.strct-cmdp__item.is-active .strct-cmdp__icon{color:var(--acc)}.strct-cmdp__label{flex:1;min-width:0;font-size:var(--text-lg);color:var(--t1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-cmdp__group{font-size:var(--text-sm);color:var(--t3);flex-shrink:0}.strct-cmdp__empty{padding:20px;text-align:center;font-size:var(--text-md);color:var(--t3)}@keyframes strct-cmdp-fade{0%{opacity:0}}@keyframes strct-cmdp-rise{0%{opacity:0;transform:translateY(-8px)}}@media(prefers-reduced-motion:reduce){.strct-cmdp__backdrop,.strct-cmdp{animation:none}}\n"] }]
4457
- }], ctorParameters: () => [], propDecorators: { inputRef: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], hotkey: [{ type: i0.Input, args: [{ isSignal: true, alias: "hotkey", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], maxResults: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxResults", required: false }] }], picked: [{ type: i0.Output, args: ["picked"] }] } });
4564
+ `, styles: [".strct-cmdp__backdrop{position:fixed;inset:0;z-index:1200;display:flex;justify-content:center;align-items:flex-start;padding:14vh 16px 16px;background:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);animation:strct-cmdp-fade .12s ease}.strct-cmdp{width:100%;max-width:560px;max-height:60vh;display:flex;flex-direction:column;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-xl);box-shadow:var(--shadow-floating);overflow:hidden;animation:strct-cmdp-rise .14s ease}.strct-cmdp__search{display:flex;align-items:center;gap:10px;padding:13px 16px;border-bottom:1px solid var(--b1);color:var(--t3)}.strct-cmdp__input{flex:1;min-width:0;border:0;background:transparent;color:var(--t1);font-size:15px;font-family:var(--font);outline:none}.strct-cmdp__list{overflow-y:auto;padding:6px}.strct-cmdp__item{display:flex;align-items:center;gap:11px;width:100%;padding:9px 11px;border:0;border-radius:var(--radius-md);background:transparent;cursor:pointer;text-align:start;font-family:var(--font)}.strct-cmdp__item.is-active{background:var(--acc-m)}.strct-cmdp__icon{color:var(--t2);flex-shrink:0}.strct-cmdp__item.is-active .strct-cmdp__icon{color:var(--acc)}.strct-cmdp__label{flex:1;min-width:0;font-size:var(--text-lg);color:var(--t1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.strct-cmdp__group{font-size:var(--text-sm);color:var(--t3);flex-shrink:0}.strct-cmdp__loading{display:flex;align-items:center;gap:9px;padding:10px 12px;font-size:var(--text-md);color:var(--t3)}.strct-cmdp__spin{width:13px;height:13px;border:2px solid var(--acc30);border-top-color:var(--acc);border-radius:50%;flex-shrink:0}@media(prefers-reduced-motion:no-preference){.strct-cmdp__spin{animation:strct-cmdp-spin .8s linear infinite}}@keyframes strct-cmdp-spin{to{transform:rotate(360deg)}}.strct-cmdp__empty{padding:20px;text-align:center;font-size:var(--text-md);color:var(--t3)}@keyframes strct-cmdp-fade{0%{opacity:0}}@keyframes strct-cmdp-rise{0%{opacity:0;transform:translateY(-8px)}}@media(prefers-reduced-motion:reduce){.strct-cmdp__backdrop,.strct-cmdp{animation:none}}\n"] }]
4565
+ }], ctorParameters: () => [], propDecorators: { inputRef: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], hotkey: [{ type: i0.Input, args: [{ isSignal: true, alias: "hotkey", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], maxResults: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxResults", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], picked: [{ type: i0.Output, args: ["picked"] }], query: [{ type: i0.Input, args: [{ isSignal: true, alias: "query", required: false }] }, { type: i0.Output, args: ["queryChange"] }] } });
4458
4566
 
4459
4567
  /**
4460
4568
  * Compact search pill — the pattern from the docs header: a leading search
@@ -4727,6 +4835,12 @@ class StrctCode {
4727
4835
  collapsed = model(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
4728
4836
  /** Show a line-number gutter (numbers are never copied — `code` is). */
4729
4837
  lineNumbers = input(false, { ...(ngDevMode ? { debugName: "lineNumbers" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4838
+ /**
4839
+ * Soft-wrap long unbroken text (PEM/CSR blocks, base64, long commands) so a
4840
+ * dialog never scrolls horizontally. Wrapping breaks the gutter's visual
4841
+ * alignment, so `wrap` takes precedence and hides `lineNumbers`.
4842
+ */
4843
+ wrap = input(false, { ...(ngDevMode ? { debugName: "wrap" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4730
4844
  /** Scroll the body past this height (px); null grows freely. */
4731
4845
  maxHeight = input(null, ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
4732
4846
  /** Localizable labels for the collapse toggle. */
@@ -4737,7 +4851,7 @@ class StrctCode {
4737
4851
  return Array.from({ length: n }, (_, i) => i + 1);
4738
4852
  }, ...(ngDevMode ? [{ debugName: "lineNos" }] : /* istanbul ignore next */ []));
4739
4853
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctCode, deps: [], target: i0.ɵɵFactoryTarget.Component });
4740
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctCode, isStandalone: true, selector: "strct-code", inputs: { code: { classPropertyName: "code", publicName: "code", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: false, transformFunction: null }, copyable: { classPropertyName: "copyable", publicName: "copyable", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, lineNumbers: { classPropertyName: "lineNumbers", publicName: "lineNumbers", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, collapseLabel: { classPropertyName: "collapseLabel", publicName: "collapseLabel", isSignal: true, isRequired: false, transformFunction: null }, expandLabel: { classPropertyName: "expandLabel", publicName: "expandLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { properties: { "class.strct-code--collapsed": "collapsible() && collapsed()" }, classAttribute: "strct-code" }, ngImport: i0, template: `
4854
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctCode, isStandalone: true, selector: "strct-code", inputs: { code: { classPropertyName: "code", publicName: "code", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: false, transformFunction: null }, copyable: { classPropertyName: "copyable", publicName: "copyable", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, lineNumbers: { classPropertyName: "lineNumbers", publicName: "lineNumbers", isSignal: true, isRequired: false, transformFunction: null }, wrap: { classPropertyName: "wrap", publicName: "wrap", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, collapseLabel: { classPropertyName: "collapseLabel", publicName: "collapseLabel", isSignal: true, isRequired: false, transformFunction: null }, expandLabel: { classPropertyName: "expandLabel", publicName: "expandLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { properties: { "class.strct-code--collapsed": "collapsible() && collapsed()" }, classAttribute: "strct-code" }, ngImport: i0, template: `
4741
4855
  @if (title() || language() || copyable() || collapsible()) {
4742
4856
  <div class="strct-code__head">
4743
4857
  @if (collapsible()) {
@@ -4775,19 +4889,20 @@ class StrctCode {
4775
4889
  @if (!collapsible() || !collapsed()) {
4776
4890
  <div
4777
4891
  class="strct-code__scroll"
4892
+ [class.strct-code__scroll--wrap]="wrap()"
4778
4893
  tabindex="0"
4779
4894
  role="region"
4780
4895
  [attr.aria-label]="title() || language() || 'code'"
4781
4896
  [style.max-height.px]="maxHeight()"
4782
4897
  >
4783
4898
  <pre class="strct-code__pre"><!--
4784
- -->@if (lineNumbers()) {<!--
4899
+ -->@if (lineNumbers() && !wrap()) {<!--
4785
4900
  --><span class="strct-code__gutter" aria-hidden="true">@for (n of lineNos(); track n) {<span class="strct-code__ln">{{ n }}</span>}</span><!--
4786
4901
  -->}<!--
4787
4902
  --><code class="strct-code__code">{{ code() }}</code></pre>
4788
4903
  </div>
4789
4904
  }
4790
- `, isInline: true, styles: [".strct-code{display:block;border:1px solid var(--b2);border-radius:9px;background:var(--bg-2);overflow:hidden}.strct-code__head{display:flex;align-items:center;gap:8px;padding:6px 10px;border-bottom:1px solid var(--b1)}.strct-code--collapsed .strct-code__head{border-bottom:0}.strct-code__toggle{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin:-3px 0 -3px -4px;padding:0;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer}.strct-code__toggle:hover{color:var(--t1);background:var(--bg-3)}.strct-code__toggle:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-code__toggle strct-icon{transition:transform .15s ease}.strct-code__chev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-code__toggle strct-icon{transition:none}}.strct-code__title{font-size:12.5px;font-weight:600;color:var(--t1)}.strct-code__lang{font-family:var(--mono);font-size:10px;letter-spacing:.6px;text-transform:uppercase;color:var(--t3);border:1px solid var(--b2);border-radius:4px;padding:2px 6px}.strct-code__grow{flex:1}.strct-code__scroll{overflow:auto}.strct-code__scroll:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-code__pre{display:flex;margin:0;padding:10px 12px;font-family:var(--mono);font-size:12px;line-height:1.55;color:var(--t1)}.strct-code__gutter{display:flex;flex-direction:column;flex-shrink:0;margin-inline-end:12px;padding-inline-end:10px;border-inline-end:1px solid var(--b1);color:var(--t3);text-align:end;-webkit-user-select:none;user-select:none;font-variant-numeric:tabular-nums}.strct-code__code{display:block;white-space:pre}\n"], dependencies: [{ kind: "component", type: StrctCopy, selector: "strct-copy", inputs: ["text", "label", "ariaLabel", "copyLabel", "copiedLabel"], outputs: ["copied"] }, { kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4905
+ `, isInline: true, styles: [".strct-code{display:block;border:1px solid var(--b2);border-radius:9px;background:var(--bg-2);overflow:hidden}.strct-code__head{display:flex;align-items:center;gap:8px;padding:6px 10px;border-bottom:1px solid var(--b1)}.strct-code--collapsed .strct-code__head{border-bottom:0}.strct-code__toggle{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin:-3px 0 -3px -4px;padding:0;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer}.strct-code__toggle:hover{color:var(--t1);background:var(--bg-3)}.strct-code__toggle:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-code__toggle strct-icon{transition:transform .15s ease}.strct-code__chev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-code__toggle strct-icon{transition:none}}.strct-code__title{font-size:12.5px;font-weight:600;color:var(--t1)}.strct-code__lang{font-family:var(--mono);font-size:10px;letter-spacing:.6px;text-transform:uppercase;color:var(--t3);border:1px solid var(--b2);border-radius:4px;padding:2px 6px}.strct-code__grow{flex:1}.strct-code__scroll{overflow:auto}.strct-code__scroll:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-code__pre{display:flex;margin:0;padding:10px 12px;font-family:var(--mono);font-size:12px;line-height:1.55;color:var(--t1)}.strct-code__gutter{display:flex;flex-direction:column;flex-shrink:0;margin-inline-end:12px;padding-inline-end:10px;border-inline-end:1px solid var(--b1);color:var(--t3);text-align:end;-webkit-user-select:none;user-select:none;font-variant-numeric:tabular-nums}.strct-code__code{display:block;white-space:pre}.strct-code__scroll--wrap .strct-code__code{white-space:pre-wrap;overflow-wrap:anywhere}\n"], dependencies: [{ kind: "component", type: StrctCopy, selector: "strct-copy", inputs: ["text", "label", "ariaLabel", "copyLabel", "copiedLabel"], outputs: ["copied"] }, { kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4791
4906
  }
4792
4907
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctCode, decorators: [{
4793
4908
  type: Component,
@@ -4829,13 +4944,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
4829
4944
  @if (!collapsible() || !collapsed()) {
4830
4945
  <div
4831
4946
  class="strct-code__scroll"
4947
+ [class.strct-code__scroll--wrap]="wrap()"
4832
4948
  tabindex="0"
4833
4949
  role="region"
4834
4950
  [attr.aria-label]="title() || language() || 'code'"
4835
4951
  [style.max-height.px]="maxHeight()"
4836
4952
  >
4837
4953
  <pre class="strct-code__pre"><!--
4838
- -->@if (lineNumbers()) {<!--
4954
+ -->@if (lineNumbers() && !wrap()) {<!--
4839
4955
  --><span class="strct-code__gutter" aria-hidden="true">@for (n of lineNos(); track n) {<span class="strct-code__ln">{{ n }}</span>}</span><!--
4840
4956
  -->}<!--
4841
4957
  --><code class="strct-code__code">{{ code() }}</code></pre>
@@ -4844,8 +4960,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
4844
4960
  `, host: {
4845
4961
  class: 'strct-code',
4846
4962
  '[class.strct-code--collapsed]': 'collapsible() && collapsed()',
4847
- }, styles: [".strct-code{display:block;border:1px solid var(--b2);border-radius:9px;background:var(--bg-2);overflow:hidden}.strct-code__head{display:flex;align-items:center;gap:8px;padding:6px 10px;border-bottom:1px solid var(--b1)}.strct-code--collapsed .strct-code__head{border-bottom:0}.strct-code__toggle{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin:-3px 0 -3px -4px;padding:0;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer}.strct-code__toggle:hover{color:var(--t1);background:var(--bg-3)}.strct-code__toggle:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-code__toggle strct-icon{transition:transform .15s ease}.strct-code__chev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-code__toggle strct-icon{transition:none}}.strct-code__title{font-size:12.5px;font-weight:600;color:var(--t1)}.strct-code__lang{font-family:var(--mono);font-size:10px;letter-spacing:.6px;text-transform:uppercase;color:var(--t3);border:1px solid var(--b2);border-radius:4px;padding:2px 6px}.strct-code__grow{flex:1}.strct-code__scroll{overflow:auto}.strct-code__scroll:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-code__pre{display:flex;margin:0;padding:10px 12px;font-family:var(--mono);font-size:12px;line-height:1.55;color:var(--t1)}.strct-code__gutter{display:flex;flex-direction:column;flex-shrink:0;margin-inline-end:12px;padding-inline-end:10px;border-inline-end:1px solid var(--b1);color:var(--t3);text-align:end;-webkit-user-select:none;user-select:none;font-variant-numeric:tabular-nums}.strct-code__code{display:block;white-space:pre}\n"] }]
4848
- }], propDecorators: { code: [{ type: i0.Input, args: [{ isSignal: true, alias: "code", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], language: [{ type: i0.Input, args: [{ isSignal: true, alias: "language", required: false }] }], copyable: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyable", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], lineNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "lineNumbers", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], collapseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseLabel", required: false }] }], expandLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandLabel", required: false }] }] } });
4963
+ }, styles: [".strct-code{display:block;border:1px solid var(--b2);border-radius:9px;background:var(--bg-2);overflow:hidden}.strct-code__head{display:flex;align-items:center;gap:8px;padding:6px 10px;border-bottom:1px solid var(--b1)}.strct-code--collapsed .strct-code__head{border-bottom:0}.strct-code__toggle{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin:-3px 0 -3px -4px;padding:0;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer}.strct-code__toggle:hover{color:var(--t1);background:var(--bg-3)}.strct-code__toggle:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-code__toggle strct-icon{transition:transform .15s ease}.strct-code__chev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-code__toggle strct-icon{transition:none}}.strct-code__title{font-size:12.5px;font-weight:600;color:var(--t1)}.strct-code__lang{font-family:var(--mono);font-size:10px;letter-spacing:.6px;text-transform:uppercase;color:var(--t3);border:1px solid var(--b2);border-radius:4px;padding:2px 6px}.strct-code__grow{flex:1}.strct-code__scroll{overflow:auto}.strct-code__scroll:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-code__pre{display:flex;margin:0;padding:10px 12px;font-family:var(--mono);font-size:12px;line-height:1.55;color:var(--t1)}.strct-code__gutter{display:flex;flex-direction:column;flex-shrink:0;margin-inline-end:12px;padding-inline-end:10px;border-inline-end:1px solid var(--b1);color:var(--t3);text-align:end;-webkit-user-select:none;user-select:none;font-variant-numeric:tabular-nums}.strct-code__code{display:block;white-space:pre}.strct-code__scroll--wrap .strct-code__code{white-space:pre-wrap;overflow-wrap:anywhere}\n"] }]
4964
+ }], propDecorators: { code: [{ type: i0.Input, args: [{ isSignal: true, alias: "code", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], language: [{ type: i0.Input, args: [{ isSignal: true, alias: "language", required: false }] }], copyable: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyable", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], lineNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "lineNumbers", required: false }] }], wrap: [{ type: i0.Input, args: [{ isSignal: true, alias: "wrap", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], collapseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseLabel", required: false }] }], expandLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandLabel", required: false }] }] } });
4849
4965
 
4850
4966
  /**
4851
4967
  * The standard strip above a data grid: a search field, the active filter
@@ -12652,5 +12768,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
12652
12768
  * Generated bundle index. Do not edit.
12653
12769
  */
12654
12770
 
12655
- export { STRCT_ICONS, STRCT_ICON_GROUPS, STRCT_MASKS, STRCT_PALETTES, STRCT_RAW_ICONS, StrctAccordion, StrctAccordionPanel, StrctAlert, StrctAvatar, StrctBadge, StrctBreadcrumb, StrctBreadcrumbItem, StrctButton, StrctButtonGroup, StrctCard, StrctCardBlock, StrctCardFooter, StrctCardHeader, StrctCascadeHost, StrctCascadeNode, StrctCascadeSelect, StrctCellDef, StrctCellStatus, StrctChart, StrctCheckbox, StrctChips, StrctCode, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctContextMenu, StrctContextMenuTrigger, StrctCopy, StrctDatagrid, StrctDatagridActionBar, StrctDatepicker, StrctDesc, StrctDescriptionList, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownItem, StrctEmptyState, StrctField, StrctFile, StrctFilterBar, StrctFlow, StrctFooter, StrctGauge, StrctHeader, StrctHero, StrctIcon, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctLogin, StrctMenuPanel, StrctMenuService, StrctMetricTile, StrctModal, StrctNav, StrctNavItem, StrctOverlay, StrctPageHeader, StrctPageHeaderActions, StrctPageHeaderCrumbs, StrctPagination, StrctPassword, StrctProgress, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRating, StrctRowDetailDef, StrctSearchbox, StrctSectionMenu, StrctSegmented, StrctShell, StrctShellService, StrctSignpost, StrctSkeleton, StrctSparkline, StrctSpeedDial, StrctSpinner, StrctStack, StrctStackItem, StrctStep, StrctSubmenu, StrctTab, StrctTable, StrctTabs, StrctTag, StrctThemeService, StrctThemeSwitcher, StrctTimeline, StrctTimelineItem, StrctToastOutlet, StrctToastService, StrctToggle, StrctTooltip, StrctTree, StrctTreeNode, StrctVerticalNav, StrctWizard, registerStrctIcon, strctValidationIcon, strctValidationTone };
12771
+ export { STRCT_ICONS, STRCT_ICON_GROUPS, STRCT_ICON_NAMES, STRCT_MASKS, STRCT_PALETTES, STRCT_RAW_ICONS, StrctAccordion, StrctAccordionPanel, StrctAlert, StrctAvatar, StrctBadge, StrctBreadcrumb, StrctBreadcrumbItem, StrctButton, StrctButtonGroup, StrctCard, StrctCardBlock, StrctCardFooter, StrctCardHeader, StrctCascadeHost, StrctCascadeNode, StrctCascadeSelect, StrctCellDef, StrctCellStatus, StrctChart, StrctCheckbox, StrctChips, StrctCode, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctContextMenu, StrctContextMenuTrigger, StrctCopy, StrctDatagrid, StrctDatagridActionBar, StrctDatepicker, StrctDesc, StrctDescriptionList, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownItem, StrctEmptyState, StrctField, StrctFile, StrctFilterBar, StrctFlow, StrctFooter, StrctGauge, StrctHeader, StrctHero, StrctIcon, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctLogin, StrctMenuPanel, StrctMenuService, StrctMetricTile, StrctModal, StrctNav, StrctNavItem, StrctOverlay, StrctPageHeader, StrctPageHeaderActions, StrctPageHeaderCrumbs, StrctPagination, StrctPassword, StrctProgress, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRating, StrctRowDetailDef, StrctSearchbox, StrctSectionMenu, StrctSegmented, StrctShell, StrctShellService, StrctSignpost, StrctSkeleton, StrctSparkline, StrctSpeedDial, StrctSpinner, StrctStack, StrctStackItem, StrctStep, StrctSubmenu, StrctTab, StrctTable, StrctTabs, StrctTag, StrctThemeService, StrctThemeSwitcher, StrctTimeline, StrctTimelineItem, StrctToastOutlet, StrctToastService, StrctToggle, StrctTooltip, StrctTree, StrctTreeNode, StrctVerticalNav, StrctWizard, registerStrctIcon, strctValidationIcon, strctValidationTone };
12656
12772
  //# sourceMappingURL=akcelik-strct.mjs.map