@akcelik/strct 1.3.0 → 1.5.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.
@@ -1326,6 +1326,76 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
1326
1326
  `, host: { class: 'strct-login' }, styles: [".strct-login{display:flex;align-items:center;justify-content:center;width:100%;min-height:100%;padding:32px}.strct-login__inner{width:100%}.strct-login__card{display:grid;grid-template-columns:1.05fr 1fr;width:100%;overflow:hidden}.strct-login__main{padding:40px 38px;display:flex;flex-direction:column;justify-content:center}.strct-login__aside{position:relative;overflow:hidden;min-height:420px;color:var(--t1);border-inline-end:1px solid var(--b2)}.strct-login__aside:before,.strct-login__aside:after{display:none}.strct-login__aside-inner{position:relative;z-index:1;height:100%;display:flex;flex-direction:column;justify-content:space-between;padding:34px 36px}@media(max-width:720px){.strct-login__card{grid-template-columns:1fr}.strct-login__aside{min-height:220px}.strct-login__main{padding:30px 26px}}\n"] }]
1327
1327
  }], propDecorators: { maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], split: [{ type: i0.Input, args: [{ isSignal: true, alias: "split", required: false }] }] } });
1328
1328
 
1329
+ /** Marks the breadcrumb row projected above the title. */
1330
+ class StrctPageHeaderCrumbs {
1331
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctPageHeaderCrumbs, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1332
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.16", type: StrctPageHeaderCrumbs, isStandalone: true, selector: "[strctPageHeaderCrumbs]", ngImport: i0 });
1333
+ }
1334
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctPageHeaderCrumbs, decorators: [{
1335
+ type: Directive,
1336
+ args: [{ selector: '[strctPageHeaderCrumbs]' }]
1337
+ }] });
1338
+ /** Marks the action buttons aligned to the end of the title row. */
1339
+ class StrctPageHeaderActions {
1340
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctPageHeaderActions, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1341
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.16", type: StrctPageHeaderActions, isStandalone: true, selector: "[strctPageHeaderActions]", ngImport: i0 });
1342
+ }
1343
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctPageHeaderActions, decorators: [{
1344
+ type: Directive,
1345
+ args: [{ selector: '[strctPageHeaderActions]' }]
1346
+ }] });
1347
+ /**
1348
+ * Page header — the top of every console object page: an optional breadcrumb
1349
+ * row, a title + subtitle, and actions aligned to the end. Default content
1350
+ * projects below the title row (status badges, meta strips).
1351
+ *
1352
+ * <strct-page-header title="hv-02" subtitle="Hypervisor · cluster-01">
1353
+ * <strct-breadcrumb strctPageHeaderCrumbs>…</strct-breadcrumb>
1354
+ * <button strct-button strctPageHeaderActions variant="primary">Migrate</button>
1355
+ * </strct-page-header>
1356
+ */
1357
+ class StrctPageHeader {
1358
+ /** Page title (an h1). */
1359
+ title = input.required(...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
1360
+ /** One-line description under the title. */
1361
+ subtitle = input('', ...(ngDevMode ? [{ debugName: "subtitle" }] : /* istanbul ignore next */ []));
1362
+ /** Draw a hairline divider under the header. */
1363
+ divider = input(false, { ...(ngDevMode ? { debugName: "divider" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1364
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctPageHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
1365
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctPageHeader, isStandalone: true, selector: "strct-page-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, divider: { classPropertyName: "divider", publicName: "divider", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.strct-ph--divider": "divider()" }, classAttribute: "strct-ph" }, ngImport: i0, template: `
1366
+ <div class="strct-ph__crumbs"><ng-content select="[strctPageHeaderCrumbs]" /></div>
1367
+ <div class="strct-ph__row">
1368
+ <div class="strct-ph__text">
1369
+ <h1 class="strct-ph__title">{{ title() }}</h1>
1370
+ @if (subtitle()) {
1371
+ <p class="strct-ph__subtitle">{{ subtitle() }}</p>
1372
+ }
1373
+ </div>
1374
+ <div class="strct-ph__actions"><ng-content select="[strctPageHeaderActions]" /></div>
1375
+ </div>
1376
+ <ng-content />
1377
+ `, isInline: true, styles: [".strct-ph{display:block}.strct-ph--divider{padding-bottom:16px;border-bottom:1px solid var(--b1)}.strct-ph__crumbs:empty{display:none}.strct-ph__crumbs{margin-bottom:6px}.strct-ph__row{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.strct-ph__text{flex:1;min-width:0}.strct-ph__title{margin:0;font-size:var(--text-2xl);font-weight:700;letter-spacing:-.01em;color:var(--t1);text-wrap:balance}.strct-ph__subtitle{margin:6px 0 0;font-size:13px;line-height:1.55;color:var(--t2);max-width:72ch}.strct-ph__actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.strct-ph__actions:empty{display:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1378
+ }
1379
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctPageHeader, decorators: [{
1380
+ type: Component,
1381
+ args: [{ selector: 'strct-page-header', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `
1382
+ <div class="strct-ph__crumbs"><ng-content select="[strctPageHeaderCrumbs]" /></div>
1383
+ <div class="strct-ph__row">
1384
+ <div class="strct-ph__text">
1385
+ <h1 class="strct-ph__title">{{ title() }}</h1>
1386
+ @if (subtitle()) {
1387
+ <p class="strct-ph__subtitle">{{ subtitle() }}</p>
1388
+ }
1389
+ </div>
1390
+ <div class="strct-ph__actions"><ng-content select="[strctPageHeaderActions]" /></div>
1391
+ </div>
1392
+ <ng-content />
1393
+ `, host: {
1394
+ class: 'strct-ph',
1395
+ '[class.strct-ph--divider]': 'divider()',
1396
+ }, styles: [".strct-ph{display:block}.strct-ph--divider{padding-bottom:16px;border-bottom:1px solid var(--b1)}.strct-ph__crumbs:empty{display:none}.strct-ph__crumbs{margin-bottom:6px}.strct-ph__row{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}.strct-ph__text{flex:1;min-width:0}.strct-ph__title{margin:0;font-size:var(--text-2xl);font-weight:700;letter-spacing:-.01em;color:var(--t1);text-wrap:balance}.strct-ph__subtitle{margin:6px 0 0;font-size:13px;line-height:1.55;color:var(--t2);max-width:72ch}.strct-ph__actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.strct-ph__actions:empty{display:none}\n"] }]
1397
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], divider: [{ type: i0.Input, args: [{ isSignal: true, alias: "divider", required: false }] }] } });
1398
+
1329
1399
  /**
1330
1400
  * Styles a native `<button>` / `<a>` so it stays fully accessible and form-aware.
1331
1401
  *
@@ -4386,6 +4456,491 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
4386
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"] }]
4387
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"] }] } });
4388
4458
 
4459
+ /**
4460
+ * Compact search pill — the pattern from the docs header: a leading search
4461
+ * icon, a label / input and an optional keyboard-hint chip. Two modes:
4462
+ *
4463
+ * - **input** (default): a real search field. Two-way `value` (also
4464
+ * CVA-compatible), `(search)` emits on Enter, Escape / the × clears.
4465
+ *
4466
+ * <strct-searchbox [(value)]="q" (search)="run($event)" />
4467
+ *
4468
+ * - **`trigger`**: a button that only announces activation — the classic
4469
+ * "fake search that opens the command palette" header pattern:
4470
+ *
4471
+ * <strct-searchbox trigger hint="⌘K" (activated)="palette.open.set(true)" />
4472
+ */
4473
+ class StrctSearchbox {
4474
+ host = inject(ElementRef);
4475
+ /** Placeholder text (and the trigger mode's label). */
4476
+ placeholder = input('Search', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
4477
+ /** Keyboard-hint chip (e.g. "⌘K"); hidden while typing. */
4478
+ hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
4479
+ /** Render as an activation button instead of a real input (palette opener). */
4480
+ trigger = input(false, { ...(ngDevMode ? { debugName: "trigger" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4481
+ /** Show the × clear button when there is a value. */
4482
+ clearable = input(true, { ...(ngDevMode ? { debugName: "clearable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4483
+ /** Accessible label; falls back to `placeholder`. */
4484
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
4485
+ /** Accessible label of the clear button (localizable). */
4486
+ clearLabel = input('Clear search', ...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
4487
+ /** Current text (two-way; also drives the CVA value). */
4488
+ value = model('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
4489
+ /** Enter pressed in input mode — run the search with the current text. */
4490
+ search = output();
4491
+ /** Trigger mode clicked (open your command palette / search surface). */
4492
+ activated = output();
4493
+ focused = signal(false, ...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
4494
+ isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
4495
+ onChange = () => { };
4496
+ onTouched = () => { };
4497
+ onInput(event) {
4498
+ const next = event.target.value;
4499
+ this.value.set(next);
4500
+ this.onChange(next);
4501
+ }
4502
+ /** Clear the text (Escape / the × button). */
4503
+ clear() {
4504
+ if (!this.value())
4505
+ return;
4506
+ this.value.set('');
4507
+ this.onChange('');
4508
+ }
4509
+ /** Focus the input programmatically (e.g. from a global shortcut). */
4510
+ focus() {
4511
+ this.host.nativeElement.querySelector('.strct-sb__input')?.focus();
4512
+ }
4513
+ writeValue(value) {
4514
+ this.value.set(value ?? '');
4515
+ }
4516
+ registerOnChange(fn) {
4517
+ this.onChange = fn;
4518
+ }
4519
+ registerOnTouched(fn) {
4520
+ this.onTouched = fn;
4521
+ }
4522
+ setDisabledState(isDisabled) {
4523
+ this.isDisabled.set(isDisabled);
4524
+ }
4525
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctSearchbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
4526
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctSearchbox, isStandalone: true, selector: "strct-searchbox", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", search: "search", activated: "activated" }, host: { classAttribute: "strct-sb-host" }, providers: [
4527
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StrctSearchbox), multi: true },
4528
+ ], ngImport: i0, template: `
4529
+ @if (trigger()) {
4530
+ <button
4531
+ type="button"
4532
+ class="strct-sb strct-sb--trigger"
4533
+ [disabled]="isDisabled()"
4534
+ [attr.aria-label]="ariaLabel() || placeholder()"
4535
+ (click)="activated.emit()"
4536
+ >
4537
+ <strct-icon class="strct-sb__icon" name="search" [size]="14" [strokeWidth]="1.6" />
4538
+ <span class="strct-sb__label">{{ placeholder() }}</span>
4539
+ @if (hint()) {
4540
+ <kbd class="strct-sb__kbd">{{ hint() }}</kbd>
4541
+ }
4542
+ </button>
4543
+ } @else {
4544
+ <div class="strct-sb" [class.strct-sb--disabled]="isDisabled()">
4545
+ <strct-icon class="strct-sb__icon" name="search" [size]="14" [strokeWidth]="1.6" />
4546
+ <input
4547
+ #field
4548
+ class="strct-sb__input"
4549
+ type="text"
4550
+ role="searchbox"
4551
+ [attr.aria-label]="ariaLabel() || placeholder()"
4552
+ [placeholder]="placeholder()"
4553
+ [disabled]="isDisabled()"
4554
+ [value]="value()"
4555
+ (input)="onInput($event)"
4556
+ (keydown.enter)="search.emit(value())"
4557
+ (keydown.escape)="clear()"
4558
+ (focus)="focused.set(true)"
4559
+ (blur)="focused.set(false); onTouched()"
4560
+ />
4561
+ @if (clearable() && value()) {
4562
+ <button
4563
+ type="button"
4564
+ class="strct-sb__clear"
4565
+ [attr.aria-label]="clearLabel()"
4566
+ (click)="clear(); field.focus()"
4567
+ >
4568
+ <strct-icon name="close" [size]="11" [strokeWidth]="1.8" />
4569
+ </button>
4570
+ } @else if (hint() && !focused()) {
4571
+ <kbd class="strct-sb__kbd">{{ hint() }}</kbd>
4572
+ }
4573
+ </div>
4574
+ }
4575
+ `, isInline: true, styles: [".strct-sb-host{display:inline-flex;max-width:100%}.strct-sb{display:inline-flex;align-items:center;gap:8px;width:100%;min-width:0;padding:5px 8px 5px 10px;border:1px solid var(--strct-sb-border, var(--b2));border-radius:7px;background:var(--strct-sb-bg, var(--bg-2));color:var(--strct-sb-fg, var(--t2));font-family:var(--font);font-size:var(--strct-sb-font-size, 12.5px);transition:background .14s ease,border-color .14s ease,color .14s ease}.strct-sb--trigger{cursor:pointer;text-align:start}.strct-sb--trigger:hover:not(:disabled){color:var(--strct-sb-fg-hover, var(--t1));background:var(--strct-sb-bg-hover, var(--bg-3))}.strct-sb--trigger:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-sb:focus-within:not(.strct-sb--trigger){border-color:var(--acc50);color:var(--t1)}.strct-sb--disabled,.strct-sb--trigger:disabled{opacity:.55;cursor:not-allowed}.strct-sb__icon{flex-shrink:0;color:var(--strct-sb-muted, var(--t3))}.strct-sb__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.strct-sb__input{flex:1;min-width:0;border:0;padding:0;background:transparent;color:var(--t1);font-family:var(--font);font-size:12.5px;outline:none}.strct-sb__input::placeholder{color:var(--t3)}.strct-sb__kbd{flex-shrink:0;font-family:var(--mono);font-size:10px;line-height:1;padding:3px 5px;border:1px solid var(--strct-sb-kbd-border, var(--b2));border-radius:4px;background:var(--strct-sb-kbd-bg, var(--bg-2));color:var(--strct-sb-kbd-fg, var(--t3))}.strct-sb__clear{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin:-2px;padding:0;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer}.strct-sb__clear:hover{color:var(--t1);background:var(--bg-3)}.strct-sb__clear:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}@media(prefers-reduced-motion:reduce){.strct-sb{transition:none}}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4576
+ }
4577
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctSearchbox, decorators: [{
4578
+ type: Component,
4579
+ args: [{ selector: 'strct-searchbox', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon], providers: [
4580
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StrctSearchbox), multi: true },
4581
+ ], template: `
4582
+ @if (trigger()) {
4583
+ <button
4584
+ type="button"
4585
+ class="strct-sb strct-sb--trigger"
4586
+ [disabled]="isDisabled()"
4587
+ [attr.aria-label]="ariaLabel() || placeholder()"
4588
+ (click)="activated.emit()"
4589
+ >
4590
+ <strct-icon class="strct-sb__icon" name="search" [size]="14" [strokeWidth]="1.6" />
4591
+ <span class="strct-sb__label">{{ placeholder() }}</span>
4592
+ @if (hint()) {
4593
+ <kbd class="strct-sb__kbd">{{ hint() }}</kbd>
4594
+ }
4595
+ </button>
4596
+ } @else {
4597
+ <div class="strct-sb" [class.strct-sb--disabled]="isDisabled()">
4598
+ <strct-icon class="strct-sb__icon" name="search" [size]="14" [strokeWidth]="1.6" />
4599
+ <input
4600
+ #field
4601
+ class="strct-sb__input"
4602
+ type="text"
4603
+ role="searchbox"
4604
+ [attr.aria-label]="ariaLabel() || placeholder()"
4605
+ [placeholder]="placeholder()"
4606
+ [disabled]="isDisabled()"
4607
+ [value]="value()"
4608
+ (input)="onInput($event)"
4609
+ (keydown.enter)="search.emit(value())"
4610
+ (keydown.escape)="clear()"
4611
+ (focus)="focused.set(true)"
4612
+ (blur)="focused.set(false); onTouched()"
4613
+ />
4614
+ @if (clearable() && value()) {
4615
+ <button
4616
+ type="button"
4617
+ class="strct-sb__clear"
4618
+ [attr.aria-label]="clearLabel()"
4619
+ (click)="clear(); field.focus()"
4620
+ >
4621
+ <strct-icon name="close" [size]="11" [strokeWidth]="1.8" />
4622
+ </button>
4623
+ } @else if (hint() && !focused()) {
4624
+ <kbd class="strct-sb__kbd">{{ hint() }}</kbd>
4625
+ }
4626
+ </div>
4627
+ }
4628
+ `, host: { class: 'strct-sb-host' }, styles: [".strct-sb-host{display:inline-flex;max-width:100%}.strct-sb{display:inline-flex;align-items:center;gap:8px;width:100%;min-width:0;padding:5px 8px 5px 10px;border:1px solid var(--strct-sb-border, var(--b2));border-radius:7px;background:var(--strct-sb-bg, var(--bg-2));color:var(--strct-sb-fg, var(--t2));font-family:var(--font);font-size:var(--strct-sb-font-size, 12.5px);transition:background .14s ease,border-color .14s ease,color .14s ease}.strct-sb--trigger{cursor:pointer;text-align:start}.strct-sb--trigger:hover:not(:disabled){color:var(--strct-sb-fg-hover, var(--t1));background:var(--strct-sb-bg-hover, var(--bg-3))}.strct-sb--trigger:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-sb:focus-within:not(.strct-sb--trigger){border-color:var(--acc50);color:var(--t1)}.strct-sb--disabled,.strct-sb--trigger:disabled{opacity:.55;cursor:not-allowed}.strct-sb__icon{flex-shrink:0;color:var(--strct-sb-muted, var(--t3))}.strct-sb__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.strct-sb__input{flex:1;min-width:0;border:0;padding:0;background:transparent;color:var(--t1);font-family:var(--font);font-size:12.5px;outline:none}.strct-sb__input::placeholder{color:var(--t3)}.strct-sb__kbd{flex-shrink:0;font-family:var(--mono);font-size:10px;line-height:1;padding:3px 5px;border:1px solid var(--strct-sb-kbd-border, var(--b2));border-radius:4px;background:var(--strct-sb-kbd-bg, var(--bg-2));color:var(--strct-sb-kbd-fg, var(--t3))}.strct-sb__clear{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin:-2px;padding:0;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer}.strct-sb__clear:hover{color:var(--t1);background:var(--bg-3)}.strct-sb__clear:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}@media(prefers-reduced-motion:reduce){.strct-sb{transition:none}}\n"] }]
4629
+ }], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], search: [{ type: i0.Output, args: ["search"] }], activated: [{ type: i0.Output, args: ["activated"] }] } });
4630
+
4631
+ /**
4632
+ * Click-to-copy chip with built-in feedback: an icon (or icon + label) button
4633
+ * that writes `text` to the clipboard and flips to a ✓ "Copied" state for a
4634
+ * moment. The console workhorse for UUIDs, IPs, serials and snippets:
4635
+ *
4636
+ * <strct-copy text="172.16.75.100" />
4637
+ * <strct-copy [text]="host.id" label="Copy ID" />
4638
+ */
4639
+ class StrctCopy {
4640
+ destroyRef = inject(DestroyRef);
4641
+ /** The text written to the clipboard. */
4642
+ text = input.required(...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
4643
+ /** Optional visible label next to the icon (icon-only by default). */
4644
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
4645
+ /** Accessible label; falls back to `copyLabel`. */
4646
+ ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
4647
+ /** Localizable strings. */
4648
+ copyLabel = input('Copy', ...(ngDevMode ? [{ debugName: "copyLabel" }] : /* istanbul ignore next */ []));
4649
+ copiedLabel = input('Copied', ...(ngDevMode ? [{ debugName: "copiedLabel" }] : /* istanbul ignore next */ []));
4650
+ /** Emitted after a successful copy, with the copied text. */
4651
+ copied = output();
4652
+ done = signal(false, ...(ngDevMode ? [{ debugName: "done" }] : /* istanbul ignore next */ []));
4653
+ timer = null;
4654
+ constructor() {
4655
+ this.destroyRef.onDestroy(() => {
4656
+ if (this.timer)
4657
+ clearTimeout(this.timer);
4658
+ });
4659
+ }
4660
+ /** Write `text` to the clipboard and show the ✓ feedback. */
4661
+ copy() {
4662
+ const value = this.text();
4663
+ void navigator.clipboard?.writeText(value).then(() => {
4664
+ this.copied.emit(value);
4665
+ this.done.set(true);
4666
+ if (this.timer)
4667
+ clearTimeout(this.timer);
4668
+ this.timer = setTimeout(() => this.done.set(false), 1600);
4669
+ });
4670
+ }
4671
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctCopy, deps: [], target: i0.ɵɵFactoryTarget.Component });
4672
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctCopy, isStandalone: true, selector: "strct-copy", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, copyLabel: { classPropertyName: "copyLabel", publicName: "copyLabel", isSignal: true, isRequired: false, transformFunction: null }, copiedLabel: { classPropertyName: "copiedLabel", publicName: "copiedLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { copied: "copied" }, host: { classAttribute: "strct-copy-host" }, ngImport: i0, template: `
4673
+ <button
4674
+ type="button"
4675
+ class="strct-copy"
4676
+ [class.strct-copy--done]="done()"
4677
+ [attr.aria-label]="done() ? copiedLabel() : ariaLabel() || copyLabel()"
4678
+ (click)="copy()"
4679
+ >
4680
+ <strct-icon [name]="done() ? 'check' : 'copy'" [size]="13" [strokeWidth]="1.6" />
4681
+ @if (label()) {
4682
+ <span class="strct-copy__label">{{ done() ? copiedLabel() : label() }}</span>
4683
+ }
4684
+ <span class="strct-copy__sr" aria-live="polite">{{ done() ? copiedLabel() : '' }}</span>
4685
+ </button>
4686
+ `, isInline: true, styles: [".strct-copy-host{display:inline-flex}.strct-copy{display:inline-flex;align-items:center;gap:5px;padding:3px 6px;border:0;border-radius:5px;background:transparent;color:var(--t3);font-family:var(--font);font-size:12px;cursor:pointer;transition:color .13s ease,background .13s ease}.strct-copy:hover{color:var(--t1);background:var(--bg-3)}.strct-copy:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-copy--done,.strct-copy--done:hover{color:var(--success)}.strct-copy__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}@media(prefers-reduced-motion:reduce){.strct-copy{transition:none}}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4687
+ }
4688
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctCopy, decorators: [{
4689
+ type: Component,
4690
+ args: [{ selector: 'strct-copy', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon], template: `
4691
+ <button
4692
+ type="button"
4693
+ class="strct-copy"
4694
+ [class.strct-copy--done]="done()"
4695
+ [attr.aria-label]="done() ? copiedLabel() : ariaLabel() || copyLabel()"
4696
+ (click)="copy()"
4697
+ >
4698
+ <strct-icon [name]="done() ? 'check' : 'copy'" [size]="13" [strokeWidth]="1.6" />
4699
+ @if (label()) {
4700
+ <span class="strct-copy__label">{{ done() ? copiedLabel() : label() }}</span>
4701
+ }
4702
+ <span class="strct-copy__sr" aria-live="polite">{{ done() ? copiedLabel() : '' }}</span>
4703
+ </button>
4704
+ `, host: { class: 'strct-copy-host' }, styles: [".strct-copy-host{display:inline-flex}.strct-copy{display:inline-flex;align-items:center;gap:5px;padding:3px 6px;border:0;border-radius:5px;background:transparent;color:var(--t3);font-family:var(--font);font-size:12px;cursor:pointer;transition:color .13s ease,background .13s ease}.strct-copy:hover{color:var(--t1);background:var(--bg-3)}.strct-copy:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-copy--done,.strct-copy--done:hover{color:var(--success)}.strct-copy__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}@media(prefers-reduced-motion:reduce){.strct-copy{transition:none}}\n"] }]
4705
+ }], ctorParameters: () => [], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], copyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyLabel", required: false }] }], copiedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "copiedLabel", required: false }] }], copied: [{ type: i0.Output, args: ["copied"] }] } });
4706
+
4707
+ /**
4708
+ * Copyable mono code / rendered-config block — the component form of the
4709
+ * `<details><pre>` pattern consoles keep hand-rolling. A header row carries an
4710
+ * optional title, a language tag, a copy button and (when `collapsible`) a
4711
+ * chevron; the body is a scrollable, keyboard-focusable `<pre>`.
4712
+ *
4713
+ * <strct-code [code]="yaml" language="yaml" title="cloud-init" collapsible />
4714
+ */
4715
+ class StrctCode {
4716
+ /** The code / rendered config text (copied verbatim). */
4717
+ code = input.required(...(ngDevMode ? [{ debugName: "code" }] : /* istanbul ignore next */ []));
4718
+ /** Header title (e.g. a filename). */
4719
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
4720
+ /** Small uppercase language tag (yaml, json, bash …). */
4721
+ language = input('', ...(ngDevMode ? [{ debugName: "language" }] : /* istanbul ignore next */ []));
4722
+ /** Show the copy button. */
4723
+ copyable = input(true, { ...(ngDevMode ? { debugName: "copyable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4724
+ /** Collapse to just the header (the `<details><pre>` pattern, done right). */
4725
+ collapsible = input(false, { ...(ngDevMode ? { debugName: "collapsible" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4726
+ /** Collapsed state (two-way; only meaningful with `collapsible`). */
4727
+ collapsed = model(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
4728
+ /** Show a line-number gutter (numbers are never copied — `code` is). */
4729
+ lineNumbers = input(false, { ...(ngDevMode ? { debugName: "lineNumbers" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
4730
+ /** Scroll the body past this height (px); null grows freely. */
4731
+ maxHeight = input(null, ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
4732
+ /** Localizable labels for the collapse toggle. */
4733
+ collapseLabel = input('Collapse', ...(ngDevMode ? [{ debugName: "collapseLabel" }] : /* istanbul ignore next */ []));
4734
+ expandLabel = input('Expand', ...(ngDevMode ? [{ debugName: "expandLabel" }] : /* istanbul ignore next */ []));
4735
+ lineNos = computed(() => {
4736
+ const n = this.code().split('\n').length;
4737
+ return Array.from({ length: n }, (_, i) => i + 1);
4738
+ }, ...(ngDevMode ? [{ debugName: "lineNos" }] : /* istanbul ignore next */ []));
4739
+ 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: `
4741
+ @if (title() || language() || copyable() || collapsible()) {
4742
+ <div class="strct-code__head">
4743
+ @if (collapsible()) {
4744
+ <button
4745
+ type="button"
4746
+ class="strct-code__toggle"
4747
+ [attr.aria-expanded]="!collapsed()"
4748
+ [attr.aria-label]="
4749
+ (collapsed() ? expandLabel() : collapseLabel()) +
4750
+ ' ' +
4751
+ (title() || language() || 'code')
4752
+ "
4753
+ (click)="collapsed.set(!collapsed())"
4754
+ >
4755
+ <strct-icon
4756
+ name="chevronRight"
4757
+ [size]="12"
4758
+ [strokeWidth]="1.7"
4759
+ [class.strct-code__chev--open]="!collapsed()"
4760
+ />
4761
+ </button>
4762
+ }
4763
+ @if (title()) {
4764
+ <span class="strct-code__title">{{ title() }}</span>
4765
+ }
4766
+ @if (language()) {
4767
+ <span class="strct-code__lang">{{ language() }}</span>
4768
+ }
4769
+ <span class="strct-code__grow"></span>
4770
+ @if (copyable()) {
4771
+ <strct-copy [text]="code()" />
4772
+ }
4773
+ </div>
4774
+ }
4775
+ @if (!collapsible() || !collapsed()) {
4776
+ <div
4777
+ class="strct-code__scroll"
4778
+ tabindex="0"
4779
+ role="region"
4780
+ [attr.aria-label]="title() || language() || 'code'"
4781
+ [style.max-height.px]="maxHeight()"
4782
+ >
4783
+ <pre class="strct-code__pre"><!--
4784
+ -->@if (lineNumbers()) {<!--
4785
+ --><span class="strct-code__gutter" aria-hidden="true">@for (n of lineNos(); track n) {<span class="strct-code__ln">{{ n }}</span>}</span><!--
4786
+ -->}<!--
4787
+ --><code class="strct-code__code">{{ code() }}</code></pre>
4788
+ </div>
4789
+ }
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 });
4791
+ }
4792
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctCode, decorators: [{
4793
+ type: Component,
4794
+ args: [{ selector: 'strct-code', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctCopy, StrctIcon], template: `
4795
+ @if (title() || language() || copyable() || collapsible()) {
4796
+ <div class="strct-code__head">
4797
+ @if (collapsible()) {
4798
+ <button
4799
+ type="button"
4800
+ class="strct-code__toggle"
4801
+ [attr.aria-expanded]="!collapsed()"
4802
+ [attr.aria-label]="
4803
+ (collapsed() ? expandLabel() : collapseLabel()) +
4804
+ ' ' +
4805
+ (title() || language() || 'code')
4806
+ "
4807
+ (click)="collapsed.set(!collapsed())"
4808
+ >
4809
+ <strct-icon
4810
+ name="chevronRight"
4811
+ [size]="12"
4812
+ [strokeWidth]="1.7"
4813
+ [class.strct-code__chev--open]="!collapsed()"
4814
+ />
4815
+ </button>
4816
+ }
4817
+ @if (title()) {
4818
+ <span class="strct-code__title">{{ title() }}</span>
4819
+ }
4820
+ @if (language()) {
4821
+ <span class="strct-code__lang">{{ language() }}</span>
4822
+ }
4823
+ <span class="strct-code__grow"></span>
4824
+ @if (copyable()) {
4825
+ <strct-copy [text]="code()" />
4826
+ }
4827
+ </div>
4828
+ }
4829
+ @if (!collapsible() || !collapsed()) {
4830
+ <div
4831
+ class="strct-code__scroll"
4832
+ tabindex="0"
4833
+ role="region"
4834
+ [attr.aria-label]="title() || language() || 'code'"
4835
+ [style.max-height.px]="maxHeight()"
4836
+ >
4837
+ <pre class="strct-code__pre"><!--
4838
+ -->@if (lineNumbers()) {<!--
4839
+ --><span class="strct-code__gutter" aria-hidden="true">@for (n of lineNos(); track n) {<span class="strct-code__ln">{{ n }}</span>}</span><!--
4840
+ -->}<!--
4841
+ --><code class="strct-code__code">{{ code() }}</code></pre>
4842
+ </div>
4843
+ }
4844
+ `, host: {
4845
+ class: 'strct-code',
4846
+ '[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 }] }] } });
4849
+
4850
+ /**
4851
+ * The standard strip above a data grid: a search field, the active filter
4852
+ * chips (each removable), a result count and a clear-all action. The bar owns
4853
+ * no filtering logic — it renders state and announces intent:
4854
+ *
4855
+ * <strct-filter-bar [(query)]="q" [filters]="chips" [count]="rows.length"
4856
+ * (removed)="drop($event)" (cleared)="reset()" />
4857
+ */
4858
+ class StrctFilterBar {
4859
+ /** Search text (two-way; forwards to the embedded searchbox). */
4860
+ query = model('', ...(ngDevMode ? [{ debugName: "query" }] : /* istanbul ignore next */ []));
4861
+ /** Active filter chips. */
4862
+ filters = input([], ...(ngDevMode ? [{ debugName: "filters" }] : /* istanbul ignore next */ []));
4863
+ /** Result count shown at the end; null hides it. */
4864
+ count = input(null, ...(ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []));
4865
+ /** Localizable strings. */
4866
+ placeholder = input('Search', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
4867
+ countLabel = input('results', ...(ngDevMode ? [{ debugName: "countLabel" }] : /* istanbul ignore next */ []));
4868
+ clearLabel = input('Clear filters', ...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
4869
+ removeLabel = input('Remove filter', ...(ngDevMode ? [{ debugName: "removeLabel" }] : /* istanbul ignore next */ []));
4870
+ /** Enter pressed in the search field. */
4871
+ search = output();
4872
+ /** A chip's × was clicked. */
4873
+ removed = output();
4874
+ /** "Clear filters" was clicked. */
4875
+ cleared = output();
4876
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctFilterBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
4877
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctFilterBar, isStandalone: true, selector: "strct-filter-bar", inputs: { query: { classPropertyName: "query", publicName: "query", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, count: { classPropertyName: "count", publicName: "count", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, countLabel: { classPropertyName: "countLabel", publicName: "countLabel", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { query: "queryChange", search: "search", removed: "removed", cleared: "cleared" }, host: { classAttribute: "strct-fb" }, ngImport: i0, template: `
4878
+ <strct-searchbox
4879
+ class="strct-fb__search"
4880
+ [placeholder]="placeholder()"
4881
+ [(value)]="query"
4882
+ (search)="search.emit($event)"
4883
+ />
4884
+ @for (chip of filters(); track chip.id) {
4885
+ <span class="strct-fb__chip">
4886
+ <span class="strct-fb__chip-label">{{ chip.label }}</span>
4887
+ <button
4888
+ type="button"
4889
+ class="strct-fb__chip-x"
4890
+ [attr.aria-label]="removeLabel() + ' ' + chip.label"
4891
+ (click)="removed.emit(chip)"
4892
+ >
4893
+ <strct-icon name="close" [size]="10" [strokeWidth]="1.9" />
4894
+ </button>
4895
+ </span>
4896
+ }
4897
+ @if (filters().length > 1) {
4898
+ <button type="button" class="strct-fb__clear" (click)="cleared.emit()">
4899
+ {{ clearLabel() }}
4900
+ </button>
4901
+ }
4902
+ <ng-content />
4903
+ <span class="strct-fb__grow"></span>
4904
+ @if (count() !== null) {
4905
+ <span class="strct-fb__count" aria-live="polite">{{ count() }} {{ countLabel() }}</span>
4906
+ }
4907
+ `, isInline: true, styles: [".strct-fb{display:flex;align-items:center;gap:8px;flex-wrap:wrap;width:100%}.strct-fb__search{width:240px;max-width:100%}.strct-fb__chip{display:inline-flex;align-items:center;gap:5px;padding:3px 4px 3px 9px;border:1px solid var(--b2);border-radius:99px;background:var(--acc-m);color:var(--acc);font-size:12px;font-weight:500}.strct-fb__chip-x{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:0;border-radius:50%;background:transparent;color:inherit;cursor:pointer}.strct-fb__chip-x:hover{background:var(--acc30)}.strct-fb__chip-x:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-fb__clear{border:0;padding:3px 6px;border-radius:5px;background:transparent;color:var(--t3);font-family:var(--font);font-size:12px;cursor:pointer}.strct-fb__clear:hover{color:var(--t1);background:var(--bg-3)}.strct-fb__clear:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-fb__grow{flex:1}.strct-fb__count{font-size:12px;color:var(--t3);font-variant-numeric:tabular-nums;white-space:nowrap}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctSearchbox, selector: "strct-searchbox", inputs: ["placeholder", "hint", "trigger", "clearable", "ariaLabel", "clearLabel", "value"], outputs: ["valueChange", "search", "activated"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4908
+ }
4909
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctFilterBar, decorators: [{
4910
+ type: Component,
4911
+ args: [{ selector: 'strct-filter-bar', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon, StrctSearchbox], template: `
4912
+ <strct-searchbox
4913
+ class="strct-fb__search"
4914
+ [placeholder]="placeholder()"
4915
+ [(value)]="query"
4916
+ (search)="search.emit($event)"
4917
+ />
4918
+ @for (chip of filters(); track chip.id) {
4919
+ <span class="strct-fb__chip">
4920
+ <span class="strct-fb__chip-label">{{ chip.label }}</span>
4921
+ <button
4922
+ type="button"
4923
+ class="strct-fb__chip-x"
4924
+ [attr.aria-label]="removeLabel() + ' ' + chip.label"
4925
+ (click)="removed.emit(chip)"
4926
+ >
4927
+ <strct-icon name="close" [size]="10" [strokeWidth]="1.9" />
4928
+ </button>
4929
+ </span>
4930
+ }
4931
+ @if (filters().length > 1) {
4932
+ <button type="button" class="strct-fb__clear" (click)="cleared.emit()">
4933
+ {{ clearLabel() }}
4934
+ </button>
4935
+ }
4936
+ <ng-content />
4937
+ <span class="strct-fb__grow"></span>
4938
+ @if (count() !== null) {
4939
+ <span class="strct-fb__count" aria-live="polite">{{ count() }} {{ countLabel() }}</span>
4940
+ }
4941
+ `, host: { class: 'strct-fb' }, styles: [".strct-fb{display:flex;align-items:center;gap:8px;flex-wrap:wrap;width:100%}.strct-fb__search{width:240px;max-width:100%}.strct-fb__chip{display:inline-flex;align-items:center;gap:5px;padding:3px 4px 3px 9px;border:1px solid var(--b2);border-radius:99px;background:var(--acc-m);color:var(--acc);font-size:12px;font-weight:500}.strct-fb__chip-x{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:0;border-radius:50%;background:transparent;color:inherit;cursor:pointer}.strct-fb__chip-x:hover{background:var(--acc30)}.strct-fb__chip-x:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-fb__clear{border:0;padding:3px 6px;border-radius:5px;background:transparent;color:var(--t3);font-family:var(--font);font-size:12px;cursor:pointer}.strct-fb__clear:hover{color:var(--t1);background:var(--bg-3)}.strct-fb__clear:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-fb__grow{flex:1}.strct-fb__count{font-size:12px;color:var(--t3);font-variant-numeric:tabular-nums;white-space:nowrap}\n"] }]
4942
+ }], propDecorators: { query: [{ type: i0.Input, args: [{ isSignal: true, alias: "query", required: false }] }, { type: i0.Output, args: ["queryChange"] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], count: [{ type: i0.Input, args: [{ isSignal: true, alias: "count", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], countLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "countLabel", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], removeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeLabel", required: false }] }], search: [{ type: i0.Output, args: ["search"] }], removed: [{ type: i0.Output, args: ["removed"] }], cleared: [{ type: i0.Output, args: ["cleared"] }] } });
4943
+
4389
4944
  /** Tone class suffix per validation status (used by field + cell helper styles). */
4390
4945
  function strctValidationTone(status) {
4391
4946
  return status;
@@ -12097,5 +12652,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
12097
12652
  * Generated bundle index. Do not edit.
12098
12653
  */
12099
12654
 
12100
- 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, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctContextMenu, StrctContextMenuTrigger, StrctDatagrid, StrctDatagridActionBar, StrctDatepicker, StrctDesc, StrctDescriptionList, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownItem, StrctEmptyState, StrctField, StrctFile, StrctFlow, StrctFooter, StrctGauge, StrctHeader, StrctHero, StrctIcon, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctLogin, StrctMenuPanel, StrctMenuService, StrctMetricTile, StrctModal, StrctNav, StrctNavItem, StrctOverlay, StrctPagination, StrctPassword, StrctProgress, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRating, StrctRowDetailDef, 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 };
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 };
12101
12656
  //# sourceMappingURL=akcelik-strct.mjs.map