-
Notifications
You must be signed in to change notification settings - Fork 6.8k
feat(cdk-experimental/menu): add ability to open menus from a standalone trigger #20363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
/** Injection token for CloseDecider function. */ | ||
export const CLOSE_DECIDER = new InjectionToken<CloseDecider>('cdk-menu-close-decider'); | ||
|
||
@Injectable({providedIn: 'root'}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should have some documentation, especially since I'm a little unclear whether the client developer will call this directly, or whether it will only be internally invoked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@teflonwaffles done
19b3e57
to
ef73bff
Compare
* out. It is provided alongside the MenuStack to the BackgroundClickService and is called on each | ||
* background click event. | ||
*/ | ||
export type CloseDecider = (target: Element | null) => boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export type CloseDecider = (target: Element | null) => boolean; | |
export type ClosePredicate = (target: Element | null) => boolean; |
https://en.wikipedia.org/wiki/Predicate_(mathematical_logic)
* set of menus is closed out resulting in only having a single set of open menus at any given time. | ||
*/ | ||
@Injectable({providedIn: 'root'}) | ||
export class BackgroundClickService implements OnDestroy { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't totally follow why this service is necessary. Why can't we use the outsidePointerEvents
stream on OverlayRef
for most of this, filtering the stream to the events that we care about for each type of overlay? I tried doing roughly what I had in mind here: jelbourn@584265c
What am I missing with this approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed offline to update the Overlay logic to listen to contextmenu
events (#20373) and to exclude buttons with a cdk-menu-trigger
class in the predicate function.
ef73bff
to
f55bcec
Compare
@jelbourn @teflonwaffles feedback should be addressed however we're still blocked on the issue in #20377 |
const isOpenTrigger = | ||
coerceBooleanProperty(target.getAttribute('aria-expanded')) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const isOpenTrigger = | |
coerceBooleanProperty(target.getAttribute('aria-expanded')) && | |
const isTriggerOpen = target.getAttribute('aria-expanded') === 'true'; |
I would use a direct comparison to 'true'
here since coerceBooleanProperty
will treat the empty string as true
since it's intended to match the behavior of HTML boolean attributes
const isOpenTrigger = | ||
coerceBooleanProperty(target.getAttribute('aria-expanded')) && | ||
target.classList.contains('cdk-menu-trigger'); | ||
const isNoninlineMenu = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const isNoninlineMenu = | |
const isOverlayMenu = |
.outsidePointerEvents() | ||
.pipe(takeUntil(this._stopOutsideClicksListener)) | ||
.subscribe(event => { | ||
if (event.target instanceof Element && !isClickInsideMenuOverlay(event.target)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the instanceof
check necessary because of something that might happen at run-time, or is it just to satisfy typescript that event.target
is an element? If the latter, you can just do isClickInsideMenuOverlay(event.target as Element)
since we know that something has to be an element to receive a click
f55bcec
to
880309d
Compare
@jelbourn feedback should be addressed. |
880309d
to
82bc091
Compare
…one trigger Adds the ability to open a menu from a menu trigger placed outside of a menu or menubar.
82bc091
to
fca424b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
…one trigger (angular#20363) Adds the ability to open a menu from a menu trigger placed outside of a menu or menubar.
…one trigger (angular#20363) Adds the ability to open a menu from a menu trigger placed outside of a menu or menubar.
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Adds the ability to open a menu from a menu trigger placed outside of a menu or menubar.