@akcelik/strct 4.8.0 → 4.10.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.
- package/fesm2022/akcelik-strct.mjs +1795 -1545
- package/fesm2022/akcelik-strct.mjs.map +1 -1
- package/package.json +1 -1
- package/types/akcelik-strct.d.ts +90 -4
|
@@ -7438,6 +7438,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
7438
7438
|
}], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: true }] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }] } });
|
|
7439
7439
|
|
|
7440
7440
|
let fieldCounter = 0;
|
|
7441
|
+
/** Text or a control rendered inside the field's box, before the input. */
|
|
7442
|
+
class StrctFieldPrefix {
|
|
7443
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctFieldPrefix, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
7444
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctFieldPrefix, isStandalone: true, selector: "[strctFieldPrefix]", ngImport: i0 });
|
|
7445
|
+
}
|
|
7446
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctFieldPrefix, decorators: [{
|
|
7447
|
+
type: Directive,
|
|
7448
|
+
args: [{ selector: '[strctFieldPrefix]' }]
|
|
7449
|
+
}] });
|
|
7450
|
+
/** Text or a control rendered inside the field's box, after the input. */
|
|
7451
|
+
class StrctFieldSuffix {
|
|
7452
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctFieldSuffix, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
7453
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctFieldSuffix, isStandalone: true, selector: "[strctFieldSuffix]", ngImport: i0 });
|
|
7454
|
+
}
|
|
7455
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctFieldSuffix, decorators: [{
|
|
7456
|
+
type: Directive,
|
|
7457
|
+
args: [{ selector: '[strctFieldSuffix]' }]
|
|
7458
|
+
}] });
|
|
7459
|
+
/**
|
|
7460
|
+
* A hint with markup in it, rendered where the string `hint` renders and
|
|
7461
|
+
* carrying the same id, so it is still the control's description.
|
|
7462
|
+
*
|
|
7463
|
+
* <ng-template strctFieldHint>Hosts with a switch named <strong>{{ n }}</strong> join it.</ng-template>
|
|
7464
|
+
*/
|
|
7465
|
+
class StrctFieldHint {
|
|
7466
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctFieldHint, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
7467
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctFieldHint, isStandalone: true, selector: "ng-template[strctFieldHint]", ngImport: i0 });
|
|
7468
|
+
}
|
|
7469
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctFieldHint, decorators: [{
|
|
7470
|
+
type: Directive,
|
|
7471
|
+
args: [{ selector: 'ng-template[strctFieldHint]' }]
|
|
7472
|
+
}] });
|
|
7473
|
+
/**
|
|
7474
|
+
* Wrapper that opts a run of `layout="inline"` fields out of the hairlines
|
|
7475
|
+
* between them — for settings that belong together and should read as one
|
|
7476
|
+
* block.
|
|
7477
|
+
*/
|
|
7478
|
+
class StrctFieldGroup {
|
|
7479
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctFieldGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
7480
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctFieldGroup, isStandalone: true, selector: "[strctFieldGroup]", host: { classAttribute: "strct-field-group" }, ngImport: i0 });
|
|
7481
|
+
}
|
|
7482
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctFieldGroup, decorators: [{
|
|
7483
|
+
type: Directive,
|
|
7484
|
+
args: [{ selector: '[strctFieldGroup]', host: { class: 'strct-field-group' } }]
|
|
7485
|
+
}] });
|
|
7441
7486
|
/**
|
|
7442
7487
|
* Form-field wrapper: a label (with optional required marker), the projected
|
|
7443
7488
|
* control, and a hint or error message. It auto-links the control via
|
|
@@ -7459,6 +7504,13 @@ class StrctField {
|
|
|
7459
7504
|
/** Error message (string or first-of array); falsy clears the error state. */
|
|
7460
7505
|
error = input(null, /* @ts-ignore */
|
|
7461
7506
|
...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
7507
|
+
/**
|
|
7508
|
+
* `'inline'` puts the label and its hint in a fixed-width column
|
|
7509
|
+
* (`--strct-field-label-w`, 220px) and the control beside them — how a long
|
|
7510
|
+
* settings form reads. Below 480px of field width it falls back to stacked.
|
|
7511
|
+
*/
|
|
7512
|
+
layout = input('stacked', /* @ts-ignore */
|
|
7513
|
+
...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
|
|
7462
7514
|
/**
|
|
7463
7515
|
* Async-validation state rendered as a trailing adornment (spinner / check /
|
|
7464
7516
|
* warning) plus its message in the hint/error slot — so apps stop composing a
|
|
@@ -7470,8 +7522,15 @@ class StrctField {
|
|
|
7470
7522
|
n = ++fieldCounter;
|
|
7471
7523
|
hintId = `strct-field-hint-${this.n}`;
|
|
7472
7524
|
errorId = `strct-field-err-${this.n}`;
|
|
7525
|
+
prefixId = `strct-field-pre-${this.n}`;
|
|
7526
|
+
suffixId = `strct-field-suf-${this.n}`;
|
|
7473
7527
|
controlId = signal('', /* @ts-ignore */
|
|
7474
7528
|
...(ngDevMode ? [{ debugName: "controlId" }] : /* istanbul ignore next */ []));
|
|
7529
|
+
hintTpl = contentChild(StrctFieldHint, { ...(ngDevMode ? { debugName: "hintTpl" } : /* istanbul ignore next */ {}), read: TemplateRef });
|
|
7530
|
+
hasPrefix = contentChild(StrctFieldPrefix, /* @ts-ignore */
|
|
7531
|
+
...(ngDevMode ? [{ debugName: "hasPrefix" }] : /* istanbul ignore next */ []));
|
|
7532
|
+
hasSuffix = contentChild(StrctFieldSuffix, /* @ts-ignore */
|
|
7533
|
+
...(ngDevMode ? [{ debugName: "hasSuffix" }] : /* istanbul ignore next */ []));
|
|
7475
7534
|
errorText = computed(() => {
|
|
7476
7535
|
const e = this.error();
|
|
7477
7536
|
return (Array.isArray(e) ? e[0] : e) ?? '';
|
|
@@ -7497,6 +7556,9 @@ class StrctField {
|
|
|
7497
7556
|
effect(() => {
|
|
7498
7557
|
this.errorText();
|
|
7499
7558
|
this.hint();
|
|
7559
|
+
this.hintTpl();
|
|
7560
|
+
this.hasPrefix();
|
|
7561
|
+
this.hasSuffix();
|
|
7500
7562
|
this.stateStatus();
|
|
7501
7563
|
this.stateMessage();
|
|
7502
7564
|
this.applyAria();
|
|
@@ -7514,15 +7576,37 @@ class StrctField {
|
|
|
7514
7576
|
this.controlId.set(el.id);
|
|
7515
7577
|
this.applyAria();
|
|
7516
7578
|
}
|
|
7579
|
+
/**
|
|
7580
|
+
* A text addon belongs to the control's description — "Minimum memory, MB" —
|
|
7581
|
+
* while an addon holding its own control (a send button) is a tab stop of its
|
|
7582
|
+
* own and says nothing about the value.
|
|
7583
|
+
*/
|
|
7584
|
+
addonDescription(sel, id) {
|
|
7585
|
+
const el = this.host.nativeElement.querySelector(sel);
|
|
7586
|
+
if (!el || !el.textContent?.trim())
|
|
7587
|
+
return '';
|
|
7588
|
+
if (el.matches('button, a, input, select, textarea'))
|
|
7589
|
+
return '';
|
|
7590
|
+
if (el.querySelector('button, a, input, select, textarea'))
|
|
7591
|
+
return '';
|
|
7592
|
+
return id;
|
|
7593
|
+
}
|
|
7517
7594
|
applyAria() {
|
|
7518
7595
|
const el = this.control();
|
|
7519
7596
|
if (!el)
|
|
7520
7597
|
return;
|
|
7521
|
-
const
|
|
7598
|
+
const message = this.errorText()
|
|
7522
7599
|
? this.errorId
|
|
7523
|
-
: this.stateMessage() || this.hint()
|
|
7600
|
+
: this.stateMessage() || this.hintTpl() || this.hint()
|
|
7524
7601
|
? this.hintId
|
|
7525
7602
|
: '';
|
|
7603
|
+
const describedBy = [
|
|
7604
|
+
this.addonDescription('[strctFieldPrefix]', this.prefixId),
|
|
7605
|
+
this.addonDescription('[strctFieldSuffix]', this.suffixId),
|
|
7606
|
+
message,
|
|
7607
|
+
]
|
|
7608
|
+
.filter(Boolean)
|
|
7609
|
+
.join(' ');
|
|
7526
7610
|
if (describedBy)
|
|
7527
7611
|
el.setAttribute('aria-describedby', describedBy);
|
|
7528
7612
|
else
|
|
@@ -7533,7 +7617,7 @@ class StrctField {
|
|
|
7533
7617
|
el.removeAttribute('aria-invalid');
|
|
7534
7618
|
}
|
|
7535
7619
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctField, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7536
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctField, isStandalone: true, selector: "strct-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, validationState: { classPropertyName: "validationState", publicName: "validationState", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.strct-field--invalid": "isInvalid()", "class.strct-field--validating": "stateActive()" }, classAttribute: "strct-field" }, ngImport: i0, template: `
|
|
7620
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctField, isStandalone: true, selector: "strct-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, validationState: { classPropertyName: "validationState", publicName: "validationState", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.strct-field--invalid": "isInvalid()", "class.strct-field--validating": "stateActive()", "class.strct-field--inline": "layout() === 'inline'", "class.strct-field--prefix": "hasPrefix()", "class.strct-field--suffix": "hasSuffix()" }, classAttribute: "strct-field" }, queries: [{ propertyName: "hintTpl", first: true, predicate: StrctFieldHint, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "hasPrefix", first: true, predicate: StrctFieldPrefix, descendants: true, isSignal: true }, { propertyName: "hasSuffix", first: true, predicate: StrctFieldSuffix, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
7537
7621
|
@if (label()) {
|
|
7538
7622
|
<label class="strct-field__label" [attr.for]="controlId() || null">
|
|
7539
7623
|
{{ label() }}
|
|
@@ -7543,6 +7627,15 @@ class StrctField {
|
|
|
7543
7627
|
</label>
|
|
7544
7628
|
}
|
|
7545
7629
|
<div class="strct-field__control">
|
|
7630
|
+
<!-- The addon slots come first so their selectors win over the catch-all
|
|
7631
|
+
below (Angular matches in template order); CSS order puts them
|
|
7632
|
+
either side of the control. -->
|
|
7633
|
+
<span class="strct-field__addon strct-field__addon--prefix" [id]="prefixId">
|
|
7634
|
+
<ng-content select="[strctFieldPrefix]" />
|
|
7635
|
+
</span>
|
|
7636
|
+
<span class="strct-field__addon strct-field__addon--suffix" [id]="suffixId">
|
|
7637
|
+
<ng-content select="[strctFieldSuffix]" />
|
|
7638
|
+
</span>
|
|
7546
7639
|
<ng-content />
|
|
7547
7640
|
@if (stateActive()) {
|
|
7548
7641
|
<span class="strct-field__adorn strct-field__adorn--{{ stateStatus() }}" aria-hidden="true">
|
|
@@ -7567,14 +7660,18 @@ class StrctField {
|
|
|
7567
7660
|
>
|
|
7568
7661
|
{{ stateMessage() }}
|
|
7569
7662
|
</div>
|
|
7663
|
+
} @else if (hintTpl()) {
|
|
7664
|
+
<div class="strct-field__msg strct-field__msg--hint" [id]="hintId">
|
|
7665
|
+
<ng-container [ngTemplateOutlet]="hintTpl()!" />
|
|
7666
|
+
</div>
|
|
7570
7667
|
} @else if (hint()) {
|
|
7571
7668
|
<div class="strct-field__msg strct-field__msg--hint" [id]="hintId">{{ hint() }}</div>
|
|
7572
7669
|
}
|
|
7573
|
-
`, isInline: true, styles: [".strct-field{display:flex;flex-direction:column;gap:6px}.strct-field__label{font-size:12px;font-weight:600;color:var(--t2)}.strct-field__req{color:var(--critical);margin-inline-start:2px}.strct-field__control{position:relative;display:flex;flex-direction:column}.strct-field__adorn{position:absolute;top:50%;inset-inline-end:10px;transform:translateY(-50%);display:inline-flex;align-items:center;pointer-events:none}.strct-field__adorn--ok{color:var(--success)}.strct-field__adorn--warning{color:var(--warning)}.strct-field__adorn--error{color:var(--critical)}.strct-field--validating .strct-control{padding-inline-end:32px}.strct-field__msg{font-size:12px;line-height:1.4}.strct-field__msg--hint,.strct-field__msg--checking{color:var(--t3)}.strct-field__msg--ok{color:var(--success)}.strct-field__msg--warning{color:var(--warning)}.strct-field__msg--error{color:var(--critical)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctSpinner, selector: "strct-spinner", inputs: ["size", "label", "caption"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
7670
|
+
`, isInline: true, styles: [".strct-field{display:flex;flex-direction:column;gap:6px}.strct-field__label{font-size:12px;font-weight:600;color:var(--t2)}.strct-field__req{color:var(--critical);margin-inline-start:2px}.strct-field__control{position:relative;display:flex;flex-direction:column}.strct-field__adorn{position:absolute;top:50%;inset-inline-end:10px;transform:translateY(-50%);display:inline-flex;align-items:center;pointer-events:none}.strct-field__adorn--ok{color:var(--success)}.strct-field__adorn--warning{color:var(--warning)}.strct-field__adorn--error{color:var(--critical)}.strct-field--validating .strct-control{padding-inline-end:32px}.strct-field__msg{font-size:12px;line-height:1.4}.strct-field__msg--hint,.strct-field__msg--checking{color:var(--t3)}.strct-field__msg--ok{color:var(--success)}.strct-field__msg--warning{color:var(--warning)}.strct-field__msg--error{color:var(--critical)}.strct-field__addon{display:none;align-items:center;flex:none;font-size:13px;color:var(--t3)}.strct-field__addon--prefix{order:-1;padding-inline-start:var(--space-3)}.strct-field__addon--suffix{order:1;padding-inline-end:var(--space-3)}.strct-field--prefix .strct-field__addon--prefix,.strct-field--suffix .strct-field__addon--suffix{display:inline-flex}.strct-field__addon:has(.strct-btn){padding:3px}.strct-field--prefix .strct-field__control,.strct-field--suffix .strct-field__control{flex-direction:row;align-items:center;background:var(--bg-2);border:1px solid var(--b2);border-radius:var(--radius-md);transition:border-color .14s ease,box-shadow .14s ease,background .14s ease}.strct-field--prefix .strct-field__control:hover,.strct-field--suffix .strct-field__control:hover{border-color:var(--b3)}.strct-field--prefix .strct-field__control:focus-within,.strct-field--suffix .strct-field__control:focus-within{border-color:var(--acc50);box-shadow:0 0 0 3px var(--acc18);background:var(--bg-1)}.strct-field--invalid.strct-field--prefix .strct-field__control,.strct-field--invalid.strct-field--suffix .strct-field__control{border-color:var(--critical)}.strct-field--prefix .strct-control,.strct-field--suffix .strct-control{flex:1;min-width:0;border:0;background:transparent}.strct-field--prefix .strct-control:focus,.strct-field--prefix .strct-control:focus-visible,.strct-field--suffix .strct-control:focus,.strct-field--suffix .strct-control:focus-visible{box-shadow:none;background:transparent}.strct-field--prefix textarea.strct-control,.strct-field--suffix textarea.strct-control{min-height:0}.strct-field--inline{container-type:inline-size;display:grid;grid-template-columns:var(--strct-field-label-w, 220px) minmax(0,1fr);column-gap:var(--space-3);row-gap:4px;align-items:start}.strct-field--inline>.strct-field__label{grid-column:1;grid-row:1;padding-block-start:9px}.strct-field--inline>.strct-field__control{grid-column:2;grid-row:1}.strct-field--inline>.strct-field__msg{grid-column:2;grid-row:2}.strct-field--inline>.strct-field__msg--hint{grid-column:1;padding-block-end:var(--space-2)}.strct-field--inline+.strct-field--inline{border-block-start:1px solid var(--b1);margin-block-start:var(--space-3);padding-block-start:var(--space-3)}.strct-field-group .strct-field--inline+.strct-field--inline{border-block-start:0;padding-block-start:0}@container (max-width: 480px){.strct-field--inline>.strct-field__label,.strct-field--inline>.strct-field__control,.strct-field--inline>.strct-field__msg{grid-column:1 / -1;grid-row:auto}.strct-field--inline>.strct-field__label{padding-block-start:0}.strct-field--inline>.strct-field__msg--hint{padding-block-end:0}}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctSpinner, selector: "strct-spinner", inputs: ["size", "label", "caption"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
7574
7671
|
}
|
|
7575
7672
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctField, decorators: [{
|
|
7576
7673
|
type: Component,
|
|
7577
|
-
args: [{ selector: 'strct-field', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon, StrctSpinner], template: `
|
|
7674
|
+
args: [{ selector: 'strct-field', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon, StrctSpinner, NgTemplateOutlet], template: `
|
|
7578
7675
|
@if (label()) {
|
|
7579
7676
|
<label class="strct-field__label" [attr.for]="controlId() || null">
|
|
7580
7677
|
{{ label() }}
|
|
@@ -7584,6 +7681,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
7584
7681
|
</label>
|
|
7585
7682
|
}
|
|
7586
7683
|
<div class="strct-field__control">
|
|
7684
|
+
<!-- The addon slots come first so their selectors win over the catch-all
|
|
7685
|
+
below (Angular matches in template order); CSS order puts them
|
|
7686
|
+
either side of the control. -->
|
|
7687
|
+
<span class="strct-field__addon strct-field__addon--prefix" [id]="prefixId">
|
|
7688
|
+
<ng-content select="[strctFieldPrefix]" />
|
|
7689
|
+
</span>
|
|
7690
|
+
<span class="strct-field__addon strct-field__addon--suffix" [id]="suffixId">
|
|
7691
|
+
<ng-content select="[strctFieldSuffix]" />
|
|
7692
|
+
</span>
|
|
7587
7693
|
<ng-content />
|
|
7588
7694
|
@if (stateActive()) {
|
|
7589
7695
|
<span class="strct-field__adorn strct-field__adorn--{{ stateStatus() }}" aria-hidden="true">
|
|
@@ -7608,6 +7714,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
7608
7714
|
>
|
|
7609
7715
|
{{ stateMessage() }}
|
|
7610
7716
|
</div>
|
|
7717
|
+
} @else if (hintTpl()) {
|
|
7718
|
+
<div class="strct-field__msg strct-field__msg--hint" [id]="hintId">
|
|
7719
|
+
<ng-container [ngTemplateOutlet]="hintTpl()!" />
|
|
7720
|
+
</div>
|
|
7611
7721
|
} @else if (hint()) {
|
|
7612
7722
|
<div class="strct-field__msg strct-field__msg--hint" [id]="hintId">{{ hint() }}</div>
|
|
7613
7723
|
}
|
|
@@ -7615,8 +7725,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
7615
7725
|
class: 'strct-field',
|
|
7616
7726
|
'[class.strct-field--invalid]': 'isInvalid()',
|
|
7617
7727
|
'[class.strct-field--validating]': 'stateActive()',
|
|
7618
|
-
|
|
7619
|
-
|
|
7728
|
+
'[class.strct-field--inline]': "layout() === 'inline'",
|
|
7729
|
+
'[class.strct-field--prefix]': 'hasPrefix()',
|
|
7730
|
+
'[class.strct-field--suffix]': 'hasSuffix()',
|
|
7731
|
+
}, styles: [".strct-field{display:flex;flex-direction:column;gap:6px}.strct-field__label{font-size:12px;font-weight:600;color:var(--t2)}.strct-field__req{color:var(--critical);margin-inline-start:2px}.strct-field__control{position:relative;display:flex;flex-direction:column}.strct-field__adorn{position:absolute;top:50%;inset-inline-end:10px;transform:translateY(-50%);display:inline-flex;align-items:center;pointer-events:none}.strct-field__adorn--ok{color:var(--success)}.strct-field__adorn--warning{color:var(--warning)}.strct-field__adorn--error{color:var(--critical)}.strct-field--validating .strct-control{padding-inline-end:32px}.strct-field__msg{font-size:12px;line-height:1.4}.strct-field__msg--hint,.strct-field__msg--checking{color:var(--t3)}.strct-field__msg--ok{color:var(--success)}.strct-field__msg--warning{color:var(--warning)}.strct-field__msg--error{color:var(--critical)}.strct-field__addon{display:none;align-items:center;flex:none;font-size:13px;color:var(--t3)}.strct-field__addon--prefix{order:-1;padding-inline-start:var(--space-3)}.strct-field__addon--suffix{order:1;padding-inline-end:var(--space-3)}.strct-field--prefix .strct-field__addon--prefix,.strct-field--suffix .strct-field__addon--suffix{display:inline-flex}.strct-field__addon:has(.strct-btn){padding:3px}.strct-field--prefix .strct-field__control,.strct-field--suffix .strct-field__control{flex-direction:row;align-items:center;background:var(--bg-2);border:1px solid var(--b2);border-radius:var(--radius-md);transition:border-color .14s ease,box-shadow .14s ease,background .14s ease}.strct-field--prefix .strct-field__control:hover,.strct-field--suffix .strct-field__control:hover{border-color:var(--b3)}.strct-field--prefix .strct-field__control:focus-within,.strct-field--suffix .strct-field__control:focus-within{border-color:var(--acc50);box-shadow:0 0 0 3px var(--acc18);background:var(--bg-1)}.strct-field--invalid.strct-field--prefix .strct-field__control,.strct-field--invalid.strct-field--suffix .strct-field__control{border-color:var(--critical)}.strct-field--prefix .strct-control,.strct-field--suffix .strct-control{flex:1;min-width:0;border:0;background:transparent}.strct-field--prefix .strct-control:focus,.strct-field--prefix .strct-control:focus-visible,.strct-field--suffix .strct-control:focus,.strct-field--suffix .strct-control:focus-visible{box-shadow:none;background:transparent}.strct-field--prefix textarea.strct-control,.strct-field--suffix textarea.strct-control{min-height:0}.strct-field--inline{container-type:inline-size;display:grid;grid-template-columns:var(--strct-field-label-w, 220px) minmax(0,1fr);column-gap:var(--space-3);row-gap:4px;align-items:start}.strct-field--inline>.strct-field__label{grid-column:1;grid-row:1;padding-block-start:9px}.strct-field--inline>.strct-field__control{grid-column:2;grid-row:1}.strct-field--inline>.strct-field__msg{grid-column:2;grid-row:2}.strct-field--inline>.strct-field__msg--hint{grid-column:1;padding-block-end:var(--space-2)}.strct-field--inline+.strct-field--inline{border-block-start:1px solid var(--b1);margin-block-start:var(--space-3);padding-block-start:var(--space-3)}.strct-field-group .strct-field--inline+.strct-field--inline{border-block-start:0;padding-block-start:0}@container (max-width: 480px){.strct-field--inline>.strct-field__label,.strct-field--inline>.strct-field__control,.strct-field--inline>.strct-field__msg{grid-column:1 / -1;grid-row:auto}.strct-field--inline>.strct-field__label{padding-block-start:0}.strct-field--inline>.strct-field__msg--hint{padding-block-end:0}}\n"] }]
|
|
7732
|
+
}], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], validationState: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationState", required: false }] }], hintTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctFieldHint), { ...{ read: TemplateRef }, isSignal: true }] }], hasPrefix: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctFieldPrefix), { isSignal: true }] }], hasSuffix: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctFieldSuffix), { isSignal: true }] }] } });
|
|
7620
7733
|
|
|
7621
7734
|
/**
|
|
7622
7735
|
* Applies the shared `.strct-control` look to a native input / textarea / select.
|
|
@@ -11740,178 +11853,452 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
11740
11853
|
}], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], striped: [{ type: i0.Input, args: [{ isSignal: true, alias: "striped", required: false }] }], hover: [{ type: i0.Input, args: [{ isSignal: true, alias: "hover", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], cellDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctCellDef), { isSignal: true }] }] } });
|
|
11741
11854
|
|
|
11742
11855
|
/**
|
|
11743
|
-
*
|
|
11856
|
+
* Numeric stepper input: − / + buttons flanking a text field. The value is
|
|
11857
|
+
* `number | null` (null = empty); typing is free-form (intermediate states
|
|
11858
|
+
* like "-" are kept), committed values clamp to `min`/`max` on blur, and the
|
|
11859
|
+
* buttons + keyboard always clamp immediately.
|
|
11744
11860
|
*
|
|
11745
|
-
*
|
|
11746
|
-
*
|
|
11747
|
-
*
|
|
11748
|
-
*
|
|
11861
|
+
* <strct-number [min]="0" [max]="64" [step]="4" [(ngModel)]="vcpus" />
|
|
11862
|
+
*
|
|
11863
|
+
* Keyboard on the field: ArrowUp/Down ±step, PageUp/Down ±10×step,
|
|
11864
|
+
* Home/End jump to min/max. The field exposes `role="spinbutton"` with
|
|
11865
|
+
* aria-valuemin/max/now so assistive tech announces it as a number control.
|
|
11749
11866
|
*/
|
|
11750
|
-
|
|
11751
|
-
|
|
11752
|
-
|
|
11753
|
-
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11867
|
+
class StrctNumber {
|
|
11868
|
+
/** Minimum allowed value; null = unbounded. */
|
|
11869
|
+
min = input(null, /* @ts-ignore */
|
|
11870
|
+
...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
|
|
11871
|
+
/** Maximum allowed value; null = unbounded. */
|
|
11872
|
+
max = input(null, /* @ts-ignore */
|
|
11873
|
+
...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
|
|
11874
|
+
/** Step increment for buttons and Arrow keys (PageUp/Down use 10×). */
|
|
11875
|
+
step = input(1, /* @ts-ignore */
|
|
11876
|
+
...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
|
|
11877
|
+
/** Placeholder text when empty. */
|
|
11878
|
+
placeholder = input('', /* @ts-ignore */
|
|
11879
|
+
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
11880
|
+
/** Accessible label of the + button (localizable). */
|
|
11881
|
+
incrementLabel = input('Increment', /* @ts-ignore */
|
|
11882
|
+
...(ngDevMode ? [{ debugName: "incrementLabel" }] : /* istanbul ignore next */ []));
|
|
11883
|
+
/** Accessible label of the − button (localizable). */
|
|
11884
|
+
decrementLabel = input('Decrement', /* @ts-ignore */
|
|
11885
|
+
...(ngDevMode ? [{ debugName: "decrementLabel" }] : /* istanbul ignore next */ []));
|
|
11886
|
+
/** Static disable; forms' setDisabledState also drives the disabled state. */
|
|
11887
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
11888
|
+
value = signal(null, /* @ts-ignore */
|
|
11889
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
11890
|
+
/** Raw field text — may hold an unparseable intermediate state while typing. */
|
|
11891
|
+
text = signal('', /* @ts-ignore */
|
|
11892
|
+
...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
|
|
11893
|
+
/** Disabled state pushed by the forms API (setDisabledState). */
|
|
11894
|
+
cvaDisabled = signal(false, /* @ts-ignore */
|
|
11895
|
+
...(ngDevMode ? [{ debugName: "cvaDisabled" }] : /* istanbul ignore next */ []));
|
|
11896
|
+
isDisabled = computed(() => this.disabled() || this.cvaDisabled(), /* @ts-ignore */
|
|
11897
|
+
...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
11898
|
+
/** At/below min (or min unset → never) — greys out the − button. */
|
|
11899
|
+
atMin = computed(() => {
|
|
11900
|
+
const v = this.value();
|
|
11901
|
+
const m = this.min();
|
|
11902
|
+
return v !== null && m !== null && v <= m;
|
|
11903
|
+
}, /* @ts-ignore */
|
|
11904
|
+
...(ngDevMode ? [{ debugName: "atMin" }] : /* istanbul ignore next */ []));
|
|
11905
|
+
/** At/above max (or max unset → never) — greys out the + button. */
|
|
11906
|
+
atMax = computed(() => {
|
|
11907
|
+
const v = this.value();
|
|
11908
|
+
const m = this.max();
|
|
11909
|
+
return v !== null && m !== null && v >= m;
|
|
11910
|
+
}, /* @ts-ignore */
|
|
11911
|
+
...(ngDevMode ? [{ debugName: "atMax" }] : /* istanbul ignore next */ []));
|
|
11912
|
+
onChange = () => { };
|
|
11913
|
+
onTouched = () => { };
|
|
11914
|
+
onInput(event) {
|
|
11915
|
+
const raw = event.target.value;
|
|
11916
|
+
this.text.set(raw);
|
|
11917
|
+
const trimmed = raw.trim();
|
|
11918
|
+
if (trimmed === '') {
|
|
11919
|
+
this.value.set(null);
|
|
11920
|
+
this.onChange(null);
|
|
11921
|
+
return;
|
|
11922
|
+
}
|
|
11923
|
+
const parsed = Number(trimmed);
|
|
11924
|
+
// Intermediate states ("-", "1.", "2e") don't parse yet — keep the text,
|
|
11925
|
+
// hold the last value; clamping happens on blur.
|
|
11926
|
+
if (Number.isFinite(parsed)) {
|
|
11927
|
+
this.value.set(parsed);
|
|
11928
|
+
this.onChange(parsed);
|
|
11929
|
+
}
|
|
11757
11930
|
}
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
|
|
11771
|
-
|
|
11772
|
-
|
|
11773
|
-
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11931
|
+
onKeydown(event) {
|
|
11932
|
+
if (this.isDisabled())
|
|
11933
|
+
return;
|
|
11934
|
+
switch (event.key) {
|
|
11935
|
+
case 'ArrowUp':
|
|
11936
|
+
event.preventDefault();
|
|
11937
|
+
this.stepBy(1);
|
|
11938
|
+
break;
|
|
11939
|
+
case 'ArrowDown':
|
|
11940
|
+
event.preventDefault();
|
|
11941
|
+
this.stepBy(-1);
|
|
11942
|
+
break;
|
|
11943
|
+
case 'PageUp':
|
|
11944
|
+
event.preventDefault();
|
|
11945
|
+
this.stepBy(1, 10);
|
|
11946
|
+
break;
|
|
11947
|
+
case 'PageDown':
|
|
11948
|
+
event.preventDefault();
|
|
11949
|
+
this.stepBy(-1, 10);
|
|
11950
|
+
break;
|
|
11951
|
+
case 'Home': {
|
|
11952
|
+
const m = this.min();
|
|
11953
|
+
if (m === null)
|
|
11954
|
+
return;
|
|
11955
|
+
event.preventDefault();
|
|
11956
|
+
this.commitTo(m);
|
|
11957
|
+
break;
|
|
11958
|
+
}
|
|
11959
|
+
case 'End': {
|
|
11960
|
+
const m = this.max();
|
|
11961
|
+
if (m === null)
|
|
11962
|
+
return;
|
|
11963
|
+
event.preventDefault();
|
|
11964
|
+
this.commitTo(m);
|
|
11965
|
+
break;
|
|
11966
|
+
}
|
|
11781
11967
|
}
|
|
11782
|
-
return out;
|
|
11783
|
-
};
|
|
11784
|
-
for (const { name, data } of entries) {
|
|
11785
|
-
const nameBytes = enc.encode(name);
|
|
11786
|
-
const crc = crc32(data);
|
|
11787
|
-
const local = cat(u32(0x04034b50), u16(20), // version needed
|
|
11788
|
-
u16(0), // flags
|
|
11789
|
-
u16(0), // method: stored
|
|
11790
|
-
u16(0), u16(0), // mod time/date
|
|
11791
|
-
u32(crc), u32(data.length), u32(data.length), u16(nameBytes.length), u16(0), nameBytes, data);
|
|
11792
|
-
central.push(cat(u32(0x02014b50), u16(20), u16(20), u16(0), u16(0), u16(0), u16(0), u32(crc), u32(data.length), u32(data.length), u16(nameBytes.length), u16(0), u16(0), u16(0), u16(0), u32(0), u32(offset), nameBytes));
|
|
11793
|
-
chunks.push(local);
|
|
11794
|
-
offset += local.length;
|
|
11795
11968
|
}
|
|
11796
|
-
|
|
11797
|
-
|
|
11798
|
-
|
|
11799
|
-
|
|
11800
|
-
|
|
11801
|
-
|
|
11802
|
-
|
|
11803
|
-
.replace(/</g, '<')
|
|
11804
|
-
.replace(/>/g, '>')
|
|
11805
|
-
.replace(/"/g, '"');
|
|
11806
|
-
/** A1-style column ref: 0 → A, 26 → AA … */
|
|
11807
|
-
function colRef(i) {
|
|
11808
|
-
let s = '';
|
|
11809
|
-
for (let n = i; n >= 0; n = Math.floor(n / 26) - 1)
|
|
11810
|
-
s = String.fromCharCode(65 + (n % 26)) + s;
|
|
11811
|
-
return s;
|
|
11812
|
-
}
|
|
11813
|
-
/**
|
|
11814
|
-
* Build a single-sheet workbook: `header` as a bold-free first row, then
|
|
11815
|
-
* `rows`. Numbers stay numeric; everything else exports as inline strings.
|
|
11816
|
-
*/
|
|
11817
|
-
function buildXlsx(header, rows, sheetName = 'Data') {
|
|
11818
|
-
const rowXml = (cells, r) => `<row r="${r}">` +
|
|
11819
|
-
cells
|
|
11820
|
-
.map((v, c) => {
|
|
11821
|
-
const ref = `${colRef(c)}${r}`;
|
|
11822
|
-
if (typeof v === 'number' && Number.isFinite(v)) {
|
|
11823
|
-
return `<c r="${ref}"><v>${v}</v></c>`;
|
|
11969
|
+
/** Commit the pending text on blur: parse, clamp, restore on garbage. */
|
|
11970
|
+
onBlur() {
|
|
11971
|
+
const trimmed = this.text().trim();
|
|
11972
|
+
if (trimmed === '') {
|
|
11973
|
+
if (this.value() !== null) {
|
|
11974
|
+
this.value.set(null);
|
|
11975
|
+
this.onChange(null);
|
|
11824
11976
|
}
|
|
11825
|
-
|
|
11826
|
-
}
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11977
|
+
this.text.set('');
|
|
11978
|
+
}
|
|
11979
|
+
else {
|
|
11980
|
+
const parsed = Number(trimmed);
|
|
11981
|
+
if (Number.isFinite(parsed)) {
|
|
11982
|
+
const clamped = this.clamp(parsed);
|
|
11983
|
+
this.value.set(clamped);
|
|
11984
|
+
if (clamped !== parsed)
|
|
11985
|
+
this.onChange(clamped);
|
|
11986
|
+
this.text.set(String(clamped));
|
|
11987
|
+
}
|
|
11988
|
+
else {
|
|
11989
|
+
// Unparseable — restore the last committed value.
|
|
11990
|
+
this.text.set(this.value() === null ? '' : String(this.value()));
|
|
11991
|
+
}
|
|
11992
|
+
}
|
|
11993
|
+
this.onTouched();
|
|
11994
|
+
}
|
|
11995
|
+
/** Button / keyboard step: an empty field first lands on min (or 0). */
|
|
11996
|
+
stepBy(dir, factor = 1) {
|
|
11997
|
+
if (this.isDisabled())
|
|
11998
|
+
return;
|
|
11999
|
+
const v = this.value();
|
|
12000
|
+
if (v === null) {
|
|
12001
|
+
this.commitTo(this.min() ?? 0);
|
|
12002
|
+
return;
|
|
12003
|
+
}
|
|
12004
|
+
this.commitTo(v + dir * factor * this.step());
|
|
12005
|
+
}
|
|
12006
|
+
commitTo(n) {
|
|
12007
|
+
const clamped = this.clamp(this.snap(n));
|
|
12008
|
+
this.value.set(clamped);
|
|
12009
|
+
this.text.set(String(clamped));
|
|
12010
|
+
this.onChange(clamped);
|
|
12011
|
+
this.onTouched();
|
|
12012
|
+
}
|
|
12013
|
+
clamp(n) {
|
|
12014
|
+
const lo = this.min();
|
|
12015
|
+
const hi = this.max();
|
|
12016
|
+
if (lo !== null && n < lo)
|
|
12017
|
+
return lo;
|
|
12018
|
+
if (hi !== null && n > hi)
|
|
12019
|
+
return hi;
|
|
12020
|
+
return n;
|
|
12021
|
+
}
|
|
12022
|
+
/** Trim float dust from step arithmetic (0.1 + 0.2), not a grid snap. */
|
|
12023
|
+
snap(n) {
|
|
12024
|
+
const step = this.step();
|
|
12025
|
+
if (!Number.isFinite(step) || step <= 0)
|
|
12026
|
+
return n;
|
|
12027
|
+
const decimals = (String(step).split('.')[1] ?? '').length;
|
|
12028
|
+
return Number(n.toFixed(Math.min(decimals + 2, 12)));
|
|
12029
|
+
}
|
|
12030
|
+
writeValue(value) {
|
|
12031
|
+
const parsed = value === null || value === undefined ? null : Number(value);
|
|
12032
|
+
const v = parsed !== null && Number.isFinite(parsed) ? this.clamp(parsed) : null;
|
|
12033
|
+
this.value.set(v);
|
|
12034
|
+
this.text.set(v === null ? '' : String(v));
|
|
12035
|
+
}
|
|
12036
|
+
registerOnChange(fn) {
|
|
12037
|
+
this.onChange = fn;
|
|
12038
|
+
}
|
|
12039
|
+
registerOnTouched(fn) {
|
|
12040
|
+
this.onTouched = fn;
|
|
12041
|
+
}
|
|
12042
|
+
setDisabledState(isDisabled) {
|
|
12043
|
+
this.cvaDisabled.set(isDisabled);
|
|
12044
|
+
}
|
|
12045
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctNumber, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12046
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: StrctNumber, isStandalone: true, selector: "strct-number", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, incrementLabel: { classPropertyName: "incrementLabel", publicName: "incrementLabel", isSignal: true, isRequired: false, transformFunction: null }, decrementLabel: { classPropertyName: "decrementLabel", publicName: "decrementLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "strct-num" }, providers: [
|
|
12047
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StrctNumber), multi: true },
|
|
12048
|
+
], ngImport: i0, template: `
|
|
12049
|
+
<div class="strct-num__wrap">
|
|
12050
|
+
<button
|
|
12051
|
+
type="button"
|
|
12052
|
+
class="strct-num__btn"
|
|
12053
|
+
[attr.aria-label]="decrementLabel()"
|
|
12054
|
+
[disabled]="isDisabled() || atMin()"
|
|
12055
|
+
(click)="stepBy(-1)"
|
|
12056
|
+
>
|
|
12057
|
+
<strct-icon strictName="minus" [size]="12" [strokeWidth]="1.8" />
|
|
12058
|
+
</button>
|
|
12059
|
+
<input
|
|
12060
|
+
type="text"
|
|
12061
|
+
inputmode="decimal"
|
|
12062
|
+
class="strct-control strct-num__input"
|
|
12063
|
+
role="spinbutton"
|
|
12064
|
+
[attr.aria-valuemin]="min()"
|
|
12065
|
+
[attr.aria-valuemax]="max()"
|
|
12066
|
+
[attr.aria-valuenow]="value()"
|
|
12067
|
+
[placeholder]="placeholder()"
|
|
12068
|
+
[value]="text()"
|
|
12069
|
+
[disabled]="isDisabled()"
|
|
12070
|
+
(input)="onInput($event)"
|
|
12071
|
+
(keydown)="onKeydown($event)"
|
|
12072
|
+
(blur)="onBlur()"
|
|
12073
|
+
/>
|
|
12074
|
+
<button
|
|
12075
|
+
type="button"
|
|
12076
|
+
class="strct-num__btn"
|
|
12077
|
+
[attr.aria-label]="incrementLabel()"
|
|
12078
|
+
[disabled]="isDisabled() || atMax()"
|
|
12079
|
+
(click)="stepBy(1)"
|
|
12080
|
+
>
|
|
12081
|
+
<strct-icon strictName="plus" [size]="12" [strokeWidth]="1.8" />
|
|
12082
|
+
</button>
|
|
12083
|
+
</div>
|
|
12084
|
+
`, isInline: true, styles: [".strct-num{display:block;width:100%}.strct-num__wrap{display:flex;align-items:stretch;gap:var(--space-1)}.strct-num__input{flex:1;min-width:0;text-align:center;font-variant-numeric:tabular-nums}.strct-num__btn{display:inline-flex;align-items:center;justify-content:center;flex:none;padding-inline:var(--space-2);color:var(--t2);background:var(--bg-2);border:1px solid var(--b2);border-radius:var(--radius-md);cursor:pointer;transition:border-color .14s ease,color .14s ease,background .14s ease}.strct-num__btn:hover:not(:disabled){color:var(--t1);border-color:var(--b3);background:var(--bg-3)}.strct-num__btn:disabled{opacity:var(--disabled-opacity);cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
11860
12085
|
}
|
|
12086
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctNumber, decorators: [{
|
|
12087
|
+
type: Component,
|
|
12088
|
+
args: [{ selector: 'strct-number', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon], providers: [
|
|
12089
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StrctNumber), multi: true },
|
|
12090
|
+
], template: `
|
|
12091
|
+
<div class="strct-num__wrap">
|
|
12092
|
+
<button
|
|
12093
|
+
type="button"
|
|
12094
|
+
class="strct-num__btn"
|
|
12095
|
+
[attr.aria-label]="decrementLabel()"
|
|
12096
|
+
[disabled]="isDisabled() || atMin()"
|
|
12097
|
+
(click)="stepBy(-1)"
|
|
12098
|
+
>
|
|
12099
|
+
<strct-icon strictName="minus" [size]="12" [strokeWidth]="1.8" />
|
|
12100
|
+
</button>
|
|
12101
|
+
<input
|
|
12102
|
+
type="text"
|
|
12103
|
+
inputmode="decimal"
|
|
12104
|
+
class="strct-control strct-num__input"
|
|
12105
|
+
role="spinbutton"
|
|
12106
|
+
[attr.aria-valuemin]="min()"
|
|
12107
|
+
[attr.aria-valuemax]="max()"
|
|
12108
|
+
[attr.aria-valuenow]="value()"
|
|
12109
|
+
[placeholder]="placeholder()"
|
|
12110
|
+
[value]="text()"
|
|
12111
|
+
[disabled]="isDisabled()"
|
|
12112
|
+
(input)="onInput($event)"
|
|
12113
|
+
(keydown)="onKeydown($event)"
|
|
12114
|
+
(blur)="onBlur()"
|
|
12115
|
+
/>
|
|
12116
|
+
<button
|
|
12117
|
+
type="button"
|
|
12118
|
+
class="strct-num__btn"
|
|
12119
|
+
[attr.aria-label]="incrementLabel()"
|
|
12120
|
+
[disabled]="isDisabled() || atMax()"
|
|
12121
|
+
(click)="stepBy(1)"
|
|
12122
|
+
>
|
|
12123
|
+
<strct-icon strictName="plus" [size]="12" [strokeWidth]="1.8" />
|
|
12124
|
+
</button>
|
|
12125
|
+
</div>
|
|
12126
|
+
`, host: { class: 'strct-num' }, styles: [".strct-num{display:block;width:100%}.strct-num__wrap{display:flex;align-items:stretch;gap:var(--space-1)}.strct-num__input{flex:1;min-width:0;text-align:center;font-variant-numeric:tabular-nums}.strct-num__btn{display:inline-flex;align-items:center;justify-content:center;flex:none;padding-inline:var(--space-2);color:var(--t2);background:var(--bg-2);border:1px solid var(--b2);border-radius:var(--radius-md);cursor:pointer;transition:border-color .14s ease,color .14s ease,background .14s ease}.strct-num__btn:hover:not(:disabled){color:var(--t1);border-color:var(--b3);background:var(--bg-3)}.strct-num__btn:disabled{opacity:var(--disabled-opacity);cursor:not-allowed}\n"] }]
|
|
12127
|
+
}], propDecorators: { min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], incrementLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "incrementLabel", required: false }] }], decrementLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "decrementLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
|
|
11861
12128
|
|
|
11862
|
-
const DG_LABELS = {
|
|
11863
|
-
row: 'row',
|
|
11864
|
-
rows: 'rows',
|
|
11865
|
-
selected: 'selected',
|
|
11866
|
-
selectAll: 'Select all rows on this page',
|
|
11867
|
-
selectRow: 'Select row',
|
|
11868
|
-
selectRowFor: (id) => `Select row ${id}`,
|
|
11869
|
-
selectAllInGroup: (group) => `Select all in ${group}`,
|
|
11870
|
-
openDetail: 'Open detail',
|
|
11871
|
-
toggleDetail: 'Toggle detail',
|
|
11872
|
-
closeDetail: 'Close detail',
|
|
11873
|
-
rowActions: 'Row actions',
|
|
11874
|
-
chooseColumns: 'Choose columns',
|
|
11875
|
-
refresh: 'Refresh data',
|
|
11876
|
-
actions: 'Actions',
|
|
11877
|
-
filterColumn: 'Filter',
|
|
11878
|
-
filterPlaceholder: 'Filter…',
|
|
11879
|
-
clearFilter: 'Clear filter',
|
|
11880
|
-
editCell: 'Edit',
|
|
11881
|
-
toggleChildren: 'Toggle children',
|
|
11882
|
-
quickFilter: 'Quick filter',
|
|
11883
|
-
};
|
|
11884
|
-
let datagridCounter = 0;
|
|
11885
|
-
/** Utility-column widths used when sticky columns are active (px). */
|
|
11886
|
-
const UTIL_W = { detail: 36, expand: 36, sel: 40 };
|
|
11887
|
-
/** Fallback width for a sticky column without an explicit px width. */
|
|
11888
|
-
const STICKY_FALLBACK_W = 120;
|
|
11889
12129
|
/**
|
|
11890
|
-
*
|
|
11891
|
-
*
|
|
12130
|
+
* Minimal, dependency-free XLSX writer for the datagrid's Excel export.
|
|
12131
|
+
*
|
|
12132
|
+
* An .xlsx file is a ZIP of SpreadsheetML parts. This builds the five
|
|
12133
|
+
* required parts with inline strings and zips them with STORED (uncompressed)
|
|
12134
|
+
* entries — no runtime dependency, byte-accurate CRC32, opens in Excel,
|
|
12135
|
+
* LibreOffice and Google Sheets.
|
|
11892
12136
|
*/
|
|
11893
|
-
|
|
11894
|
-
|
|
11895
|
-
|
|
11896
|
-
|
|
12137
|
+
const CRC_TABLE = (() => {
|
|
12138
|
+
const t = new Uint32Array(256);
|
|
12139
|
+
for (let n = 0; n < 256; n++) {
|
|
12140
|
+
let c = n;
|
|
12141
|
+
for (let k = 0; k < 8; k++)
|
|
12142
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
12143
|
+
t[n] = c >>> 0;
|
|
12144
|
+
}
|
|
12145
|
+
return t;
|
|
12146
|
+
})();
|
|
12147
|
+
function crc32(data) {
|
|
12148
|
+
let c = 0xffffffff;
|
|
12149
|
+
for (const byte of data)
|
|
12150
|
+
c = CRC_TABLE[(c ^ byte) & 0xff] ^ (c >>> 8);
|
|
12151
|
+
return (c ^ 0xffffffff) >>> 0;
|
|
11897
12152
|
}
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
12153
|
+
const enc = new TextEncoder();
|
|
12154
|
+
/** ZIP with STORED entries (no compression — spreadsheets are small). */
|
|
12155
|
+
function zip(entries) {
|
|
12156
|
+
const chunks = [];
|
|
12157
|
+
const central = [];
|
|
12158
|
+
let offset = 0;
|
|
12159
|
+
const u16 = (n) => new Uint8Array([n & 0xff, (n >> 8) & 0xff]);
|
|
12160
|
+
const u32 = (n) => new Uint8Array([n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, (n >> 24) & 0xff]);
|
|
12161
|
+
const cat = (...parts) => {
|
|
12162
|
+
const total = parts.reduce((s, p) => s + p.length, 0);
|
|
12163
|
+
const out = new Uint8Array(total);
|
|
12164
|
+
let o = 0;
|
|
12165
|
+
for (const p of parts) {
|
|
12166
|
+
out.set(p, o);
|
|
12167
|
+
o += p.length;
|
|
12168
|
+
}
|
|
12169
|
+
return out;
|
|
12170
|
+
};
|
|
12171
|
+
for (const { name, data } of entries) {
|
|
12172
|
+
const nameBytes = enc.encode(name);
|
|
12173
|
+
const crc = crc32(data);
|
|
12174
|
+
const local = cat(u32(0x04034b50), u16(20), // version needed
|
|
12175
|
+
u16(0), // flags
|
|
12176
|
+
u16(0), // method: stored
|
|
12177
|
+
u16(0), u16(0), // mod time/date
|
|
12178
|
+
u32(crc), u32(data.length), u32(data.length), u16(nameBytes.length), u16(0), nameBytes, data);
|
|
12179
|
+
central.push(cat(u32(0x02014b50), u16(20), u16(20), u16(0), u16(0), u16(0), u16(0), u32(crc), u32(data.length), u32(data.length), u16(nameBytes.length), u16(0), u16(0), u16(0), u16(0), u32(0), u32(offset), nameBytes));
|
|
12180
|
+
chunks.push(local);
|
|
12181
|
+
offset += local.length;
|
|
12182
|
+
}
|
|
12183
|
+
const centralStart = offset;
|
|
12184
|
+
const centralBytes = cat(...central);
|
|
12185
|
+
const end = cat(u32(0x06054b50), u16(0), u16(0), u16(entries.length), u16(entries.length), u32(centralBytes.length), u32(centralStart), u16(0));
|
|
12186
|
+
return cat(...chunks, centralBytes, end);
|
|
11906
12187
|
}
|
|
11907
|
-
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
|
|
11912
|
-
|
|
11913
|
-
|
|
11914
|
-
|
|
12188
|
+
const xml = (s) => String(s ?? '')
|
|
12189
|
+
.replace(/&/g, '&')
|
|
12190
|
+
.replace(/</g, '<')
|
|
12191
|
+
.replace(/>/g, '>')
|
|
12192
|
+
.replace(/"/g, '"');
|
|
12193
|
+
/** A1-style column ref: 0 → A, 26 → AA … */
|
|
12194
|
+
function colRef(i) {
|
|
12195
|
+
let s = '';
|
|
12196
|
+
for (let n = i; n >= 0; n = Math.floor(n / 26) - 1)
|
|
12197
|
+
s = String.fromCharCode(65 + (n % 26)) + s;
|
|
12198
|
+
return s;
|
|
12199
|
+
}
|
|
12200
|
+
/**
|
|
12201
|
+
* Build a single-sheet workbook: `header` as a bold-free first row, then
|
|
12202
|
+
* `rows`. Numbers stay numeric; everything else exports as inline strings.
|
|
12203
|
+
*/
|
|
12204
|
+
function buildXlsx(header, rows, sheetName = 'Data') {
|
|
12205
|
+
const rowXml = (cells, r) => `<row r="${r}">` +
|
|
12206
|
+
cells
|
|
12207
|
+
.map((v, c) => {
|
|
12208
|
+
const ref = `${colRef(c)}${r}`;
|
|
12209
|
+
if (typeof v === 'number' && Number.isFinite(v)) {
|
|
12210
|
+
return `<c r="${ref}"><v>${v}</v></c>`;
|
|
12211
|
+
}
|
|
12212
|
+
return `<c r="${ref}" t="inlineStr"><is><t xml:space="preserve">${xml(v)}</t></is></c>`;
|
|
12213
|
+
})
|
|
12214
|
+
.join('') +
|
|
12215
|
+
'</row>';
|
|
12216
|
+
const sheet = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
12217
|
+
`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData>` +
|
|
12218
|
+
rowXml(header, 1) +
|
|
12219
|
+
rows.map((cells, i) => rowXml(cells, i + 2)).join('') +
|
|
12220
|
+
`</sheetData></worksheet>`;
|
|
12221
|
+
const workbook = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
12222
|
+
`<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" ` +
|
|
12223
|
+
`xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">` +
|
|
12224
|
+
`<sheets><sheet name="${xml(sheetName)}" sheetId="1" r:id="rId1"/></sheets></workbook>`;
|
|
12225
|
+
const workbookRels = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
12226
|
+
`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">` +
|
|
12227
|
+
`<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>` +
|
|
12228
|
+
`</Relationships>`;
|
|
12229
|
+
const rootRels = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
12230
|
+
`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">` +
|
|
12231
|
+
`<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>` +
|
|
12232
|
+
`</Relationships>`;
|
|
12233
|
+
const contentTypes = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
12234
|
+
`<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">` +
|
|
12235
|
+
`<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>` +
|
|
12236
|
+
`<Default Extension="xml" ContentType="application/xml"/>` +
|
|
12237
|
+
`<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>` +
|
|
12238
|
+
`<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>` +
|
|
12239
|
+
`</Types>`;
|
|
12240
|
+
return zip([
|
|
12241
|
+
{ name: '[Content_Types].xml', data: enc.encode(contentTypes) },
|
|
12242
|
+
{ name: '_rels/.rels', data: enc.encode(rootRels) },
|
|
12243
|
+
{ name: 'xl/workbook.xml', data: enc.encode(workbook) },
|
|
12244
|
+
{ name: 'xl/_rels/workbook.xml.rels', data: enc.encode(workbookRels) },
|
|
12245
|
+
{ name: 'xl/worksheets/sheet1.xml', data: enc.encode(sheet) },
|
|
12246
|
+
]);
|
|
12247
|
+
}
|
|
12248
|
+
|
|
12249
|
+
const DG_LABELS = {
|
|
12250
|
+
row: 'row',
|
|
12251
|
+
rows: 'rows',
|
|
12252
|
+
selected: 'selected',
|
|
12253
|
+
selectAll: 'Select all rows on this page',
|
|
12254
|
+
selectRow: 'Select row',
|
|
12255
|
+
selectRowFor: (id) => `Select row ${id}`,
|
|
12256
|
+
selectAllInGroup: (group) => `Select all in ${group}`,
|
|
12257
|
+
openDetail: 'Open detail',
|
|
12258
|
+
toggleDetail: 'Toggle detail',
|
|
12259
|
+
closeDetail: 'Close detail',
|
|
12260
|
+
rowActions: 'Row actions',
|
|
12261
|
+
chooseColumns: 'Choose columns',
|
|
12262
|
+
refresh: 'Refresh data',
|
|
12263
|
+
actions: 'Actions',
|
|
12264
|
+
filterColumn: 'Filter',
|
|
12265
|
+
filterPlaceholder: 'Filter…',
|
|
12266
|
+
clearFilter: 'Clear filter',
|
|
12267
|
+
editCell: 'Edit',
|
|
12268
|
+
toggleChildren: 'Toggle children',
|
|
12269
|
+
quickFilter: 'Quick filter',
|
|
12270
|
+
};
|
|
12271
|
+
let datagridCounter = 0;
|
|
12272
|
+
/** Utility-column widths used when sticky columns are active (px). */
|
|
12273
|
+
const UTIL_W = { detail: 36, expand: 36, sel: 40 };
|
|
12274
|
+
/** Fallback width for a sticky column without an explicit px width. */
|
|
12275
|
+
const STICKY_FALLBACK_W = 120;
|
|
12276
|
+
/**
|
|
12277
|
+
* Marks the expandable-row detail template. The row is the template's implicit
|
|
12278
|
+
* context (`let-row`, or `let-row="row"`): `<ng-template strctRowDetail let-row> … {{ row['name'] }} … </ng-template>`.
|
|
12279
|
+
*/
|
|
12280
|
+
class StrctRowDetailDef {
|
|
12281
|
+
template = inject(TemplateRef);
|
|
12282
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctRowDetailDef, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
12283
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctRowDetailDef, isStandalone: true, selector: "[strctRowDetail]", ngImport: i0 });
|
|
12284
|
+
}
|
|
12285
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctRowDetailDef, decorators: [{
|
|
12286
|
+
type: Directive,
|
|
12287
|
+
args: [{ selector: '[strctRowDetail]' }]
|
|
12288
|
+
}] });
|
|
12289
|
+
/** Muted note inside the action bar, before the buttons. */
|
|
12290
|
+
class StrctDatagridActionBarCaption {
|
|
12291
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDatagridActionBarCaption, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
12292
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctDatagridActionBarCaption, isStandalone: true, selector: "[strctDatagridActionBarCaption]", ngImport: i0 });
|
|
12293
|
+
}
|
|
12294
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDatagridActionBarCaption, decorators: [{
|
|
12295
|
+
type: Directive,
|
|
12296
|
+
args: [{ selector: '[strctDatagridActionBarCaption]' }]
|
|
12297
|
+
}] });
|
|
12298
|
+
/** Marks the persistent action-bar (toolbar) content shown above the grid. */
|
|
12299
|
+
class StrctDatagridActionBar {
|
|
12300
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDatagridActionBar, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
12301
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctDatagridActionBar, isStandalone: true, selector: "[strctDatagridActionBar]", ngImport: i0 });
|
|
11915
12302
|
}
|
|
11916
12303
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDatagridActionBar, decorators: [{
|
|
11917
12304
|
type: Directive,
|
|
@@ -12103,8 +12490,9 @@ class StrctDatagrid {
|
|
|
12103
12490
|
rowAction = output();
|
|
12104
12491
|
/** Server-side data request (lazy mode): load this page / sort and set `rows`. */
|
|
12105
12492
|
lazyLoad = output();
|
|
12106
|
-
/** An editable cell was committed (Enter / blur
|
|
12107
|
-
* rows — apply
|
|
12493
|
+
/** An editable cell was committed (Enter / blur, or choosing in a `select`
|
|
12494
|
+
* editor). The grid does not mutate rows — apply the value to your data and
|
|
12495
|
+
* pass the updated array back in. */
|
|
12108
12496
|
cellEdit = output();
|
|
12109
12497
|
menu = inject(StrctMenuService);
|
|
12110
12498
|
detailDef = contentChild(StrctRowDetailDef, /* @ts-ignore */
|
|
@@ -12479,9 +12867,80 @@ class StrctDatagrid {
|
|
|
12479
12867
|
const e = this.editing();
|
|
12480
12868
|
return !!e && e.rowKey === this.rowKey(row) && e.colKey === col.key;
|
|
12481
12869
|
}
|
|
12870
|
+
/** The value a typed editor holds while it is open (committed on Enter / blur). */
|
|
12871
|
+
editDraft = signal(null, /* @ts-ignore */
|
|
12872
|
+
...(ngDevMode ? [{ debugName: "editDraft" }] : /* istanbul ignore next */ []));
|
|
12482
12873
|
startEdit(row, col) {
|
|
12483
12874
|
this.editing.set({ rowKey: this.rowKey(row), colKey: col.key });
|
|
12484
|
-
|
|
12875
|
+
this.editDraft.set(row[col.key]);
|
|
12876
|
+
setTimeout(() => {
|
|
12877
|
+
const editor = this.hostRef.nativeElement.querySelector('.strct-dg__editinput, .strct-dg__editselect, .strct-dg__editnumber');
|
|
12878
|
+
if (!editor)
|
|
12879
|
+
return;
|
|
12880
|
+
// The stepper buttons come first in the DOM; the value is what the user
|
|
12881
|
+
// came to change, so focus lands on the field itself.
|
|
12882
|
+
(editor.matches('input')
|
|
12883
|
+
? editor
|
|
12884
|
+
: (editor.querySelector('input') ??
|
|
12885
|
+
editor.querySelector('button')))?.focus();
|
|
12886
|
+
});
|
|
12887
|
+
}
|
|
12888
|
+
/** A select column reads as its option's label, not as the stored value. */
|
|
12889
|
+
displayValue(row, col) {
|
|
12890
|
+
const raw = row[col.key];
|
|
12891
|
+
if (col.editor !== 'select')
|
|
12892
|
+
return raw;
|
|
12893
|
+
return col.editorOptions?.find((o) => o.value === raw)?.label ?? raw;
|
|
12894
|
+
}
|
|
12895
|
+
/** Close the editor and emit `cellEdit` when the value actually changed. */
|
|
12896
|
+
commitValue(row, col, raw) {
|
|
12897
|
+
if (!this.isEditingCell(row, col))
|
|
12898
|
+
return;
|
|
12899
|
+
this.editing.set(null);
|
|
12900
|
+
const value = this.clampToColumn(col, raw);
|
|
12901
|
+
const previous = row[col.key];
|
|
12902
|
+
if (previous === value)
|
|
12903
|
+
return;
|
|
12904
|
+
this.cellEdit.emit({
|
|
12905
|
+
row,
|
|
12906
|
+
column: col,
|
|
12907
|
+
value: value == null ? '' : String(value),
|
|
12908
|
+
typedValue: value,
|
|
12909
|
+
previous,
|
|
12910
|
+
});
|
|
12911
|
+
}
|
|
12912
|
+
/** Enter / blur on a typed editor commits what it currently holds. */
|
|
12913
|
+
commitDraft(row, col, event) {
|
|
12914
|
+
event?.stopPropagation();
|
|
12915
|
+
this.commitValue(row, col, this.editDraft());
|
|
12916
|
+
}
|
|
12917
|
+
/**
|
|
12918
|
+
* A column that declares bounds means them: Enter commits what the field
|
|
12919
|
+
* holds, and `strct-number` only clamps on blur, so the grid clamps here
|
|
12920
|
+
* rather than letting an out-of-range value reach `cellEdit`.
|
|
12921
|
+
*/
|
|
12922
|
+
clampToColumn(col, value) {
|
|
12923
|
+
if (col.editor !== 'number' || typeof value !== 'number' || !Number.isFinite(value))
|
|
12924
|
+
return value;
|
|
12925
|
+
const min = col.editorMin;
|
|
12926
|
+
const max = col.editorMax;
|
|
12927
|
+
let v = value;
|
|
12928
|
+
if (min != null && v < min)
|
|
12929
|
+
v = min;
|
|
12930
|
+
if (max != null && v > max)
|
|
12931
|
+
v = max;
|
|
12932
|
+
return v;
|
|
12933
|
+
}
|
|
12934
|
+
/**
|
|
12935
|
+
* A number editor is a field between two stepper buttons, so focus moves
|
|
12936
|
+
* inside it — only a move that actually leaves the editor is a blur.
|
|
12937
|
+
*/
|
|
12938
|
+
commitOnLeave(row, col, event) {
|
|
12939
|
+
const editor = event.currentTarget;
|
|
12940
|
+
const next = event.relatedTarget;
|
|
12941
|
+
if (next instanceof Node && editor.contains(next))
|
|
12942
|
+
return;
|
|
12943
|
+
this.commitDraft(row, col, event);
|
|
12485
12944
|
}
|
|
12486
12945
|
commitEdit(row, col, event) {
|
|
12487
12946
|
if (!this.isEditingCell(row, col))
|
|
@@ -12490,7 +12949,7 @@ class StrctDatagrid {
|
|
|
12490
12949
|
this.editing.set(null);
|
|
12491
12950
|
const previous = row[col.key];
|
|
12492
12951
|
if (String(previous ?? '') !== value)
|
|
12493
|
-
this.cellEdit.emit({ row, column: col, value, previous });
|
|
12952
|
+
this.cellEdit.emit({ row, column: col, value, typedValue: value, previous });
|
|
12494
12953
|
}
|
|
12495
12954
|
cancelEdit(event) {
|
|
12496
12955
|
event?.stopPropagation();
|
|
@@ -13603,16 +14062,47 @@ class StrctDatagrid {
|
|
|
13603
14062
|
}
|
|
13604
14063
|
}
|
|
13605
14064
|
@if (isEditingCell(row, col)) {
|
|
13606
|
-
|
|
13607
|
-
|
|
13608
|
-
|
|
13609
|
-
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
|
|
13615
|
-
|
|
14065
|
+
@switch (col.editor ?? 'text') {
|
|
14066
|
+
@case ('select') {
|
|
14067
|
+
<!-- Choosing is the commit: there is nothing to
|
|
14068
|
+
confirm with Enter once an option is picked. -->
|
|
14069
|
+
<strct-select
|
|
14070
|
+
class="strct-dg__editselect"
|
|
14071
|
+
[options]="col.editorOptions ?? []"
|
|
14072
|
+
[listLabel]="L().editCell + ': ' + col.label"
|
|
14073
|
+
[ngModel]="row[col.key]"
|
|
14074
|
+
(ngModelChange)="commitValue(row, col, $event)"
|
|
14075
|
+
(keydown.escape)="cancelEdit($event)"
|
|
14076
|
+
(click)="$event.stopPropagation()"
|
|
14077
|
+
/>
|
|
14078
|
+
}
|
|
14079
|
+
@case ('number') {
|
|
14080
|
+
<strct-number
|
|
14081
|
+
class="strct-dg__editnumber"
|
|
14082
|
+
[min]="col.editorMin ?? null"
|
|
14083
|
+
[max]="col.editorMax ?? null"
|
|
14084
|
+
[step]="col.editorStep ?? 1"
|
|
14085
|
+
[ngModel]="row[col.key]"
|
|
14086
|
+
(ngModelChange)="editDraft.set($event)"
|
|
14087
|
+
(keydown.enter)="commitDraft(row, col, $event)"
|
|
14088
|
+
(keydown.escape)="cancelEdit($event)"
|
|
14089
|
+
(focusout)="commitOnLeave(row, col, $event)"
|
|
14090
|
+
(click)="$event.stopPropagation()"
|
|
14091
|
+
/>
|
|
14092
|
+
}
|
|
14093
|
+
@default {
|
|
14094
|
+
<input
|
|
14095
|
+
class="strct-dg__editinput"
|
|
14096
|
+
type="text"
|
|
14097
|
+
[value]="row[col.key] ?? ''"
|
|
14098
|
+
[attr.aria-label]="L().editCell + ': ' + col.label"
|
|
14099
|
+
(keydown.enter)="commitEdit(row, col, $event)"
|
|
14100
|
+
(keydown.escape)="cancelEdit($event)"
|
|
14101
|
+
(blur)="commitEdit(row, col, $event)"
|
|
14102
|
+
(click)="$event.stopPropagation()"
|
|
14103
|
+
/>
|
|
14104
|
+
}
|
|
14105
|
+
}
|
|
13616
14106
|
} @else if (cellTemplate(col.key); as tpl) {
|
|
13617
14107
|
<ng-container
|
|
13618
14108
|
[ngTemplateOutlet]="tpl"
|
|
@@ -13624,7 +14114,7 @@ class StrctDatagrid {
|
|
|
13624
14114
|
}"
|
|
13625
14115
|
/>
|
|
13626
14116
|
} @else {
|
|
13627
|
-
{{ row
|
|
14117
|
+
{{ displayValue(row, col) }}
|
|
13628
14118
|
}
|
|
13629
14119
|
</td>
|
|
13630
14120
|
}
|
|
@@ -13759,7 +14249,7 @@ class StrctDatagrid {
|
|
|
13759
14249
|
</div>
|
|
13760
14250
|
</div>
|
|
13761
14251
|
}
|
|
13762
|
-
`, isInline: true, styles: [".strct-dg__radio{width:15px;height:15px;accent-color:var(--acc);cursor:pointer}.strct-dg__radio:disabled{cursor:not-allowed}.strct-dg__row--locked .strct-dg__sel{opacity:.55}.strct-dg__actioncaption:empty{display:none}.strct-dg__actioncaption{display:inline-flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);color:var(--t3)}.strct-dg-host{display:block;border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg-host--virtual .strct-dg__scroll{overflow-y:auto}.strct-dg-host--virtual .strct-dg thead th{position:sticky;top:0;z-index:var(--z-raised)}.strct-dg__vspacer td{padding:0;border:0;background:transparent}.strct-dg th[draggable]{cursor:grab}.strct-dg__th--drop{box-shadow:inset 3px 0 0 var(--acc)}.strct-dg__grouprow td{background:var(--bg-2)!important;padding:0}.strct-dg__groupbtn{display:flex;align-items:center;gap:8px;width:100%;padding:7px 13px;border:0;background:transparent;color:var(--t1);font-family:var(--font);font-size:12.5px;font-weight:600;cursor:pointer;text-align:start}.strct-dg__groupbtn:hover{background:var(--bg-3)}.strct-dg__groupbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__groupchev{display:inline-flex;color:var(--t3);transition:transform .15s ease}.strct-dg__groupchev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-dg__groupchev{transition:none}}.strct-dg__groupcount{min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;border-radius:9px;background:var(--acc-m);color:var(--acc);font-variant-numeric:tabular-nums}.strct-dg-host--sticky .strct-dg,.strct-dg-host--virtual .strct-dg{border-collapse:separate;border-spacing:0;overflow:visible;border-radius:0}.strct-dg-host--sticky .strct-dg{width:max-content;min-width:100%}.strct-dg .strct-dg__cell--sticky{position:sticky;z-index:calc(var(--z-base) + 2)}.strct-dg thead th.strct-dg__cell--sticky{z-index:calc(var(--z-raised) + 1)}.strct-dg .strct-dg__cell--sticky-last:after{content:\"\";position:absolute;top:0;bottom:0;inset-inline-end:-1px;width:7px;pointer-events:none;background:linear-gradient(to right,rgba(0,0,0,.14),transparent)}[dir=rtl] .strct-dg .strct-dg__cell--sticky-last:after{background:linear-gradient(to left,rgba(0,0,0,.14),transparent)}.strct-dg-host--sticky .strct-dg__expandcol,.strct-dg-host--sticky .strct-dg__expandcell{width:36px;min-width:36px;max-width:36px;box-sizing:border-box}.strct-dg-host--sticky .strct-dg__sel{width:40px;min-width:40px;max-width:40px;box-sizing:border-box}.strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-3)}.strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:9px;border-start-end-radius:9px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:9px;border-end-end-radius:9px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;inset-inline-end:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:calc(var(--z-base) + 1)}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:var(--acc-s)}.strct-dg__row--selected td{background:var(--acc-m)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned .strct-dg__scroll{flex:0 0 auto;width:260px;min-width:260px;max-width:260px}.strct-dg__layout--paned .strct-dg{width:260px;min-width:260px;max-width:260px;flex-shrink:0;border-start-end-radius:0;border-end-end-radius:0}.strct-dg__row--clickable{cursor:pointer}.strct-dg__row--active td{background:var(--acc-m)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;inset-inline-end:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:8px;border-start-start-radius:0;border-end-start-radius:0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;border-radius:var(--radius-sm);background:linear-gradient(90deg,var(--bg-3) 25%,var(--skeleton-hi, var(--acc18)) 50%,var(--bg-3) 75%);background-size:200% 100%;animation:strct-dg-skeleton-sweep 1.1s linear infinite}@keyframes strct-dg-skeleton-sweep{0%{background-position:100% 0}to{background-position:-100% 0}}@media(prefers-reduced-motion:reduce){.strct-dg__skeleton-block{animation:none;background:var(--skeleton-hi, var(--acc18))}}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t3);padding:22px}.strct-dg__quickfilter{min-width:180px;max-width:260px}.strct-dg__quickfilter--end{order:2;margin-inline-start:auto}.strct-dg__filternote--end{order:3}.strct-dg__filternote{font-size:11.5px;color:var(--t3);font-variant-numeric:tabular-nums;white-space:nowrap}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);inset-inline-start:0;z-index:var(--z-sticky);min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:8px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{inset-inline-start:auto;inset-inline-end:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}.strct-dg__filterbtn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-inline-start:2px;padding:0;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__filterbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__filterbtn--active{color:var(--acc)}.strct-dg__filterbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filterpanel{position:absolute;z-index:calc(var(--z-dropdown) + 10);display:flex;flex-direction:column;gap:6px;min-width:180px;padding:10px;background:var(--bg-1);border:1px solid var(--b2);border-radius:7px;box-shadow:var(--shh);font-weight:400;text-transform:none;letter-spacing:normal;white-space:nowrap}.strct-dg__filterinput{padding:5px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:var(--bg-2);color:var(--t1);font-family:var(--font);font-size:12px}.strct-dg__filterinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filteropt{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--t1);cursor:pointer}.strct-dg__filterclear{align-self:flex-start;padding:3px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:transparent;color:var(--t2);font-family:var(--font);font-size:11.5px;cursor:pointer}.strct-dg__filterclear:hover:not(:disabled){color:var(--t1);background:var(--bg-3)}.strct-dg__filterclear:disabled{color:var(--t4);cursor:default}.strct-dg tbody tr[tabindex]:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__treepad{display:inline-block;height:1px;vertical-align:middle}.strct-dg__treebtn{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-inline-end:4px;padding:0;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__treebtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__treebtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__treebtn strct-icon{transition:transform .15s ease}.strct-dg__treebtn--open strct-icon{transform:rotate(90deg)}.strct-dg__treebtn--leaf{cursor:default;pointer-events:none}@media(prefers-reduced-motion:reduce){.strct-dg__treebtn strct-icon{transition:none}}.strct-dg__cell--editable{cursor:text}.strct-dg__cell--editable:hover{box-shadow:inset 0 0 0 1px var(--b2)}.strct-dg__editinput{width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid var(--acc);border-radius:var(--radius-sm);background:var(--bg-1);color:var(--t1);font:inherit}.strct-dg__editinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctPagination, selector: "strct-pagination", inputs: ["prevLabel", "nextLabel", "regionLabel", "pageLabel", "total", "pageSize", "page"], outputs: ["pageChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: StrctCheckbox, selector: "strct-checkbox", inputs: ["checked", "disabled", "indeterminate", "ariaLabel"], outputs: ["checkedChange"] }, { kind: "component", type: StrctButton, selector: "button[strct-button], a[strct-button]", inputs: ["variant", "size", "solid", "block", "iconOnly"] }, { kind: "component", type: StrctButtonGroup, selector: "strct-button-group" }, { kind: "directive", type: StrctOverlay, selector: "[strctOverlay]", inputs: ["strctOverlay", "strctOverlayPlacement", "strctOverlayMatchWidth", "strctOverlayGap"] }, { 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 });
|
|
14252
|
+
`, isInline: true, styles: [".strct-dg__radio{width:15px;height:15px;accent-color:var(--acc);cursor:pointer}.strct-dg__radio:disabled{cursor:not-allowed}.strct-dg__row--locked .strct-dg__sel{opacity:.55}.strct-dg__actioncaption:empty{display:none}.strct-dg__actioncaption{display:inline-flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);color:var(--t3)}.strct-dg-host{display:block;border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg-host--virtual .strct-dg__scroll{overflow-y:auto}.strct-dg-host--virtual .strct-dg thead th{position:sticky;top:0;z-index:var(--z-raised)}.strct-dg__vspacer td{padding:0;border:0;background:transparent}.strct-dg th[draggable]{cursor:grab}.strct-dg__th--drop{box-shadow:inset 3px 0 0 var(--acc)}.strct-dg__grouprow td{background:var(--bg-2)!important;padding:0}.strct-dg__groupbtn{display:flex;align-items:center;gap:8px;width:100%;padding:7px 13px;border:0;background:transparent;color:var(--t1);font-family:var(--font);font-size:12.5px;font-weight:600;cursor:pointer;text-align:start}.strct-dg__groupbtn:hover{background:var(--bg-3)}.strct-dg__groupbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__groupchev{display:inline-flex;color:var(--t3);transition:transform .15s ease}.strct-dg__groupchev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-dg__groupchev{transition:none}}.strct-dg__groupcount{min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;border-radius:9px;background:var(--acc-m);color:var(--acc);font-variant-numeric:tabular-nums}.strct-dg-host--sticky .strct-dg,.strct-dg-host--virtual .strct-dg{border-collapse:separate;border-spacing:0;overflow:visible;border-radius:0}.strct-dg-host--sticky .strct-dg{width:max-content;min-width:100%}.strct-dg .strct-dg__cell--sticky{position:sticky;z-index:calc(var(--z-base) + 2)}.strct-dg thead th.strct-dg__cell--sticky{z-index:calc(var(--z-raised) + 1)}.strct-dg .strct-dg__cell--sticky-last:after{content:\"\";position:absolute;top:0;bottom:0;inset-inline-end:-1px;width:7px;pointer-events:none;background:linear-gradient(to right,rgba(0,0,0,.14),transparent)}[dir=rtl] .strct-dg .strct-dg__cell--sticky-last:after{background:linear-gradient(to left,rgba(0,0,0,.14),transparent)}.strct-dg-host--sticky .strct-dg__expandcol,.strct-dg-host--sticky .strct-dg__expandcell{width:36px;min-width:36px;max-width:36px;box-sizing:border-box}.strct-dg-host--sticky .strct-dg__sel{width:40px;min-width:40px;max-width:40px;box-sizing:border-box}.strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-3)}.strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:9px;border-start-end-radius:9px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:9px;border-end-end-radius:9px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;inset-inline-end:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:calc(var(--z-base) + 1)}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:var(--acc-s)}.strct-dg__row--selected td{background:var(--acc-m)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned .strct-dg__scroll{flex:0 0 auto;width:260px;min-width:260px;max-width:260px}.strct-dg__layout--paned .strct-dg{width:260px;min-width:260px;max-width:260px;flex-shrink:0;border-start-end-radius:0;border-end-end-radius:0}.strct-dg__row--clickable{cursor:pointer}.strct-dg__row--active td{background:var(--acc-m)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;inset-inline-end:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:8px;border-start-start-radius:0;border-end-start-radius:0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;border-radius:var(--radius-sm);background:linear-gradient(90deg,var(--bg-3) 25%,var(--skeleton-hi, var(--acc18)) 50%,var(--bg-3) 75%);background-size:200% 100%;animation:strct-dg-skeleton-sweep 1.1s linear infinite}@keyframes strct-dg-skeleton-sweep{0%{background-position:100% 0}to{background-position:-100% 0}}@media(prefers-reduced-motion:reduce){.strct-dg__skeleton-block{animation:none;background:var(--skeleton-hi, var(--acc18))}}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t3);padding:22px}.strct-dg__quickfilter{min-width:180px;max-width:260px}.strct-dg__quickfilter--end{order:2;margin-inline-start:auto}.strct-dg__filternote--end{order:3}.strct-dg__filternote{font-size:11.5px;color:var(--t3);font-variant-numeric:tabular-nums;white-space:nowrap}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);inset-inline-start:0;z-index:var(--z-sticky);min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:8px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{inset-inline-start:auto;inset-inline-end:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}.strct-dg__filterbtn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-inline-start:2px;padding:0;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__filterbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__filterbtn--active{color:var(--acc)}.strct-dg__filterbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filterpanel{position:absolute;z-index:calc(var(--z-dropdown) + 10);display:flex;flex-direction:column;gap:6px;min-width:180px;padding:10px;background:var(--bg-1);border:1px solid var(--b2);border-radius:7px;box-shadow:var(--shh);font-weight:400;text-transform:none;letter-spacing:normal;white-space:nowrap}.strct-dg__filterinput{padding:5px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:var(--bg-2);color:var(--t1);font-family:var(--font);font-size:12px}.strct-dg__filterinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filteropt{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--t1);cursor:pointer}.strct-dg__filterclear{align-self:flex-start;padding:3px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:transparent;color:var(--t2);font-family:var(--font);font-size:11.5px;cursor:pointer}.strct-dg__filterclear:hover:not(:disabled){color:var(--t1);background:var(--bg-3)}.strct-dg__filterclear:disabled{color:var(--t4);cursor:default}.strct-dg tbody tr[tabindex]:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__treepad{display:inline-block;height:1px;vertical-align:middle}.strct-dg__treebtn{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-inline-end:4px;padding:0;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__treebtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__treebtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__treebtn strct-icon{transition:transform .15s ease}.strct-dg__treebtn--open strct-icon{transform:rotate(90deg)}.strct-dg__treebtn--leaf{cursor:default;pointer-events:none}@media(prefers-reduced-motion:reduce){.strct-dg__treebtn strct-icon{transition:none}}.strct-dg__cell--editable{cursor:text}.strct-dg__cell--editable:hover{box-shadow:inset 0 0 0 1px var(--b2)}.strct-dg__editinput{width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid var(--acc);border-radius:var(--radius-sm);background:var(--bg-1);color:var(--t1);font:inherit}.strct-dg__editselect,.strct-dg__editnumber{display:block;width:100%}.strct-dg__editinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctPagination, selector: "strct-pagination", inputs: ["prevLabel", "nextLabel", "regionLabel", "pageLabel", "total", "pageSize", "page"], outputs: ["pageChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: StrctCheckbox, selector: "strct-checkbox", inputs: ["checked", "disabled", "indeterminate", "ariaLabel"], outputs: ["checkedChange"] }, { kind: "component", type: StrctButton, selector: "button[strct-button], a[strct-button]", inputs: ["variant", "size", "solid", "block", "iconOnly"] }, { kind: "component", type: StrctButtonGroup, selector: "strct-button-group" }, { kind: "directive", type: StrctOverlay, selector: "[strctOverlay]", inputs: ["strctOverlay", "strctOverlayPlacement", "strctOverlayMatchWidth", "strctOverlayGap"] }, { kind: "component", type: StrctSearchbox, selector: "strct-searchbox", inputs: ["placeholder", "hint", "trigger", "clearable", "ariaLabel", "clearLabel", "value"], outputs: ["valueChange", "search", "activated"] }, { kind: "component", type: StrctSelect, selector: "strct-select", inputs: ["options", "placeholder", "listLabel", "emptyText", "disabled", "compareWith"] }, { kind: "component", type: StrctNumber, selector: "strct-number", inputs: ["min", "max", "step", "placeholder", "incrementLabel", "decrementLabel", "disabled"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
13763
14253
|
}
|
|
13764
14254
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctDatagrid, decorators: [{
|
|
13765
14255
|
type: Component,
|
|
@@ -13772,6 +14262,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
13772
14262
|
StrctButtonGroup,
|
|
13773
14263
|
StrctOverlay,
|
|
13774
14264
|
StrctSearchbox,
|
|
14265
|
+
StrctSelect,
|
|
14266
|
+
StrctNumber,
|
|
14267
|
+
FormsModule,
|
|
13775
14268
|
], template: `
|
|
13776
14269
|
@if (actionBarDef() || quickFilterable()) {
|
|
13777
14270
|
<div class="strct-dg__toolbar">
|
|
@@ -14136,16 +14629,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
14136
14629
|
}
|
|
14137
14630
|
}
|
|
14138
14631
|
@if (isEditingCell(row, col)) {
|
|
14139
|
-
|
|
14140
|
-
|
|
14141
|
-
|
|
14142
|
-
|
|
14143
|
-
|
|
14144
|
-
|
|
14145
|
-
|
|
14146
|
-
|
|
14147
|
-
|
|
14148
|
-
|
|
14632
|
+
@switch (col.editor ?? 'text') {
|
|
14633
|
+
@case ('select') {
|
|
14634
|
+
<!-- Choosing is the commit: there is nothing to
|
|
14635
|
+
confirm with Enter once an option is picked. -->
|
|
14636
|
+
<strct-select
|
|
14637
|
+
class="strct-dg__editselect"
|
|
14638
|
+
[options]="col.editorOptions ?? []"
|
|
14639
|
+
[listLabel]="L().editCell + ': ' + col.label"
|
|
14640
|
+
[ngModel]="row[col.key]"
|
|
14641
|
+
(ngModelChange)="commitValue(row, col, $event)"
|
|
14642
|
+
(keydown.escape)="cancelEdit($event)"
|
|
14643
|
+
(click)="$event.stopPropagation()"
|
|
14644
|
+
/>
|
|
14645
|
+
}
|
|
14646
|
+
@case ('number') {
|
|
14647
|
+
<strct-number
|
|
14648
|
+
class="strct-dg__editnumber"
|
|
14649
|
+
[min]="col.editorMin ?? null"
|
|
14650
|
+
[max]="col.editorMax ?? null"
|
|
14651
|
+
[step]="col.editorStep ?? 1"
|
|
14652
|
+
[ngModel]="row[col.key]"
|
|
14653
|
+
(ngModelChange)="editDraft.set($event)"
|
|
14654
|
+
(keydown.enter)="commitDraft(row, col, $event)"
|
|
14655
|
+
(keydown.escape)="cancelEdit($event)"
|
|
14656
|
+
(focusout)="commitOnLeave(row, col, $event)"
|
|
14657
|
+
(click)="$event.stopPropagation()"
|
|
14658
|
+
/>
|
|
14659
|
+
}
|
|
14660
|
+
@default {
|
|
14661
|
+
<input
|
|
14662
|
+
class="strct-dg__editinput"
|
|
14663
|
+
type="text"
|
|
14664
|
+
[value]="row[col.key] ?? ''"
|
|
14665
|
+
[attr.aria-label]="L().editCell + ': ' + col.label"
|
|
14666
|
+
(keydown.enter)="commitEdit(row, col, $event)"
|
|
14667
|
+
(keydown.escape)="cancelEdit($event)"
|
|
14668
|
+
(blur)="commitEdit(row, col, $event)"
|
|
14669
|
+
(click)="$event.stopPropagation()"
|
|
14670
|
+
/>
|
|
14671
|
+
}
|
|
14672
|
+
}
|
|
14149
14673
|
} @else if (cellTemplate(col.key); as tpl) {
|
|
14150
14674
|
<ng-container
|
|
14151
14675
|
[ngTemplateOutlet]="tpl"
|
|
@@ -14157,7 +14681,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
14157
14681
|
}"
|
|
14158
14682
|
/>
|
|
14159
14683
|
} @else {
|
|
14160
|
-
{{ row
|
|
14684
|
+
{{ displayValue(row, col) }}
|
|
14161
14685
|
}
|
|
14162
14686
|
</td>
|
|
14163
14687
|
}
|
|
@@ -14298,7 +14822,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
14298
14822
|
'[class.strct-dg-host--singleline]': 'singleLine()',
|
|
14299
14823
|
'[class.strct-dg-host--virtual]': 'virtual()',
|
|
14300
14824
|
'[class.strct-dg-host--sticky]': 'stickyActive()',
|
|
14301
|
-
}, styles: [".strct-dg__radio{width:15px;height:15px;accent-color:var(--acc);cursor:pointer}.strct-dg__radio:disabled{cursor:not-allowed}.strct-dg__row--locked .strct-dg__sel{opacity:.55}.strct-dg__actioncaption:empty{display:none}.strct-dg__actioncaption{display:inline-flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);color:var(--t3)}.strct-dg-host{display:block;border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg-host--virtual .strct-dg__scroll{overflow-y:auto}.strct-dg-host--virtual .strct-dg thead th{position:sticky;top:0;z-index:var(--z-raised)}.strct-dg__vspacer td{padding:0;border:0;background:transparent}.strct-dg th[draggable]{cursor:grab}.strct-dg__th--drop{box-shadow:inset 3px 0 0 var(--acc)}.strct-dg__grouprow td{background:var(--bg-2)!important;padding:0}.strct-dg__groupbtn{display:flex;align-items:center;gap:8px;width:100%;padding:7px 13px;border:0;background:transparent;color:var(--t1);font-family:var(--font);font-size:12.5px;font-weight:600;cursor:pointer;text-align:start}.strct-dg__groupbtn:hover{background:var(--bg-3)}.strct-dg__groupbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__groupchev{display:inline-flex;color:var(--t3);transition:transform .15s ease}.strct-dg__groupchev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-dg__groupchev{transition:none}}.strct-dg__groupcount{min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;border-radius:9px;background:var(--acc-m);color:var(--acc);font-variant-numeric:tabular-nums}.strct-dg-host--sticky .strct-dg,.strct-dg-host--virtual .strct-dg{border-collapse:separate;border-spacing:0;overflow:visible;border-radius:0}.strct-dg-host--sticky .strct-dg{width:max-content;min-width:100%}.strct-dg .strct-dg__cell--sticky{position:sticky;z-index:calc(var(--z-base) + 2)}.strct-dg thead th.strct-dg__cell--sticky{z-index:calc(var(--z-raised) + 1)}.strct-dg .strct-dg__cell--sticky-last:after{content:\"\";position:absolute;top:0;bottom:0;inset-inline-end:-1px;width:7px;pointer-events:none;background:linear-gradient(to right,rgba(0,0,0,.14),transparent)}[dir=rtl] .strct-dg .strct-dg__cell--sticky-last:after{background:linear-gradient(to left,rgba(0,0,0,.14),transparent)}.strct-dg-host--sticky .strct-dg__expandcol,.strct-dg-host--sticky .strct-dg__expandcell{width:36px;min-width:36px;max-width:36px;box-sizing:border-box}.strct-dg-host--sticky .strct-dg__sel{width:40px;min-width:40px;max-width:40px;box-sizing:border-box}.strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-3)}.strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:9px;border-start-end-radius:9px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:9px;border-end-end-radius:9px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;inset-inline-end:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:calc(var(--z-base) + 1)}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:var(--acc-s)}.strct-dg__row--selected td{background:var(--acc-m)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned .strct-dg__scroll{flex:0 0 auto;width:260px;min-width:260px;max-width:260px}.strct-dg__layout--paned .strct-dg{width:260px;min-width:260px;max-width:260px;flex-shrink:0;border-start-end-radius:0;border-end-end-radius:0}.strct-dg__row--clickable{cursor:pointer}.strct-dg__row--active td{background:var(--acc-m)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;inset-inline-end:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:8px;border-start-start-radius:0;border-end-start-radius:0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;border-radius:var(--radius-sm);background:linear-gradient(90deg,var(--bg-3) 25%,var(--skeleton-hi, var(--acc18)) 50%,var(--bg-3) 75%);background-size:200% 100%;animation:strct-dg-skeleton-sweep 1.1s linear infinite}@keyframes strct-dg-skeleton-sweep{0%{background-position:100% 0}to{background-position:-100% 0}}@media(prefers-reduced-motion:reduce){.strct-dg__skeleton-block{animation:none;background:var(--skeleton-hi, var(--acc18))}}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t3);padding:22px}.strct-dg__quickfilter{min-width:180px;max-width:260px}.strct-dg__quickfilter--end{order:2;margin-inline-start:auto}.strct-dg__filternote--end{order:3}.strct-dg__filternote{font-size:11.5px;color:var(--t3);font-variant-numeric:tabular-nums;white-space:nowrap}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);inset-inline-start:0;z-index:var(--z-sticky);min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:8px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{inset-inline-start:auto;inset-inline-end:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}.strct-dg__filterbtn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-inline-start:2px;padding:0;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__filterbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__filterbtn--active{color:var(--acc)}.strct-dg__filterbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filterpanel{position:absolute;z-index:calc(var(--z-dropdown) + 10);display:flex;flex-direction:column;gap:6px;min-width:180px;padding:10px;background:var(--bg-1);border:1px solid var(--b2);border-radius:7px;box-shadow:var(--shh);font-weight:400;text-transform:none;letter-spacing:normal;white-space:nowrap}.strct-dg__filterinput{padding:5px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:var(--bg-2);color:var(--t1);font-family:var(--font);font-size:12px}.strct-dg__filterinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filteropt{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--t1);cursor:pointer}.strct-dg__filterclear{align-self:flex-start;padding:3px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:transparent;color:var(--t2);font-family:var(--font);font-size:11.5px;cursor:pointer}.strct-dg__filterclear:hover:not(:disabled){color:var(--t1);background:var(--bg-3)}.strct-dg__filterclear:disabled{color:var(--t4);cursor:default}.strct-dg tbody tr[tabindex]:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__treepad{display:inline-block;height:1px;vertical-align:middle}.strct-dg__treebtn{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-inline-end:4px;padding:0;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__treebtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__treebtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__treebtn strct-icon{transition:transform .15s ease}.strct-dg__treebtn--open strct-icon{transform:rotate(90deg)}.strct-dg__treebtn--leaf{cursor:default;pointer-events:none}@media(prefers-reduced-motion:reduce){.strct-dg__treebtn strct-icon{transition:none}}.strct-dg__cell--editable{cursor:text}.strct-dg__cell--editable:hover{box-shadow:inset 0 0 0 1px var(--b2)}.strct-dg__editinput{width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid var(--acc);border-radius:var(--radius-sm);background:var(--bg-1);color:var(--t1);font:inherit}.strct-dg__editinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}\n"] }]
|
|
14825
|
+
}, styles: [".strct-dg__radio{width:15px;height:15px;accent-color:var(--acc);cursor:pointer}.strct-dg__radio:disabled{cursor:not-allowed}.strct-dg__row--locked .strct-dg__sel{opacity:.55}.strct-dg__actioncaption:empty{display:none}.strct-dg__actioncaption{display:inline-flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--text-sm);color:var(--t3)}.strct-dg-host{display:block;border:1px solid var(--b2);border-radius:var(--radius-lg);background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg-host--virtual .strct-dg__scroll{overflow-y:auto}.strct-dg-host--virtual .strct-dg thead th{position:sticky;top:0;z-index:var(--z-raised)}.strct-dg__vspacer td{padding:0;border:0;background:transparent}.strct-dg th[draggable]{cursor:grab}.strct-dg__th--drop{box-shadow:inset 3px 0 0 var(--acc)}.strct-dg__grouprow td{background:var(--bg-2)!important;padding:0}.strct-dg__groupbtn{display:flex;align-items:center;gap:8px;width:100%;padding:7px 13px;border:0;background:transparent;color:var(--t1);font-family:var(--font);font-size:12.5px;font-weight:600;cursor:pointer;text-align:start}.strct-dg__groupbtn:hover{background:var(--bg-3)}.strct-dg__groupbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__groupchev{display:inline-flex;color:var(--t3);transition:transform .15s ease}.strct-dg__groupchev--open{transform:rotate(90deg)}@media(prefers-reduced-motion:reduce){.strct-dg__groupchev{transition:none}}.strct-dg__groupcount{min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;border-radius:9px;background:var(--acc-m);color:var(--acc);font-variant-numeric:tabular-nums}.strct-dg-host--sticky .strct-dg,.strct-dg-host--virtual .strct-dg{border-collapse:separate;border-spacing:0;overflow:visible;border-radius:0}.strct-dg-host--sticky .strct-dg{width:max-content;min-width:100%}.strct-dg .strct-dg__cell--sticky{position:sticky;z-index:calc(var(--z-base) + 2)}.strct-dg thead th.strct-dg__cell--sticky{z-index:calc(var(--z-raised) + 1)}.strct-dg .strct-dg__cell--sticky-last:after{content:\"\";position:absolute;top:0;bottom:0;inset-inline-end:-1px;width:7px;pointer-events:none;background:linear-gradient(to right,rgba(0,0,0,.14),transparent)}[dir=rtl] .strct-dg .strct-dg__cell--sticky-last:after{background:linear-gradient(to left,rgba(0,0,0,.14),transparent)}.strct-dg-host--sticky .strct-dg__expandcol,.strct-dg-host--sticky .strct-dg__expandcell{width:36px;min-width:36px;max-width:36px;box-sizing:border-box}.strct-dg-host--sticky .strct-dg__sel{width:40px;min-width:40px;max-width:40px;box-sizing:border-box}.strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-3)}.strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:9px;border-start-end-radius:9px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:9px;border-end-end-radius:9px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;inset-inline-end:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:calc(var(--z-base) + 1)}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:var(--acc-s)}.strct-dg__row--selected td{background:var(--acc-m)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned .strct-dg__scroll{flex:0 0 auto;width:260px;min-width:260px;max-width:260px}.strct-dg__layout--paned .strct-dg{width:260px;min-width:260px;max-width:260px;flex-shrink:0;border-start-end-radius:0;border-end-end-radius:0}.strct-dg__row--clickable{cursor:pointer}.strct-dg__row--active td{background:var(--acc-m)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;inset-inline-end:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:8px;border-start-start-radius:0;border-end-start-radius:0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;border-radius:var(--radius-sm);background:linear-gradient(90deg,var(--bg-3) 25%,var(--skeleton-hi, var(--acc18)) 50%,var(--bg-3) 75%);background-size:200% 100%;animation:strct-dg-skeleton-sweep 1.1s linear infinite}@keyframes strct-dg-skeleton-sweep{0%{background-position:100% 0}to{background-position:-100% 0}}@media(prefers-reduced-motion:reduce){.strct-dg__skeleton-block{animation:none;background:var(--skeleton-hi, var(--acc18))}}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t3);padding:22px}.strct-dg__quickfilter{min-width:180px;max-width:260px}.strct-dg__quickfilter--end{order:2;margin-inline-start:auto}.strct-dg__filternote--end{order:3}.strct-dg__filternote{font-size:11.5px;color:var(--t3);font-variant-numeric:tabular-nums;white-space:nowrap}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);inset-inline-start:0;z-index:var(--z-sticky);min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:8px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{inset-inline-start:auto;inset-inline-end:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}.strct-dg__filterbtn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-inline-start:2px;padding:0;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__filterbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__filterbtn--active{color:var(--acc)}.strct-dg__filterbtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filterpanel{position:absolute;z-index:calc(var(--z-dropdown) + 10);display:flex;flex-direction:column;gap:6px;min-width:180px;padding:10px;background:var(--bg-1);border:1px solid var(--b2);border-radius:7px;box-shadow:var(--shh);font-weight:400;text-transform:none;letter-spacing:normal;white-space:nowrap}.strct-dg__filterinput{padding:5px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:var(--bg-2);color:var(--t1);font-family:var(--font);font-size:12px}.strct-dg__filterinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__filteropt{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--t1);cursor:pointer}.strct-dg__filterclear{align-self:flex-start;padding:3px 8px;border:1px solid var(--b2);border-radius:var(--radius-sm);background:transparent;color:var(--t2);font-family:var(--font);font-size:11.5px;cursor:pointer}.strct-dg__filterclear:hover:not(:disabled){color:var(--t1);background:var(--bg-3)}.strct-dg__filterclear:disabled{color:var(--t4);cursor:default}.strct-dg tbody tr[tabindex]:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__treepad{display:inline-block;height:1px;vertical-align:middle}.strct-dg__treebtn{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-inline-end:4px;padding:0;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;vertical-align:middle}.strct-dg__treebtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__treebtn:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-dg__treebtn strct-icon{transition:transform .15s ease}.strct-dg__treebtn--open strct-icon{transform:rotate(90deg)}.strct-dg__treebtn--leaf{cursor:default;pointer-events:none}@media(prefers-reduced-motion:reduce){.strct-dg__treebtn strct-icon{transition:none}}.strct-dg__cell--editable{cursor:text}.strct-dg__cell--editable:hover{box-shadow:inset 0 0 0 1px var(--b2)}.strct-dg__editinput{width:100%;box-sizing:border-box;padding:3px 6px;border:1px solid var(--acc);border-radius:var(--radius-sm);background:var(--bg-1);color:var(--t1);font:inherit}.strct-dg__editselect,.strct-dg__editnumber{display:block;width:100%}.strct-dg__editinput:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}\n"] }]
|
|
14302
14826
|
}], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], expandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandable", required: false }] }], detailPane: [{ type: i0.Input, args: [{ isSignal: true, alias: "detailPane", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], singleLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "singleLine", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], columnChooser: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnChooser", required: false }] }], sync: [{ type: i0.Input, args: [{ isSignal: true, alias: "sync", required: false }] }], footerActionsDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerActionsDisabled", required: false }] }], rowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowId", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], selectedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedId", required: false }] }, { type: i0.Output, args: ["selectedIdChange"] }], rowSelectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSelectable", required: false }] }], groupSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupSelect", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], initialSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSelection", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], virtual: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtual", required: false }] }], viewportHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewportHeight", required: false }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: false }] }], stateKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateKey", required: false }] }], columnState: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnState", required: false }] }, { type: i0.Output, args: ["columnStateChange"] }], reorderable: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderable", required: false }] }], groupBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }, { type: i0.Output, args: ["filtersChange"] }], quickFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickFilter", required: false }] }, { type: i0.Output, args: ["quickFilterChange"] }], quickFilterFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickFilterFields", required: false }] }], quickFilterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickFilterable", required: false }] }], quickFilterAlign: [{ type: i0.Input, args: [{ isSignal: true, alias: "quickFilterAlign", required: false }] }], childrenKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "childrenKey", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], syncChange: [{ type: i0.Output, args: ["syncChange"] }], rowAction: [{ type: i0.Output, args: ["rowAction"] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }], cellEdit: [{ type: i0.Output, args: ["cellEdit"] }], detailDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctRowDetailDef), { isSignal: true }] }], actionBarDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctDatagridActionBar), { isSignal: true }] }], cellDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctCellDef), { isSignal: true }] }], onDocClickOverlays: [{
|
|
14303
14827
|
type: HostListener,
|
|
14304
14828
|
args: ['document:click', ['$event']]
|
|
@@ -19699,1441 +20223,1167 @@ class StrctTour {
|
|
|
19699
20223
|
const w = 300;
|
|
19700
20224
|
const h = 170;
|
|
19701
20225
|
if (!r) {
|
|
19702
|
-
return {
|
|
19703
|
-
top: Math.max(20, window.innerHeight / 2 - h / 2),
|
|
19704
|
-
left: Math.max(20, window.innerWidth / 2 - w / 2),
|
|
19705
|
-
};
|
|
19706
|
-
}
|
|
19707
|
-
// Below the target if it fits, else above; clamped into the viewport.
|
|
19708
|
-
let top = r.top + r.height + 14;
|
|
19709
|
-
if (top + h > window.innerHeight - 12)
|
|
19710
|
-
top = Math.max(12, r.top - h - 14);
|
|
19711
|
-
const left = Math.min(Math.max(12, r.left), window.innerWidth - w - 12);
|
|
19712
|
-
return { top, left };
|
|
19713
|
-
}, /* @ts-ignore */
|
|
19714
|
-
...(ngDevMode ? [{ debugName: "cardPos" }] : /* istanbul ignore next */ []));
|
|
19715
|
-
constructor() {
|
|
19716
|
-
// Restart from step 0 on open; scroll the first target into view.
|
|
19717
|
-
effect(() => {
|
|
19718
|
-
if (this.open()) {
|
|
19719
|
-
this.previousActive = saveFocusedElement();
|
|
19720
|
-
this.index.set(0);
|
|
19721
|
-
this.scrollToTarget();
|
|
19722
|
-
this.focusNextButton();
|
|
19723
|
-
}
|
|
19724
|
-
else {
|
|
19725
|
-
restoreFocus(this.previousActive);
|
|
19726
|
-
this.previousActive = null;
|
|
19727
|
-
}
|
|
19728
|
-
});
|
|
19729
|
-
}
|
|
19730
|
-
next() {
|
|
19731
|
-
if (this.index() >= this.steps().length - 1) {
|
|
19732
|
-
this.open.set(false);
|
|
19733
|
-
this.finished.emit();
|
|
19734
|
-
return;
|
|
19735
|
-
}
|
|
19736
|
-
this.index.update((i) => i + 1);
|
|
19737
|
-
this.scrollToTarget();
|
|
19738
|
-
this.focusNextButton();
|
|
19739
|
-
}
|
|
19740
|
-
prev() {
|
|
19741
|
-
this.index.update((i) => Math.max(0, i - 1));
|
|
19742
|
-
this.scrollToTarget();
|
|
19743
|
-
this.focusNextButton();
|
|
19744
|
-
}
|
|
19745
|
-
close() {
|
|
19746
|
-
this.open.set(false);
|
|
19747
|
-
this.dismissed.emit();
|
|
19748
|
-
}
|
|
19749
|
-
/** Wrap Tab focus within the card. */
|
|
19750
|
-
onTab(event) {
|
|
19751
|
-
const card = this.card();
|
|
19752
|
-
if (card)
|
|
19753
|
-
keepTabInside(event, card);
|
|
19754
|
-
}
|
|
19755
|
-
/** Escape closes; stopPropagation so a host modal/drawer does not also close. */
|
|
19756
|
-
onEscapeKey(event) {
|
|
19757
|
-
event.stopPropagation();
|
|
19758
|
-
this.close();
|
|
19759
|
-
}
|
|
19760
|
-
/**
|
|
19761
|
-
* Arrow keys step through the tour, mirrored under RTL. No shared direction
|
|
19762
|
-
* helper exists (other components handle RTL in CSS only), so read the
|
|
19763
|
-
* card's computed direction here.
|
|
19764
|
-
*/
|
|
19765
|
-
onArrow(event, dir) {
|
|
19766
|
-
event.preventDefault();
|
|
19767
|
-
const rtl = getComputedStyle(event.currentTarget).direction === 'rtl';
|
|
19768
|
-
if ((dir === 'right') !== rtl)
|
|
19769
|
-
this.next();
|
|
19770
|
-
else
|
|
19771
|
-
this.prev();
|
|
19772
|
-
}
|
|
19773
|
-
/** Home/End jump to the first/last step. */
|
|
19774
|
-
onHomeEnd(event, last) {
|
|
19775
|
-
event.preventDefault();
|
|
19776
|
-
this.index.set(last ? this.steps().length - 1 : 0);
|
|
19777
|
-
this.scrollToTarget();
|
|
19778
|
-
this.focusNextButton();
|
|
19779
|
-
}
|
|
19780
|
-
scrollToTarget() {
|
|
19781
|
-
setTimeout(() => {
|
|
19782
|
-
const sel = this.steps()[this.index()]?.target;
|
|
19783
|
-
if (sel)
|
|
19784
|
-
document.querySelector(sel)?.scrollIntoView?.({ block: 'center' });
|
|
19785
|
-
this.measureTick.update((n) => n + 1);
|
|
19786
|
-
});
|
|
19787
|
-
}
|
|
19788
|
-
card() {
|
|
19789
|
-
return this.elementRef.nativeElement.querySelector('.strct-tour__card');
|
|
19790
|
-
}
|
|
19791
|
-
/** Move focus to the step's primary (Next/Done) action once the card has rendered. */
|
|
19792
|
-
focusNextButton() {
|
|
19793
|
-
setTimeout(() => {
|
|
19794
|
-
if (!this.open())
|
|
19795
|
-
return;
|
|
19796
|
-
const card = this.card();
|
|
19797
|
-
if (!card)
|
|
19798
|
-
return;
|
|
19799
|
-
const nav = card.querySelectorAll('.strct-tour__nav button');
|
|
19800
|
-
const primary = nav[nav.length - 1];
|
|
19801
|
-
if (primary)
|
|
19802
|
-
primary.focus();
|
|
19803
|
-
else
|
|
19804
|
-
focusFirstIn(card);
|
|
19805
|
-
});
|
|
19806
|
-
}
|
|
19807
|
-
onReflow() {
|
|
19808
|
-
if (this.open())
|
|
19809
|
-
this.measureTick.update((n) => n + 1);
|
|
19810
|
-
}
|
|
19811
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctTour, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
19812
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctTour, isStandalone: true, selector: "strct-tour", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: true, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null }, skipLabel: { classPropertyName: "skipLabel", publicName: "skipLabel", isSignal: true, isRequired: false, transformFunction: null }, doneLabel: { classPropertyName: "doneLabel", publicName: "doneLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", finished: "finished", dismissed: "dismissed" }, host: { listeners: { "window:resize": "onReflow()", "window:scroll": "onReflow()" } }, ngImport: i0, template: `
|
|
19813
|
-
@if (open() && current(); as step) {
|
|
19814
|
-
<!-- Always the click-catcher; dims only when no ring (its shadow dims). -->
|
|
19815
|
-
<div
|
|
19816
|
-
class="strct-tour__backdrop"
|
|
19817
|
-
[class.strct-tour__backdrop--dim]="!spot()"
|
|
19818
|
-
(click)="close()"
|
|
19819
|
-
></div>
|
|
19820
|
-
@if (spot(); as r) {
|
|
19821
|
-
<div
|
|
19822
|
-
class="strct-tour__ring"
|
|
19823
|
-
[style.top.px]="r.top - 6"
|
|
19824
|
-
[style.left.px]="r.left - 6"
|
|
19825
|
-
[style.width.px]="r.width + 12"
|
|
19826
|
-
[style.height.px]="r.height + 12"
|
|
19827
|
-
></div>
|
|
19828
|
-
}
|
|
19829
|
-
<div
|
|
19830
|
-
class="strct-tour__card"
|
|
19831
|
-
role="dialog"
|
|
19832
|
-
[attr.aria-labelledby]="titleId"
|
|
19833
|
-
[style.top.px]="cardPos().top"
|
|
19834
|
-
[style.left.px]="cardPos().left"
|
|
19835
|
-
(keydown.tab)="onTab($event)"
|
|
19836
|
-
(keydown.shift.tab)="onTab($event)"
|
|
19837
|
-
(keydown.escape)="onEscapeKey($event)"
|
|
19838
|
-
(keydown.arrowleft)="onArrow($event, 'left')"
|
|
19839
|
-
(keydown.arrowright)="onArrow($event, 'right')"
|
|
19840
|
-
(keydown.home)="onHomeEnd($event, false)"
|
|
19841
|
-
(keydown.end)="onHomeEnd($event, true)"
|
|
19842
|
-
>
|
|
19843
|
-
<div class="strct-tour__step">{{ index() + 1 }} / {{ steps().length }}</div>
|
|
19844
|
-
<div class="strct-tour__title" [id]="titleId">{{ step.title }}</div>
|
|
19845
|
-
<div class="strct-tour__body">{{ step.body }}</div>
|
|
19846
|
-
<div class="strct-tour__nav">
|
|
19847
|
-
<button strct-button size="sm" variant="flat" (click)="close()">
|
|
19848
|
-
{{ skipLabel() }}
|
|
19849
|
-
</button>
|
|
19850
|
-
<span class="strct-tour__grow"></span>
|
|
19851
|
-
@if (index() > 0) {
|
|
19852
|
-
<button strct-button size="sm" variant="neutral" (click)="prev()">
|
|
19853
|
-
{{ backLabel() }}
|
|
19854
|
-
</button>
|
|
19855
|
-
}
|
|
19856
|
-
<button strct-button size="sm" variant="primary" solid (click)="next()">
|
|
19857
|
-
{{ index() === steps().length - 1 ? doneLabel() : nextLabel() }}
|
|
19858
|
-
</button>
|
|
19859
|
-
</div>
|
|
19860
|
-
</div>
|
|
19861
|
-
}
|
|
19862
|
-
`, isInline: true, styles: [".strct-tour__backdrop{position:fixed;inset:0;z-index:var(--z-tour);background:transparent}.strct-tour__backdrop--dim{background:var(--backdrop)}.strct-tour__ring{position:fixed;z-index:calc(var(--z-tour) + 1);border:2px solid var(--acc);border-radius:9px;box-shadow:0 0 0 4px var(--acc30),0 0 0 9999px var(--backdrop);pointer-events:none}.strct-tour__card{position:fixed;z-index:calc(var(--z-tour) + 2);width:300px;padding:14px 16px;background:var(--bg-1);border:1px solid var(--b2);border-radius:9px;box-shadow:var(--shh)}.strct-tour__step{font-size:10.5px;font-weight:600;letter-spacing:.6px;color:var(--t3);margin-bottom:4px;font-variant-numeric:tabular-nums}.strct-tour__title{font-size:13.5px;font-weight:650;color:var(--t1);margin-bottom:6px}.strct-tour__body{font-size:12.5px;line-height:1.5;color:var(--t2);margin-bottom:12px}.strct-tour__nav{display:flex;align-items:center;gap:8px}.strct-tour__grow{flex:1}\n"], dependencies: [{ kind: "component", type: StrctButton, selector: "button[strct-button], a[strct-button]", inputs: ["variant", "size", "solid", "block", "iconOnly"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
19863
|
-
}
|
|
19864
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctTour, decorators: [{
|
|
19865
|
-
type: Component,
|
|
19866
|
-
args: [{ selector: 'strct-tour', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctButton], template: `
|
|
19867
|
-
@if (open() && current(); as step) {
|
|
19868
|
-
<!-- Always the click-catcher; dims only when no ring (its shadow dims). -->
|
|
19869
|
-
<div
|
|
19870
|
-
class="strct-tour__backdrop"
|
|
19871
|
-
[class.strct-tour__backdrop--dim]="!spot()"
|
|
19872
|
-
(click)="close()"
|
|
19873
|
-
></div>
|
|
19874
|
-
@if (spot(); as r) {
|
|
19875
|
-
<div
|
|
19876
|
-
class="strct-tour__ring"
|
|
19877
|
-
[style.top.px]="r.top - 6"
|
|
19878
|
-
[style.left.px]="r.left - 6"
|
|
19879
|
-
[style.width.px]="r.width + 12"
|
|
19880
|
-
[style.height.px]="r.height + 12"
|
|
19881
|
-
></div>
|
|
19882
|
-
}
|
|
19883
|
-
<div
|
|
19884
|
-
class="strct-tour__card"
|
|
19885
|
-
role="dialog"
|
|
19886
|
-
[attr.aria-labelledby]="titleId"
|
|
19887
|
-
[style.top.px]="cardPos().top"
|
|
19888
|
-
[style.left.px]="cardPos().left"
|
|
19889
|
-
(keydown.tab)="onTab($event)"
|
|
19890
|
-
(keydown.shift.tab)="onTab($event)"
|
|
19891
|
-
(keydown.escape)="onEscapeKey($event)"
|
|
19892
|
-
(keydown.arrowleft)="onArrow($event, 'left')"
|
|
19893
|
-
(keydown.arrowright)="onArrow($event, 'right')"
|
|
19894
|
-
(keydown.home)="onHomeEnd($event, false)"
|
|
19895
|
-
(keydown.end)="onHomeEnd($event, true)"
|
|
19896
|
-
>
|
|
19897
|
-
<div class="strct-tour__step">{{ index() + 1 }} / {{ steps().length }}</div>
|
|
19898
|
-
<div class="strct-tour__title" [id]="titleId">{{ step.title }}</div>
|
|
19899
|
-
<div class="strct-tour__body">{{ step.body }}</div>
|
|
19900
|
-
<div class="strct-tour__nav">
|
|
19901
|
-
<button strct-button size="sm" variant="flat" (click)="close()">
|
|
19902
|
-
{{ skipLabel() }}
|
|
19903
|
-
</button>
|
|
19904
|
-
<span class="strct-tour__grow"></span>
|
|
19905
|
-
@if (index() > 0) {
|
|
19906
|
-
<button strct-button size="sm" variant="neutral" (click)="prev()">
|
|
19907
|
-
{{ backLabel() }}
|
|
19908
|
-
</button>
|
|
19909
|
-
}
|
|
19910
|
-
<button strct-button size="sm" variant="primary" solid (click)="next()">
|
|
19911
|
-
{{ index() === steps().length - 1 ? doneLabel() : nextLabel() }}
|
|
19912
|
-
</button>
|
|
19913
|
-
</div>
|
|
19914
|
-
</div>
|
|
19915
|
-
}
|
|
19916
|
-
`, styles: [".strct-tour__backdrop{position:fixed;inset:0;z-index:var(--z-tour);background:transparent}.strct-tour__backdrop--dim{background:var(--backdrop)}.strct-tour__ring{position:fixed;z-index:calc(var(--z-tour) + 1);border:2px solid var(--acc);border-radius:9px;box-shadow:0 0 0 4px var(--acc30),0 0 0 9999px var(--backdrop);pointer-events:none}.strct-tour__card{position:fixed;z-index:calc(var(--z-tour) + 2);width:300px;padding:14px 16px;background:var(--bg-1);border:1px solid var(--b2);border-radius:9px;box-shadow:var(--shh)}.strct-tour__step{font-size:10.5px;font-weight:600;letter-spacing:.6px;color:var(--t3);margin-bottom:4px;font-variant-numeric:tabular-nums}.strct-tour__title{font-size:13.5px;font-weight:650;color:var(--t1);margin-bottom:6px}.strct-tour__body{font-size:12.5px;line-height:1.5;color:var(--t2);margin-bottom:12px}.strct-tour__nav{display:flex;align-items:center;gap:8px}.strct-tour__grow{flex:1}\n"] }]
|
|
19917
|
-
}], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: true }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], backLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "backLabel", required: false }] }], skipLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "skipLabel", required: false }] }], doneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "doneLabel", required: false }] }], finished: [{ type: i0.Output, args: ["finished"] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }], onReflow: [{
|
|
19918
|
-
type: HostListener,
|
|
19919
|
-
args: ['window:resize']
|
|
19920
|
-
}, {
|
|
19921
|
-
type: HostListener,
|
|
19922
|
-
args: ['window:scroll']
|
|
19923
|
-
}] } });
|
|
19924
|
-
|
|
19925
|
-
let menubarCounter = 0;
|
|
19926
|
-
/**
|
|
19927
|
-
* Horizontal menubar — the application-menu strip ("File · Edit · View") for
|
|
19928
|
-
* dense tool-style consoles:
|
|
19929
|
-
*
|
|
19930
|
-
* <strct-menubar [menus]="menus" (picked)="run($event)" />
|
|
19931
|
-
*
|
|
19932
|
-
* Click (or Enter/Down) opens a menu and focus moves into it; Left/Right move
|
|
19933
|
-
* across the bar and, while open, switch the open menu (the APG menubar
|
|
19934
|
-
* convention). Up/Down (+Home/End) rove the open menu, Right/Left enter and
|
|
19935
|
-
* leave an item's one-level `children` submenu. Escape and outside click
|
|
19936
|
-
* close, returning focus to the bar. `(picked)` carries `{ menu, item }`.
|
|
19937
|
-
*/
|
|
19938
|
-
class StrctMenubar {
|
|
19939
|
-
host = inject(ElementRef);
|
|
19940
|
-
/** Top-level menus. */
|
|
19941
|
-
menus = input.required(/* @ts-ignore */
|
|
19942
|
-
...(ngDevMode ? [{ debugName: "menus" }] : /* istanbul ignore next */ []));
|
|
19943
|
-
/** Accessible name of the bar (localizable). */
|
|
19944
|
-
ariaLabel = input('Application menu', /* @ts-ignore */
|
|
19945
|
-
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
19946
|
-
/** A menu entry was chosen. */
|
|
19947
|
-
picked = output();
|
|
19948
|
-
openId = signal(null, /* @ts-ignore */
|
|
19949
|
-
...(ngDevMode ? [{ debugName: "openId" }] : /* istanbul ignore next */ []));
|
|
19950
|
-
focusIdx = signal(0, /* @ts-ignore */
|
|
19951
|
-
...(ngDevMode ? [{ debugName: "focusIdx" }] : /* istanbul ignore next */ []));
|
|
19952
|
-
/** Index of the item whose one-level submenu is open. */
|
|
19953
|
-
subIdx = signal(null, /* @ts-ignore */
|
|
19954
|
-
...(ngDevMode ? [{ debugName: "subIdx" }] : /* istanbul ignore next */ []));
|
|
19955
|
-
/** Top-level button that opened the menu — focus returns here on close. */
|
|
19956
|
-
trigger = null;
|
|
19957
|
-
toggleMenu(id, i) {
|
|
19958
|
-
this.focusIdx.set(i);
|
|
19959
|
-
if (this.openId() === id) {
|
|
19960
|
-
this.closeMenu(false);
|
|
19961
|
-
}
|
|
19962
|
-
else {
|
|
19963
|
-
this.trigger = saveFocusedElement();
|
|
19964
|
-
this.openId.set(id);
|
|
19965
|
-
this.subIdx.set(null);
|
|
19966
|
-
}
|
|
19967
|
-
}
|
|
19968
|
-
onItemClick(menu, item, i) {
|
|
19969
|
-
if (item.disabled)
|
|
19970
|
-
return;
|
|
19971
|
-
if (item.children?.length) {
|
|
19972
|
-
this.subIdx.set(this.subIdx() === i ? null : i);
|
|
19973
|
-
return;
|
|
19974
|
-
}
|
|
19975
|
-
this.pick(menu, item);
|
|
19976
|
-
}
|
|
19977
|
-
onItemHover(item, i) {
|
|
19978
|
-
if (item.disabled)
|
|
19979
|
-
return;
|
|
19980
|
-
if (item.children?.length)
|
|
19981
|
-
this.subIdx.set(i);
|
|
19982
|
-
else if (this.subIdx() != null)
|
|
19983
|
-
this.subIdx.set(null);
|
|
19984
|
-
}
|
|
19985
|
-
pick(menu, item) {
|
|
19986
|
-
if (item.disabled)
|
|
19987
|
-
return;
|
|
19988
|
-
this.closeMenu(true);
|
|
19989
|
-
item.action?.(item.data);
|
|
19990
|
-
this.picked.emit({ menu, item });
|
|
19991
|
-
}
|
|
19992
|
-
onTopKey(event, i) {
|
|
19993
|
-
const menus = this.menus();
|
|
19994
|
-
if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {
|
|
19995
|
-
event.preventDefault();
|
|
19996
|
-
if (this.openId()) {
|
|
19997
|
-
// While a menu is open, moving across the bar switches the open menu.
|
|
19998
|
-
this.switchTop(event.key === 'ArrowRight' ? 1 : -1);
|
|
19999
|
-
}
|
|
20000
|
-
else {
|
|
20001
|
-
const dir = event.key === 'ArrowRight' ? 1 : -1;
|
|
20002
|
-
const next = (i + dir + menus.length) % menus.length;
|
|
20003
|
-
this.focusIdx.set(next);
|
|
20004
|
-
setTimeout(() => this.topButtons()[next]?.focus());
|
|
20005
|
-
}
|
|
20006
|
-
}
|
|
20007
|
-
else if (event.key === 'ArrowDown' || event.key === 'Enter') {
|
|
20008
|
-
event.preventDefault();
|
|
20009
|
-
this.trigger = saveFocusedElement();
|
|
20010
|
-
this.openId.set(menus[i].id);
|
|
20011
|
-
this.subIdx.set(null);
|
|
20012
|
-
setTimeout(() => {
|
|
20013
|
-
const menuEl = this.host.nativeElement.querySelector('.strct-mb__menu');
|
|
20014
|
-
if (menuEl)
|
|
20015
|
-
focusFirstIn(menuEl);
|
|
20016
|
-
});
|
|
20017
|
-
}
|
|
20018
|
-
else if (event.key === 'Escape' && this.openId()) {
|
|
20019
|
-
event.preventDefault();
|
|
20020
|
-
event.stopPropagation();
|
|
20021
|
-
this.closeMenu(true);
|
|
20022
|
-
}
|
|
20023
|
-
}
|
|
20024
|
-
onMenuKey(event, menu) {
|
|
20025
|
-
const active = document.activeElement;
|
|
20026
|
-
const inSub = !!active?.classList.contains('strct-mb__subitem');
|
|
20027
|
-
switch (event.key) {
|
|
20028
|
-
case 'ArrowDown':
|
|
20029
|
-
case 'ArrowUp': {
|
|
20030
|
-
event.preventDefault();
|
|
20031
|
-
event.stopPropagation();
|
|
20032
|
-
const list = this.navButtons(inSub);
|
|
20033
|
-
const dir = event.key === 'ArrowDown' ? 1 : -1;
|
|
20034
|
-
const cur = list.indexOf(active);
|
|
20035
|
-
list[(cur + dir + list.length) % list.length]?.focus();
|
|
20036
|
-
break;
|
|
20037
|
-
}
|
|
20038
|
-
case 'Home':
|
|
20039
|
-
case 'End': {
|
|
20040
|
-
event.preventDefault();
|
|
20041
|
-
event.stopPropagation();
|
|
20042
|
-
const list = this.navButtons(inSub);
|
|
20043
|
-
(event.key === 'Home' ? list[0] : list[list.length - 1])?.focus();
|
|
20044
|
-
break;
|
|
20045
|
-
}
|
|
20046
|
-
case 'ArrowRight': {
|
|
20047
|
-
if (inSub)
|
|
20048
|
-
break; // deepest level — nothing further to open
|
|
20049
|
-
event.preventDefault();
|
|
20050
|
-
event.stopPropagation();
|
|
20051
|
-
const idx = Number(active?.getAttribute('data-idx'));
|
|
20052
|
-
if (menu.items[idx]?.children?.length && !menu.items[idx].disabled) {
|
|
20053
|
-
this.subIdx.set(idx);
|
|
20054
|
-
setTimeout(() => this.navButtons(true)[0]?.focus());
|
|
20055
|
-
}
|
|
20056
|
-
else {
|
|
20057
|
-
this.switchTop(1);
|
|
20058
|
-
}
|
|
20059
|
-
break;
|
|
20060
|
-
}
|
|
20061
|
-
case 'ArrowLeft': {
|
|
20062
|
-
event.preventDefault();
|
|
20063
|
-
event.stopPropagation();
|
|
20064
|
-
if (inSub) {
|
|
20065
|
-
const parent = this.subIdx();
|
|
20066
|
-
this.subIdx.set(null);
|
|
20067
|
-
this.host.nativeElement
|
|
20068
|
-
.querySelector(`.strct-mb__item[data-idx="${parent}"]`)
|
|
20069
|
-
?.focus();
|
|
20070
|
-
}
|
|
20071
|
-
else if (this.subIdx() != null) {
|
|
20072
|
-
this.subIdx.set(null);
|
|
20073
|
-
}
|
|
20074
|
-
else {
|
|
20075
|
-
this.switchTop(-1);
|
|
20076
|
-
}
|
|
20077
|
-
break;
|
|
20226
|
+
return {
|
|
20227
|
+
top: Math.max(20, window.innerHeight / 2 - h / 2),
|
|
20228
|
+
left: Math.max(20, window.innerWidth / 2 - w / 2),
|
|
20229
|
+
};
|
|
20230
|
+
}
|
|
20231
|
+
// Below the target if it fits, else above; clamped into the viewport.
|
|
20232
|
+
let top = r.top + r.height + 14;
|
|
20233
|
+
if (top + h > window.innerHeight - 12)
|
|
20234
|
+
top = Math.max(12, r.top - h - 14);
|
|
20235
|
+
const left = Math.min(Math.max(12, r.left), window.innerWidth - w - 12);
|
|
20236
|
+
return { top, left };
|
|
20237
|
+
}, /* @ts-ignore */
|
|
20238
|
+
...(ngDevMode ? [{ debugName: "cardPos" }] : /* istanbul ignore next */ []));
|
|
20239
|
+
constructor() {
|
|
20240
|
+
// Restart from step 0 on open; scroll the first target into view.
|
|
20241
|
+
effect(() => {
|
|
20242
|
+
if (this.open()) {
|
|
20243
|
+
this.previousActive = saveFocusedElement();
|
|
20244
|
+
this.index.set(0);
|
|
20245
|
+
this.scrollToTarget();
|
|
20246
|
+
this.focusNextButton();
|
|
20078
20247
|
}
|
|
20079
|
-
|
|
20080
|
-
|
|
20081
|
-
|
|
20082
|
-
this.closeMenu(true);
|
|
20083
|
-
break;
|
|
20248
|
+
else {
|
|
20249
|
+
restoreFocus(this.previousActive);
|
|
20250
|
+
this.previousActive = null;
|
|
20084
20251
|
}
|
|
20252
|
+
});
|
|
20253
|
+
}
|
|
20254
|
+
next() {
|
|
20255
|
+
if (this.index() >= this.steps().length - 1) {
|
|
20256
|
+
this.open.set(false);
|
|
20257
|
+
this.finished.emit();
|
|
20258
|
+
return;
|
|
20085
20259
|
}
|
|
20260
|
+
this.index.update((i) => i + 1);
|
|
20261
|
+
this.scrollToTarget();
|
|
20262
|
+
this.focusNextButton();
|
|
20086
20263
|
}
|
|
20087
|
-
|
|
20088
|
-
|
|
20089
|
-
|
|
20090
|
-
|
|
20091
|
-
this.focusIdx.set(next);
|
|
20092
|
-
this.openId.set(menus[next].id);
|
|
20093
|
-
this.subIdx.set(null);
|
|
20094
|
-
setTimeout(() => this.topButtons()[next]?.focus());
|
|
20264
|
+
prev() {
|
|
20265
|
+
this.index.update((i) => Math.max(0, i - 1));
|
|
20266
|
+
this.scrollToTarget();
|
|
20267
|
+
this.focusNextButton();
|
|
20095
20268
|
}
|
|
20096
|
-
|
|
20097
|
-
this.
|
|
20098
|
-
this.
|
|
20099
|
-
if (returnFocus)
|
|
20100
|
-
restoreFocus(this.trigger);
|
|
20101
|
-
this.trigger = null;
|
|
20269
|
+
close() {
|
|
20270
|
+
this.open.set(false);
|
|
20271
|
+
this.dismissed.emit();
|
|
20102
20272
|
}
|
|
20103
|
-
|
|
20104
|
-
|
|
20105
|
-
|
|
20106
|
-
|
|
20107
|
-
|
|
20273
|
+
/** Wrap Tab focus within the card. */
|
|
20274
|
+
onTab(event) {
|
|
20275
|
+
const card = this.card();
|
|
20276
|
+
if (card)
|
|
20277
|
+
keepTabInside(event, card);
|
|
20108
20278
|
}
|
|
20109
|
-
|
|
20110
|
-
|
|
20279
|
+
/** Escape closes; stopPropagation so a host modal/drawer does not also close. */
|
|
20280
|
+
onEscapeKey(event) {
|
|
20281
|
+
event.stopPropagation();
|
|
20282
|
+
this.close();
|
|
20111
20283
|
}
|
|
20112
|
-
/**
|
|
20113
|
-
*
|
|
20114
|
-
*
|
|
20115
|
-
|
|
20116
|
-
|
|
20117
|
-
|
|
20118
|
-
|
|
20119
|
-
const
|
|
20120
|
-
|
|
20284
|
+
/**
|
|
20285
|
+
* Arrow keys step through the tour, mirrored under RTL. No shared direction
|
|
20286
|
+
* helper exists (other components handle RTL in CSS only), so read the
|
|
20287
|
+
* card's computed direction here.
|
|
20288
|
+
*/
|
|
20289
|
+
onArrow(event, dir) {
|
|
20290
|
+
event.preventDefault();
|
|
20291
|
+
const rtl = getComputedStyle(event.currentTarget).direction === 'rtl';
|
|
20292
|
+
if ((dir === 'right') !== rtl)
|
|
20293
|
+
this.next();
|
|
20294
|
+
else
|
|
20295
|
+
this.prev();
|
|
20121
20296
|
}
|
|
20122
|
-
|
|
20123
|
-
|
|
20124
|
-
|
|
20125
|
-
|
|
20297
|
+
/** Home/End jump to the first/last step. */
|
|
20298
|
+
onHomeEnd(event, last) {
|
|
20299
|
+
event.preventDefault();
|
|
20300
|
+
this.index.set(last ? this.steps().length - 1 : 0);
|
|
20301
|
+
this.scrollToTarget();
|
|
20302
|
+
this.focusNextButton();
|
|
20126
20303
|
}
|
|
20127
|
-
|
|
20128
|
-
|
|
20129
|
-
|
|
20130
|
-
|
|
20131
|
-
|
|
20304
|
+
scrollToTarget() {
|
|
20305
|
+
setTimeout(() => {
|
|
20306
|
+
const sel = this.steps()[this.index()]?.target;
|
|
20307
|
+
if (sel)
|
|
20308
|
+
document.querySelector(sel)?.scrollIntoView?.({ block: 'center' });
|
|
20309
|
+
this.measureTick.update((n) => n + 1);
|
|
20310
|
+
});
|
|
20132
20311
|
}
|
|
20133
|
-
|
|
20134
|
-
|
|
20135
|
-
|
|
20136
|
-
|
|
20137
|
-
|
|
20138
|
-
|
|
20139
|
-
|
|
20140
|
-
|
|
20141
|
-
|
|
20142
|
-
|
|
20143
|
-
|
|
20144
|
-
|
|
20145
|
-
|
|
20146
|
-
(
|
|
20147
|
-
|
|
20148
|
-
|
|
20149
|
-
|
|
20150
|
-
|
|
20151
|
-
|
|
20152
|
-
|
|
20153
|
-
|
|
20154
|
-
|
|
20155
|
-
|
|
20156
|
-
|
|
20157
|
-
|
|
20158
|
-
|
|
20159
|
-
|
|
20160
|
-
|
|
20161
|
-
|
|
20162
|
-
|
|
20163
|
-
|
|
20164
|
-
|
|
20165
|
-
|
|
20166
|
-
|
|
20167
|
-
|
|
20168
|
-
|
|
20169
|
-
|
|
20170
|
-
|
|
20171
|
-
|
|
20172
|
-
|
|
20173
|
-
|
|
20174
|
-
|
|
20175
|
-
|
|
20176
|
-
|
|
20177
|
-
|
|
20178
|
-
|
|
20179
|
-
|
|
20180
|
-
|
|
20181
|
-
|
|
20182
|
-
|
|
20183
|
-
|
|
20184
|
-
|
|
20185
|
-
|
|
20186
|
-
|
|
20187
|
-
|
|
20188
|
-
|
|
20189
|
-
|
|
20190
|
-
|
|
20191
|
-
|
|
20192
|
-
|
|
20193
|
-
|
|
20194
|
-
|
|
20195
|
-
|
|
20196
|
-
|
|
20197
|
-
|
|
20198
|
-
|
|
20199
|
-
|
|
20200
|
-
[attr.aria-disabled]="sub.disabled ? 'true' : null"
|
|
20201
|
-
[attr.aria-describedby]="sub.hint ? hintId(menu.id, i, j) : null"
|
|
20202
|
-
[attr.title]="sub.hint || null"
|
|
20203
|
-
(click)="pick(menu, sub)"
|
|
20204
|
-
>
|
|
20205
|
-
@if (sub.icon) {
|
|
20206
|
-
<strct-icon [name]="sub.icon" [size]="13" />
|
|
20207
|
-
}
|
|
20208
|
-
{{ sub.label }}
|
|
20209
|
-
</button>
|
|
20210
|
-
@if (sub.hint) {
|
|
20211
|
-
<span [id]="hintId(menu.id, i, j)" hidden>{{ sub.hint }}</span>
|
|
20212
|
-
}
|
|
20213
|
-
}
|
|
20214
|
-
}
|
|
20215
|
-
</div>
|
|
20216
|
-
}
|
|
20217
|
-
</div>
|
|
20218
|
-
}
|
|
20219
|
-
}
|
|
20220
|
-
</div>
|
|
20312
|
+
card() {
|
|
20313
|
+
return this.elementRef.nativeElement.querySelector('.strct-tour__card');
|
|
20314
|
+
}
|
|
20315
|
+
/** Move focus to the step's primary (Next/Done) action once the card has rendered. */
|
|
20316
|
+
focusNextButton() {
|
|
20317
|
+
setTimeout(() => {
|
|
20318
|
+
if (!this.open())
|
|
20319
|
+
return;
|
|
20320
|
+
const card = this.card();
|
|
20321
|
+
if (!card)
|
|
20322
|
+
return;
|
|
20323
|
+
const nav = card.querySelectorAll('.strct-tour__nav button');
|
|
20324
|
+
const primary = nav[nav.length - 1];
|
|
20325
|
+
if (primary)
|
|
20326
|
+
primary.focus();
|
|
20327
|
+
else
|
|
20328
|
+
focusFirstIn(card);
|
|
20329
|
+
});
|
|
20330
|
+
}
|
|
20331
|
+
onReflow() {
|
|
20332
|
+
if (this.open())
|
|
20333
|
+
this.measureTick.update((n) => n + 1);
|
|
20334
|
+
}
|
|
20335
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctTour, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
20336
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctTour, isStandalone: true, selector: "strct-tour", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: true, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null }, skipLabel: { classPropertyName: "skipLabel", publicName: "skipLabel", isSignal: true, isRequired: false, transformFunction: null }, doneLabel: { classPropertyName: "doneLabel", publicName: "doneLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", finished: "finished", dismissed: "dismissed" }, host: { listeners: { "window:resize": "onReflow()", "window:scroll": "onReflow()" } }, ngImport: i0, template: `
|
|
20337
|
+
@if (open() && current(); as step) {
|
|
20338
|
+
<!-- Always the click-catcher; dims only when no ring (its shadow dims). -->
|
|
20339
|
+
<div
|
|
20340
|
+
class="strct-tour__backdrop"
|
|
20341
|
+
[class.strct-tour__backdrop--dim]="!spot()"
|
|
20342
|
+
(click)="close()"
|
|
20343
|
+
></div>
|
|
20344
|
+
@if (spot(); as r) {
|
|
20345
|
+
<div
|
|
20346
|
+
class="strct-tour__ring"
|
|
20347
|
+
[style.top.px]="r.top - 6"
|
|
20348
|
+
[style.left.px]="r.left - 6"
|
|
20349
|
+
[style.width.px]="r.width + 12"
|
|
20350
|
+
[style.height.px]="r.height + 12"
|
|
20351
|
+
></div>
|
|
20352
|
+
}
|
|
20353
|
+
<div
|
|
20354
|
+
class="strct-tour__card"
|
|
20355
|
+
role="dialog"
|
|
20356
|
+
[attr.aria-labelledby]="titleId"
|
|
20357
|
+
[style.top.px]="cardPos().top"
|
|
20358
|
+
[style.left.px]="cardPos().left"
|
|
20359
|
+
(keydown.tab)="onTab($event)"
|
|
20360
|
+
(keydown.shift.tab)="onTab($event)"
|
|
20361
|
+
(keydown.escape)="onEscapeKey($event)"
|
|
20362
|
+
(keydown.arrowleft)="onArrow($event, 'left')"
|
|
20363
|
+
(keydown.arrowright)="onArrow($event, 'right')"
|
|
20364
|
+
(keydown.home)="onHomeEnd($event, false)"
|
|
20365
|
+
(keydown.end)="onHomeEnd($event, true)"
|
|
20366
|
+
>
|
|
20367
|
+
<div class="strct-tour__step">{{ index() + 1 }} / {{ steps().length }}</div>
|
|
20368
|
+
<div class="strct-tour__title" [id]="titleId">{{ step.title }}</div>
|
|
20369
|
+
<div class="strct-tour__body">{{ step.body }}</div>
|
|
20370
|
+
<div class="strct-tour__nav">
|
|
20371
|
+
<button strct-button size="sm" variant="flat" (click)="close()">
|
|
20372
|
+
{{ skipLabel() }}
|
|
20373
|
+
</button>
|
|
20374
|
+
<span class="strct-tour__grow"></span>
|
|
20375
|
+
@if (index() > 0) {
|
|
20376
|
+
<button strct-button size="sm" variant="neutral" (click)="prev()">
|
|
20377
|
+
{{ backLabel() }}
|
|
20378
|
+
</button>
|
|
20221
20379
|
}
|
|
20380
|
+
<button strct-button size="sm" variant="primary" solid (click)="next()">
|
|
20381
|
+
{{ index() === steps().length - 1 ? doneLabel() : nextLabel() }}
|
|
20382
|
+
</button>
|
|
20222
20383
|
</div>
|
|
20223
|
-
|
|
20224
|
-
|
|
20225
|
-
`, isInline: true, styles: [".strct-
|
|
20384
|
+
</div>
|
|
20385
|
+
}
|
|
20386
|
+
`, isInline: true, styles: [".strct-tour__backdrop{position:fixed;inset:0;z-index:var(--z-tour);background:transparent}.strct-tour__backdrop--dim{background:var(--backdrop)}.strct-tour__ring{position:fixed;z-index:calc(var(--z-tour) + 1);border:2px solid var(--acc);border-radius:9px;box-shadow:0 0 0 4px var(--acc30),0 0 0 9999px var(--backdrop);pointer-events:none}.strct-tour__card{position:fixed;z-index:calc(var(--z-tour) + 2);width:300px;padding:14px 16px;background:var(--bg-1);border:1px solid var(--b2);border-radius:9px;box-shadow:var(--shh)}.strct-tour__step{font-size:10.5px;font-weight:600;letter-spacing:.6px;color:var(--t3);margin-bottom:4px;font-variant-numeric:tabular-nums}.strct-tour__title{font-size:13.5px;font-weight:650;color:var(--t1);margin-bottom:6px}.strct-tour__body{font-size:12.5px;line-height:1.5;color:var(--t2);margin-bottom:12px}.strct-tour__nav{display:flex;align-items:center;gap:8px}.strct-tour__grow{flex:1}\n"], dependencies: [{ kind: "component", type: StrctButton, selector: "button[strct-button], a[strct-button]", inputs: ["variant", "size", "solid", "block", "iconOnly"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
20226
20387
|
}
|
|
20227
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
20388
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctTour, decorators: [{
|
|
20228
20389
|
type: Component,
|
|
20229
|
-
args: [{ selector: 'strct-
|
|
20230
|
-
|
|
20231
|
-
|
|
20232
|
-
|
|
20233
|
-
|
|
20234
|
-
|
|
20235
|
-
|
|
20236
|
-
|
|
20237
|
-
|
|
20238
|
-
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
|
|
20244
|
-
|
|
20390
|
+
args: [{ selector: 'strct-tour', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctButton], template: `
|
|
20391
|
+
@if (open() && current(); as step) {
|
|
20392
|
+
<!-- Always the click-catcher; dims only when no ring (its shadow dims). -->
|
|
20393
|
+
<div
|
|
20394
|
+
class="strct-tour__backdrop"
|
|
20395
|
+
[class.strct-tour__backdrop--dim]="!spot()"
|
|
20396
|
+
(click)="close()"
|
|
20397
|
+
></div>
|
|
20398
|
+
@if (spot(); as r) {
|
|
20399
|
+
<div
|
|
20400
|
+
class="strct-tour__ring"
|
|
20401
|
+
[style.top.px]="r.top - 6"
|
|
20402
|
+
[style.left.px]="r.left - 6"
|
|
20403
|
+
[style.width.px]="r.width + 12"
|
|
20404
|
+
[style.height.px]="r.height + 12"
|
|
20405
|
+
></div>
|
|
20406
|
+
}
|
|
20407
|
+
<div
|
|
20408
|
+
class="strct-tour__card"
|
|
20409
|
+
role="dialog"
|
|
20410
|
+
[attr.aria-labelledby]="titleId"
|
|
20411
|
+
[style.top.px]="cardPos().top"
|
|
20412
|
+
[style.left.px]="cardPos().left"
|
|
20413
|
+
(keydown.tab)="onTab($event)"
|
|
20414
|
+
(keydown.shift.tab)="onTab($event)"
|
|
20415
|
+
(keydown.escape)="onEscapeKey($event)"
|
|
20416
|
+
(keydown.arrowleft)="onArrow($event, 'left')"
|
|
20417
|
+
(keydown.arrowright)="onArrow($event, 'right')"
|
|
20418
|
+
(keydown.home)="onHomeEnd($event, false)"
|
|
20419
|
+
(keydown.end)="onHomeEnd($event, true)"
|
|
20420
|
+
>
|
|
20421
|
+
<div class="strct-tour__step">{{ index() + 1 }} / {{ steps().length }}</div>
|
|
20422
|
+
<div class="strct-tour__title" [id]="titleId">{{ step.title }}</div>
|
|
20423
|
+
<div class="strct-tour__body">{{ step.body }}</div>
|
|
20424
|
+
<div class="strct-tour__nav">
|
|
20425
|
+
<button strct-button size="sm" variant="flat" (click)="close()">
|
|
20426
|
+
{{ skipLabel() }}
|
|
20245
20427
|
</button>
|
|
20246
|
-
|
|
20247
|
-
|
|
20248
|
-
|
|
20249
|
-
|
|
20250
|
-
|
|
20251
|
-
[attr.aria-label]="menu.label"
|
|
20252
|
-
(keydown)="onMenuKey($event, menu)"
|
|
20253
|
-
>
|
|
20254
|
-
@for (item of menu.items; track $index; let i = $index) {
|
|
20255
|
-
@if (item.divider) {
|
|
20256
|
-
<div class="strct-mb__divider" role="separator"></div>
|
|
20257
|
-
} @else {
|
|
20258
|
-
<div class="strct-mb__row">
|
|
20259
|
-
<button
|
|
20260
|
-
type="button"
|
|
20261
|
-
class="strct-mb__item"
|
|
20262
|
-
role="menuitem"
|
|
20263
|
-
[attr.data-idx]="i"
|
|
20264
|
-
[class.strct-mb__item--critical]="item.critical"
|
|
20265
|
-
[attr.aria-haspopup]="item.children?.length ? 'menu' : null"
|
|
20266
|
-
[attr.aria-expanded]="item.children?.length ? subIdx() === i : null"
|
|
20267
|
-
[attr.aria-disabled]="item.disabled ? 'true' : null"
|
|
20268
|
-
[attr.aria-describedby]="item.hint ? hintId(menu.id, i) : null"
|
|
20269
|
-
[attr.title]="item.hint || null"
|
|
20270
|
-
(click)="onItemClick(menu, item, i)"
|
|
20271
|
-
(mouseenter)="onItemHover(item, i)"
|
|
20272
|
-
>
|
|
20273
|
-
@if (item.icon) {
|
|
20274
|
-
<strct-icon [name]="item.icon" [size]="13" />
|
|
20275
|
-
}
|
|
20276
|
-
{{ item.label }}
|
|
20277
|
-
@if (item.children?.length) {
|
|
20278
|
-
<strct-icon class="strct-mb__caret" name="chevronRight" [size]="12" />
|
|
20279
|
-
}
|
|
20280
|
-
</button>
|
|
20281
|
-
@if (item.hint) {
|
|
20282
|
-
<span [id]="hintId(menu.id, i)" hidden>{{ item.hint }}</span>
|
|
20283
|
-
}
|
|
20284
|
-
@if (subIdx() === i && item.children?.length) {
|
|
20285
|
-
<div class="strct-mb__submenu" role="menu" [attr.aria-label]="item.label">
|
|
20286
|
-
@for (sub of item.children; track $index; let j = $index) {
|
|
20287
|
-
@if (sub.divider) {
|
|
20288
|
-
<div class="strct-mb__divider" role="separator"></div>
|
|
20289
|
-
} @else {
|
|
20290
|
-
<button
|
|
20291
|
-
type="button"
|
|
20292
|
-
class="strct-mb__item strct-mb__subitem"
|
|
20293
|
-
role="menuitem"
|
|
20294
|
-
[class.strct-mb__item--critical]="sub.critical"
|
|
20295
|
-
[attr.aria-disabled]="sub.disabled ? 'true' : null"
|
|
20296
|
-
[attr.aria-describedby]="sub.hint ? hintId(menu.id, i, j) : null"
|
|
20297
|
-
[attr.title]="sub.hint || null"
|
|
20298
|
-
(click)="pick(menu, sub)"
|
|
20299
|
-
>
|
|
20300
|
-
@if (sub.icon) {
|
|
20301
|
-
<strct-icon [name]="sub.icon" [size]="13" />
|
|
20302
|
-
}
|
|
20303
|
-
{{ sub.label }}
|
|
20304
|
-
</button>
|
|
20305
|
-
@if (sub.hint) {
|
|
20306
|
-
<span [id]="hintId(menu.id, i, j)" hidden>{{ sub.hint }}</span>
|
|
20307
|
-
}
|
|
20308
|
-
}
|
|
20309
|
-
}
|
|
20310
|
-
</div>
|
|
20311
|
-
}
|
|
20312
|
-
</div>
|
|
20313
|
-
}
|
|
20314
|
-
}
|
|
20315
|
-
</div>
|
|
20428
|
+
<span class="strct-tour__grow"></span>
|
|
20429
|
+
@if (index() > 0) {
|
|
20430
|
+
<button strct-button size="sm" variant="neutral" (click)="prev()">
|
|
20431
|
+
{{ backLabel() }}
|
|
20432
|
+
</button>
|
|
20316
20433
|
}
|
|
20434
|
+
<button strct-button size="sm" variant="primary" solid (click)="next()">
|
|
20435
|
+
{{ index() === steps().length - 1 ? doneLabel() : nextLabel() }}
|
|
20436
|
+
</button>
|
|
20317
20437
|
</div>
|
|
20318
|
-
|
|
20319
|
-
|
|
20320
|
-
`, styles: [".strct-
|
|
20321
|
-
}], propDecorators: {
|
|
20438
|
+
</div>
|
|
20439
|
+
}
|
|
20440
|
+
`, styles: [".strct-tour__backdrop{position:fixed;inset:0;z-index:var(--z-tour);background:transparent}.strct-tour__backdrop--dim{background:var(--backdrop)}.strct-tour__ring{position:fixed;z-index:calc(var(--z-tour) + 1);border:2px solid var(--acc);border-radius:9px;box-shadow:0 0 0 4px var(--acc30),0 0 0 9999px var(--backdrop);pointer-events:none}.strct-tour__card{position:fixed;z-index:calc(var(--z-tour) + 2);width:300px;padding:14px 16px;background:var(--bg-1);border:1px solid var(--b2);border-radius:9px;box-shadow:var(--shh)}.strct-tour__step{font-size:10.5px;font-weight:600;letter-spacing:.6px;color:var(--t3);margin-bottom:4px;font-variant-numeric:tabular-nums}.strct-tour__title{font-size:13.5px;font-weight:650;color:var(--t1);margin-bottom:6px}.strct-tour__body{font-size:12.5px;line-height:1.5;color:var(--t2);margin-bottom:12px}.strct-tour__nav{display:flex;align-items:center;gap:8px}.strct-tour__grow{flex:1}\n"] }]
|
|
20441
|
+
}], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: true }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], backLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "backLabel", required: false }] }], skipLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "skipLabel", required: false }] }], doneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "doneLabel", required: false }] }], finished: [{ type: i0.Output, args: ["finished"] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }], onReflow: [{
|
|
20322
20442
|
type: HostListener,
|
|
20323
|
-
args: ['
|
|
20324
|
-
}
|
|
20443
|
+
args: ['window:resize']
|
|
20444
|
+
}, {
|
|
20325
20445
|
type: HostListener,
|
|
20326
|
-
args: ['
|
|
20446
|
+
args: ['window:scroll']
|
|
20327
20447
|
}] } });
|
|
20328
20448
|
|
|
20329
|
-
|
|
20330
|
-
return combo
|
|
20331
|
-
.toLowerCase()
|
|
20332
|
-
.split('+')
|
|
20333
|
-
.map((p) => p.trim())
|
|
20334
|
-
.sort()
|
|
20335
|
-
.join('+');
|
|
20336
|
-
}
|
|
20337
|
-
function comboOf(event) {
|
|
20338
|
-
const parts = [];
|
|
20339
|
-
if (event.ctrlKey)
|
|
20340
|
-
parts.push('ctrl');
|
|
20341
|
-
if (event.metaKey)
|
|
20342
|
-
parts.push('meta');
|
|
20343
|
-
if (event.altKey)
|
|
20344
|
-
parts.push('alt');
|
|
20345
|
-
if (event.shiftKey)
|
|
20346
|
-
parts.push('shift');
|
|
20347
|
-
parts.push(event.key.toLowerCase());
|
|
20348
|
-
return parts.sort().join('+');
|
|
20349
|
-
}
|
|
20350
|
-
/** `mod` matches Ctrl (and ⌘ on mac keyboards) — expand to both. */
|
|
20351
|
-
function expand(combo) {
|
|
20352
|
-
const n = combo.toLowerCase();
|
|
20353
|
-
if (!n.includes('mod'))
|
|
20354
|
-
return [normalize(n)];
|
|
20355
|
-
return [normalize(n.replace('mod', 'ctrl')), normalize(n.replace('mod', 'meta'))];
|
|
20356
|
-
}
|
|
20449
|
+
let menubarCounter = 0;
|
|
20357
20450
|
/**
|
|
20358
|
-
*
|
|
20359
|
-
*
|
|
20451
|
+
* Horizontal menubar — the application-menu strip ("File · Edit · View") for
|
|
20452
|
+
* dense tool-style consoles:
|
|
20360
20453
|
*
|
|
20361
|
-
*
|
|
20362
|
-
* ngOnInit() { this.dispose = this.hotkeys.register(
|
|
20363
|
-
* { combo: 'mod+k', description: 'Open command palette', group: 'Global',
|
|
20364
|
-
* handler: () => this.palette.open() }); }
|
|
20454
|
+
* <strct-menubar [menus]="menus" (picked)="run($event)" />
|
|
20365
20455
|
*
|
|
20366
|
-
*
|
|
20367
|
-
*
|
|
20368
|
-
*
|
|
20369
|
-
*
|
|
20456
|
+
* Click (or Enter/Down) opens a menu and focus moves into it; Left/Right move
|
|
20457
|
+
* across the bar and, while open, switch the open menu (the APG menubar
|
|
20458
|
+
* convention). Up/Down (+Home/End) rove the open menu, Right/Left enter and
|
|
20459
|
+
* leave an item's one-level `children` submenu. Escape and outside click
|
|
20460
|
+
* close, returning focus to the bar. `(picked)` carries `{ menu, item }`.
|
|
20370
20461
|
*/
|
|
20371
|
-
class
|
|
20372
|
-
|
|
20373
|
-
|
|
20374
|
-
|
|
20375
|
-
|
|
20376
|
-
|
|
20377
|
-
|
|
20378
|
-
|
|
20379
|
-
|
|
20380
|
-
|
|
20381
|
-
|
|
20382
|
-
|
|
20383
|
-
|
|
20462
|
+
class StrctMenubar {
|
|
20463
|
+
host = inject(ElementRef);
|
|
20464
|
+
/** Top-level menus. */
|
|
20465
|
+
menus = input.required(/* @ts-ignore */
|
|
20466
|
+
...(ngDevMode ? [{ debugName: "menus" }] : /* istanbul ignore next */ []));
|
|
20467
|
+
/** Accessible name of the bar (localizable). */
|
|
20468
|
+
ariaLabel = input('Application menu', /* @ts-ignore */
|
|
20469
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
20470
|
+
/** A menu entry was chosen. */
|
|
20471
|
+
picked = output();
|
|
20472
|
+
openId = signal(null, /* @ts-ignore */
|
|
20473
|
+
...(ngDevMode ? [{ debugName: "openId" }] : /* istanbul ignore next */ []));
|
|
20474
|
+
focusIdx = signal(0, /* @ts-ignore */
|
|
20475
|
+
...(ngDevMode ? [{ debugName: "focusIdx" }] : /* istanbul ignore next */ []));
|
|
20476
|
+
/** Index of the item whose one-level submenu is open. */
|
|
20477
|
+
subIdx = signal(null, /* @ts-ignore */
|
|
20478
|
+
...(ngDevMode ? [{ debugName: "subIdx" }] : /* istanbul ignore next */ []));
|
|
20479
|
+
/** Top-level button that opened the menu — focus returns here on close. */
|
|
20480
|
+
trigger = null;
|
|
20481
|
+
toggleMenu(id, i) {
|
|
20482
|
+
this.focusIdx.set(i);
|
|
20483
|
+
if (this.openId() === id) {
|
|
20484
|
+
this.closeMenu(false);
|
|
20485
|
+
}
|
|
20486
|
+
else {
|
|
20487
|
+
this.trigger = saveFocusedElement();
|
|
20488
|
+
this.openId.set(id);
|
|
20489
|
+
this.subIdx.set(null);
|
|
20490
|
+
}
|
|
20384
20491
|
}
|
|
20385
|
-
|
|
20386
|
-
|
|
20387
|
-
|
|
20388
|
-
|
|
20389
|
-
|
|
20390
|
-
continue;
|
|
20391
|
-
// While typing, only modifier combos may fire.
|
|
20392
|
-
if (typing && !(event.ctrlKey || event.metaKey || event.altKey))
|
|
20393
|
-
continue;
|
|
20394
|
-
event.preventDefault();
|
|
20395
|
-
hk.handler(event);
|
|
20492
|
+
onItemClick(menu, item, i) {
|
|
20493
|
+
if (item.disabled)
|
|
20494
|
+
return;
|
|
20495
|
+
if (item.children?.length) {
|
|
20496
|
+
this.subIdx.set(this.subIdx() === i ? null : i);
|
|
20396
20497
|
return;
|
|
20397
20498
|
}
|
|
20499
|
+
this.pick(menu, item);
|
|
20398
20500
|
}
|
|
20399
|
-
|
|
20400
|
-
|
|
20501
|
+
onItemHover(item, i) {
|
|
20502
|
+
if (item.disabled)
|
|
20503
|
+
return;
|
|
20504
|
+
if (item.children?.length)
|
|
20505
|
+
this.subIdx.set(i);
|
|
20506
|
+
else if (this.subIdx() != null)
|
|
20507
|
+
this.subIdx.set(null);
|
|
20401
20508
|
}
|
|
20402
|
-
|
|
20403
|
-
|
|
20404
|
-
|
|
20405
|
-
|
|
20406
|
-
|
|
20407
|
-
|
|
20408
|
-
|
|
20409
|
-
|
|
20410
|
-
|
|
20411
|
-
|
|
20412
|
-
|
|
20413
|
-
|
|
20414
|
-
|
|
20415
|
-
|
|
20416
|
-
el.isContentEditable);
|
|
20417
|
-
}
|
|
20418
|
-
/**
|
|
20419
|
-
* The hotkey cheatsheet overlay. Mount once near the app root; it registers
|
|
20420
|
-
* `shift+?` (typed as `?`) itself and lists everything in the service, grouped:
|
|
20421
|
-
*
|
|
20422
|
-
* <strct-hotkeys-help />
|
|
20423
|
-
*/
|
|
20424
|
-
class StrctHotkeysHelp {
|
|
20425
|
-
service = inject(StrctHotkeysService);
|
|
20426
|
-
host = inject((ElementRef));
|
|
20427
|
-
/** Overlay visibility (two-way; `?` toggles it too). */
|
|
20428
|
-
open = model(false, /* @ts-ignore */
|
|
20429
|
-
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
20430
|
-
/** Localizable strings. */
|
|
20431
|
-
title = input('Keyboard shortcuts', /* @ts-ignore */
|
|
20432
|
-
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
20433
|
-
emptyText = input('No shortcuts registered.', /* @ts-ignore */
|
|
20434
|
-
...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
|
|
20435
|
-
/** Accessible label of the × close button (localizable). */
|
|
20436
|
-
closeLabel = input('Close', /* @ts-ignore */
|
|
20437
|
-
...(ngDevMode ? [{ debugName: "closeLabel" }] : /* istanbul ignore next */ []));
|
|
20438
|
-
/** Element that had focus before the overlay opened, restored on close. */
|
|
20439
|
-
previousActive = null;
|
|
20440
|
-
grouped = computed(() => {
|
|
20441
|
-
const groups = new Map();
|
|
20442
|
-
for (const hk of this.service.hotkeys()) {
|
|
20443
|
-
const name = hk.group ?? 'General';
|
|
20444
|
-
const list = groups.get(name);
|
|
20445
|
-
if (list)
|
|
20446
|
-
list.push(hk);
|
|
20447
|
-
else
|
|
20448
|
-
groups.set(name, [hk]);
|
|
20449
|
-
}
|
|
20450
|
-
return [...groups.entries()].map(([name, keys]) => ({ name, keys }));
|
|
20451
|
-
}, /* @ts-ignore */
|
|
20452
|
-
...(ngDevMode ? [{ debugName: "grouped" }] : /* istanbul ignore next */ []));
|
|
20453
|
-
constructor() {
|
|
20454
|
-
const dispose = this.service.register({
|
|
20455
|
-
combo: 'shift+?',
|
|
20456
|
-
description: 'Show this help',
|
|
20457
|
-
group: 'General',
|
|
20458
|
-
handler: () => this.open.update((v) => !v),
|
|
20459
|
-
});
|
|
20460
|
-
inject(DestroyRef).onDestroy(dispose);
|
|
20461
|
-
// Focus lifecycle: remember the trigger, move focus into the dialog once
|
|
20462
|
-
// it has rendered, and hand focus back on close.
|
|
20463
|
-
effect(() => {
|
|
20464
|
-
if (this.open()) {
|
|
20465
|
-
this.previousActive = saveFocusedElement();
|
|
20466
|
-
setTimeout(() => {
|
|
20467
|
-
const dialog = this.host.nativeElement.querySelector('.strct-hkh');
|
|
20468
|
-
if (dialog)
|
|
20469
|
-
focusFirstIn(dialog);
|
|
20470
|
-
});
|
|
20509
|
+
pick(menu, item) {
|
|
20510
|
+
if (item.disabled)
|
|
20511
|
+
return;
|
|
20512
|
+
this.closeMenu(true);
|
|
20513
|
+
item.action?.(item.data);
|
|
20514
|
+
this.picked.emit({ menu, item });
|
|
20515
|
+
}
|
|
20516
|
+
onTopKey(event, i) {
|
|
20517
|
+
const menus = this.menus();
|
|
20518
|
+
if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {
|
|
20519
|
+
event.preventDefault();
|
|
20520
|
+
if (this.openId()) {
|
|
20521
|
+
// While a menu is open, moving across the bar switches the open menu.
|
|
20522
|
+
this.switchTop(event.key === 'ArrowRight' ? 1 : -1);
|
|
20471
20523
|
}
|
|
20472
20524
|
else {
|
|
20473
|
-
|
|
20474
|
-
|
|
20525
|
+
const dir = event.key === 'ArrowRight' ? 1 : -1;
|
|
20526
|
+
const next = (i + dir + menus.length) % menus.length;
|
|
20527
|
+
this.focusIdx.set(next);
|
|
20528
|
+
setTimeout(() => this.topButtons()[next]?.focus());
|
|
20475
20529
|
}
|
|
20476
|
-
}
|
|
20530
|
+
}
|
|
20531
|
+
else if (event.key === 'ArrowDown' || event.key === 'Enter') {
|
|
20532
|
+
event.preventDefault();
|
|
20533
|
+
this.trigger = saveFocusedElement();
|
|
20534
|
+
this.openId.set(menus[i].id);
|
|
20535
|
+
this.subIdx.set(null);
|
|
20536
|
+
setTimeout(() => {
|
|
20537
|
+
const menuEl = this.host.nativeElement.querySelector('.strct-mb__menu');
|
|
20538
|
+
if (menuEl)
|
|
20539
|
+
focusFirstIn(menuEl);
|
|
20540
|
+
});
|
|
20541
|
+
}
|
|
20542
|
+
else if (event.key === 'Escape' && this.openId()) {
|
|
20543
|
+
event.preventDefault();
|
|
20544
|
+
event.stopPropagation();
|
|
20545
|
+
this.closeMenu(true);
|
|
20546
|
+
}
|
|
20477
20547
|
}
|
|
20478
|
-
|
|
20479
|
-
|
|
20480
|
-
|
|
20481
|
-
|
|
20482
|
-
|
|
20483
|
-
|
|
20484
|
-
|
|
20485
|
-
|
|
20486
|
-
|
|
20548
|
+
onMenuKey(event, menu) {
|
|
20549
|
+
const active = document.activeElement;
|
|
20550
|
+
const inSub = !!active?.classList.contains('strct-mb__subitem');
|
|
20551
|
+
switch (event.key) {
|
|
20552
|
+
case 'ArrowDown':
|
|
20553
|
+
case 'ArrowUp': {
|
|
20554
|
+
event.preventDefault();
|
|
20555
|
+
event.stopPropagation();
|
|
20556
|
+
const list = this.navButtons(inSub);
|
|
20557
|
+
const dir = event.key === 'ArrowDown' ? 1 : -1;
|
|
20558
|
+
const cur = list.indexOf(active);
|
|
20559
|
+
list[(cur + dir + list.length) % list.length]?.focus();
|
|
20560
|
+
break;
|
|
20561
|
+
}
|
|
20562
|
+
case 'Home':
|
|
20563
|
+
case 'End': {
|
|
20564
|
+
event.preventDefault();
|
|
20565
|
+
event.stopPropagation();
|
|
20566
|
+
const list = this.navButtons(inSub);
|
|
20567
|
+
(event.key === 'Home' ? list[0] : list[list.length - 1])?.focus();
|
|
20568
|
+
break;
|
|
20569
|
+
}
|
|
20570
|
+
case 'ArrowRight': {
|
|
20571
|
+
if (inSub)
|
|
20572
|
+
break; // deepest level — nothing further to open
|
|
20573
|
+
event.preventDefault();
|
|
20574
|
+
event.stopPropagation();
|
|
20575
|
+
const idx = Number(active?.getAttribute('data-idx'));
|
|
20576
|
+
if (menu.items[idx]?.children?.length && !menu.items[idx].disabled) {
|
|
20577
|
+
this.subIdx.set(idx);
|
|
20578
|
+
setTimeout(() => this.navButtons(true)[0]?.focus());
|
|
20579
|
+
}
|
|
20580
|
+
else {
|
|
20581
|
+
this.switchTop(1);
|
|
20582
|
+
}
|
|
20583
|
+
break;
|
|
20584
|
+
}
|
|
20585
|
+
case 'ArrowLeft': {
|
|
20586
|
+
event.preventDefault();
|
|
20587
|
+
event.stopPropagation();
|
|
20588
|
+
if (inSub) {
|
|
20589
|
+
const parent = this.subIdx();
|
|
20590
|
+
this.subIdx.set(null);
|
|
20591
|
+
this.host.nativeElement
|
|
20592
|
+
.querySelector(`.strct-mb__item[data-idx="${parent}"]`)
|
|
20593
|
+
?.focus();
|
|
20594
|
+
}
|
|
20595
|
+
else if (this.subIdx() != null) {
|
|
20596
|
+
this.subIdx.set(null);
|
|
20597
|
+
}
|
|
20598
|
+
else {
|
|
20599
|
+
this.switchTop(-1);
|
|
20600
|
+
}
|
|
20601
|
+
break;
|
|
20602
|
+
}
|
|
20603
|
+
case 'Escape': {
|
|
20604
|
+
event.preventDefault();
|
|
20605
|
+
event.stopPropagation();
|
|
20606
|
+
this.closeMenu(true);
|
|
20607
|
+
break;
|
|
20608
|
+
}
|
|
20609
|
+
}
|
|
20487
20610
|
}
|
|
20488
|
-
|
|
20489
|
-
|
|
20490
|
-
|
|
20491
|
-
|
|
20492
|
-
|
|
20493
|
-
|
|
20494
|
-
|
|
20495
|
-
|
|
20496
|
-
|
|
20497
|
-
|
|
20498
|
-
|
|
20499
|
-
|
|
20611
|
+
/** Switch the open menu to the next/previous top-level entry; focus follows. */
|
|
20612
|
+
switchTop(dir) {
|
|
20613
|
+
const menus = this.menus();
|
|
20614
|
+
const next = (this.focusIdx() + dir + menus.length) % menus.length;
|
|
20615
|
+
this.focusIdx.set(next);
|
|
20616
|
+
this.openId.set(menus[next].id);
|
|
20617
|
+
this.subIdx.set(null);
|
|
20618
|
+
setTimeout(() => this.topButtons()[next]?.focus());
|
|
20619
|
+
}
|
|
20620
|
+
closeMenu(returnFocus) {
|
|
20621
|
+
this.openId.set(null);
|
|
20622
|
+
this.subIdx.set(null);
|
|
20623
|
+
if (returnFocus)
|
|
20624
|
+
restoreFocus(this.trigger);
|
|
20625
|
+
this.trigger = null;
|
|
20626
|
+
}
|
|
20627
|
+
uid = ++menubarCounter;
|
|
20628
|
+
hintId(menuId, i, j) {
|
|
20629
|
+
// menu ids are consumer data; aria-describedby splits on whitespace.
|
|
20630
|
+
const menu = menuId.replace(/\s+/g, '_');
|
|
20631
|
+
return `strct-mb-${this.uid}-${menu}-${i}${j == null ? '' : '-' + j}-hint`;
|
|
20632
|
+
}
|
|
20633
|
+
topButtons() {
|
|
20634
|
+
return Array.from(this.host.nativeElement.querySelectorAll('.strct-mb__top'));
|
|
20635
|
+
}
|
|
20636
|
+
/** Keyboard-reachable item buttons of the open menu — either its items or the
|
|
20637
|
+
* open submenu's: enabled ones, plus disabled ones that carry a hint (so the
|
|
20638
|
+
* reason can be read). A disabled entry with nothing to say is skipped. */
|
|
20639
|
+
navButtons(sub) {
|
|
20640
|
+
const menuEl = this.host.nativeElement.querySelector('.strct-mb__menu');
|
|
20641
|
+
if (!menuEl)
|
|
20642
|
+
return [];
|
|
20643
|
+
const sel = sub ? '.strct-mb__subitem' : '.strct-mb__item:not(.strct-mb__subitem)';
|
|
20644
|
+
return Array.from(menuEl.querySelectorAll(sel)).filter((b) => b.getAttribute('aria-disabled') !== 'true' || b.hasAttribute('aria-describedby'));
|
|
20500
20645
|
}
|
|
20501
|
-
|
|
20502
|
-
|
|
20503
|
-
|
|
20504
|
-
<div class="strct-hkh__backdrop" (click)="open.set(false)"></div>
|
|
20505
|
-
<div class="strct-hkh" role="dialog" aria-modal="true" [attr.aria-label]="title()">
|
|
20506
|
-
<div class="strct-hkh__head">
|
|
20507
|
-
<span class="strct-hkh__title">{{ title() }}</span>
|
|
20508
|
-
<span class="strct-hkh__headside">
|
|
20509
|
-
<strct-kbd>?</strct-kbd>
|
|
20510
|
-
<button
|
|
20511
|
-
type="button"
|
|
20512
|
-
class="strct-hkh__close"
|
|
20513
|
-
[attr.aria-label]="closeLabel()"
|
|
20514
|
-
(click)="open.set(false)"
|
|
20515
|
-
>
|
|
20516
|
-
<strct-icon name="close" [size]="14" />
|
|
20517
|
-
</button>
|
|
20518
|
-
</span>
|
|
20519
|
-
</div>
|
|
20520
|
-
@for (group of grouped(); track group.name) {
|
|
20521
|
-
<div class="strct-hkh__group">
|
|
20522
|
-
<div class="strct-hkh__groupname">{{ group.name }}</div>
|
|
20523
|
-
@for (hk of group.keys; track hk.combo + hk.description) {
|
|
20524
|
-
<div class="strct-hkh__row">
|
|
20525
|
-
<span class="strct-hkh__desc">{{ hk.description }}</span>
|
|
20526
|
-
<span class="strct-hkh__keys">
|
|
20527
|
-
@for (part of parts(hk.combo); track $index) {
|
|
20528
|
-
<strct-kbd>{{ part }}</strct-kbd>
|
|
20529
|
-
}
|
|
20530
|
-
</span>
|
|
20531
|
-
</div>
|
|
20532
|
-
}
|
|
20533
|
-
</div>
|
|
20534
|
-
} @empty {
|
|
20535
|
-
<p class="strct-hkh__empty">{{ emptyText() }}</p>
|
|
20646
|
+
onDocClick(event) {
|
|
20647
|
+
if (this.openId() && !this.host.nativeElement.contains(event.target)) {
|
|
20648
|
+
this.closeMenu(false);
|
|
20536
20649
|
}
|
|
20537
|
-
</div>
|
|
20538
20650
|
}
|
|
20539
|
-
|
|
20651
|
+
onEscape(event) {
|
|
20652
|
+
if (!this.openId())
|
|
20653
|
+
return;
|
|
20654
|
+
event.stopPropagation();
|
|
20655
|
+
this.closeMenu(true);
|
|
20656
|
+
}
|
|
20657
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctMenubar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
20658
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctMenubar, isStandalone: true, selector: "strct-menubar", inputs: { menus: { classPropertyName: "menus", publicName: "menus", isSignal: true, isRequired: true, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { picked: "picked" }, host: { listeners: { "document:click": "onDocClick($event)", "document:keydown.escape": "onEscape($event)" } }, ngImport: i0, template: `
|
|
20659
|
+
<div class="strct-mb" role="menubar" [attr.aria-label]="ariaLabel()">
|
|
20660
|
+
@for (menu of menus(); track menu.id; let i = $index) {
|
|
20661
|
+
<div class="strct-mb__wrap">
|
|
20662
|
+
<button
|
|
20663
|
+
type="button"
|
|
20664
|
+
class="strct-mb__top"
|
|
20665
|
+
role="menuitem"
|
|
20666
|
+
[class.strct-mb__top--open]="openId() === menu.id"
|
|
20667
|
+
[attr.aria-haspopup]="'menu'"
|
|
20668
|
+
[attr.aria-expanded]="openId() === menu.id"
|
|
20669
|
+
[attr.tabindex]="i === focusIdx() ? 0 : -1"
|
|
20670
|
+
(click)="toggleMenu(menu.id, i)"
|
|
20671
|
+
(keydown)="onTopKey($event, i)"
|
|
20672
|
+
>
|
|
20673
|
+
{{ menu.label }}
|
|
20674
|
+
</button>
|
|
20675
|
+
@if (openId() === menu.id) {
|
|
20676
|
+
<div
|
|
20677
|
+
class="strct-mb__menu"
|
|
20678
|
+
role="menu"
|
|
20679
|
+
tabindex="-1"
|
|
20680
|
+
[attr.aria-label]="menu.label"
|
|
20681
|
+
(keydown)="onMenuKey($event, menu)"
|
|
20682
|
+
>
|
|
20683
|
+
@for (item of menu.items; track $index; let i = $index) {
|
|
20684
|
+
@if (item.divider) {
|
|
20685
|
+
<div class="strct-mb__divider" role="separator"></div>
|
|
20686
|
+
} @else {
|
|
20687
|
+
<div class="strct-mb__row">
|
|
20688
|
+
<button
|
|
20689
|
+
type="button"
|
|
20690
|
+
class="strct-mb__item"
|
|
20691
|
+
role="menuitem"
|
|
20692
|
+
[attr.data-idx]="i"
|
|
20693
|
+
[class.strct-mb__item--critical]="item.critical"
|
|
20694
|
+
[attr.aria-haspopup]="item.children?.length ? 'menu' : null"
|
|
20695
|
+
[attr.aria-expanded]="item.children?.length ? subIdx() === i : null"
|
|
20696
|
+
[attr.aria-disabled]="item.disabled ? 'true' : null"
|
|
20697
|
+
[attr.aria-describedby]="item.hint ? hintId(menu.id, i) : null"
|
|
20698
|
+
[attr.title]="item.hint || null"
|
|
20699
|
+
(click)="onItemClick(menu, item, i)"
|
|
20700
|
+
(mouseenter)="onItemHover(item, i)"
|
|
20701
|
+
>
|
|
20702
|
+
@if (item.icon) {
|
|
20703
|
+
<strct-icon [name]="item.icon" [size]="13" />
|
|
20704
|
+
}
|
|
20705
|
+
{{ item.label }}
|
|
20706
|
+
@if (item.children?.length) {
|
|
20707
|
+
<strct-icon class="strct-mb__caret" name="chevronRight" [size]="12" />
|
|
20708
|
+
}
|
|
20709
|
+
</button>
|
|
20710
|
+
@if (item.hint) {
|
|
20711
|
+
<span [id]="hintId(menu.id, i)" hidden>{{ item.hint }}</span>
|
|
20712
|
+
}
|
|
20713
|
+
@if (subIdx() === i && item.children?.length) {
|
|
20714
|
+
<div class="strct-mb__submenu" role="menu" [attr.aria-label]="item.label">
|
|
20715
|
+
@for (sub of item.children; track $index; let j = $index) {
|
|
20716
|
+
@if (sub.divider) {
|
|
20717
|
+
<div class="strct-mb__divider" role="separator"></div>
|
|
20718
|
+
} @else {
|
|
20719
|
+
<button
|
|
20720
|
+
type="button"
|
|
20721
|
+
class="strct-mb__item strct-mb__subitem"
|
|
20722
|
+
role="menuitem"
|
|
20723
|
+
[class.strct-mb__item--critical]="sub.critical"
|
|
20724
|
+
[attr.aria-disabled]="sub.disabled ? 'true' : null"
|
|
20725
|
+
[attr.aria-describedby]="sub.hint ? hintId(menu.id, i, j) : null"
|
|
20726
|
+
[attr.title]="sub.hint || null"
|
|
20727
|
+
(click)="pick(menu, sub)"
|
|
20728
|
+
>
|
|
20729
|
+
@if (sub.icon) {
|
|
20730
|
+
<strct-icon [name]="sub.icon" [size]="13" />
|
|
20731
|
+
}
|
|
20732
|
+
{{ sub.label }}
|
|
20733
|
+
</button>
|
|
20734
|
+
@if (sub.hint) {
|
|
20735
|
+
<span [id]="hintId(menu.id, i, j)" hidden>{{ sub.hint }}</span>
|
|
20736
|
+
}
|
|
20737
|
+
}
|
|
20738
|
+
}
|
|
20739
|
+
</div>
|
|
20740
|
+
}
|
|
20741
|
+
</div>
|
|
20742
|
+
}
|
|
20743
|
+
}
|
|
20744
|
+
</div>
|
|
20745
|
+
}
|
|
20746
|
+
</div>
|
|
20747
|
+
}
|
|
20748
|
+
</div>
|
|
20749
|
+
`, isInline: true, styles: [".strct-mb{display:inline-flex;gap:2px;padding:2px;background:var(--bg-2);border:1px solid var(--b1);border-radius:var(--radius-md)}.strct-mb__wrap{position:relative}.strct-mb__top{padding:4px 11px;border:0;border-radius:5px;background:transparent;color:var(--t1);font-family:var(--font);font-size:12.5px;cursor:pointer;white-space:nowrap}.strct-mb__top:hover,.strct-mb__top--open{background:var(--bg-3)}.strct-mb__top:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-mb__menu{position:absolute;top:calc(100% + 4px);inset-inline-start:0;z-index:var(--z-dropdown);min-width:180px;padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-md);box-shadow:var(--shh);display:flex;flex-direction:column}.strct-mb__menu:focus{outline:none}.strct-mb__item{display:flex;align-items:center;gap:8px;width:100%;padding:6px 10px;border:0;border-radius:5px;background:transparent;color:var(--t1);font-family:var(--font);font-size:12.5px;text-align:start;cursor:pointer;white-space:nowrap}.strct-mb__item:hover:not([aria-disabled=true]){background:var(--bg-3)}.strct-mb__item--critical{color:var(--critical)}.strct-mb__item--critical:hover:not([aria-disabled=true]){background:var(--critical-bg)}.strct-mb__item[aria-disabled=true]{color:var(--t4);cursor:default}.strct-mb__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-mb__divider{height:1px;margin:4px 6px;background:var(--b2)}.strct-mb__row{position:relative}.strct-mb__caret{margin-inline-start:auto;color:var(--t3)}[dir=rtl] .strct-mb__caret{transform:rotate(180deg)}.strct-mb__submenu{position:absolute;top:-5px;inset-inline-start:calc(100% + 2px);z-index:var(--z-base);min-width:160px;padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-md);box-shadow:var(--shh);display:flex;flex-direction:column}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
20540
20750
|
}
|
|
20541
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
20751
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctMenubar, decorators: [{
|
|
20542
20752
|
type: Component,
|
|
20543
|
-
args: [{ selector: 'strct-
|
|
20544
|
-
|
|
20545
|
-
|
|
20546
|
-
|
|
20547
|
-
|
|
20548
|
-
|
|
20549
|
-
|
|
20550
|
-
|
|
20551
|
-
|
|
20552
|
-
|
|
20553
|
-
|
|
20554
|
-
|
|
20555
|
-
|
|
20753
|
+
args: [{ selector: 'strct-menubar', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon], template: `
|
|
20754
|
+
<div class="strct-mb" role="menubar" [attr.aria-label]="ariaLabel()">
|
|
20755
|
+
@for (menu of menus(); track menu.id; let i = $index) {
|
|
20756
|
+
<div class="strct-mb__wrap">
|
|
20757
|
+
<button
|
|
20758
|
+
type="button"
|
|
20759
|
+
class="strct-mb__top"
|
|
20760
|
+
role="menuitem"
|
|
20761
|
+
[class.strct-mb__top--open]="openId() === menu.id"
|
|
20762
|
+
[attr.aria-haspopup]="'menu'"
|
|
20763
|
+
[attr.aria-expanded]="openId() === menu.id"
|
|
20764
|
+
[attr.tabindex]="i === focusIdx() ? 0 : -1"
|
|
20765
|
+
(click)="toggleMenu(menu.id, i)"
|
|
20766
|
+
(keydown)="onTopKey($event, i)"
|
|
20767
|
+
>
|
|
20768
|
+
{{ menu.label }}
|
|
20769
|
+
</button>
|
|
20770
|
+
@if (openId() === menu.id) {
|
|
20771
|
+
<div
|
|
20772
|
+
class="strct-mb__menu"
|
|
20773
|
+
role="menu"
|
|
20774
|
+
tabindex="-1"
|
|
20775
|
+
[attr.aria-label]="menu.label"
|
|
20776
|
+
(keydown)="onMenuKey($event, menu)"
|
|
20556
20777
|
>
|
|
20557
|
-
|
|
20558
|
-
|
|
20559
|
-
|
|
20560
|
-
|
|
20561
|
-
|
|
20562
|
-
|
|
20563
|
-
|
|
20564
|
-
|
|
20565
|
-
|
|
20566
|
-
|
|
20567
|
-
|
|
20568
|
-
|
|
20569
|
-
|
|
20570
|
-
|
|
20571
|
-
|
|
20572
|
-
|
|
20573
|
-
|
|
20574
|
-
|
|
20575
|
-
|
|
20576
|
-
|
|
20577
|
-
|
|
20578
|
-
|
|
20579
|
-
|
|
20580
|
-
|
|
20581
|
-
|
|
20778
|
+
@for (item of menu.items; track $index; let i = $index) {
|
|
20779
|
+
@if (item.divider) {
|
|
20780
|
+
<div class="strct-mb__divider" role="separator"></div>
|
|
20781
|
+
} @else {
|
|
20782
|
+
<div class="strct-mb__row">
|
|
20783
|
+
<button
|
|
20784
|
+
type="button"
|
|
20785
|
+
class="strct-mb__item"
|
|
20786
|
+
role="menuitem"
|
|
20787
|
+
[attr.data-idx]="i"
|
|
20788
|
+
[class.strct-mb__item--critical]="item.critical"
|
|
20789
|
+
[attr.aria-haspopup]="item.children?.length ? 'menu' : null"
|
|
20790
|
+
[attr.aria-expanded]="item.children?.length ? subIdx() === i : null"
|
|
20791
|
+
[attr.aria-disabled]="item.disabled ? 'true' : null"
|
|
20792
|
+
[attr.aria-describedby]="item.hint ? hintId(menu.id, i) : null"
|
|
20793
|
+
[attr.title]="item.hint || null"
|
|
20794
|
+
(click)="onItemClick(menu, item, i)"
|
|
20795
|
+
(mouseenter)="onItemHover(item, i)"
|
|
20796
|
+
>
|
|
20797
|
+
@if (item.icon) {
|
|
20798
|
+
<strct-icon [name]="item.icon" [size]="13" />
|
|
20799
|
+
}
|
|
20800
|
+
{{ item.label }}
|
|
20801
|
+
@if (item.children?.length) {
|
|
20802
|
+
<strct-icon class="strct-mb__caret" name="chevronRight" [size]="12" />
|
|
20803
|
+
}
|
|
20804
|
+
</button>
|
|
20805
|
+
@if (item.hint) {
|
|
20806
|
+
<span [id]="hintId(menu.id, i)" hidden>{{ item.hint }}</span>
|
|
20807
|
+
}
|
|
20808
|
+
@if (subIdx() === i && item.children?.length) {
|
|
20809
|
+
<div class="strct-mb__submenu" role="menu" [attr.aria-label]="item.label">
|
|
20810
|
+
@for (sub of item.children; track $index; let j = $index) {
|
|
20811
|
+
@if (sub.divider) {
|
|
20812
|
+
<div class="strct-mb__divider" role="separator"></div>
|
|
20813
|
+
} @else {
|
|
20814
|
+
<button
|
|
20815
|
+
type="button"
|
|
20816
|
+
class="strct-mb__item strct-mb__subitem"
|
|
20817
|
+
role="menuitem"
|
|
20818
|
+
[class.strct-mb__item--critical]="sub.critical"
|
|
20819
|
+
[attr.aria-disabled]="sub.disabled ? 'true' : null"
|
|
20820
|
+
[attr.aria-describedby]="sub.hint ? hintId(menu.id, i, j) : null"
|
|
20821
|
+
[attr.title]="sub.hint || null"
|
|
20822
|
+
(click)="pick(menu, sub)"
|
|
20823
|
+
>
|
|
20824
|
+
@if (sub.icon) {
|
|
20825
|
+
<strct-icon [name]="sub.icon" [size]="13" />
|
|
20826
|
+
}
|
|
20827
|
+
{{ sub.label }}
|
|
20828
|
+
</button>
|
|
20829
|
+
@if (sub.hint) {
|
|
20830
|
+
<span [id]="hintId(menu.id, i, j)" hidden>{{ sub.hint }}</span>
|
|
20831
|
+
}
|
|
20832
|
+
}
|
|
20833
|
+
}
|
|
20834
|
+
</div>
|
|
20835
|
+
}
|
|
20836
|
+
</div>
|
|
20837
|
+
}
|
|
20838
|
+
}
|
|
20839
|
+
</div>
|
|
20840
|
+
}
|
|
20841
|
+
</div>
|
|
20842
|
+
}
|
|
20843
|
+
</div>
|
|
20844
|
+
`, styles: [".strct-mb{display:inline-flex;gap:2px;padding:2px;background:var(--bg-2);border:1px solid var(--b1);border-radius:var(--radius-md)}.strct-mb__wrap{position:relative}.strct-mb__top{padding:4px 11px;border:0;border-radius:5px;background:transparent;color:var(--t1);font-family:var(--font);font-size:12.5px;cursor:pointer;white-space:nowrap}.strct-mb__top:hover,.strct-mb__top--open{background:var(--bg-3)}.strct-mb__top:focus-visible{outline:2px solid var(--acc50);outline-offset:1px}.strct-mb__menu{position:absolute;top:calc(100% + 4px);inset-inline-start:0;z-index:var(--z-dropdown);min-width:180px;padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-md);box-shadow:var(--shh);display:flex;flex-direction:column}.strct-mb__menu:focus{outline:none}.strct-mb__item{display:flex;align-items:center;gap:8px;width:100%;padding:6px 10px;border:0;border-radius:5px;background:transparent;color:var(--t1);font-family:var(--font);font-size:12.5px;text-align:start;cursor:pointer;white-space:nowrap}.strct-mb__item:hover:not([aria-disabled=true]){background:var(--bg-3)}.strct-mb__item--critical{color:var(--critical)}.strct-mb__item--critical:hover:not([aria-disabled=true]){background:var(--critical-bg)}.strct-mb__item[aria-disabled=true]{color:var(--t4);cursor:default}.strct-mb__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-mb__divider{height:1px;margin:4px 6px;background:var(--b2)}.strct-mb__row{position:relative}.strct-mb__caret{margin-inline-start:auto;color:var(--t3)}[dir=rtl] .strct-mb__caret{transform:rotate(180deg)}.strct-mb__submenu{position:absolute;top:-5px;inset-inline-start:calc(100% + 2px);z-index:var(--z-base);min-width:160px;padding:4px;background:var(--bg-1);border:1px solid var(--b2);border-radius:var(--radius-md);box-shadow:var(--shh);display:flex;flex-direction:column}\n"] }]
|
|
20845
|
+
}], propDecorators: { menus: [{ type: i0.Input, args: [{ isSignal: true, alias: "menus", required: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], picked: [{ type: i0.Output, args: ["picked"] }], onDocClick: [{
|
|
20846
|
+
type: HostListener,
|
|
20847
|
+
args: ['document:click', ['$event']]
|
|
20848
|
+
}], onEscape: [{
|
|
20582
20849
|
type: HostListener,
|
|
20583
20850
|
args: ['document:keydown.escape', ['$event']]
|
|
20584
20851
|
}] } });
|
|
20585
20852
|
|
|
20586
|
-
|
|
20853
|
+
function normalize(combo) {
|
|
20854
|
+
return combo
|
|
20855
|
+
.toLowerCase()
|
|
20856
|
+
.split('+')
|
|
20857
|
+
.map((p) => p.trim())
|
|
20858
|
+
.sort()
|
|
20859
|
+
.join('+');
|
|
20860
|
+
}
|
|
20861
|
+
function comboOf(event) {
|
|
20862
|
+
const parts = [];
|
|
20863
|
+
if (event.ctrlKey)
|
|
20864
|
+
parts.push('ctrl');
|
|
20865
|
+
if (event.metaKey)
|
|
20866
|
+
parts.push('meta');
|
|
20867
|
+
if (event.altKey)
|
|
20868
|
+
parts.push('alt');
|
|
20869
|
+
if (event.shiftKey)
|
|
20870
|
+
parts.push('shift');
|
|
20871
|
+
parts.push(event.key.toLowerCase());
|
|
20872
|
+
return parts.sort().join('+');
|
|
20873
|
+
}
|
|
20874
|
+
/** `mod` matches Ctrl (and ⌘ on mac keyboards) — expand to both. */
|
|
20875
|
+
function expand(combo) {
|
|
20876
|
+
const n = combo.toLowerCase();
|
|
20877
|
+
if (!n.includes('mod'))
|
|
20878
|
+
return [normalize(n)];
|
|
20879
|
+
return [normalize(n.replace('mod', 'ctrl')), normalize(n.replace('mod', 'meta'))];
|
|
20880
|
+
}
|
|
20587
20881
|
/**
|
|
20588
|
-
*
|
|
20589
|
-
*
|
|
20590
|
-
* <ul strctReorder (reordered)="move($event)">
|
|
20591
|
-
* @for (s of steps(); track s.id) {
|
|
20592
|
-
* <li strctReorderItem>{{ s.label }}</li>
|
|
20593
|
-
* }
|
|
20594
|
-
* </ul>
|
|
20882
|
+
* Application hotkeys, centrally registered so they are discoverable — the
|
|
20883
|
+
* Blueprint pattern:
|
|
20595
20884
|
*
|
|
20596
|
-
*
|
|
20597
|
-
*
|
|
20598
|
-
*
|
|
20885
|
+
* private hotkeys = inject(StrctHotkeysService);
|
|
20886
|
+
* ngOnInit() { this.dispose = this.hotkeys.register(
|
|
20887
|
+
* { combo: 'mod+k', description: 'Open command palette', group: 'Global',
|
|
20888
|
+
* handler: () => this.palette.open() }); }
|
|
20599
20889
|
*
|
|
20600
|
-
*
|
|
20601
|
-
*
|
|
20602
|
-
*
|
|
20603
|
-
*
|
|
20604
|
-
* items reference the sr-only `instructions` via `aria-describedby`.
|
|
20890
|
+
* Combos: `'a'`, `'shift+?'`, `'ctrl+k'`, `'meta+shift+p'`, `'mod+k'` (mod = Ctrl/⌘).
|
|
20891
|
+
* Plain-key combos are suppressed while typing in inputs / textareas /
|
|
20892
|
+
* contenteditable; modifier combos always fire. Pair with
|
|
20893
|
+
* `<strct-hotkeys-help/>` for the ⌘/ ("?") cheatsheet overlay.
|
|
20605
20894
|
*/
|
|
20606
|
-
class
|
|
20607
|
-
|
|
20608
|
-
|
|
20609
|
-
|
|
20610
|
-
|
|
20611
|
-
|
|
20612
|
-
reordered = output();
|
|
20613
|
-
/** Disable all reordering (display-only mode). */
|
|
20614
|
-
reorderDisabled = input(false, { ...(ngDevMode ? { debugName: "reorderDisabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
20615
|
-
/**
|
|
20616
|
-
* Keyboard instructions (localizable), rendered sr-only and referenced by
|
|
20617
|
-
* every item's `aria-describedby`. Set to '' to opt out.
|
|
20618
|
-
*/
|
|
20619
|
-
instructions = input('Press Alt+ArrowUp or Alt+ArrowDown to move this item', /* @ts-ignore */
|
|
20620
|
-
...(ngDevMode ? [{ debugName: "instructions" }] : /* istanbul ignore next */ []));
|
|
20621
|
-
/**
|
|
20622
|
-
* Builds the live-region announcement after a move (localizable):
|
|
20623
|
-
* (moved item's text, new 1-based position, item count).
|
|
20624
|
-
*/
|
|
20625
|
-
announcement = input((label, position, total) => `Moved ${label} to position ${position} of ${total}`, /* @ts-ignore */
|
|
20626
|
-
...(ngDevMode ? [{ debugName: "announcement" }] : /* istanbul ignore next */ []));
|
|
20627
|
-
dragIndex = signal(null, /* @ts-ignore */
|
|
20628
|
-
...(ngDevMode ? [{ debugName: "dragIndex" }] : /* istanbul ignore next */ []));
|
|
20629
|
-
overIndex = signal(null, /* @ts-ignore */
|
|
20630
|
-
...(ngDevMode ? [{ debugName: "overIndex" }] : /* istanbul ignore next */ []));
|
|
20631
|
-
/** Id of the sr-only instructions element the items point to. */
|
|
20632
|
-
instructionsId = `strct-reorder-hint-${++reorderCounter}`;
|
|
20633
|
-
hint = null;
|
|
20895
|
+
class StrctHotkeysService {
|
|
20896
|
+
registry = signal([], /* @ts-ignore */
|
|
20897
|
+
...(ngDevMode ? [{ debugName: "registry" }] : /* istanbul ignore next */ []));
|
|
20898
|
+
/** All registered hotkeys (for the help overlay). */
|
|
20899
|
+
hotkeys = this.registry.asReadonly();
|
|
20900
|
+
listener = (event) => this.onKeydown(event);
|
|
20634
20901
|
constructor() {
|
|
20635
|
-
|
|
20636
|
-
effect(() => {
|
|
20637
|
-
const text = this.instructions();
|
|
20638
|
-
if (text && !this.hint) {
|
|
20639
|
-
this.hint = this.renderer.createElement('span');
|
|
20640
|
-
this.renderer.setAttribute(this.hint, 'id', this.instructionsId);
|
|
20641
|
-
this.hint.style.cssText =
|
|
20642
|
-
'position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;';
|
|
20643
|
-
this.renderer.appendChild(this.doc.body, this.hint);
|
|
20644
|
-
}
|
|
20645
|
-
if (this.hint)
|
|
20646
|
-
this.hint.textContent = text;
|
|
20647
|
-
});
|
|
20648
|
-
}
|
|
20649
|
-
items() {
|
|
20650
|
-
return [...this.host.nativeElement.querySelectorAll('[strctReorderItem]')];
|
|
20651
|
-
}
|
|
20652
|
-
indexOf(el) {
|
|
20653
|
-
return this.items().indexOf(el);
|
|
20654
|
-
}
|
|
20655
|
-
commit(from, to) {
|
|
20656
|
-
this.dragIndex.set(null);
|
|
20657
|
-
this.overIndex.set(null);
|
|
20658
|
-
if (from < 0 || to < 0 || from === to)
|
|
20659
|
-
return;
|
|
20660
|
-
const label = this.items()[from]?.textContent?.trim() ?? '';
|
|
20661
|
-
this.reordered.emit({ from, to });
|
|
20662
|
-
this.announcer.announce(this.announcement()(label, to + 1, this.items().length));
|
|
20663
|
-
}
|
|
20664
|
-
onContainerDragOver(event) {
|
|
20665
|
-
// Only the container's own empty space (below the last item); drags over
|
|
20666
|
-
// items are handled by the items themselves.
|
|
20667
|
-
if (this.dragIndex() == null)
|
|
20668
|
-
return;
|
|
20669
|
-
if (event.target.closest('[strctReorderItem]'))
|
|
20670
|
-
return;
|
|
20671
|
-
event.preventDefault();
|
|
20902
|
+
document.addEventListener('keydown', this.listener);
|
|
20672
20903
|
}
|
|
20673
|
-
|
|
20674
|
-
|
|
20675
|
-
|
|
20676
|
-
|
|
20677
|
-
if (event.target.closest('[strctReorderItem]'))
|
|
20678
|
-
return;
|
|
20679
|
-
event.preventDefault();
|
|
20680
|
-
// Drop into empty space moves the item to the end.
|
|
20681
|
-
this.commit(from, this.items().length - 1);
|
|
20904
|
+
/** Register a hotkey; the returned function unregisters it. */
|
|
20905
|
+
register(hotkey) {
|
|
20906
|
+
this.registry.update((list) => [...list, hotkey]);
|
|
20907
|
+
return () => this.registry.update((list) => list.filter((h) => h !== hotkey));
|
|
20682
20908
|
}
|
|
20683
|
-
|
|
20684
|
-
|
|
20685
|
-
|
|
20686
|
-
const
|
|
20687
|
-
|
|
20909
|
+
onKeydown(event) {
|
|
20910
|
+
const combo = comboOf(event);
|
|
20911
|
+
const typing = isTyping(event);
|
|
20912
|
+
for (const hk of this.registry()) {
|
|
20913
|
+
if (!expand(hk.combo).includes(combo))
|
|
20914
|
+
continue;
|
|
20915
|
+
// While typing, only modifier combos may fire.
|
|
20916
|
+
if (typing && !(event.ctrlKey || event.metaKey || event.altKey))
|
|
20917
|
+
continue;
|
|
20918
|
+
event.preventDefault();
|
|
20919
|
+
hk.handler(event);
|
|
20688
20920
|
return;
|
|
20689
|
-
|
|
20921
|
+
}
|
|
20690
20922
|
}
|
|
20691
20923
|
ngOnDestroy() {
|
|
20692
|
-
|
|
20693
|
-
this.renderer.removeChild(this.doc.body, this.hint);
|
|
20694
|
-
this.hint = null;
|
|
20695
|
-
}
|
|
20924
|
+
document.removeEventListener('keydown', this.listener);
|
|
20696
20925
|
}
|
|
20697
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
20698
|
-
static
|
|
20926
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctHotkeysService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
20927
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctHotkeysService, providedIn: 'root' });
|
|
20699
20928
|
}
|
|
20700
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
20701
|
-
type:
|
|
20702
|
-
args: [{
|
|
20703
|
-
}], ctorParameters: () => []
|
|
20704
|
-
|
|
20705
|
-
|
|
20706
|
-
|
|
20707
|
-
|
|
20708
|
-
|
|
20709
|
-
|
|
20710
|
-
|
|
20711
|
-
|
|
20712
|
-
|
|
20713
|
-
/**
|
|
20714
|
-
|
|
20715
|
-
|
|
20716
|
-
|
|
20717
|
-
|
|
20718
|
-
|
|
20719
|
-
|
|
20720
|
-
|
|
20721
|
-
|
|
20722
|
-
|
|
20723
|
-
|
|
20724
|
-
}
|
|
20725
|
-
|
|
20726
|
-
|
|
20727
|
-
}
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
|
|
20732
|
-
|
|
20733
|
-
|
|
20734
|
-
|
|
20735
|
-
|
|
20736
|
-
|
|
20737
|
-
|
|
20738
|
-
|
|
20739
|
-
|
|
20740
|
-
|
|
20741
|
-
|
|
20742
|
-
|
|
20743
|
-
|
|
20929
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctHotkeysService, decorators: [{
|
|
20930
|
+
type: Injectable,
|
|
20931
|
+
args: [{ providedIn: 'root' }]
|
|
20932
|
+
}], ctorParameters: () => [] });
|
|
20933
|
+
function isTyping(event) {
|
|
20934
|
+
const el = event.target;
|
|
20935
|
+
if (!el)
|
|
20936
|
+
return false;
|
|
20937
|
+
return (el.tagName === 'INPUT' ||
|
|
20938
|
+
el.tagName === 'TEXTAREA' ||
|
|
20939
|
+
el.tagName === 'SELECT' ||
|
|
20940
|
+
el.isContentEditable);
|
|
20941
|
+
}
|
|
20942
|
+
/**
|
|
20943
|
+
* The hotkey cheatsheet overlay. Mount once near the app root; it registers
|
|
20944
|
+
* `shift+?` (typed as `?`) itself and lists everything in the service, grouped:
|
|
20945
|
+
*
|
|
20946
|
+
* <strct-hotkeys-help />
|
|
20947
|
+
*/
|
|
20948
|
+
class StrctHotkeysHelp {
|
|
20949
|
+
service = inject(StrctHotkeysService);
|
|
20950
|
+
host = inject((ElementRef));
|
|
20951
|
+
/** Overlay visibility (two-way; `?` toggles it too). */
|
|
20952
|
+
open = model(false, /* @ts-ignore */
|
|
20953
|
+
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
20954
|
+
/** Localizable strings. */
|
|
20955
|
+
title = input('Keyboard shortcuts', /* @ts-ignore */
|
|
20956
|
+
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
20957
|
+
emptyText = input('No shortcuts registered.', /* @ts-ignore */
|
|
20958
|
+
...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
|
|
20959
|
+
/** Accessible label of the × close button (localizable). */
|
|
20960
|
+
closeLabel = input('Close', /* @ts-ignore */
|
|
20961
|
+
...(ngDevMode ? [{ debugName: "closeLabel" }] : /* istanbul ignore next */ []));
|
|
20962
|
+
/** Element that had focus before the overlay opened, restored on close. */
|
|
20963
|
+
previousActive = null;
|
|
20964
|
+
grouped = computed(() => {
|
|
20965
|
+
const groups = new Map();
|
|
20966
|
+
for (const hk of this.service.hotkeys()) {
|
|
20967
|
+
const name = hk.group ?? 'General';
|
|
20968
|
+
const list = groups.get(name);
|
|
20969
|
+
if (list)
|
|
20970
|
+
list.push(hk);
|
|
20971
|
+
else
|
|
20972
|
+
groups.set(name, [hk]);
|
|
20973
|
+
}
|
|
20974
|
+
return [...groups.entries()].map(([name, keys]) => ({ name, keys }));
|
|
20975
|
+
}, /* @ts-ignore */
|
|
20976
|
+
...(ngDevMode ? [{ debugName: "grouped" }] : /* istanbul ignore next */ []));
|
|
20977
|
+
constructor() {
|
|
20978
|
+
const dispose = this.service.register({
|
|
20979
|
+
combo: 'shift+?',
|
|
20980
|
+
description: 'Show this help',
|
|
20981
|
+
group: 'General',
|
|
20982
|
+
handler: () => this.open.update((v) => !v),
|
|
20983
|
+
});
|
|
20984
|
+
inject(DestroyRef).onDestroy(dispose);
|
|
20985
|
+
// Focus lifecycle: remember the trigger, move focus into the dialog once
|
|
20986
|
+
// it has rendered, and hand focus back on close.
|
|
20987
|
+
effect(() => {
|
|
20988
|
+
if (this.open()) {
|
|
20989
|
+
this.previousActive = saveFocusedElement();
|
|
20990
|
+
setTimeout(() => {
|
|
20991
|
+
const dialog = this.host.nativeElement.querySelector('.strct-hkh');
|
|
20992
|
+
if (dialog)
|
|
20993
|
+
focusFirstIn(dialog);
|
|
20994
|
+
});
|
|
20995
|
+
}
|
|
20996
|
+
else {
|
|
20997
|
+
restoreFocus(this.previousActive);
|
|
20998
|
+
this.previousActive = null;
|
|
20999
|
+
}
|
|
21000
|
+
});
|
|
20744
21001
|
}
|
|
20745
|
-
|
|
20746
|
-
|
|
20747
|
-
|
|
20748
|
-
if (
|
|
21002
|
+
// Escape is handled locally — registering it in the service would swallow
|
|
21003
|
+
// every Escape in the app (the service preventDefaults on match).
|
|
21004
|
+
onEscape(event) {
|
|
21005
|
+
if (!this.open())
|
|
20749
21006
|
return;
|
|
20750
|
-
|
|
21007
|
+
// Document-level: stopImmediatePropagation so a host modal/drawer with its
|
|
21008
|
+
// own document listener doesn't also see the Escape the overlay consumed.
|
|
21009
|
+
event.stopImmediatePropagation();
|
|
21010
|
+
this.open.set(false);
|
|
20751
21011
|
}
|
|
20752
|
-
|
|
20753
|
-
|
|
20754
|
-
|
|
21012
|
+
parts(combo) {
|
|
21013
|
+
return combo.split('+').map((p) => {
|
|
21014
|
+
const map = {
|
|
21015
|
+
mod: '⌘/Ctrl',
|
|
21016
|
+
meta: '⌘',
|
|
21017
|
+
ctrl: 'Ctrl',
|
|
21018
|
+
alt: 'Alt',
|
|
21019
|
+
shift: 'Shift',
|
|
21020
|
+
escape: 'Esc',
|
|
21021
|
+
};
|
|
21022
|
+
return map[p.trim().toLowerCase()] ?? p.trim().toUpperCase();
|
|
21023
|
+
});
|
|
20755
21024
|
}
|
|
20756
|
-
|
|
20757
|
-
|
|
20758
|
-
|
|
20759
|
-
|
|
20760
|
-
|
|
20761
|
-
|
|
20762
|
-
|
|
20763
|
-
|
|
20764
|
-
|
|
20765
|
-
|
|
20766
|
-
|
|
20767
|
-
|
|
20768
|
-
|
|
21025
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctHotkeysHelp, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
21026
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: StrctHotkeysHelp, isStandalone: true, selector: "strct-hotkeys-help", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { listeners: { "document:keydown.escape": "onEscape($event)" } }, ngImport: i0, template: `
|
|
21027
|
+
@if (open()) {
|
|
21028
|
+
<div class="strct-hkh__backdrop" (click)="open.set(false)"></div>
|
|
21029
|
+
<div class="strct-hkh" role="dialog" aria-modal="true" [attr.aria-label]="title()">
|
|
21030
|
+
<div class="strct-hkh__head">
|
|
21031
|
+
<span class="strct-hkh__title">{{ title() }}</span>
|
|
21032
|
+
<span class="strct-hkh__headside">
|
|
21033
|
+
<strct-kbd>?</strct-kbd>
|
|
21034
|
+
<button
|
|
21035
|
+
type="button"
|
|
21036
|
+
class="strct-hkh__close"
|
|
21037
|
+
[attr.aria-label]="closeLabel()"
|
|
21038
|
+
(click)="open.set(false)"
|
|
21039
|
+
>
|
|
21040
|
+
<strct-icon name="close" [size]="14" />
|
|
21041
|
+
</button>
|
|
21042
|
+
</span>
|
|
21043
|
+
</div>
|
|
21044
|
+
@for (group of grouped(); track group.name) {
|
|
21045
|
+
<div class="strct-hkh__group">
|
|
21046
|
+
<div class="strct-hkh__groupname">{{ group.name }}</div>
|
|
21047
|
+
@for (hk of group.keys; track hk.combo + hk.description) {
|
|
21048
|
+
<div class="strct-hkh__row">
|
|
21049
|
+
<span class="strct-hkh__desc">{{ hk.description }}</span>
|
|
21050
|
+
<span class="strct-hkh__keys">
|
|
21051
|
+
@for (part of parts(hk.combo); track $index) {
|
|
21052
|
+
<strct-kbd>{{ part }}</strct-kbd>
|
|
21053
|
+
}
|
|
21054
|
+
</span>
|
|
21055
|
+
</div>
|
|
21056
|
+
}
|
|
21057
|
+
</div>
|
|
21058
|
+
} @empty {
|
|
21059
|
+
<p class="strct-hkh__empty">{{ emptyText() }}</p>
|
|
21060
|
+
}
|
|
21061
|
+
</div>
|
|
20769
21062
|
}
|
|
20770
|
-
|
|
20771
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctReorderItem, isStandalone: true, selector: "[strctReorderItem]", host: { listeners: { "dragstart": "onDragStart($event)", "dragover": "onDragOver($event)", "drop": "onDrop($event)", "dragend": "onDragEnd()", "keydown": "onKeydown($event)" }, properties: { "attr.draggable": "!list.reorderDisabled()", "attr.tabindex": "hostTabindex()", "class.strct-reorder--dragging": "isDragging()", "class.strct-reorder--over": "isOver()", "attr.aria-roledescription": "'sortable'", "attr.aria-keyshortcuts": "'Alt+ArrowUp Alt+ArrowDown'", "attr.aria-posinset": "index() + 1", "attr.aria-setsize": "list.items().length", "attr.aria-describedby": "list.instructions() ? list.instructionsId : null" } }, ngImport: i0 });
|
|
20772
|
-
}
|
|
20773
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctReorderItem, decorators: [{
|
|
20774
|
-
type: Directive,
|
|
20775
|
-
args: [{
|
|
20776
|
-
selector: '[strctReorderItem]',
|
|
20777
|
-
host: {
|
|
20778
|
-
'[attr.draggable]': '!list.reorderDisabled()',
|
|
20779
|
-
'[attr.tabindex]': 'hostTabindex()',
|
|
20780
|
-
'[class.strct-reorder--dragging]': 'isDragging()',
|
|
20781
|
-
'[class.strct-reorder--over]': 'isOver()',
|
|
20782
|
-
'[attr.aria-roledescription]': "'sortable'",
|
|
20783
|
-
'[attr.aria-keyshortcuts]': "'Alt+ArrowUp Alt+ArrowDown'",
|
|
20784
|
-
'[attr.aria-posinset]': 'index() + 1',
|
|
20785
|
-
'[attr.aria-setsize]': 'list.items().length',
|
|
20786
|
-
'[attr.aria-describedby]': 'list.instructions() ? list.instructionsId : null',
|
|
20787
|
-
},
|
|
20788
|
-
}]
|
|
20789
|
-
}], propDecorators: { onDragStart: [{
|
|
20790
|
-
type: HostListener,
|
|
20791
|
-
args: ['dragstart', ['$event']]
|
|
20792
|
-
}], onDragOver: [{
|
|
20793
|
-
type: HostListener,
|
|
20794
|
-
args: ['dragover', ['$event']]
|
|
20795
|
-
}], onDrop: [{
|
|
20796
|
-
type: HostListener,
|
|
20797
|
-
args: ['drop', ['$event']]
|
|
20798
|
-
}], onDragEnd: [{
|
|
20799
|
-
type: HostListener,
|
|
20800
|
-
args: ['dragend']
|
|
20801
|
-
}], onKeydown: [{
|
|
20802
|
-
type: HostListener,
|
|
20803
|
-
args: ['keydown', ['$event']]
|
|
20804
|
-
}] } });
|
|
20805
|
-
|
|
20806
|
-
/**
|
|
20807
|
-
* Default accessible text per status, used when `label` is not given
|
|
20808
|
-
* (localizable — override via `label`). The canonical `StrctStatus` vocabulary
|
|
20809
|
-
* has no 'ok'/'info': OK maps to 'success', info to 'accent'.
|
|
20810
|
-
*/
|
|
20811
|
-
const DEFAULT_LABEL = {
|
|
20812
|
-
neutral: 'Neutral',
|
|
20813
|
-
accent: 'Info',
|
|
20814
|
-
success: 'OK',
|
|
20815
|
-
warning: 'Warning',
|
|
20816
|
-
critical: 'Critical',
|
|
20817
|
-
};
|
|
20818
|
-
/**
|
|
20819
|
-
* Presence/state dot that never relies on colour alone: the tone is painted by
|
|
20820
|
-
* a pure-CSS dot while the state is also rendered as visually-hidden text, so
|
|
20821
|
-
* screen readers (and colour-blind users copying text) get "Warning", not just
|
|
20822
|
-
* a yellow circle. Use it inside avatars, menu rows, metric tiles — anywhere a
|
|
20823
|
-
* bare coloured dot would otherwise carry meaning.
|
|
20824
|
-
*
|
|
20825
|
-
* <strct-status-dot status="success" />
|
|
20826
|
-
* <strct-status-dot status="critical" size="sm" label="Node unreachable" />
|
|
20827
|
-
*/
|
|
20828
|
-
class StrctStatusDot {
|
|
20829
|
-
/** Status tone (canonical vocabulary: OK = 'success', info = 'accent'). */
|
|
20830
|
-
status = input('neutral', /* @ts-ignore */
|
|
20831
|
-
...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
20832
|
-
/**
|
|
20833
|
-
* Accessible text describing the state (localizable). Empty falls back to a
|
|
20834
|
-
* per-status default ("OK", "Warning", …) so the dot is never color-only.
|
|
20835
|
-
*/
|
|
20836
|
-
label = input('', /* @ts-ignore */
|
|
20837
|
-
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
20838
|
-
/** Dot size: `sm` for dense rows, `md` standalone. */
|
|
20839
|
-
size = input('md', /* @ts-ignore */
|
|
20840
|
-
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
20841
|
-
text = computed(() => this.label() || DEFAULT_LABEL[this.status()], /* @ts-ignore */
|
|
20842
|
-
...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
|
|
20843
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctStatusDot, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
20844
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: StrctStatusDot, isStandalone: true, selector: "strct-status-dot", inputs: { status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.strct-dot--accent": "status() === 'accent'", "class.strct-dot--success": "status() === 'success'", "class.strct-dot--warning": "status() === 'warning'", "class.strct-dot--critical": "status() === 'critical'", "class.strct-dot--sm": "size() === 'sm'" }, classAttribute: "strct-dot" }, ngImport: i0, template: `
|
|
20845
|
-
<span class="strct-dot__dot" aria-hidden="true"></span>
|
|
20846
|
-
<span class="strct-dot__sr">{{ text() }}</span>
|
|
20847
|
-
`, isInline: true, styles: [".strct-dot{display:inline-flex;align-items:center;flex:none;line-height:0}.strct-dot__dot{width:10px;height:10px;border-radius:50%;background:var(--t3)}.strct-dot--sm .strct-dot__dot{width:8px;height:8px}.strct-dot--accent .strct-dot__dot{background:var(--acc)}.strct-dot--success .strct-dot__dot{background:var(--success)}.strct-dot--warning .strct-dot__dot{background:var(--warning)}.strct-dot--critical .strct-dot__dot{background:var(--critical)}.strct-dot__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
21063
|
+
`, isInline: true, styles: [".strct-hkh__backdrop{position:fixed;inset:0;z-index:var(--z-tour);background:var(--backdrop)}.strct-hkh{position:fixed;z-index:calc(var(--z-tour) + 1);top:50%;left:50%;transform:translate(-50%,-50%);width:min(420px,calc(100vw - 32px));max-height:min(70vh,520px);overflow:auto;padding:16px 18px;background:var(--bg-1);border:1px solid var(--b2);border-radius:10px;box-shadow:var(--shh)}.strct-hkh__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}.strct-hkh__title{font-size:13.5px;font-weight:650;color:var(--t1)}.strct-hkh__headside{display:inline-flex;align-items:center;gap:8px}.strct-hkh__close{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer}.strct-hkh__close:hover{color:var(--t1);background:var(--bg-3)}.strct-hkh__group{margin-bottom:12px}.strct-hkh__groupname{font-size:10.5px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--t3);margin-bottom:5px}.strct-hkh__row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:4px 0}.strct-hkh__desc{font-size:12.5px;color:var(--t1)}.strct-hkh__keys{display:inline-flex;gap:4px}.strct-hkh__empty{font-size:12.5px;color:var(--t3)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctKbd, selector: "strct-kbd" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
20848
21064
|
}
|
|
20849
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
21065
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctHotkeysHelp, decorators: [{
|
|
20850
21066
|
type: Component,
|
|
20851
|
-
args: [{ selector: 'strct-
|
|
20852
|
-
|
|
20853
|
-
|
|
20854
|
-
|
|
20855
|
-
|
|
20856
|
-
|
|
20857
|
-
|
|
20858
|
-
|
|
20859
|
-
|
|
20860
|
-
|
|
20861
|
-
|
|
20862
|
-
|
|
21067
|
+
args: [{ selector: 'strct-hotkeys-help', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [StrctIcon, StrctKbd], template: `
|
|
21068
|
+
@if (open()) {
|
|
21069
|
+
<div class="strct-hkh__backdrop" (click)="open.set(false)"></div>
|
|
21070
|
+
<div class="strct-hkh" role="dialog" aria-modal="true" [attr.aria-label]="title()">
|
|
21071
|
+
<div class="strct-hkh__head">
|
|
21072
|
+
<span class="strct-hkh__title">{{ title() }}</span>
|
|
21073
|
+
<span class="strct-hkh__headside">
|
|
21074
|
+
<strct-kbd>?</strct-kbd>
|
|
21075
|
+
<button
|
|
21076
|
+
type="button"
|
|
21077
|
+
class="strct-hkh__close"
|
|
21078
|
+
[attr.aria-label]="closeLabel()"
|
|
21079
|
+
(click)="open.set(false)"
|
|
21080
|
+
>
|
|
21081
|
+
<strct-icon name="close" [size]="14" />
|
|
21082
|
+
</button>
|
|
21083
|
+
</span>
|
|
21084
|
+
</div>
|
|
21085
|
+
@for (group of grouped(); track group.name) {
|
|
21086
|
+
<div class="strct-hkh__group">
|
|
21087
|
+
<div class="strct-hkh__groupname">{{ group.name }}</div>
|
|
21088
|
+
@for (hk of group.keys; track hk.combo + hk.description) {
|
|
21089
|
+
<div class="strct-hkh__row">
|
|
21090
|
+
<span class="strct-hkh__desc">{{ hk.description }}</span>
|
|
21091
|
+
<span class="strct-hkh__keys">
|
|
21092
|
+
@for (part of parts(hk.combo); track $index) {
|
|
21093
|
+
<strct-kbd>{{ part }}</strct-kbd>
|
|
21094
|
+
}
|
|
21095
|
+
</span>
|
|
21096
|
+
</div>
|
|
21097
|
+
}
|
|
21098
|
+
</div>
|
|
21099
|
+
} @empty {
|
|
21100
|
+
<p class="strct-hkh__empty">{{ emptyText() }}</p>
|
|
21101
|
+
}
|
|
21102
|
+
</div>
|
|
21103
|
+
}
|
|
21104
|
+
`, styles: [".strct-hkh__backdrop{position:fixed;inset:0;z-index:var(--z-tour);background:var(--backdrop)}.strct-hkh{position:fixed;z-index:calc(var(--z-tour) + 1);top:50%;left:50%;transform:translate(-50%,-50%);width:min(420px,calc(100vw - 32px));max-height:min(70vh,520px);overflow:auto;padding:16px 18px;background:var(--bg-1);border:1px solid var(--b2);border-radius:10px;box-shadow:var(--shh)}.strct-hkh__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}.strct-hkh__title{font-size:13.5px;font-weight:650;color:var(--t1)}.strct-hkh__headside{display:inline-flex;align-items:center;gap:8px}.strct-hkh__close{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer}.strct-hkh__close:hover{color:var(--t1);background:var(--bg-3)}.strct-hkh__group{margin-bottom:12px}.strct-hkh__groupname{font-size:10.5px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--t3);margin-bottom:5px}.strct-hkh__row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:4px 0}.strct-hkh__desc{font-size:12.5px;color:var(--t1)}.strct-hkh__keys{display:inline-flex;gap:4px}.strct-hkh__empty{font-size:12.5px;color:var(--t3)}\n"] }]
|
|
21105
|
+
}], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], onEscape: [{
|
|
21106
|
+
type: HostListener,
|
|
21107
|
+
args: ['document:keydown.escape', ['$event']]
|
|
21108
|
+
}] } });
|
|
20863
21109
|
|
|
21110
|
+
let reorderCounter = 0;
|
|
20864
21111
|
/**
|
|
20865
|
-
*
|
|
20866
|
-
* `number | null` (null = empty); typing is free-form (intermediate states
|
|
20867
|
-
* like "-" are kept), committed values clamp to `min`/`max` on blur, and the
|
|
20868
|
-
* buttons + keyboard always clamp immediately.
|
|
21112
|
+
* List drag-reorder primitive — the consumer owns the array:
|
|
20869
21113
|
*
|
|
20870
|
-
* <
|
|
21114
|
+
* <ul strctReorder (reordered)="move($event)">
|
|
21115
|
+
* @for (s of steps(); track s.id) {
|
|
21116
|
+
* <li strctReorderItem>{{ s.label }}</li>
|
|
21117
|
+
* }
|
|
21118
|
+
* </ul>
|
|
20871
21119
|
*
|
|
20872
|
-
*
|
|
20873
|
-
*
|
|
20874
|
-
*
|
|
21120
|
+
* move({ from, to }: StrctReorderEvent) {
|
|
21121
|
+
* this.steps.update((s) => { const c = [...s]; c.splice(to, 0, ...c.splice(from, 1)); return c; });
|
|
21122
|
+
* }
|
|
21123
|
+
*
|
|
21124
|
+
* Items are HTML5-draggable; keyboard reorder is Alt+ArrowUp / Alt+ArrowDown
|
|
21125
|
+
* on the focused item (items get `tabindex="0"` unless they already manage
|
|
21126
|
+
* focus). Indexes are positions among the `strctReorderItem` siblings.
|
|
21127
|
+
* Completed moves are announced in a live region (see `announcement`) and
|
|
21128
|
+
* items reference the sr-only `instructions` via `aria-describedby`.
|
|
20875
21129
|
*/
|
|
20876
|
-
class
|
|
20877
|
-
|
|
20878
|
-
|
|
20879
|
-
|
|
20880
|
-
|
|
20881
|
-
|
|
20882
|
-
|
|
20883
|
-
/**
|
|
20884
|
-
|
|
20885
|
-
|
|
20886
|
-
|
|
20887
|
-
|
|
20888
|
-
|
|
20889
|
-
|
|
20890
|
-
|
|
20891
|
-
|
|
20892
|
-
|
|
20893
|
-
|
|
20894
|
-
|
|
20895
|
-
|
|
20896
|
-
|
|
20897
|
-
|
|
20898
|
-
...(ngDevMode ? [{ debugName: "
|
|
20899
|
-
|
|
20900
|
-
|
|
20901
|
-
|
|
20902
|
-
|
|
20903
|
-
|
|
20904
|
-
|
|
20905
|
-
|
|
20906
|
-
|
|
20907
|
-
|
|
20908
|
-
|
|
20909
|
-
|
|
20910
|
-
|
|
20911
|
-
|
|
20912
|
-
|
|
20913
|
-
|
|
20914
|
-
|
|
20915
|
-
|
|
20916
|
-
|
|
20917
|
-
|
|
20918
|
-
|
|
20919
|
-
|
|
20920
|
-
|
|
20921
|
-
|
|
20922
|
-
|
|
20923
|
-
|
|
20924
|
-
|
|
20925
|
-
|
|
20926
|
-
|
|
20927
|
-
|
|
20928
|
-
|
|
20929
|
-
this.onChange(null);
|
|
21130
|
+
class StrctReorder {
|
|
21131
|
+
host = inject(ElementRef);
|
|
21132
|
+
renderer = inject(Renderer2);
|
|
21133
|
+
doc = inject(DOCUMENT);
|
|
21134
|
+
announcer = inject(StrctAnnouncer);
|
|
21135
|
+
/** Emits when a drag or keyboard move completes. */
|
|
21136
|
+
reordered = output();
|
|
21137
|
+
/** Disable all reordering (display-only mode). */
|
|
21138
|
+
reorderDisabled = input(false, { ...(ngDevMode ? { debugName: "reorderDisabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
21139
|
+
/**
|
|
21140
|
+
* Keyboard instructions (localizable), rendered sr-only and referenced by
|
|
21141
|
+
* every item's `aria-describedby`. Set to '' to opt out.
|
|
21142
|
+
*/
|
|
21143
|
+
instructions = input('Press Alt+ArrowUp or Alt+ArrowDown to move this item', /* @ts-ignore */
|
|
21144
|
+
...(ngDevMode ? [{ debugName: "instructions" }] : /* istanbul ignore next */ []));
|
|
21145
|
+
/**
|
|
21146
|
+
* Builds the live-region announcement after a move (localizable):
|
|
21147
|
+
* (moved item's text, new 1-based position, item count).
|
|
21148
|
+
*/
|
|
21149
|
+
announcement = input((label, position, total) => `Moved ${label} to position ${position} of ${total}`, /* @ts-ignore */
|
|
21150
|
+
...(ngDevMode ? [{ debugName: "announcement" }] : /* istanbul ignore next */ []));
|
|
21151
|
+
dragIndex = signal(null, /* @ts-ignore */
|
|
21152
|
+
...(ngDevMode ? [{ debugName: "dragIndex" }] : /* istanbul ignore next */ []));
|
|
21153
|
+
overIndex = signal(null, /* @ts-ignore */
|
|
21154
|
+
...(ngDevMode ? [{ debugName: "overIndex" }] : /* istanbul ignore next */ []));
|
|
21155
|
+
/** Id of the sr-only instructions element the items point to. */
|
|
21156
|
+
instructionsId = `strct-reorder-hint-${++reorderCounter}`;
|
|
21157
|
+
hint = null;
|
|
21158
|
+
constructor() {
|
|
21159
|
+
// Keep the sr-only instructions element in sync with the input.
|
|
21160
|
+
effect(() => {
|
|
21161
|
+
const text = this.instructions();
|
|
21162
|
+
if (text && !this.hint) {
|
|
21163
|
+
this.hint = this.renderer.createElement('span');
|
|
21164
|
+
this.renderer.setAttribute(this.hint, 'id', this.instructionsId);
|
|
21165
|
+
this.hint.style.cssText =
|
|
21166
|
+
'position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;';
|
|
21167
|
+
this.renderer.appendChild(this.doc.body, this.hint);
|
|
21168
|
+
}
|
|
21169
|
+
if (this.hint)
|
|
21170
|
+
this.hint.textContent = text;
|
|
21171
|
+
});
|
|
21172
|
+
}
|
|
21173
|
+
items() {
|
|
21174
|
+
return [...this.host.nativeElement.querySelectorAll('[strctReorderItem]')];
|
|
21175
|
+
}
|
|
21176
|
+
indexOf(el) {
|
|
21177
|
+
return this.items().indexOf(el);
|
|
21178
|
+
}
|
|
21179
|
+
commit(from, to) {
|
|
21180
|
+
this.dragIndex.set(null);
|
|
21181
|
+
this.overIndex.set(null);
|
|
21182
|
+
if (from < 0 || to < 0 || from === to)
|
|
20930
21183
|
return;
|
|
20931
|
-
|
|
20932
|
-
|
|
20933
|
-
|
|
20934
|
-
// hold the last value; clamping happens on blur.
|
|
20935
|
-
if (Number.isFinite(parsed)) {
|
|
20936
|
-
this.value.set(parsed);
|
|
20937
|
-
this.onChange(parsed);
|
|
20938
|
-
}
|
|
21184
|
+
const label = this.items()[from]?.textContent?.trim() ?? '';
|
|
21185
|
+
this.reordered.emit({ from, to });
|
|
21186
|
+
this.announcer.announce(this.announcement()(label, to + 1, this.items().length));
|
|
20939
21187
|
}
|
|
20940
|
-
|
|
20941
|
-
|
|
21188
|
+
onContainerDragOver(event) {
|
|
21189
|
+
// Only the container's own empty space (below the last item); drags over
|
|
21190
|
+
// items are handled by the items themselves.
|
|
21191
|
+
if (this.dragIndex() == null)
|
|
20942
21192
|
return;
|
|
20943
|
-
|
|
20944
|
-
|
|
20945
|
-
|
|
20946
|
-
this.stepBy(1);
|
|
20947
|
-
break;
|
|
20948
|
-
case 'ArrowDown':
|
|
20949
|
-
event.preventDefault();
|
|
20950
|
-
this.stepBy(-1);
|
|
20951
|
-
break;
|
|
20952
|
-
case 'PageUp':
|
|
20953
|
-
event.preventDefault();
|
|
20954
|
-
this.stepBy(1, 10);
|
|
20955
|
-
break;
|
|
20956
|
-
case 'PageDown':
|
|
20957
|
-
event.preventDefault();
|
|
20958
|
-
this.stepBy(-1, 10);
|
|
20959
|
-
break;
|
|
20960
|
-
case 'Home': {
|
|
20961
|
-
const m = this.min();
|
|
20962
|
-
if (m === null)
|
|
20963
|
-
return;
|
|
20964
|
-
event.preventDefault();
|
|
20965
|
-
this.commitTo(m);
|
|
20966
|
-
break;
|
|
20967
|
-
}
|
|
20968
|
-
case 'End': {
|
|
20969
|
-
const m = this.max();
|
|
20970
|
-
if (m === null)
|
|
20971
|
-
return;
|
|
20972
|
-
event.preventDefault();
|
|
20973
|
-
this.commitTo(m);
|
|
20974
|
-
break;
|
|
20975
|
-
}
|
|
20976
|
-
}
|
|
21193
|
+
if (event.target.closest('[strctReorderItem]'))
|
|
21194
|
+
return;
|
|
21195
|
+
event.preventDefault();
|
|
20977
21196
|
}
|
|
20978
|
-
|
|
20979
|
-
|
|
20980
|
-
|
|
20981
|
-
|
|
20982
|
-
|
|
20983
|
-
|
|
20984
|
-
|
|
20985
|
-
|
|
20986
|
-
|
|
20987
|
-
|
|
20988
|
-
|
|
20989
|
-
|
|
20990
|
-
|
|
20991
|
-
|
|
20992
|
-
|
|
20993
|
-
|
|
20994
|
-
|
|
20995
|
-
|
|
20996
|
-
|
|
20997
|
-
|
|
20998
|
-
|
|
20999
|
-
|
|
21000
|
-
}
|
|
21197
|
+
onContainerDrop(event) {
|
|
21198
|
+
const from = this.dragIndex();
|
|
21199
|
+
if (from == null)
|
|
21200
|
+
return; // an item already consumed this drop
|
|
21201
|
+
if (event.target.closest('[strctReorderItem]'))
|
|
21202
|
+
return;
|
|
21203
|
+
event.preventDefault();
|
|
21204
|
+
// Drop into empty space moves the item to the end.
|
|
21205
|
+
this.commit(from, this.items().length - 1);
|
|
21206
|
+
}
|
|
21207
|
+
onDragLeave(event) {
|
|
21208
|
+
// dragleave also fires when moving between children; only clear the
|
|
21209
|
+
// highlight when the drag truly leaves the container.
|
|
21210
|
+
const next = event.relatedTarget;
|
|
21211
|
+
if (next && this.host.nativeElement.contains(next))
|
|
21212
|
+
return;
|
|
21213
|
+
this.overIndex.set(null);
|
|
21214
|
+
}
|
|
21215
|
+
ngOnDestroy() {
|
|
21216
|
+
if (this.hint) {
|
|
21217
|
+
this.renderer.removeChild(this.doc.body, this.hint);
|
|
21218
|
+
this.hint = null;
|
|
21001
21219
|
}
|
|
21002
|
-
this.onTouched();
|
|
21003
21220
|
}
|
|
21004
|
-
|
|
21005
|
-
|
|
21006
|
-
|
|
21007
|
-
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
|
|
21012
|
-
|
|
21013
|
-
|
|
21221
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctReorder, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
21222
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.4", type: StrctReorder, isStandalone: true, selector: "[strctReorder]", inputs: { reorderDisabled: { classPropertyName: "reorderDisabled", publicName: "reorderDisabled", isSignal: true, isRequired: false, transformFunction: null }, instructions: { classPropertyName: "instructions", publicName: "instructions", isSignal: true, isRequired: false, transformFunction: null }, announcement: { classPropertyName: "announcement", publicName: "announcement", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { reordered: "reordered" }, host: { listeners: { "dragover": "onContainerDragOver($event)", "drop": "onContainerDrop($event)", "dragleave": "onDragLeave($event)" } }, ngImport: i0 });
|
|
21223
|
+
}
|
|
21224
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctReorder, decorators: [{
|
|
21225
|
+
type: Directive,
|
|
21226
|
+
args: [{ selector: '[strctReorder]' }]
|
|
21227
|
+
}], ctorParameters: () => [], propDecorators: { reordered: [{ type: i0.Output, args: ["reordered"] }], reorderDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderDisabled", required: false }] }], instructions: [{ type: i0.Input, args: [{ isSignal: true, alias: "instructions", required: false }] }], announcement: [{ type: i0.Input, args: [{ isSignal: true, alias: "announcement", required: false }] }], onContainerDragOver: [{
|
|
21228
|
+
type: HostListener,
|
|
21229
|
+
args: ['dragover', ['$event']]
|
|
21230
|
+
}], onContainerDrop: [{
|
|
21231
|
+
type: HostListener,
|
|
21232
|
+
args: ['drop', ['$event']]
|
|
21233
|
+
}], onDragLeave: [{
|
|
21234
|
+
type: HostListener,
|
|
21235
|
+
args: ['dragleave', ['$event']]
|
|
21236
|
+
}] } });
|
|
21237
|
+
/** One draggable row inside a `[strctReorder]` container. */
|
|
21238
|
+
class StrctReorderItem {
|
|
21239
|
+
list = inject(StrctReorder);
|
|
21240
|
+
el = inject(ElementRef);
|
|
21241
|
+
// Captured before our own binding ever writes tabindex, so it never flips.
|
|
21242
|
+
hadOwnTabindex = this.el.nativeElement.hasAttribute('tabindex');
|
|
21243
|
+
hostTabindex() {
|
|
21244
|
+
return this.hadOwnTabindex ? null : 0;
|
|
21245
|
+
}
|
|
21246
|
+
isDragging() {
|
|
21247
|
+
return this.list.dragIndex() === this.index();
|
|
21014
21248
|
}
|
|
21015
|
-
|
|
21016
|
-
|
|
21017
|
-
this.value.set(clamped);
|
|
21018
|
-
this.text.set(String(clamped));
|
|
21019
|
-
this.onChange(clamped);
|
|
21020
|
-
this.onTouched();
|
|
21249
|
+
isOver() {
|
|
21250
|
+
return this.list.overIndex() === this.index() && this.list.dragIndex() !== this.index();
|
|
21021
21251
|
}
|
|
21022
|
-
|
|
21023
|
-
|
|
21024
|
-
const hi = this.max();
|
|
21025
|
-
if (lo !== null && n < lo)
|
|
21026
|
-
return lo;
|
|
21027
|
-
if (hi !== null && n > hi)
|
|
21028
|
-
return hi;
|
|
21029
|
-
return n;
|
|
21252
|
+
index() {
|
|
21253
|
+
return this.list.indexOf(this.el.nativeElement);
|
|
21030
21254
|
}
|
|
21031
|
-
|
|
21032
|
-
|
|
21033
|
-
|
|
21034
|
-
|
|
21035
|
-
|
|
21036
|
-
|
|
21037
|
-
|
|
21255
|
+
onDragStart(event) {
|
|
21256
|
+
if (this.list.reorderDisabled())
|
|
21257
|
+
return;
|
|
21258
|
+
this.list.dragIndex.set(this.index());
|
|
21259
|
+
event.dataTransfer?.setData('text/plain', String(this.index()));
|
|
21260
|
+
if (event.dataTransfer)
|
|
21261
|
+
event.dataTransfer.effectAllowed = 'move';
|
|
21038
21262
|
}
|
|
21039
|
-
|
|
21040
|
-
|
|
21041
|
-
|
|
21042
|
-
|
|
21043
|
-
this.
|
|
21263
|
+
onDragOver(event) {
|
|
21264
|
+
if (this.list.dragIndex() == null)
|
|
21265
|
+
return;
|
|
21266
|
+
event.preventDefault();
|
|
21267
|
+
this.list.overIndex.set(this.index());
|
|
21044
21268
|
}
|
|
21045
|
-
|
|
21046
|
-
|
|
21269
|
+
onDrop(event) {
|
|
21270
|
+
event.preventDefault();
|
|
21271
|
+
const from = this.list.dragIndex();
|
|
21272
|
+
if (from == null)
|
|
21273
|
+
return;
|
|
21274
|
+
this.list.commit(from, this.index());
|
|
21047
21275
|
}
|
|
21048
|
-
|
|
21049
|
-
this.
|
|
21276
|
+
onDragEnd() {
|
|
21277
|
+
this.list.dragIndex.set(null);
|
|
21278
|
+
this.list.overIndex.set(null);
|
|
21050
21279
|
}
|
|
21051
|
-
|
|
21052
|
-
this.
|
|
21280
|
+
onKeydown(event) {
|
|
21281
|
+
if (this.list.reorderDisabled() || !event.altKey)
|
|
21282
|
+
return;
|
|
21283
|
+
if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown')
|
|
21284
|
+
return;
|
|
21285
|
+
event.preventDefault();
|
|
21286
|
+
const from = this.index();
|
|
21287
|
+
const to = event.key === 'ArrowUp' ? from - 1 : from + 1;
|
|
21288
|
+
if (to < 0 || to >= this.list.items().length)
|
|
21289
|
+
return;
|
|
21290
|
+
this.list.commit(from, to);
|
|
21291
|
+
// Keep focus on the moved item after the consumer re-renders.
|
|
21292
|
+
setTimeout(() => this.list.items()[to]?.focus());
|
|
21053
21293
|
}
|
|
21054
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
21055
|
-
static
|
|
21056
|
-
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StrctNumber), multi: true },
|
|
21057
|
-
], ngImport: i0, template: `
|
|
21058
|
-
<div class="strct-num__wrap">
|
|
21059
|
-
<button
|
|
21060
|
-
type="button"
|
|
21061
|
-
class="strct-num__btn"
|
|
21062
|
-
[attr.aria-label]="decrementLabel()"
|
|
21063
|
-
[disabled]="isDisabled() || atMin()"
|
|
21064
|
-
(click)="stepBy(-1)"
|
|
21065
|
-
>
|
|
21066
|
-
<strct-icon strictName="minus" [size]="12" [strokeWidth]="1.8" />
|
|
21067
|
-
</button>
|
|
21068
|
-
<input
|
|
21069
|
-
type="text"
|
|
21070
|
-
inputmode="decimal"
|
|
21071
|
-
class="strct-control strct-num__input"
|
|
21072
|
-
role="spinbutton"
|
|
21073
|
-
[attr.aria-valuemin]="min()"
|
|
21074
|
-
[attr.aria-valuemax]="max()"
|
|
21075
|
-
[attr.aria-valuenow]="value()"
|
|
21076
|
-
[placeholder]="placeholder()"
|
|
21077
|
-
[value]="text()"
|
|
21078
|
-
[disabled]="isDisabled()"
|
|
21079
|
-
(input)="onInput($event)"
|
|
21080
|
-
(keydown)="onKeydown($event)"
|
|
21081
|
-
(blur)="onBlur()"
|
|
21082
|
-
/>
|
|
21083
|
-
<button
|
|
21084
|
-
type="button"
|
|
21085
|
-
class="strct-num__btn"
|
|
21086
|
-
[attr.aria-label]="incrementLabel()"
|
|
21087
|
-
[disabled]="isDisabled() || atMax()"
|
|
21088
|
-
(click)="stepBy(1)"
|
|
21089
|
-
>
|
|
21090
|
-
<strct-icon strictName="plus" [size]="12" [strokeWidth]="1.8" />
|
|
21091
|
-
</button>
|
|
21092
|
-
</div>
|
|
21093
|
-
`, isInline: true, styles: [".strct-num{display:block;width:100%}.strct-num__wrap{display:flex;align-items:stretch;gap:var(--space-1)}.strct-num__input{flex:1;min-width:0;text-align:center;font-variant-numeric:tabular-nums}.strct-num__btn{display:inline-flex;align-items:center;justify-content:center;flex:none;padding-inline:var(--space-2);color:var(--t2);background:var(--bg-2);border:1px solid var(--b2);border-radius:var(--radius-md);cursor:pointer;transition:border-color .14s ease,color .14s ease,background .14s ease}.strct-num__btn:hover:not(:disabled){color:var(--t1);border-color:var(--b3);background:var(--bg-3)}.strct-num__btn:disabled{opacity:var(--disabled-opacity);cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "strictName", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
21294
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctReorderItem, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
21295
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: StrctReorderItem, isStandalone: true, selector: "[strctReorderItem]", host: { listeners: { "dragstart": "onDragStart($event)", "dragover": "onDragOver($event)", "drop": "onDrop($event)", "dragend": "onDragEnd()", "keydown": "onKeydown($event)" }, properties: { "attr.draggable": "!list.reorderDisabled()", "attr.tabindex": "hostTabindex()", "class.strct-reorder--dragging": "isDragging()", "class.strct-reorder--over": "isOver()", "attr.aria-roledescription": "'sortable'", "attr.aria-keyshortcuts": "'Alt+ArrowUp Alt+ArrowDown'", "attr.aria-posinset": "index() + 1", "attr.aria-setsize": "list.items().length", "attr.aria-describedby": "list.instructions() ? list.instructionsId : null" } }, ngImport: i0 });
|
|
21094
21296
|
}
|
|
21095
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
21297
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctReorderItem, decorators: [{
|
|
21298
|
+
type: Directive,
|
|
21299
|
+
args: [{
|
|
21300
|
+
selector: '[strctReorderItem]',
|
|
21301
|
+
host: {
|
|
21302
|
+
'[attr.draggable]': '!list.reorderDisabled()',
|
|
21303
|
+
'[attr.tabindex]': 'hostTabindex()',
|
|
21304
|
+
'[class.strct-reorder--dragging]': 'isDragging()',
|
|
21305
|
+
'[class.strct-reorder--over]': 'isOver()',
|
|
21306
|
+
'[attr.aria-roledescription]': "'sortable'",
|
|
21307
|
+
'[attr.aria-keyshortcuts]': "'Alt+ArrowUp Alt+ArrowDown'",
|
|
21308
|
+
'[attr.aria-posinset]': 'index() + 1',
|
|
21309
|
+
'[attr.aria-setsize]': 'list.items().length',
|
|
21310
|
+
'[attr.aria-describedby]': 'list.instructions() ? list.instructionsId : null',
|
|
21311
|
+
},
|
|
21312
|
+
}]
|
|
21313
|
+
}], propDecorators: { onDragStart: [{
|
|
21314
|
+
type: HostListener,
|
|
21315
|
+
args: ['dragstart', ['$event']]
|
|
21316
|
+
}], onDragOver: [{
|
|
21317
|
+
type: HostListener,
|
|
21318
|
+
args: ['dragover', ['$event']]
|
|
21319
|
+
}], onDrop: [{
|
|
21320
|
+
type: HostListener,
|
|
21321
|
+
args: ['drop', ['$event']]
|
|
21322
|
+
}], onDragEnd: [{
|
|
21323
|
+
type: HostListener,
|
|
21324
|
+
args: ['dragend']
|
|
21325
|
+
}], onKeydown: [{
|
|
21326
|
+
type: HostListener,
|
|
21327
|
+
args: ['keydown', ['$event']]
|
|
21328
|
+
}] } });
|
|
21329
|
+
|
|
21330
|
+
/**
|
|
21331
|
+
* Default accessible text per status, used when `label` is not given
|
|
21332
|
+
* (localizable — override via `label`). The canonical `StrctStatus` vocabulary
|
|
21333
|
+
* has no 'ok'/'info': OK maps to 'success', info to 'accent'.
|
|
21334
|
+
*/
|
|
21335
|
+
const DEFAULT_LABEL = {
|
|
21336
|
+
neutral: 'Neutral',
|
|
21337
|
+
accent: 'Info',
|
|
21338
|
+
success: 'OK',
|
|
21339
|
+
warning: 'Warning',
|
|
21340
|
+
critical: 'Critical',
|
|
21341
|
+
};
|
|
21342
|
+
/**
|
|
21343
|
+
* Presence/state dot that never relies on colour alone: the tone is painted by
|
|
21344
|
+
* a pure-CSS dot while the state is also rendered as visually-hidden text, so
|
|
21345
|
+
* screen readers (and colour-blind users copying text) get "Warning", not just
|
|
21346
|
+
* a yellow circle. Use it inside avatars, menu rows, metric tiles — anywhere a
|
|
21347
|
+
* bare coloured dot would otherwise carry meaning.
|
|
21348
|
+
*
|
|
21349
|
+
* <strct-status-dot status="success" />
|
|
21350
|
+
* <strct-status-dot status="critical" size="sm" label="Node unreachable" />
|
|
21351
|
+
*/
|
|
21352
|
+
class StrctStatusDot {
|
|
21353
|
+
/** Status tone (canonical vocabulary: OK = 'success', info = 'accent'). */
|
|
21354
|
+
status = input('neutral', /* @ts-ignore */
|
|
21355
|
+
...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
21356
|
+
/**
|
|
21357
|
+
* Accessible text describing the state (localizable). Empty falls back to a
|
|
21358
|
+
* per-status default ("OK", "Warning", …) so the dot is never color-only.
|
|
21359
|
+
*/
|
|
21360
|
+
label = input('', /* @ts-ignore */
|
|
21361
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
21362
|
+
/** Dot size: `sm` for dense rows, `md` standalone. */
|
|
21363
|
+
size = input('md', /* @ts-ignore */
|
|
21364
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
21365
|
+
text = computed(() => this.label() || DEFAULT_LABEL[this.status()], /* @ts-ignore */
|
|
21366
|
+
...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
|
|
21367
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctStatusDot, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
21368
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: StrctStatusDot, isStandalone: true, selector: "strct-status-dot", inputs: { status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.strct-dot--accent": "status() === 'accent'", "class.strct-dot--success": "status() === 'success'", "class.strct-dot--warning": "status() === 'warning'", "class.strct-dot--critical": "status() === 'critical'", "class.strct-dot--sm": "size() === 'sm'" }, classAttribute: "strct-dot" }, ngImport: i0, template: `
|
|
21369
|
+
<span class="strct-dot__dot" aria-hidden="true"></span>
|
|
21370
|
+
<span class="strct-dot__sr">{{ text() }}</span>
|
|
21371
|
+
`, isInline: true, styles: [".strct-dot{display:inline-flex;align-items:center;flex:none;line-height:0}.strct-dot__dot{width:10px;height:10px;border-radius:50%;background:var(--t3)}.strct-dot--sm .strct-dot__dot{width:8px;height:8px}.strct-dot--accent .strct-dot__dot{background:var(--acc)}.strct-dot--success .strct-dot__dot{background:var(--success)}.strct-dot--warning .strct-dot__dot{background:var(--warning)}.strct-dot--critical .strct-dot__dot{background:var(--critical)}.strct-dot__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
21372
|
+
}
|
|
21373
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: StrctStatusDot, decorators: [{
|
|
21096
21374
|
type: Component,
|
|
21097
|
-
args: [{ selector: 'strct-
|
|
21098
|
-
|
|
21099
|
-
|
|
21100
|
-
|
|
21101
|
-
|
|
21102
|
-
|
|
21103
|
-
|
|
21104
|
-
|
|
21105
|
-
|
|
21106
|
-
|
|
21107
|
-
|
|
21108
|
-
|
|
21109
|
-
</button>
|
|
21110
|
-
<input
|
|
21111
|
-
type="text"
|
|
21112
|
-
inputmode="decimal"
|
|
21113
|
-
class="strct-control strct-num__input"
|
|
21114
|
-
role="spinbutton"
|
|
21115
|
-
[attr.aria-valuemin]="min()"
|
|
21116
|
-
[attr.aria-valuemax]="max()"
|
|
21117
|
-
[attr.aria-valuenow]="value()"
|
|
21118
|
-
[placeholder]="placeholder()"
|
|
21119
|
-
[value]="text()"
|
|
21120
|
-
[disabled]="isDisabled()"
|
|
21121
|
-
(input)="onInput($event)"
|
|
21122
|
-
(keydown)="onKeydown($event)"
|
|
21123
|
-
(blur)="onBlur()"
|
|
21124
|
-
/>
|
|
21125
|
-
<button
|
|
21126
|
-
type="button"
|
|
21127
|
-
class="strct-num__btn"
|
|
21128
|
-
[attr.aria-label]="incrementLabel()"
|
|
21129
|
-
[disabled]="isDisabled() || atMax()"
|
|
21130
|
-
(click)="stepBy(1)"
|
|
21131
|
-
>
|
|
21132
|
-
<strct-icon strictName="plus" [size]="12" [strokeWidth]="1.8" />
|
|
21133
|
-
</button>
|
|
21134
|
-
</div>
|
|
21135
|
-
`, host: { class: 'strct-num' }, styles: [".strct-num{display:block;width:100%}.strct-num__wrap{display:flex;align-items:stretch;gap:var(--space-1)}.strct-num__input{flex:1;min-width:0;text-align:center;font-variant-numeric:tabular-nums}.strct-num__btn{display:inline-flex;align-items:center;justify-content:center;flex:none;padding-inline:var(--space-2);color:var(--t2);background:var(--bg-2);border:1px solid var(--b2);border-radius:var(--radius-md);cursor:pointer;transition:border-color .14s ease,color .14s ease,background .14s ease}.strct-num__btn:hover:not(:disabled){color:var(--t1);border-color:var(--b3);background:var(--bg-3)}.strct-num__btn:disabled{opacity:var(--disabled-opacity);cursor:not-allowed}\n"] }]
|
|
21136
|
-
}], propDecorators: { min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], incrementLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "incrementLabel", required: false }] }], decrementLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "decrementLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
|
|
21375
|
+
args: [{ selector: 'strct-status-dot', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `
|
|
21376
|
+
<span class="strct-dot__dot" aria-hidden="true"></span>
|
|
21377
|
+
<span class="strct-dot__sr">{{ text() }}</span>
|
|
21378
|
+
`, host: {
|
|
21379
|
+
class: 'strct-dot',
|
|
21380
|
+
'[class.strct-dot--accent]': "status() === 'accent'",
|
|
21381
|
+
'[class.strct-dot--success]': "status() === 'success'",
|
|
21382
|
+
'[class.strct-dot--warning]': "status() === 'warning'",
|
|
21383
|
+
'[class.strct-dot--critical]': "status() === 'critical'",
|
|
21384
|
+
'[class.strct-dot--sm]': "size() === 'sm'",
|
|
21385
|
+
}, styles: [".strct-dot{display:inline-flex;align-items:center;flex:none;line-height:0}.strct-dot__dot{width:10px;height:10px;border-radius:50%;background:var(--t3)}.strct-dot--sm .strct-dot__dot{width:8px;height:8px}.strct-dot--accent .strct-dot__dot{background:var(--acc)}.strct-dot--success .strct-dot__dot{background:var(--success)}.strct-dot--warning .strct-dot__dot{background:var(--warning)}.strct-dot--critical .strct-dot__dot{background:var(--critical)}.strct-dot__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n"] }]
|
|
21386
|
+
}], propDecorators: { status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
21137
21387
|
|
|
21138
21388
|
/**
|
|
21139
21389
|
* A generic anchored overlay panel for arbitrary projected content — the
|
|
@@ -23001,5 +23251,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
23001
23251
|
* Generated bundle index. Do not edit.
|
|
23002
23252
|
*/
|
|
23003
23253
|
|
|
23004
|
-
export { FOCUSABLE_SELECTOR, STRCT_DP_DOW, STRCT_DP_DOW_FULL, STRCT_DP_MONTHS, STRCT_ICONS, STRCT_ICON_GROUPS, STRCT_ICON_NAMES, STRCT_MASKS, STRCT_NOTIFICATION_HISTORY_LIMIT, STRCT_PALETTES, STRCT_RAW_ICONS, STRCT_TIME_RANGE_PRESETS, STRCT_WIZARD_DEFAULTS, StrctAccordion, StrctAccordionPanel, StrctAlert, StrctAnnouncer, StrctAvatar, StrctBadge, StrctBreadcrumb, StrctBreadcrumbItem, StrctButton, StrctButtonGroup, StrctBytesPipe, StrctCard, StrctCardBlock, StrctCardFooter, StrctCardHeader, StrctCardHeaderActions, StrctCardHeaderMeta, StrctCardHeaderNote, StrctCascadeColumn, StrctCascadeHost, StrctCascadeSelect, StrctCellDef, StrctCellStatus, StrctChart, StrctCheckbox, StrctChips, StrctCode, StrctCodeInline, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctConfirmOutlet, StrctConfirmService, StrctContextMenu, StrctContextMenuTrigger, StrctCopy, StrctDatagrid, StrctDatagridActionBar, StrctDatagridActionBarCaption, StrctDatepicker, StrctDatetimePicker, StrctDesc, StrctDescriptionList, StrctDiff, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownItem, StrctDropdownTrigger, StrctDurationPipe, StrctEmptyState, StrctField, StrctFile, StrctFilterBar, StrctFlow, StrctFooter, StrctGauge, StrctHeader, StrctHeatmap, StrctHero, StrctHotkeysHelp, StrctHotkeysService, StrctIcon, StrctInlineEdit, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctList, StrctListItem, StrctListItemDescription, StrctListItemLeading, StrctListItemMeta, StrctListItemTrailing, StrctLogViewer, StrctLogin, StrctMenuPanel, StrctMenuService, StrctMenubar, StrctMetricTile, StrctModal, StrctModalContent, StrctNav, StrctNavItem, StrctNotificationCenter, StrctNumber, StrctOverlay, StrctPageHeader, StrctPageHeaderActions, StrctPageHeaderCrumbs, StrctPageHeaderTitleMeta, StrctPagination, StrctPassword, StrctPopover, StrctPopoverTrigger, StrctProgress, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRatePipe, StrctRating, StrctReorder, StrctReorderItem, StrctRowDetailDef, StrctSearchbox, StrctSectionHeader, StrctSectionHeaderActions, StrctSectionHeaderMeta, StrctSectionMenu, StrctSegmented, StrctSelect, StrctShell, StrctShellService, StrctSiPipe, StrctSignpost, StrctSignpostTrigger, StrctSkeleton, StrctSparkline, StrctSpeedDial, StrctSpinner, StrctSplitButton, StrctSplitter, StrctStack, StrctStackItem, StrctStatusDot, StrctStep, StrctSubmenu, StrctTab, StrctTable, StrctTabs, StrctTag, StrctThemeService, StrctThemeSwitcher, StrctTimeRangePicker, StrctTimeline, StrctTimelineItem, StrctToastOutlet, StrctToastService, StrctToggle, StrctToolbar, StrctToolbarCaption, StrctToolbarSpacer, StrctTooltip, StrctTour, StrctTransfer, StrctTree, StrctTreeNode, StrctTreeSelect, StrctVerticalNav, StrctWatermark, StrctWizard, StrctWizardAside, focusFirstIn, keepTabInside, lockBodyScroll, parseAnsi, provideStrctWizardDefaults, registerStrctIcon, restoreFocus, saveFocusedElement, strctComputeDiff, strctDpPad, strctFormatBytes, strctFormatDuration, strctFormatRate, strctFormatSi, strctValidationIcon, strctValidationTone, unlockBodyScroll };
|
|
23254
|
+
export { FOCUSABLE_SELECTOR, STRCT_DP_DOW, STRCT_DP_DOW_FULL, STRCT_DP_MONTHS, STRCT_ICONS, STRCT_ICON_GROUPS, STRCT_ICON_NAMES, STRCT_MASKS, STRCT_NOTIFICATION_HISTORY_LIMIT, STRCT_PALETTES, STRCT_RAW_ICONS, STRCT_TIME_RANGE_PRESETS, STRCT_WIZARD_DEFAULTS, StrctAccordion, StrctAccordionPanel, StrctAlert, StrctAnnouncer, StrctAvatar, StrctBadge, StrctBreadcrumb, StrctBreadcrumbItem, StrctButton, StrctButtonGroup, StrctBytesPipe, StrctCard, StrctCardBlock, StrctCardFooter, StrctCardHeader, StrctCardHeaderActions, StrctCardHeaderMeta, StrctCardHeaderNote, StrctCascadeColumn, StrctCascadeHost, StrctCascadeSelect, StrctCellDef, StrctCellStatus, StrctChart, StrctCheckbox, StrctChips, StrctCode, StrctCodeInline, StrctColorPicker, StrctCombobox, StrctCommandPalette, StrctConfirmOutlet, StrctConfirmService, StrctContextMenu, StrctContextMenuTrigger, StrctCopy, StrctDatagrid, StrctDatagridActionBar, StrctDatagridActionBarCaption, StrctDatepicker, StrctDatetimePicker, StrctDesc, StrctDescriptionList, StrctDiff, StrctDivider, StrctDonut, StrctDrawer, StrctDrawerFooter, StrctDropdown, StrctDropdownDivider, StrctDropdownItem, StrctDropdownTrigger, StrctDurationPipe, StrctEmptyState, StrctField, StrctFieldGroup, StrctFieldHint, StrctFieldPrefix, StrctFieldSuffix, StrctFile, StrctFilterBar, StrctFlow, StrctFooter, StrctGauge, StrctHeader, StrctHeatmap, StrctHero, StrctHotkeysHelp, StrctHotkeysService, StrctIcon, StrctInlineEdit, StrctInput, StrctInputMask, StrctInputOtp, StrctKbd, StrctKnob, StrctList, StrctListItem, StrctListItemDescription, StrctListItemLeading, StrctListItemMeta, StrctListItemTrailing, StrctLogViewer, StrctLogin, StrctMenuPanel, StrctMenuService, StrctMenubar, StrctMetricTile, StrctModal, StrctModalContent, StrctNav, StrctNavItem, StrctNotificationCenter, StrctNumber, StrctOverlay, StrctPageHeader, StrctPageHeaderActions, StrctPageHeaderCrumbs, StrctPageHeaderTitleMeta, StrctPagination, StrctPassword, StrctPopover, StrctPopoverTrigger, StrctProgress, StrctRadio, StrctRadioGroup, StrctRail, StrctRange, StrctRatePipe, StrctRating, StrctReorder, StrctReorderItem, StrctRowDetailDef, StrctSearchbox, StrctSectionHeader, StrctSectionHeaderActions, StrctSectionHeaderMeta, StrctSectionMenu, StrctSegmented, StrctSelect, StrctShell, StrctShellService, StrctSiPipe, StrctSignpost, StrctSignpostTrigger, StrctSkeleton, StrctSparkline, StrctSpeedDial, StrctSpinner, StrctSplitButton, StrctSplitter, StrctStack, StrctStackItem, StrctStatusDot, StrctStep, StrctSubmenu, StrctTab, StrctTable, StrctTabs, StrctTag, StrctThemeService, StrctThemeSwitcher, StrctTimeRangePicker, StrctTimeline, StrctTimelineItem, StrctToastOutlet, StrctToastService, StrctToggle, StrctToolbar, StrctToolbarCaption, StrctToolbarSpacer, StrctTooltip, StrctTour, StrctTransfer, StrctTree, StrctTreeNode, StrctTreeSelect, StrctVerticalNav, StrctWatermark, StrctWizard, StrctWizardAside, focusFirstIn, keepTabInside, lockBodyScroll, parseAnsi, provideStrctWizardDefaults, registerStrctIcon, restoreFocus, saveFocusedElement, strctComputeDiff, strctDpPad, strctFormatBytes, strctFormatDuration, strctFormatRate, strctFormatSi, strctValidationIcon, strctValidationTone, unlockBodyScroll };
|
|
23005
23255
|
//# sourceMappingURL=akcelik-strct.mjs.map
|