From 290548376a4c2c2c34887f7de0d04c7b239b15b0 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Wed, 3 Dec 2025 14:28:12 +0100 Subject: [PATCH] fix(cdk/menu): allow user to pass selector for transform origin Adds an input that allows users to specify which element the CDK overlay will set the transform origin on. This is useful when animating the menus. Fixes #32439. --- goldens/cdk/menu/index.api.md | 5 +++-- src/cdk/menu/context-menu-trigger.ts | 9 ++++++++- src/cdk/menu/menu-trigger-base.ts | 6 ++++++ src/cdk/menu/menu-trigger.ts | 9 ++++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/goldens/cdk/menu/index.api.md b/goldens/cdk/menu/index.api.md index 27be93023ab9..318e551c75c2 100644 --- a/goldens/cdk/menu/index.api.md +++ b/goldens/cdk/menu/index.api.md @@ -46,7 +46,7 @@ export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestr open(coordinates: ContextMenuCoordinates): void; _openOnContextMenu(event: MouseEvent): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -224,7 +224,7 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD toggle(): void; _toggleOnKeydown(event: KeyboardEvent): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -250,6 +250,7 @@ export abstract class CdkMenuTriggerBase implements OnDestroy { protected overlayRef: OverlayRef | null; registerChildMenu(child: Menu): void; protected readonly stopOutsideClicksListener: rxjs.Observable; + transformOriginSelector: string | null; protected readonly viewContainerRef: ViewContainerRef; // (undocumented) static ɵdir: i0.ɵɵDirectiveDeclaration; diff --git a/src/cdk/menu/context-menu-trigger.ts b/src/cdk/menu/context-menu-trigger.ts index bf1b5a86ea67..bc6cac4f2798 100644 --- a/src/cdk/menu/context-menu-trigger.ts +++ b/src/cdk/menu/context-menu-trigger.ts @@ -62,6 +62,7 @@ export type ContextMenuCoordinates = {x: number; y: number}; {name: 'menuTemplateRef', alias: 'cdkContextMenuTriggerFor'}, {name: 'menuPosition', alias: 'cdkContextMenuPosition'}, {name: 'menuData', alias: 'cdkContextMenuTriggerData'}, + {name: 'transformOriginSelector', alias: 'cdkContextMenuTriggerTransformOriginOn'}, ], outputs: ['opened: cdkContextMenuOpened', 'closed: cdkContextMenuClosed'], providers: [ @@ -147,10 +148,16 @@ export class CdkContextMenuTrigger extends CdkMenuTriggerBase implements OnDestr private _getOverlayPositionStrategy( coordinates: ContextMenuCoordinates, ): FlexibleConnectedPositionStrategy { - return createFlexibleConnectedPositionStrategy(this._injector, coordinates) + const strategy = createFlexibleConnectedPositionStrategy(this._injector, coordinates) .withLockedPosition() .withGrowAfterOpen() .withPositions(this.menuPosition ?? CONTEXT_MENU_POSITIONS); + + if (this.transformOriginSelector) { + strategy.withTransformOriginOn(this.transformOriginSelector); + } + + return strategy; } /** Subscribe to the menu stack close events and close this menu when requested. */ diff --git a/src/cdk/menu/menu-trigger-base.ts b/src/cdk/menu/menu-trigger-base.ts index 7656603cc00a..e5addfc550d6 100644 --- a/src/cdk/menu/menu-trigger-base.ts +++ b/src/cdk/menu/menu-trigger-base.ts @@ -102,6 +102,12 @@ export abstract class CdkMenuTriggerBase implements OnDestroy { /** Context data to be passed along to the menu template */ menuData: unknown; + /** + * Selector for the element on which to set the transform origin once the menu is open. + * This makes it easier to implement animations that start from the attachment point of the menu. + */ + transformOriginSelector: string | null = null; + /** Close the opened menu. */ abstract close(): void; diff --git a/src/cdk/menu/menu-trigger.ts b/src/cdk/menu/menu-trigger.ts index d37ab81a4205..3b4d5b48dee3 100644 --- a/src/cdk/menu/menu-trigger.ts +++ b/src/cdk/menu/menu-trigger.ts @@ -69,6 +69,7 @@ import {eventDispatchesNativeClick} from './event-detection'; {name: 'menuTemplateRef', alias: 'cdkMenuTriggerFor'}, {name: 'menuPosition', alias: 'cdkMenuPosition'}, {name: 'menuData', alias: 'cdkMenuTriggerData'}, + {name: 'transformOriginSelector', alias: 'cdkMenuTriggerTransformOriginOn'}, ], outputs: ['opened: cdkMenuOpened', 'closed: cdkMenuClosed'], providers: [ @@ -281,10 +282,16 @@ export class CdkMenuTrigger extends CdkMenuTriggerBase implements OnChanges, OnD /** Build the position strategy for the overlay which specifies where to place the menu. */ private _getOverlayPositionStrategy(): FlexibleConnectedPositionStrategy { - return createFlexibleConnectedPositionStrategy(this._injector, this._elementRef) + const strategy = createFlexibleConnectedPositionStrategy(this._injector, this._elementRef) .withLockedPosition() .withFlexibleDimensions(false) .withPositions(this._getOverlayPositions()); + + if (this.transformOriginSelector) { + strategy.withTransformOriginOn(this.transformOriginSelector); + } + + return strategy; } /** Get the preferred positions for the opened menu relative to the menu item. */