Skip to content

Commit

Permalink
refactor(menu): remove :has selectors
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 552615347
  • Loading branch information
Elliott Marquez authored and copybara-github committed Jul 31, 2023
1 parent 1fa5cf3 commit fa63178
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 6 deletions.
13 changes: 12 additions & 1 deletion focus/internal/focus-ring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
* SPDX-License-Identifier: Apache-2.0
*/

import {LitElement} from 'lit';
import {LitElement, PropertyValues} from 'lit';
import {property} from 'lit/decorators.js';

import {Attachable, AttachableController} from '../../internal/controller/attachable-controller.js';

/**
* Events that the focus ring listens to.
*
* @fires visibility-changed Fired whenever `visible` changes.
*/
const EVENTS = ['focusin', 'focusout', 'pointerdown'];

Expand Down Expand Up @@ -80,6 +82,15 @@ export class FocusRing extends LitElement implements Attachable {
next?.addEventListener(event, this);
}
}

override update(changed: PropertyValues<this>) {
if (changed.has('visible')) {
// This logic can be removed once the `:has` selector has been introduced
// to Firefox. This is necessary to allow correct submenu styles.
this.dispatchEvent(new Event('visibility-changed'));
}
super.update(changed);
}
}

const HANDLED_BY_FOCUS_RING = Symbol('handledByFocusRing');
Expand Down
10 changes: 9 additions & 1 deletion list/internal/listitem/list-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,17 @@ export class ListItemEl extends LitElement implements ListItem {
* Handles rendering of the focus ring.
*/
protected renderFocusRing(): TemplateResult|typeof nothing {
return html`<md-focus-ring class="focus-ring" part="focus-ring" for="item" inward></md-focus-ring>`;
return html`
<md-focus-ring
@visibility-changed=${this.onFocusRingVisibilityChanged}
class="focus-ring"
part="focus-ring"
for="item"
inward></md-focus-ring>`;
}

protected onFocusRingVisibilityChanged(e: Event) {}

/**
* Classes applied to the list item root.
*/
Expand Down
2 changes: 1 addition & 1 deletion menu/internal/menuitem/_menu-item.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
}

// Set the ripple opacity to 0 if there is a submenu that is hovered.
.list-item:has(.submenu:hover) {
.submenu-hover {
// Have to use ripple theme directly because :has selector in this case does
// not work in this case with the :has selector, thus we cannot override the
// custom props set in :host
Expand Down
2 changes: 1 addition & 1 deletion menu/internal/menuitem/forced-colors-styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

// Show double border only when selected, and the current list item does not
// have a focus ring on it.
:host([selected]) .list-item:not(:has(.focus-ring[visible]))::before {
:host([selected]) .list-item:not(.has-focus-ring)::before {
content: '';
position: absolute;
inset: 0;
Expand Down
17 changes: 16 additions & 1 deletion menu/internal/menuitem/menu-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
* SPDX-License-Identifier: Apache-2.0
*/

import {property} from 'lit/decorators.js';
import {property, state} from 'lit/decorators.js';

import type {MdFocusRing} from '../../../focus/md-focus-ring.js';
import {ListItemEl, ListItemRole} from '../../../list/internal/listitem/list-item.js';
import {CLOSE_REASON, DefaultCloseMenuEvent, isClosableKey, MenuItem} from '../shared.js';

Expand All @@ -26,6 +27,8 @@ export class MenuItemEl extends ListItemEl implements MenuItem {
*/
@property({type: Boolean, attribute: 'keep-open'}) keepOpen = false;

@state() protected hasFocusRing = false;

/**
* Used for overriding e.g. sub-menu-item.
*/
Expand All @@ -40,6 +43,18 @@ export class MenuItemEl extends ListItemEl implements MenuItem {
new DefaultCloseMenuEvent(this, {kind: CLOSE_REASON.CLICK_SELECTION}));
}

protected override getRenderClasses() {
return {
...super.getRenderClasses(),
'has-focus-ring': this.hasFocusRing,
};
}

protected override onFocusRingVisibilityChanged(e: Event) {
const focusRing = e.target as MdFocusRing;
this.hasFocusRing = focusRing.visible;
}

protected override onKeydown(event: KeyboardEvent) {
if (this.keepOpen) return;
const keyCode = event.code;
Expand Down
18 changes: 17 additions & 1 deletion menu/internal/submenuitem/sub-menu-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import {html} from 'lit';
import {property, queryAssignedElements} from 'lit/decorators.js';
import {property, queryAssignedElements, state} from 'lit/decorators.js';

import {List} from '../../../list/internal/list.js';
import {Corner, Menu} from '../menu.js';
Expand Down Expand Up @@ -53,6 +53,8 @@ export class SubMenuItem extends MenuItemEl {
*/
@property({type: Boolean, reflect: true}) selected = false;

@state() protected submenuHover = false;

@queryAssignedElements({slot: 'submenu', flatten: true})
private readonly menus!: Menu[];

Expand Down Expand Up @@ -105,6 +107,10 @@ export class SubMenuItem extends MenuItemEl {
this.show();
}

protected override getRenderClasses() {
return {...super.getRenderClasses(), 'submenu-hover': this.submenuHover};
}

/**
* On item keydown handles opening the submenu.
*/
Expand Down Expand Up @@ -149,6 +155,8 @@ export class SubMenuItem extends MenuItemEl {
private renderSubMenu() {
return html`<span class="submenu"><slot
name="submenu"
@pointerenter=${this.onSubmenuPointerEnter}
@pointerleave=${this.onSubmenuPointerLeave}
@pointerdown=${stopPropagation}
@click=${stopPropagation}
@keydown=${this.onSubMenuKeydown}
Expand Down Expand Up @@ -298,4 +306,12 @@ export class SubMenuItem extends MenuItemEl {
return false;
}
}

private onSubmenuPointerEnter() {
this.submenuHover = true;
}

private onSubmenuPointerLeave() {
this.submenuHover = false;
}
}

0 comments on commit fa63178

Please sign in to comment.