@truenas/ui-components 0.7.7 → 0.7.9
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.
|
@@ -369,8 +369,8 @@ function kebabTestSegment(part) {
|
|
|
369
369
|
* re-implemented at each call site.
|
|
370
370
|
*
|
|
371
371
|
* Note this is *base-first*: the suffix trails the base. Fixed chrome whose role
|
|
372
|
-
* should lead (e.g. `tn-dialog-shell`'s `button-close-<base>`
|
|
373
|
-
* manually instead of calling this.
|
|
372
|
+
* should lead (e.g. `tn-dialog-shell`'s `button-close-<base>` and
|
|
373
|
+
* `dialog-title-<base>`) prepends the role manually instead of calling this.
|
|
374
374
|
*
|
|
375
375
|
* Falsy segments are preserved here (not filtered) so `composeTestId` can apply
|
|
376
376
|
* its own drop/scoping rules — `scopeTestId(undefined, 'edit')` yields
|
|
@@ -4342,6 +4342,16 @@ class TnBannerComponent {
|
|
|
4342
4342
|
message = input(undefined, ...(ngDevMode ? [{ debugName: "message" }] : []));
|
|
4343
4343
|
type = input('info', ...(ngDevMode ? [{ debugName: "type" }] : []));
|
|
4344
4344
|
bordered = input(false, ...(ngDevMode ? [{ debugName: "bordered" }] : []));
|
|
4345
|
+
/**
|
|
4346
|
+
* Semantic base for the banner's test id, rendered onto the banner root as
|
|
4347
|
+
* `banner-<testId>` through {@link TnTestIdDirective} — so the value follows
|
|
4348
|
+
* the library's own naming and honours `TN_TEST_ATTR`.
|
|
4349
|
+
*
|
|
4350
|
+
* The root, rather than the host element, because that is what carries the
|
|
4351
|
+
* live-region role: the element a test asserts a warning on is the same one
|
|
4352
|
+
* assistive tech announces.
|
|
4353
|
+
*/
|
|
4354
|
+
testId = input(undefined, ...(ngDevMode ? [{ debugName: "testId" }] : []));
|
|
4345
4355
|
constructor() {
|
|
4346
4356
|
this.registerMdiIcons();
|
|
4347
4357
|
}
|
|
@@ -4397,12 +4407,12 @@ class TnBannerComponent {
|
|
|
4397
4407
|
return result;
|
|
4398
4408
|
}, ...(ngDevMode ? [{ debugName: "classes" }] : []));
|
|
4399
4409
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnBannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4400
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnBannerComponent, isStandalone: true, selector: "tn-banner", inputs: { heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "actionContent", predicate: TnBannerActionDirective, isSignal: true }], ngImport: i0, template: "<!--\n `ariaRole()` is the only thing declaring how urgently the banner announces:\n it implies the politeness, and an explicit `aria-live` here would override it\n \u2014 which is what the static `aria-live=\"polite\"` used to do, downgrading the\n two types deliberately made assertive. See `../a11y/live-region.ts`.\n-->\n<div\n [ngClass]=\"classes()\"\n [attr.role]=\"ariaRole()\"\n>\n @if (hasStructuredContent()) {\n <div class=\"tn-banner__main\">\n <div class=\"tn-banner__icon\">\n <tn-icon\n library=\"mdi\"\n size=\"md\"\n aria-hidden=\"true\"\n [name]=\"iconName()\"\n />\n </div>\n\n <div class=\"tn-banner__content\">\n @if (heading()) {\n <div class=\"tn-banner__heading\">\n {{ heading() }}\n </div>\n }\n\n @if (message()) {\n <div class=\"tn-banner__message\">\n {{ message() }}\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"tn-banner__main\">\n <ng-content />\n </div>\n }\n\n @if (hasAction()) {\n <div class=\"tn-banner__action\">\n <ng-content select=\"[tnBannerAction]\" />\n </div>\n }\n</div>\n", styles: [".tn-banner{display:grid;gap:8px;align-items:center;padding:16px;border-radius:6px;border-left:4px solid;transition:opacity .2s ease}@media(prefers-reduced-motion:reduce){.tn-banner{transition:none}}.tn-banner--info{border-left-color:var(--tn-info, var(--tn-blue, #006997));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--info .tn-banner__heading,.tn-banner--info .tn-banner__icon{color:var(--tn-info, var(--tn-blue, #006997))}.tn-banner--warning{border-left-color:var(--tn-warning, var(--tn-orange, #955313));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--warning .tn-banner__heading,.tn-banner--warning .tn-banner__icon{color:var(--tn-warning, var(--tn-orange, #955313))}.tn-banner--error{border-left-color:var(--tn-error, var(--tn-red, #bd2626));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--error .tn-banner__heading,.tn-banner--error .tn-banner__icon{color:var(--tn-error, var(--tn-red, #bd2626))}.tn-banner--success{border-left-color:var(--tn-success, var(--tn-green, #416f26));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--success .tn-banner__heading,.tn-banner--success .tn-banner__icon{color:var(--tn-success, var(--tn-green, #416f26))}.tn-banner--bordered{border-top:1px solid var(--tn-lines, #404040);border-right:1px solid var(--tn-lines, #404040);border-bottom:1px solid var(--tn-lines, #404040)}.tn-banner__main{display:flex;align-items:flex-start;gap:12px;flex:1;min-width:0}.tn-banner__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;margin-top:2px}.tn-banner__content{flex:1;min-width:0}.tn-banner__heading{font-size:1rem;font-weight:600;line-height:1.5;margin:0}.tn-banner__message{font-size:1rem;color:var(--tn-fg2, #6b7280);line-height:1.5;margin-top:4px}.tn-banner__action{display:flex;align-items:center;gap:8px 16px;justify-content:flex-end}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }] });
|
|
4410
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnBannerComponent, isStandalone: true, selector: "tn-banner", inputs: { heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "actionContent", predicate: TnBannerActionDirective, isSignal: true }], ngImport: i0, template: "<!--\n `ariaRole()` is the only thing declaring how urgently the banner announces:\n it implies the politeness, and an explicit `aria-live` here would override it\n \u2014 which is what the static `aria-live=\"polite\"` used to do, downgrading the\n two types deliberately made assertive. See `../a11y/live-region.ts`.\n-->\n<div\n tnTestIdType=\"banner\"\n [ngClass]=\"classes()\"\n [attr.role]=\"ariaRole()\"\n [tnTestId]=\"testId()\"\n>\n @if (hasStructuredContent()) {\n <div class=\"tn-banner__main\">\n <div class=\"tn-banner__icon\">\n <tn-icon\n library=\"mdi\"\n size=\"md\"\n aria-hidden=\"true\"\n [name]=\"iconName()\"\n />\n </div>\n\n <div class=\"tn-banner__content\">\n @if (heading()) {\n <div class=\"tn-banner__heading\">\n {{ heading() }}\n </div>\n }\n\n @if (message()) {\n <div class=\"tn-banner__message\">\n {{ message() }}\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"tn-banner__main\">\n <ng-content />\n </div>\n }\n\n @if (hasAction()) {\n <div class=\"tn-banner__action\">\n <ng-content select=\"[tnBannerAction]\" />\n </div>\n }\n</div>\n", styles: [".tn-banner{display:grid;gap:8px;align-items:center;padding:16px;border-radius:6px;border-left:4px solid;transition:opacity .2s ease}@media(prefers-reduced-motion:reduce){.tn-banner{transition:none}}.tn-banner--info{border-left-color:var(--tn-info, var(--tn-blue, #006997));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--info .tn-banner__heading,.tn-banner--info .tn-banner__icon{color:var(--tn-info, var(--tn-blue, #006997))}.tn-banner--warning{border-left-color:var(--tn-warning, var(--tn-orange, #955313));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--warning .tn-banner__heading,.tn-banner--warning .tn-banner__icon{color:var(--tn-warning, var(--tn-orange, #955313))}.tn-banner--error{border-left-color:var(--tn-error, var(--tn-red, #bd2626));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--error .tn-banner__heading,.tn-banner--error .tn-banner__icon{color:var(--tn-error, var(--tn-red, #bd2626))}.tn-banner--success{border-left-color:var(--tn-success, var(--tn-green, #416f26));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--success .tn-banner__heading,.tn-banner--success .tn-banner__icon{color:var(--tn-success, var(--tn-green, #416f26))}.tn-banner--bordered{border-top:1px solid var(--tn-lines, #404040);border-right:1px solid var(--tn-lines, #404040);border-bottom:1px solid var(--tn-lines, #404040)}.tn-banner__main{display:flex;align-items:flex-start;gap:12px;flex:1;min-width:0}.tn-banner__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;margin-top:2px}.tn-banner__content{flex:1;min-width:0}.tn-banner__heading{font-size:1rem;font-weight:600;line-height:1.5;margin:0}.tn-banner__message{font-size:1rem;color:var(--tn-fg2, #6b7280);line-height:1.5;margin-top:4px}.tn-banner__action{display:flex;align-items:center;gap:8px 16px;justify-content:flex-end}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }] });
|
|
4401
4411
|
}
|
|
4402
4412
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnBannerComponent, decorators: [{
|
|
4403
4413
|
type: Component,
|
|
4404
|
-
args: [{ selector: 'tn-banner', standalone: true, imports: [CommonModule, TnIconComponent], template: "<!--\n `ariaRole()` is the only thing declaring how urgently the banner announces:\n it implies the politeness, and an explicit `aria-live` here would override it\n \u2014 which is what the static `aria-live=\"polite\"` used to do, downgrading the\n two types deliberately made assertive. See `../a11y/live-region.ts`.\n-->\n<div\n [ngClass]=\"classes()\"\n [attr.role]=\"ariaRole()\"\n>\n @if (hasStructuredContent()) {\n <div class=\"tn-banner__main\">\n <div class=\"tn-banner__icon\">\n <tn-icon\n library=\"mdi\"\n size=\"md\"\n aria-hidden=\"true\"\n [name]=\"iconName()\"\n />\n </div>\n\n <div class=\"tn-banner__content\">\n @if (heading()) {\n <div class=\"tn-banner__heading\">\n {{ heading() }}\n </div>\n }\n\n @if (message()) {\n <div class=\"tn-banner__message\">\n {{ message() }}\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"tn-banner__main\">\n <ng-content />\n </div>\n }\n\n @if (hasAction()) {\n <div class=\"tn-banner__action\">\n <ng-content select=\"[tnBannerAction]\" />\n </div>\n }\n</div>\n", styles: [".tn-banner{display:grid;gap:8px;align-items:center;padding:16px;border-radius:6px;border-left:4px solid;transition:opacity .2s ease}@media(prefers-reduced-motion:reduce){.tn-banner{transition:none}}.tn-banner--info{border-left-color:var(--tn-info, var(--tn-blue, #006997));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--info .tn-banner__heading,.tn-banner--info .tn-banner__icon{color:var(--tn-info, var(--tn-blue, #006997))}.tn-banner--warning{border-left-color:var(--tn-warning, var(--tn-orange, #955313));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--warning .tn-banner__heading,.tn-banner--warning .tn-banner__icon{color:var(--tn-warning, var(--tn-orange, #955313))}.tn-banner--error{border-left-color:var(--tn-error, var(--tn-red, #bd2626));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--error .tn-banner__heading,.tn-banner--error .tn-banner__icon{color:var(--tn-error, var(--tn-red, #bd2626))}.tn-banner--success{border-left-color:var(--tn-success, var(--tn-green, #416f26));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--success .tn-banner__heading,.tn-banner--success .tn-banner__icon{color:var(--tn-success, var(--tn-green, #416f26))}.tn-banner--bordered{border-top:1px solid var(--tn-lines, #404040);border-right:1px solid var(--tn-lines, #404040);border-bottom:1px solid var(--tn-lines, #404040)}.tn-banner__main{display:flex;align-items:flex-start;gap:12px;flex:1;min-width:0}.tn-banner__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;margin-top:2px}.tn-banner__content{flex:1;min-width:0}.tn-banner__heading{font-size:1rem;font-weight:600;line-height:1.5;margin:0}.tn-banner__message{font-size:1rem;color:var(--tn-fg2, #6b7280);line-height:1.5;margin-top:4px}.tn-banner__action{display:flex;align-items:center;gap:8px 16px;justify-content:flex-end}\n"] }]
|
|
4405
|
-
}], ctorParameters: () => [], propDecorators: { actionContent: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TnBannerActionDirective), { isSignal: true }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }] } });
|
|
4414
|
+
args: [{ selector: 'tn-banner', standalone: true, imports: [CommonModule, TnIconComponent, TnTestIdDirective], template: "<!--\n `ariaRole()` is the only thing declaring how urgently the banner announces:\n it implies the politeness, and an explicit `aria-live` here would override it\n \u2014 which is what the static `aria-live=\"polite\"` used to do, downgrading the\n two types deliberately made assertive. See `../a11y/live-region.ts`.\n-->\n<div\n tnTestIdType=\"banner\"\n [ngClass]=\"classes()\"\n [attr.role]=\"ariaRole()\"\n [tnTestId]=\"testId()\"\n>\n @if (hasStructuredContent()) {\n <div class=\"tn-banner__main\">\n <div class=\"tn-banner__icon\">\n <tn-icon\n library=\"mdi\"\n size=\"md\"\n aria-hidden=\"true\"\n [name]=\"iconName()\"\n />\n </div>\n\n <div class=\"tn-banner__content\">\n @if (heading()) {\n <div class=\"tn-banner__heading\">\n {{ heading() }}\n </div>\n }\n\n @if (message()) {\n <div class=\"tn-banner__message\">\n {{ message() }}\n </div>\n }\n </div>\n </div>\n } @else {\n <div class=\"tn-banner__main\">\n <ng-content />\n </div>\n }\n\n @if (hasAction()) {\n <div class=\"tn-banner__action\">\n <ng-content select=\"[tnBannerAction]\" />\n </div>\n }\n</div>\n", styles: [".tn-banner{display:grid;gap:8px;align-items:center;padding:16px;border-radius:6px;border-left:4px solid;transition:opacity .2s ease}@media(prefers-reduced-motion:reduce){.tn-banner{transition:none}}.tn-banner--info{border-left-color:var(--tn-info, var(--tn-blue, #006997));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--info .tn-banner__heading,.tn-banner--info .tn-banner__icon{color:var(--tn-info, var(--tn-blue, #006997))}.tn-banner--warning{border-left-color:var(--tn-warning, var(--tn-orange, #955313));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--warning .tn-banner__heading,.tn-banner--warning .tn-banner__icon{color:var(--tn-warning, var(--tn-orange, #955313))}.tn-banner--error{border-left-color:var(--tn-error, var(--tn-red, #bd2626));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--error .tn-banner__heading,.tn-banner--error .tn-banner__icon{color:var(--tn-error, var(--tn-red, #bd2626))}.tn-banner--success{border-left-color:var(--tn-success, var(--tn-green, #416f26));background-color:var(--tn-alt-bg1, #383838)}.tn-banner--success .tn-banner__heading,.tn-banner--success .tn-banner__icon{color:var(--tn-success, var(--tn-green, #416f26))}.tn-banner--bordered{border-top:1px solid var(--tn-lines, #404040);border-right:1px solid var(--tn-lines, #404040);border-bottom:1px solid var(--tn-lines, #404040)}.tn-banner__main{display:flex;align-items:flex-start;gap:12px;flex:1;min-width:0}.tn-banner__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;margin-top:2px}.tn-banner__content{flex:1;min-width:0}.tn-banner__heading{font-size:1rem;font-weight:600;line-height:1.5;margin:0}.tn-banner__message{font-size:1rem;color:var(--tn-fg2, #6b7280);line-height:1.5;margin-top:4px}.tn-banner__action{display:flex;align-items:center;gap:8px 16px;justify-content:flex-end}\n"] }]
|
|
4415
|
+
}], ctorParameters: () => [], propDecorators: { actionContent: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TnBannerActionDirective), { isSignal: true }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }] } });
|
|
4406
4416
|
|
|
4407
4417
|
/**
|
|
4408
4418
|
* Harness for a single action projected into a `tn-banner`'s action slot.
|
|
@@ -16467,6 +16477,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
16467
16477
|
* The primary-text slot is the deliberate exception — it has no gate, so
|
|
16468
16478
|
* `[tnListItemTitle]` and `[tnListItemPrimary]` render either way. See the
|
|
16469
16479
|
* comment in `list-item.component.html` for why the asymmetry is there.
|
|
16480
|
+
*
|
|
16481
|
+
* `[testId]` names the row for automation. It lands on the host, which is both
|
|
16482
|
+
* the click target (`(click)` is a host binding) and the `listitem` — so one id
|
|
16483
|
+
* addresses the row whether a suite clicks it or reads what it renders. The
|
|
16484
|
+
* value is written verbatim, with no element-type prefix, matching the other
|
|
16485
|
+
* components whose host *is* the target (`tn-tree-node`, `tn-table`): a row of
|
|
16486
|
+
* a list is not a control whose type the library can name, and its meaning
|
|
16487
|
+
* comes from the list it sits in, which only the consumer knows.
|
|
16470
16488
|
*/
|
|
16471
16489
|
class TnListItemComponent {
|
|
16472
16490
|
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
@@ -16512,11 +16530,11 @@ class TnListItemComponent {
|
|
|
16512
16530
|
}
|
|
16513
16531
|
}
|
|
16514
16532
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
16515
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnListItemComponent, isStandalone: true, selector: "tn-list-item", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, clickable: { classPropertyName: "clickable", publicName: "clickable", isSignal: true, isRequired: false, transformFunction: null }, dense: { classPropertyName: "dense", publicName: "dense", isSignal: true, isRequired: false, transformFunction: null }, wrap: { classPropertyName: "wrap", publicName: "wrap", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, host: { attributes: { "role": "listitem" }, listeners: { "click": "onClick($event)" }, properties: { "class.tn-list-item--disabled": "disabled()", "class.tn-list-item--clickable": "clickable()", "class.tn-list-item--dense": "dense()", "class.tn-list-item--wrap": "wrap()", "class.tn-list-item--two-line": "hasSecondaryText()", "class.tn-list-item--three-line": "hasThirdText()" }, classAttribute: "tn-list-item" }, queries: [{ propertyName: "leadingIcons", predicate: TnListIconDirective, descendants: true, isSignal: true }, { propertyName: "leadingAvatars", predicate: TnListAvatarDirective, descendants: true, isSignal: true }, { propertyName: "secondaryLines", predicate: TnListItemLineDirective, descendants: true, isSignal: true }, { propertyName: "secondaryTexts", predicate: TnListItemSecondaryDirective, descendants: true, isSignal: true }, { propertyName: "trailing", predicate: TnListItemTrailingDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"tn-list-item__content\">\n <!-- Leading icon/avatar slot -->\n @if (hasLeadingContent()) {\n <div class=\"tn-list-item__leading\">\n <ng-content select=\"[tnListIcon], [tnListAvatar]\" />\n </div>\n }\n\n <!-- Text content -->\n <div class=\"tn-list-item__text\">\n <!--\n Primary text. The catch-all slot needs no guard: a projected node is\n assigned to exactly one slot, so anything carrying [tnListItemTitle] or\n [tnListItemPrimary] lands in the slot above and can never reach the\n catch-all. Gating this on a directive query would instead key projection\n and rendering off two different things \u2014 the slot matches the attribute,\n a contentChildren query matches the directive instance \u2014 so an attribute\n written without its directive imported would toggle the guard while\n projecting exactly as before.\n\n The leading, secondary and trailing slots below are still gated that way,\n deliberately: their wrappers carry gutters that would space out every row\n if rendered empty. The cost is that they require the directive to be\n imported, which is documented on the component and on each directive.\n -->\n <div class=\"tn-list-item__primary-text\">\n <ng-content select=\"[tnListItemTitle], [tnListItemPrimary]\" />\n <ng-content />\n </div>\n\n <!-- Secondary text -->\n @if (hasSecondaryText()) {\n <div class=\"tn-list-item__secondary-text\">\n <ng-content select=\"[tnListItemLine], [tnListItemSecondary]\" />\n </div>\n }\n </div>\n\n <!-- Trailing content slot -->\n @if (hasTrailingContent()) {\n <div class=\"tn-list-item__trailing\">\n <ng-content select=\"[tnListItemTrailing]\" />\n </div>\n }\n</div>", styles: [".tn-list-item{display:block;position:relative;min-height:48px;padding:0;cursor:default;text-decoration:none;color:var(--tn-fg1);transition:background-color .2s ease}.tn-list-item__content{display:flex;align-items:center;padding:8px 16px;min-height:inherit;box-sizing:border-box}.tn-list-item__leading{flex-shrink:0;margin-right:16px;display:flex;align-items:center;justify-content:center}.tn-list-item__text{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}.tn-list-item__primary-text{font-size:1rem;font-weight:400;line-height:1.5;color:var(--tn-fg1);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tn-list-item__secondary-text{font-size:14px;font-weight:400;line-height:1.4;color:var(--tn-fg2);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tn-list-item__trailing{flex-shrink:0;margin-left:16px;display:flex;align-items:center}.tn-list-item--clickable{cursor:pointer}.tn-list-item--clickable:hover:not(.tn-list-item--disabled){background-color:var(--tn-alt-bg1)}.tn-list-item--clickable:focus{outline:none;background-color:var(--tn-alt-bg1)}.tn-list-item--clickable:active:not(.tn-list-item--disabled){background-color:var(--tn-alt-bg2)}.tn-list-item--two-line{min-height:64px}.tn-list-item--two-line .tn-list-item__primary-text{white-space:normal;line-height:1.4}.tn-list-item--two-line .tn-list-item__secondary-text{white-space:normal;line-height:1.3}.tn-list-item--three-line{min-height:88px}.tn-list-item--three-line .tn-list-item__text{align-items:flex-start;padding:8px 0}.tn-list-item--three-line .tn-list-item__primary-text{white-space:normal;line-height:1.4}.tn-list-item--three-line .tn-list-item__secondary-text{white-space:normal;line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.tn-list-item--dense{min-height:32px}.tn-list-item--dense .tn-list-item__content{padding:4px 16px}.tn-list-item--dense .tn-list-item__leading{margin-right:8px}.tn-list-item--dense .tn-list-item__trailing{margin-left:8px}.tn-list-item--wrap .tn-list-item__primary-text,.tn-list-item--wrap .tn-list-item__secondary-text{overflow:visible;text-overflow:clip;white-space:normal}.tn-list-item--disabled{opacity:.6;cursor:not-allowed;pointer-events:none}::ng-deep [tnListIcon]{width:24px;height:24px;font-size:24px;color:var(--tn-fg2);display:flex;align-items:center;justify-content:center}::ng-deep [tnListAvatar]{width:40px;height:40px;border-radius:50%;object-fit:cover;background-color:var(--tn-alt-bg1);color:var(--tn-fg1);display:flex;align-items:center;justify-content:center;font-weight:500}::ng-deep [tnListItemTitle]{font-weight:400}::ng-deep [tnListItemLine]{display:block;margin-top:4px;font-size:14px;color:var(--tn-fg2);line-height:1.4}::ng-deep [tnListItemTrailing]{color:var(--tn-fg2);font-size:14px}\n"] });
|
|
16533
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnListItemComponent, isStandalone: true, selector: "tn-list-item", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, clickable: { classPropertyName: "clickable", publicName: "clickable", isSignal: true, isRequired: false, transformFunction: null }, dense: { classPropertyName: "dense", publicName: "dense", isSignal: true, isRequired: false, transformFunction: null }, wrap: { classPropertyName: "wrap", publicName: "wrap", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, host: { attributes: { "role": "listitem" }, listeners: { "click": "onClick($event)" }, properties: { "class.tn-list-item--disabled": "disabled()", "class.tn-list-item--clickable": "clickable()", "class.tn-list-item--dense": "dense()", "class.tn-list-item--wrap": "wrap()", "class.tn-list-item--two-line": "hasSecondaryText()", "class.tn-list-item--three-line": "hasThirdText()" }, classAttribute: "tn-list-item" }, queries: [{ propertyName: "leadingIcons", predicate: TnListIconDirective, descendants: true, isSignal: true }, { propertyName: "leadingAvatars", predicate: TnListAvatarDirective, descendants: true, isSignal: true }, { propertyName: "secondaryLines", predicate: TnListItemLineDirective, descendants: true, isSignal: true }, { propertyName: "secondaryTexts", predicate: TnListItemSecondaryDirective, descendants: true, isSignal: true }, { propertyName: "trailing", predicate: TnListItemTrailingDirective, descendants: true, isSignal: true }], hostDirectives: [{ directive: TnTestIdDirective, inputs: ["tnTestId", "testId"] }], ngImport: i0, template: "<div class=\"tn-list-item__content\">\n <!-- Leading icon/avatar slot -->\n @if (hasLeadingContent()) {\n <div class=\"tn-list-item__leading\">\n <ng-content select=\"[tnListIcon], [tnListAvatar]\" />\n </div>\n }\n\n <!-- Text content -->\n <div class=\"tn-list-item__text\">\n <!--\n Primary text. The catch-all slot needs no guard: a projected node is\n assigned to exactly one slot, so anything carrying [tnListItemTitle] or\n [tnListItemPrimary] lands in the slot above and can never reach the\n catch-all. Gating this on a directive query would instead key projection\n and rendering off two different things \u2014 the slot matches the attribute,\n a contentChildren query matches the directive instance \u2014 so an attribute\n written without its directive imported would toggle the guard while\n projecting exactly as before.\n\n The leading, secondary and trailing slots below are still gated that way,\n deliberately: their wrappers carry gutters that would space out every row\n if rendered empty. The cost is that they require the directive to be\n imported, which is documented on the component and on each directive.\n -->\n <div class=\"tn-list-item__primary-text\">\n <ng-content select=\"[tnListItemTitle], [tnListItemPrimary]\" />\n <ng-content />\n </div>\n\n <!-- Secondary text -->\n @if (hasSecondaryText()) {\n <div class=\"tn-list-item__secondary-text\">\n <ng-content select=\"[tnListItemLine], [tnListItemSecondary]\" />\n </div>\n }\n </div>\n\n <!-- Trailing content slot -->\n @if (hasTrailingContent()) {\n <div class=\"tn-list-item__trailing\">\n <ng-content select=\"[tnListItemTrailing]\" />\n </div>\n }\n</div>", styles: [".tn-list-item{display:block;position:relative;min-height:48px;padding:0;cursor:default;text-decoration:none;color:var(--tn-fg1);transition:background-color .2s ease}.tn-list-item__content{display:flex;align-items:center;padding:8px 16px;min-height:inherit;box-sizing:border-box}.tn-list-item__leading{flex-shrink:0;margin-right:16px;display:flex;align-items:center;justify-content:center}.tn-list-item__text{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}.tn-list-item__primary-text{font-size:1rem;font-weight:400;line-height:1.5;color:var(--tn-fg1);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tn-list-item__secondary-text{font-size:14px;font-weight:400;line-height:1.4;color:var(--tn-fg2);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tn-list-item__trailing{flex-shrink:0;margin-left:16px;display:flex;align-items:center}.tn-list-item--clickable{cursor:pointer}.tn-list-item--clickable:hover:not(.tn-list-item--disabled){background-color:var(--tn-alt-bg1)}.tn-list-item--clickable:focus{outline:none;background-color:var(--tn-alt-bg1)}.tn-list-item--clickable:active:not(.tn-list-item--disabled){background-color:var(--tn-alt-bg2)}.tn-list-item--two-line{min-height:64px}.tn-list-item--two-line .tn-list-item__primary-text{white-space:normal;line-height:1.4}.tn-list-item--two-line .tn-list-item__secondary-text{white-space:normal;line-height:1.3}.tn-list-item--three-line{min-height:88px}.tn-list-item--three-line .tn-list-item__text{align-items:flex-start;padding:8px 0}.tn-list-item--three-line .tn-list-item__primary-text{white-space:normal;line-height:1.4}.tn-list-item--three-line .tn-list-item__secondary-text{white-space:normal;line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.tn-list-item--dense{min-height:32px}.tn-list-item--dense .tn-list-item__content{padding:4px 16px}.tn-list-item--dense .tn-list-item__leading{margin-right:8px}.tn-list-item--dense .tn-list-item__trailing{margin-left:8px}.tn-list-item--wrap .tn-list-item__primary-text,.tn-list-item--wrap .tn-list-item__secondary-text{overflow:visible;text-overflow:clip;white-space:normal}.tn-list-item--disabled{opacity:.6;cursor:not-allowed;pointer-events:none}::ng-deep [tnListIcon]{width:24px;height:24px;font-size:24px;color:var(--tn-fg2);display:flex;align-items:center;justify-content:center}::ng-deep [tnListAvatar]{width:40px;height:40px;border-radius:50%;object-fit:cover;background-color:var(--tn-alt-bg1);color:var(--tn-fg1);display:flex;align-items:center;justify-content:center;font-weight:500}::ng-deep [tnListItemTitle]{font-weight:400}::ng-deep [tnListItemLine]{display:block;margin-top:4px;font-size:14px;color:var(--tn-fg2);line-height:1.4}::ng-deep [tnListItemTrailing]{color:var(--tn-fg2);font-size:14px}\n"] });
|
|
16516
16534
|
}
|
|
16517
16535
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnListItemComponent, decorators: [{
|
|
16518
16536
|
type: Component,
|
|
16519
|
-
args: [{ selector: 'tn-list-item', standalone: true, imports: [], host: {
|
|
16537
|
+
args: [{ selector: 'tn-list-item', standalone: true, imports: [], hostDirectives: [{ directive: TnTestIdDirective, inputs: ['tnTestId: testId'] }], host: {
|
|
16520
16538
|
'class': 'tn-list-item',
|
|
16521
16539
|
'[class.tn-list-item--disabled]': 'disabled()',
|
|
16522
16540
|
'[class.tn-list-item--clickable]': 'clickable()',
|
|
@@ -26408,9 +26426,10 @@ class TnDialogShellComponent {
|
|
|
26408
26426
|
/** Hide the actions footer. Same wrapper-case rationale as {@link hideContent}. */
|
|
26409
26427
|
hideActions = input(false, ...(ngDevMode ? [{ debugName: "hideActions" }] : []));
|
|
26410
26428
|
/**
|
|
26411
|
-
* Optional semantic base that scopes the shell's chrome
|
|
26412
|
-
*
|
|
26413
|
-
*
|
|
26429
|
+
* Optional semantic base that scopes the shell's chrome. The close and
|
|
26430
|
+
* fullscreen buttons emit `button-close` / `button-fullscreen` by default, and
|
|
26431
|
+
* the title heading `dialog-title`, or `button-close-<testId>` /
|
|
26432
|
+
* `button-fullscreen-<testId>` / `dialog-title-<testId>` when a base is
|
|
26414
26433
|
* provided (useful when more than one dialog can be open).
|
|
26415
26434
|
*/
|
|
26416
26435
|
testId = input(undefined, ...(ngDevMode ? [{ debugName: "testId" }] : []));
|
|
@@ -26452,6 +26471,19 @@ class TnDialogShellComponent {
|
|
|
26452
26471
|
closeTestId = computed(() => ['close', ...this.baseSegments()], ...(ngDevMode ? [{ debugName: "closeTestId" }] : []));
|
|
26453
26472
|
/** Role-first test-id segments for the fullscreen button: `button-fullscreen[-<base>]`. */
|
|
26454
26473
|
fullscreenTestId = computed(() => ['fullscreen', ...this.baseSegments()], ...(ngDevMode ? [{ debugName: "fullscreenTestId" }] : []));
|
|
26474
|
+
/**
|
|
26475
|
+
* Role-first test-id segments for the title heading: `dialog-title[-<base>]`.
|
|
26476
|
+
*
|
|
26477
|
+
* The heading is fixed chrome like the two buttons, so it follows the same
|
|
26478
|
+
* role-first shape — and a test that knows a dialog's base knows its title's
|
|
26479
|
+
* id without being told separately, which is the point: dialogs raised
|
|
26480
|
+
* through one generic error path are otherwise indistinguishable by id, and
|
|
26481
|
+
* the only remaining handle is a match on their prose.
|
|
26482
|
+
*
|
|
26483
|
+
* There is no id when there is no title: the heading is not rendered at all
|
|
26484
|
+
* (see the template), so nothing is left behind to select.
|
|
26485
|
+
*/
|
|
26486
|
+
titleTestId = computed(() => ['title', ...this.baseSegments()], ...(ngDevMode ? [{ debugName: "titleTestId" }] : []));
|
|
26455
26487
|
/** Stable id for the title heading, referenced by the dialog's aria-labelledby. */
|
|
26456
26488
|
titleId = `tn-dialog-title-${nextUniqueId++}`;
|
|
26457
26489
|
isFullscreen = signal(false, ...(ngDevMode ? [{ debugName: "isFullscreen" }] : []));
|
|
@@ -26594,13 +26626,13 @@ class TnDialogShellComponent {
|
|
|
26594
26626
|
}
|
|
26595
26627
|
}
|
|
26596
26628
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnDialogShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
26597
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnDialogShellComponent, isStandalone: true, selector: "tn-dialog-shell", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, showFullscreenButton: { classPropertyName: "showFullscreenButton", publicName: "showFullscreenButton", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, hideContent: { classPropertyName: "hideContent", publicName: "hideContent", isSignal: true, isRequired: false, transformFunction: null }, hideActions: { classPropertyName: "hideActions", publicName: "hideActions", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "ariaLabelledby", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "tn-dialog-shell" }, ngImport: i0, template: "<header class=\"tn-dialog__header\">\n <!--\n No heading element at all when there is no title, rather than an empty one:\n an `<h2>` with no text is an `empty-heading` violation, and it puts a level-2\n heading with nothing in it into the document outline (#219). The dialog is\n then named by `ariaLabel`/`ariaLabelledby` instead \u2014 see the component.\n -->\n @if (hasTitle()) {\n <h2 class=\"tn-dialog__title\" [id]=\"titleId\">{{ title() }}</h2>\n }\n @if (showFullscreenButton()) {\n <!--\n `data-fullscreen` is the language-independent state hook `TnDialogHarness.isFullscreen()`\n reads. The state is also on the panel's `.tn-dialog--fullscreen` class, but the panel is an\n ANCESTOR of this component's host \u2014 out of reach for a harness locator, and ambiguous while\n more than one dialog is open. `aria-label` is not the hook: it is now DI-configurable, so a\n translated app would flip the harness's answer. Same call the table's sort-direction toggle\n makes, for the same reason (see `data-sort-direction`).\n -->\n <button\n type=\"button\"\n class=\"tn-dialog__fullscreen\"\n tnTestIdType=\"button\"\n [tnTestId]=\"fullscreenTestId()\"\n [attr.aria-label]=\"fullscreenLabel()\"\n [attr.data-fullscreen]=\"isFullscreen()\"\n (click)=\"toggleFullscreen()\">\n <span class=\"tn-dialog__fullscreen-icon\" aria-hidden=\"true\">{{ isFullscreen() ? '\u2913' : '\u2922' }}</span>\n </button>\n }\n @if (showCloseButton()) {\n <button type=\"button\" class=\"tn-dialog__close\" tnTestIdType=\"button\" [attr.aria-label]=\"labels().close\" [tnTestId]=\"closeTestId()\" (click)=\"close()\">\n <span class=\"tn-dialog__close-icon\" aria-hidden=\"true\">\u2715</span>\n </button>\n }\n</header>\n\n<section class=\"tn-dialog__content\" cdkDialogContent [class.tn-dialog__content--hidden]=\"hideContent()\">\n <ng-content />\n</section>\n\n<footer class=\"tn-dialog__actions\" cdkDialogActions [class.tn-dialog__actions--hidden]=\"hideActions()\">\n <ng-content select=\"[tnDialogAction]\" />\n</footer>\n", dependencies: [{ kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }] });
|
|
26629
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnDialogShellComponent, isStandalone: true, selector: "tn-dialog-shell", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, showFullscreenButton: { classPropertyName: "showFullscreenButton", publicName: "showFullscreenButton", isSignal: true, isRequired: false, transformFunction: null }, showCloseButton: { classPropertyName: "showCloseButton", publicName: "showCloseButton", isSignal: true, isRequired: false, transformFunction: null }, hideContent: { classPropertyName: "hideContent", publicName: "hideContent", isSignal: true, isRequired: false, transformFunction: null }, hideActions: { classPropertyName: "hideActions", publicName: "hideActions", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "ariaLabelledby", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "tn-dialog-shell" }, ngImport: i0, template: "<header class=\"tn-dialog__header\">\n <!--\n No heading element at all when there is no title, rather than an empty one:\n an `<h2>` with no text is an `empty-heading` violation, and it puts a level-2\n heading with nothing in it into the document outline (#219). The dialog is\n then named by `ariaLabel`/`ariaLabelledby` instead \u2014 see the component. Nothing\n renders, so an untitled dialog also leaves no `dialog-title-*` id behind.\n -->\n @if (hasTitle()) {\n <h2 class=\"tn-dialog__title\" tnTestIdType=\"dialog\" [id]=\"titleId\" [tnTestId]=\"titleTestId()\">{{ title() }}</h2>\n }\n @if (showFullscreenButton()) {\n <!--\n `data-fullscreen` is the language-independent state hook `TnDialogHarness.isFullscreen()`\n reads. The state is also on the panel's `.tn-dialog--fullscreen` class, but the panel is an\n ANCESTOR of this component's host \u2014 out of reach for a harness locator, and ambiguous while\n more than one dialog is open. `aria-label` is not the hook: it is now DI-configurable, so a\n translated app would flip the harness's answer. Same call the table's sort-direction toggle\n makes, for the same reason (see `data-sort-direction`).\n -->\n <button\n type=\"button\"\n class=\"tn-dialog__fullscreen\"\n tnTestIdType=\"button\"\n [tnTestId]=\"fullscreenTestId()\"\n [attr.aria-label]=\"fullscreenLabel()\"\n [attr.data-fullscreen]=\"isFullscreen()\"\n (click)=\"toggleFullscreen()\">\n <span class=\"tn-dialog__fullscreen-icon\" aria-hidden=\"true\">{{ isFullscreen() ? '\u2913' : '\u2922' }}</span>\n </button>\n }\n @if (showCloseButton()) {\n <button type=\"button\" class=\"tn-dialog__close\" tnTestIdType=\"button\" [attr.aria-label]=\"labels().close\" [tnTestId]=\"closeTestId()\" (click)=\"close()\">\n <span class=\"tn-dialog__close-icon\" aria-hidden=\"true\">\u2715</span>\n </button>\n }\n</header>\n\n<section class=\"tn-dialog__content\" cdkDialogContent [class.tn-dialog__content--hidden]=\"hideContent()\">\n <ng-content />\n</section>\n\n<footer class=\"tn-dialog__actions\" cdkDialogActions [class.tn-dialog__actions--hidden]=\"hideActions()\">\n <ng-content select=\"[tnDialogAction]\" />\n</footer>\n", dependencies: [{ kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }] });
|
|
26598
26630
|
}
|
|
26599
26631
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnDialogShellComponent, decorators: [{
|
|
26600
26632
|
type: Component,
|
|
26601
26633
|
args: [{ selector: 'tn-dialog-shell', standalone: true, imports: [TnTestIdDirective], host: {
|
|
26602
26634
|
'class': 'tn-dialog-shell'
|
|
26603
|
-
}, template: "<header class=\"tn-dialog__header\">\n <!--\n No heading element at all when there is no title, rather than an empty one:\n an `<h2>` with no text is an `empty-heading` violation, and it puts a level-2\n heading with nothing in it into the document outline (#219). The dialog is\n then named by `ariaLabel`/`ariaLabelledby` instead \u2014 see the component.\n -->\n @if (hasTitle()) {\n <h2 class=\"tn-dialog__title\" [id]=\"titleId\">{{ title() }}</h2>\n }\n @if (showFullscreenButton()) {\n <!--\n `data-fullscreen` is the language-independent state hook `TnDialogHarness.isFullscreen()`\n reads. The state is also on the panel's `.tn-dialog--fullscreen` class, but the panel is an\n ANCESTOR of this component's host \u2014 out of reach for a harness locator, and ambiguous while\n more than one dialog is open. `aria-label` is not the hook: it is now DI-configurable, so a\n translated app would flip the harness's answer. Same call the table's sort-direction toggle\n makes, for the same reason (see `data-sort-direction`).\n -->\n <button\n type=\"button\"\n class=\"tn-dialog__fullscreen\"\n tnTestIdType=\"button\"\n [tnTestId]=\"fullscreenTestId()\"\n [attr.aria-label]=\"fullscreenLabel()\"\n [attr.data-fullscreen]=\"isFullscreen()\"\n (click)=\"toggleFullscreen()\">\n <span class=\"tn-dialog__fullscreen-icon\" aria-hidden=\"true\">{{ isFullscreen() ? '\u2913' : '\u2922' }}</span>\n </button>\n }\n @if (showCloseButton()) {\n <button type=\"button\" class=\"tn-dialog__close\" tnTestIdType=\"button\" [attr.aria-label]=\"labels().close\" [tnTestId]=\"closeTestId()\" (click)=\"close()\">\n <span class=\"tn-dialog__close-icon\" aria-hidden=\"true\">\u2715</span>\n </button>\n }\n</header>\n\n<section class=\"tn-dialog__content\" cdkDialogContent [class.tn-dialog__content--hidden]=\"hideContent()\">\n <ng-content />\n</section>\n\n<footer class=\"tn-dialog__actions\" cdkDialogActions [class.tn-dialog__actions--hidden]=\"hideActions()\">\n <ng-content select=\"[tnDialogAction]\" />\n</footer>\n" }]
|
|
26635
|
+
}, template: "<header class=\"tn-dialog__header\">\n <!--\n No heading element at all when there is no title, rather than an empty one:\n an `<h2>` with no text is an `empty-heading` violation, and it puts a level-2\n heading with nothing in it into the document outline (#219). The dialog is\n then named by `ariaLabel`/`ariaLabelledby` instead \u2014 see the component. Nothing\n renders, so an untitled dialog also leaves no `dialog-title-*` id behind.\n -->\n @if (hasTitle()) {\n <h2 class=\"tn-dialog__title\" tnTestIdType=\"dialog\" [id]=\"titleId\" [tnTestId]=\"titleTestId()\">{{ title() }}</h2>\n }\n @if (showFullscreenButton()) {\n <!--\n `data-fullscreen` is the language-independent state hook `TnDialogHarness.isFullscreen()`\n reads. The state is also on the panel's `.tn-dialog--fullscreen` class, but the panel is an\n ANCESTOR of this component's host \u2014 out of reach for a harness locator, and ambiguous while\n more than one dialog is open. `aria-label` is not the hook: it is now DI-configurable, so a\n translated app would flip the harness's answer. Same call the table's sort-direction toggle\n makes, for the same reason (see `data-sort-direction`).\n -->\n <button\n type=\"button\"\n class=\"tn-dialog__fullscreen\"\n tnTestIdType=\"button\"\n [tnTestId]=\"fullscreenTestId()\"\n [attr.aria-label]=\"fullscreenLabel()\"\n [attr.data-fullscreen]=\"isFullscreen()\"\n (click)=\"toggleFullscreen()\">\n <span class=\"tn-dialog__fullscreen-icon\" aria-hidden=\"true\">{{ isFullscreen() ? '\u2913' : '\u2922' }}</span>\n </button>\n }\n @if (showCloseButton()) {\n <button type=\"button\" class=\"tn-dialog__close\" tnTestIdType=\"button\" [attr.aria-label]=\"labels().close\" [tnTestId]=\"closeTestId()\" (click)=\"close()\">\n <span class=\"tn-dialog__close-icon\" aria-hidden=\"true\">\u2715</span>\n </button>\n }\n</header>\n\n<section class=\"tn-dialog__content\" cdkDialogContent [class.tn-dialog__content--hidden]=\"hideContent()\">\n <ng-content />\n</section>\n\n<footer class=\"tn-dialog__actions\" cdkDialogActions [class.tn-dialog__actions--hidden]=\"hideActions()\">\n <ng-content select=\"[tnDialogAction]\" />\n</footer>\n" }]
|
|
26604
26636
|
}], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], showFullscreenButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFullscreenButton", required: false }] }], showCloseButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCloseButton", required: false }] }], hideContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideContent", required: false }] }], hideActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideActions", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledby", required: false }] }] } });
|
|
26605
26637
|
|
|
26606
26638
|
class TnConfirmDialogComponent {
|