@truenas/ui-components 0.1.69 → 0.1.70
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.
|
@@ -3395,7 +3395,14 @@ class TnMenuItemComponent {
|
|
|
3395
3395
|
itemClick = output();
|
|
3396
3396
|
/** Template capturing whatever the consumer projected as item content. */
|
|
3397
3397
|
content = viewChild.required('content');
|
|
3398
|
-
|
|
3398
|
+
/**
|
|
3399
|
+
* Semantic *base* for the test id — either the explicit `testId` or the `id`.
|
|
3400
|
+
* The owning `<tn-menu-panel>` button declares `tnTestIdType="button"`, so
|
|
3401
|
+
* `TnTestIdDirective` composes the final `button-…` id (and is idempotent, so
|
|
3402
|
+
* an already-`button-`-prefixed value is not doubled). Returns `undefined`
|
|
3403
|
+
* when neither is set, which composes to no attribute.
|
|
3404
|
+
*/
|
|
3405
|
+
resolvedTestId = computed(() => this.testId() ?? this.id(), ...(ngDevMode ? [{ debugName: "resolvedTestId" }] : []));
|
|
3399
3406
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnMenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3400
3407
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.0", type: TnMenuItemComponent, isStandalone: true, selector: "tn-menu-item", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, iconLibrary: { classPropertyName: "iconLibrary", publicName: "iconLibrary", isSignal: true, isRequired: false, transformFunction: null }, shortcut: { classPropertyName: "shortcut", publicName: "shortcut", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, host: { styleAttribute: "display: none;" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #content><ng-content /></ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
3401
3408
|
}
|
|
@@ -3515,13 +3522,17 @@ class TnMenuPanelComponent {
|
|
|
3515
3522
|
// back to the host `<tn-menu>` component and inject() resolves it.
|
|
3516
3523
|
menu = inject(TnMenuComponent);
|
|
3517
3524
|
/**
|
|
3518
|
-
*
|
|
3519
|
-
* `
|
|
3520
|
-
* `
|
|
3521
|
-
*
|
|
3525
|
+
* Returns the semantic *base* for an item's test id; the rendered button
|
|
3526
|
+
* declares `tnTestIdType="button"`, so `TnTestIdDirective` composes the final
|
|
3527
|
+
* `button-…` id. The item's own `testId` is used as the base when set
|
|
3528
|
+
* (idempotent — an already-`button-`-prefixed value is not doubled);
|
|
3529
|
+
* otherwise the base is `[menuBase, item.id]`, scoped by the host `<tn-menu>`'s
|
|
3530
|
+
* `testId` (e.g. menu `testId="actions"` + item `id="edit"` →
|
|
3531
|
+
* `button-actions-edit`). Nested panels resolve the same host menu via DI, so
|
|
3532
|
+
* child items share the root base. With no menu base this is `button-${item.id}`.
|
|
3522
3533
|
*/
|
|
3523
3534
|
resolvedItemTestId(item) {
|
|
3524
|
-
return item.testId ??
|
|
3535
|
+
return item.testId ?? [this.menu.testId(), item.id];
|
|
3525
3536
|
}
|
|
3526
3537
|
onItemClick(item) {
|
|
3527
3538
|
this.menu.onMenuItemClick(item);
|
|
@@ -3533,7 +3544,7 @@ class TnMenuPanelComponent {
|
|
|
3533
3544
|
return item.id;
|
|
3534
3545
|
}
|
|
3535
3546
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnMenuPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3536
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnMenuPanelComponent, isStandalone: true, selector: "tn-menu-panel", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, projectedItems: { classPropertyName: "projectedItems", publicName: "projectedItems", isSignal: true, isRequired: false, transformFunction: null }, nested: { classPropertyName: "nested", publicName: "nested", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"tn-menu\" cdkMenu tnMenuActivateHover [class.tn-menu--nested]=\"nested()\">\n <!--\n Projected <tn-menu-item> entries (root panel only) render as sibling\n cdkMenuItem buttons so they participate in CdkMenu's keyboard navigation\n (arrow keys, Home/End, type-ahead) alongside the items() array below.\n -->\n @for (projected of projectedItems(); track projected) {\n
|
|
3547
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnMenuPanelComponent, isStandalone: true, selector: "tn-menu-panel", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, projectedItems: { classPropertyName: "projectedItems", publicName: "projectedItems", isSignal: true, isRequired: false, transformFunction: null }, nested: { classPropertyName: "nested", publicName: "nested", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"tn-menu\" cdkMenu tnMenuActivateHover [class.tn-menu--nested]=\"nested()\">\n <!--\n Projected <tn-menu-item> entries (root panel only) render as sibling\n cdkMenuItem buttons so they participate in CdkMenu's keyboard navigation\n (arrow keys, Home/End, type-ahead) alongside the items() array below.\n -->\n @for (projected of projectedItems(); track projected) {\n <button\n cdkMenuItem\n class=\"tn-menu-item\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"projected.resolvedTestId()\"\n [disabled]=\"projected.disabled()\"\n [cdkMenuItemDisabled]=\"projected.disabled()\"\n [class.disabled]=\"projected.disabled()\"\n [class.tn-menu-item--selected]=\"projected.selected()\"\n [attr.aria-current]=\"projected.selected() ? 'true' : null\"\n (click)=\"onProjectedClick(projected, $event)\"\n >\n @if (projected.label() !== undefined) {\n @if (projected.icon()) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"projected.icon()!\" [library]=\"projected.iconLibrary()\" />\n }\n <span class=\"tn-menu-item-label\">{{ projected.label() }}</span>\n @if (projected.shortcut()) {\n <span class=\"tn-menu-item-shortcut\">{{ projected.shortcut() }}</span>\n }\n } @else {\n <ng-container [ngTemplateOutlet]=\"projected.content()\" />\n }\n </button>\n }\n\n @for (item of items(); track trackByItemId($index, item)) {\n @if (item.separator) {\n <div class=\"tn-menu-separator\" role=\"separator\"></div>\n } @else if (!item.children || item.children.length === 0) {\n <button\n cdkMenuItem\n class=\"tn-menu-item\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"resolvedItemTestId(item)\"\n [disabled]=\"item.disabled\"\n [cdkMenuItemDisabled]=\"!!item.disabled\"\n [class.disabled]=\"item.disabled\"\n [class.tn-menu-item--selected]=\"item.selected\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n >\n @if (item.icon) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"item.icon!\" [library]=\"item.iconLibrary\" />\n }\n <span class=\"tn-menu-item-label\">{{ item.label }}</span>\n @if (item.shortcut) {\n <span class=\"tn-menu-item-shortcut\">{{ item.shortcut }}</span>\n }\n </button>\n } @else {\n <button\n cdkMenuItem\n class=\"tn-menu-item tn-menu-item--nested\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"resolvedItemTestId(item)\"\n [cdkMenuTriggerFor]=\"submenuTpl\"\n [disabled]=\"item.disabled\"\n [cdkMenuItemDisabled]=\"!!item.disabled\"\n [class.disabled]=\"item.disabled\"\n [class.tn-menu-item--selected]=\"item.selected\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n >\n @if (item.icon) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"item.icon!\" [library]=\"item.iconLibrary\" />\n }\n <span class=\"tn-menu-item-label\">{{ item.label }}</span>\n @if (item.shortcut) {\n <span class=\"tn-menu-item-shortcut\">{{ item.shortcut }}</span>\n }\n <span class=\"tn-menu-item-arrow\">\u25B6</span>\n </button>\n\n <ng-template #submenuTpl>\n <tn-menu-panel [items]=\"item.children!\" [nested]=\"true\" />\n </ng-template>\n }\n }\n</div>\n", styles: [".tn-menu-container{display:inline-block;position:relative}.tn-menu-container.tn-menu-container--context{display:block;width:100%;height:100%;cursor:context-menu}.tn-menu-trigger{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;transition:all .2s ease}.tn-menu-trigger:hover:not(.disabled){background:var(--tn-bg2, #f5f5f5);border-color:var(--tn-lines, #cccccc)}.tn-menu-trigger:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-menu-trigger.disabled{opacity:.5;cursor:not-allowed}.tn-menu-arrow{font-size:12px;transition:transform .2s ease}.tn-menu-arrow.tn-menu-arrow--up{transform:rotate(180deg)}.tn-menu{display:flex;flex-direction:column;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;min-width:160px;max-width:300px;padding:4px 0;z-index:1000}.tn-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 16px;border:none;background:transparent;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;text-align:left;transition:background-color .2s ease}.tn-menu-item:hover:not(.disabled){background:var(--tn-alt-bg2, #e8f4fd)!important}.tn-menu-item:focus{outline:none;background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item[aria-selected=true]{background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item.tn-menu-item--selected{background:var(--tn-alt-bg2, #e8f4fd);font-weight:600;color:var(--tn-primary, #007bff)}.tn-menu-item.disabled{opacity:.5;cursor:not-allowed}.tn-menu-item.disabled:hover{background:transparent!important}.tn-menu-item-icon{font-size:1rem;width:16px;text-align:center}.tn-menu-item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tn-menu-item-shortcut{font-size:12px;color:var(--tn-fg2, #666666);margin-left:auto;padding-left:16px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-weight:400;opacity:.7}.tn-menu-item-arrow{font-size:10px;margin-left:8px;color:var(--tn-fg2, #666666);transition:transform .2s ease;flex-shrink:0}.tn-menu-item--nested{position:relative}.tn-menu-item--nested:hover .tn-menu-item-arrow{color:var(--tn-fg1, #333333)}.tn-menu-separator{height:1px;background:var(--tn-lines, #e0e0e0);margin:4px 0}.tn-menu--nested{margin-left:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;border-radius:4px}.tn-menu-context-content{width:100%;height:100%}.tn-menu-context-content:hover:before{content:\"\";position:absolute;inset:0;background:rgba(var(--tn-primary-rgb, 0, 123, 255),.05);pointer-events:none;border:1px dashed rgba(var(--tn-primary-rgb, 0, 123, 255),.3);border-radius:4px}\n"], dependencies: [{ kind: "component", type: i0.forwardRef(() => TnMenuPanelComponent), selector: "tn-menu-panel", inputs: ["items", "projectedItems", "nested"] }, { kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1$2.NgTemplateOutlet), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(() => CdkMenu), selector: "[cdkMenu]", outputs: ["closed"], exportAs: ["cdkMenu"] }, { kind: "directive", type: i0.forwardRef(() => CdkMenuItem), selector: "[cdkMenuItem]", inputs: ["cdkMenuItemDisabled", "cdkMenuitemTypeaheadLabel"], outputs: ["cdkMenuItemTriggered"], exportAs: ["cdkMenuItem"] }, { kind: "directive", type: i0.forwardRef(() => CdkMenuTrigger), selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData", "cdkMenuTriggerTransformOriginOn"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }, { kind: "component", type: i0.forwardRef(() => TnIconComponent), selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "fullSize", "customSize"] }, { kind: "directive", type: i0.forwardRef(() => TnTestIdDirective), selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "directive", type: i0.forwardRef(() => TnMenuActivateHoverDirective), selector: "[tnMenuActivateHover]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3537
3548
|
}
|
|
3538
3549
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnMenuPanelComponent, decorators: [{
|
|
3539
3550
|
type: Component,
|
|
@@ -3546,7 +3557,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
3546
3557
|
TnTestIdDirective,
|
|
3547
3558
|
TnMenuActivateHoverDirective,
|
|
3548
3559
|
forwardRef(() => TnMenuPanelComponent),
|
|
3549
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tn-menu\" cdkMenu tnMenuActivateHover [class.tn-menu--nested]=\"nested()\">\n <!--\n Projected <tn-menu-item> entries (root panel only) render as sibling\n cdkMenuItem buttons so they participate in CdkMenu's keyboard navigation\n (arrow keys, Home/End, type-ahead) alongside the items() array below.\n -->\n @for (projected of projectedItems(); track projected) {\n
|
|
3560
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tn-menu\" cdkMenu tnMenuActivateHover [class.tn-menu--nested]=\"nested()\">\n <!--\n Projected <tn-menu-item> entries (root panel only) render as sibling\n cdkMenuItem buttons so they participate in CdkMenu's keyboard navigation\n (arrow keys, Home/End, type-ahead) alongside the items() array below.\n -->\n @for (projected of projectedItems(); track projected) {\n <button\n cdkMenuItem\n class=\"tn-menu-item\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"projected.resolvedTestId()\"\n [disabled]=\"projected.disabled()\"\n [cdkMenuItemDisabled]=\"projected.disabled()\"\n [class.disabled]=\"projected.disabled()\"\n [class.tn-menu-item--selected]=\"projected.selected()\"\n [attr.aria-current]=\"projected.selected() ? 'true' : null\"\n (click)=\"onProjectedClick(projected, $event)\"\n >\n @if (projected.label() !== undefined) {\n @if (projected.icon()) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"projected.icon()!\" [library]=\"projected.iconLibrary()\" />\n }\n <span class=\"tn-menu-item-label\">{{ projected.label() }}</span>\n @if (projected.shortcut()) {\n <span class=\"tn-menu-item-shortcut\">{{ projected.shortcut() }}</span>\n }\n } @else {\n <ng-container [ngTemplateOutlet]=\"projected.content()\" />\n }\n </button>\n }\n\n @for (item of items(); track trackByItemId($index, item)) {\n @if (item.separator) {\n <div class=\"tn-menu-separator\" role=\"separator\"></div>\n } @else if (!item.children || item.children.length === 0) {\n <button\n cdkMenuItem\n class=\"tn-menu-item\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"resolvedItemTestId(item)\"\n [disabled]=\"item.disabled\"\n [cdkMenuItemDisabled]=\"!!item.disabled\"\n [class.disabled]=\"item.disabled\"\n [class.tn-menu-item--selected]=\"item.selected\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n (click)=\"onItemClick(item)\"\n >\n @if (item.icon) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"item.icon!\" [library]=\"item.iconLibrary\" />\n }\n <span class=\"tn-menu-item-label\">{{ item.label }}</span>\n @if (item.shortcut) {\n <span class=\"tn-menu-item-shortcut\">{{ item.shortcut }}</span>\n }\n </button>\n } @else {\n <button\n cdkMenuItem\n class=\"tn-menu-item tn-menu-item--nested\"\n type=\"button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"resolvedItemTestId(item)\"\n [cdkMenuTriggerFor]=\"submenuTpl\"\n [disabled]=\"item.disabled\"\n [cdkMenuItemDisabled]=\"!!item.disabled\"\n [class.disabled]=\"item.disabled\"\n [class.tn-menu-item--selected]=\"item.selected\"\n [attr.aria-current]=\"item.selected ? 'true' : null\"\n >\n @if (item.icon) {\n <tn-icon size=\"sm\" class=\"tn-menu-item-icon\" [name]=\"item.icon!\" [library]=\"item.iconLibrary\" />\n }\n <span class=\"tn-menu-item-label\">{{ item.label }}</span>\n @if (item.shortcut) {\n <span class=\"tn-menu-item-shortcut\">{{ item.shortcut }}</span>\n }\n <span class=\"tn-menu-item-arrow\">\u25B6</span>\n </button>\n\n <ng-template #submenuTpl>\n <tn-menu-panel [items]=\"item.children!\" [nested]=\"true\" />\n </ng-template>\n }\n }\n</div>\n", styles: [".tn-menu-container{display:inline-block;position:relative}.tn-menu-container.tn-menu-container--context{display:block;width:100%;height:100%;cursor:context-menu}.tn-menu-trigger{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;transition:all .2s ease}.tn-menu-trigger:hover:not(.disabled){background:var(--tn-bg2, #f5f5f5);border-color:var(--tn-lines, #cccccc)}.tn-menu-trigger:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-menu-trigger.disabled{opacity:.5;cursor:not-allowed}.tn-menu-arrow{font-size:12px;transition:transform .2s ease}.tn-menu-arrow.tn-menu-arrow--up{transform:rotate(180deg)}.tn-menu{display:flex;flex-direction:column;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #e0e0e0);border-radius:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;min-width:160px;max-width:300px;padding:4px 0;z-index:1000}.tn-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 16px;border:none;background:transparent;color:var(--tn-fg1, #333333);cursor:pointer;font-size:14px;text-align:left;transition:background-color .2s ease}.tn-menu-item:hover:not(.disabled){background:var(--tn-alt-bg2, #e8f4fd)!important}.tn-menu-item:focus{outline:none;background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item[aria-selected=true]{background:var(--tn-alt-bg2, #e8f4fd)}.tn-menu-item.tn-menu-item--selected{background:var(--tn-alt-bg2, #e8f4fd);font-weight:600;color:var(--tn-primary, #007bff)}.tn-menu-item.disabled{opacity:.5;cursor:not-allowed}.tn-menu-item.disabled:hover{background:transparent!important}.tn-menu-item-icon{font-size:1rem;width:16px;text-align:center}.tn-menu-item-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tn-menu-item-shortcut{font-size:12px;color:var(--tn-fg2, #666666);margin-left:auto;padding-left:16px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-weight:400;opacity:.7}.tn-menu-item-arrow{font-size:10px;margin-left:8px;color:var(--tn-fg2, #666666);transition:transform .2s ease;flex-shrink:0}.tn-menu-item--nested{position:relative}.tn-menu-item--nested:hover .tn-menu-item-arrow{color:var(--tn-fg1, #333333)}.tn-menu-separator{height:1px;background:var(--tn-lines, #e0e0e0);margin:4px 0}.tn-menu--nested{margin-left:4px;box-shadow:0 8px 24px #00000026,0 4px 8px #0000001a;border-radius:4px}.tn-menu-context-content{width:100%;height:100%}.tn-menu-context-content:hover:before{content:\"\";position:absolute;inset:0;background:rgba(var(--tn-primary-rgb, 0, 123, 255),.05);pointer-events:none;border:1px dashed rgba(var(--tn-primary-rgb, 0, 123, 255),.3);border-radius:4px}\n"] }]
|
|
3550
3561
|
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], projectedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "projectedItems", required: false }] }], nested: [{ type: i0.Input, args: [{ isSignal: true, alias: "nested", required: false }] }] } });
|
|
3551
3562
|
|
|
3552
3563
|
class TnMenuComponent {
|
|
@@ -3554,10 +3565,12 @@ class TnMenuComponent {
|
|
|
3554
3565
|
contextMenu = input(false, ...(ngDevMode ? [{ debugName: "contextMenu" }] : [])); // Enable context menu mode (right-click)
|
|
3555
3566
|
/**
|
|
3556
3567
|
* Semantic base that scopes the test ids of this menu's items. Each item
|
|
3557
|
-
* resolves to `
|
|
3558
|
-
* + item `id="edit"` → `
|
|
3568
|
+
* resolves to `button-${testId}-${item.id}` (e.g. menu `testId="actions"`
|
|
3569
|
+
* + item `id="edit"` → `button-actions-edit`), which keeps ids unique when
|
|
3559
3570
|
* several menus render on one page. Omit it and items fall back to the
|
|
3560
|
-
* unscoped `
|
|
3571
|
+
* unscoped `button-${item.id}`. A per-item `testId` overrides the base and is
|
|
3572
|
+
* composed with the same `button-` prefix (idempotently, so an already
|
|
3573
|
+
* `button-`-prefixed value is not doubled).
|
|
3561
3574
|
*/
|
|
3562
3575
|
testId = input(undefined, ...(ngDevMode ? [{ debugName: "testId" }] : []));
|
|
3563
3576
|
menuItemClick = output();
|