refactor(menu)!: rename corner and focus state values lowercase with dashes

BREAKING: for style guide enum consistency, we have renamed the corner values START_START etc. to be lowercase with dashes. e.g. start-start. The same has been done with MdMenu.defaultFocus' values.
PiperOrigin-RevId: 566454879
This commit is contained in:
Elliott Marquez 2023-09-18 17:07:44 -07:00 committed by Copybara-Service
parent ff3073a280
commit 6e54048f1e
10 changed files with 91 additions and 67 deletions

View File

@ -60,8 +60,8 @@ import {materialDesign} from '../svg/material-design-logo.js';
>
<md-menu
anchor="theme-button"
menu-corner="START_END"
anchor-corner="END_END"
menu-corner="start-end"
anchor-corner="end-end"
stay-open-on-focusout
.open=${this.menuOpen}
@closed=${this.onMenuClosed}

View File

@ -11,7 +11,7 @@
<md-menu slot="submenu">
<md-menu-item headline="Apricot"></md-menu-item>
<md-menu-item headline="Avocado"></md-menu-item>
<md-sub-menu-item headline="Apples" menu-corner="START_END" anchor-corner="START_START">
<md-sub-menu-item headline="Apples" menu-corner="start-end" anchor-corner="start-start">
<md-menu slot="submenu">
<md-menu-item headline="Fuji"></md-menu-item>
<md-menu-item headline="Granny Smith"></md-menu-item>

View File

@ -152,8 +152,8 @@ Granny Smith, and Red Delicious."](images/menu/usage-submenu.webp)
<!-- Nest as many as you want and control menu anchoring -->
<md-sub-menu-item
headline="Apples"
menu-corner="START_END"
anchor-corner="START_START">
menu-corner="start-end"
anchor-corner="start-start">
<md-menu slot="submenu">
<md-menu-item headline="Fuji"></md-menu-item>
<md-menu-item headline="Granny Smith"></md-menu-item>

View File

@ -8,7 +8,7 @@ import './index.js';
import './material-collection.js';
import {KnobTypesToKnobs, MaterialCollection, materialInitsToStoryInits, setUpDemo, title} from './material-collection.js';
import {Corner, DefaultFocusState} from '@material/web/menu/menu.js';
import {Corner, FocusState} from '@material/web/menu/menu.js';
import {boolInput, Knob, numberInput, selectDropdown, textInput} from './index.js';
import {stories, StoryKnobs} from './stories.js';
@ -17,35 +17,35 @@ const collection =
new MaterialCollection<KnobTypesToKnobs<StoryKnobs>>('Menu', [
new Knob('menu', {ui: title()}),
new Knob('anchorCorner', {
defaultValue: 'END_START' as Corner,
defaultValue: Corner.END_START as Corner,
ui: selectDropdown<Corner>({
options: [
{label: 'START_START', value: 'START_START'},
{label: 'START_END', value: 'START_END'},
{label: 'END_START', value: 'END_START'},
{label: 'END_END', value: 'END_END'},
{label: Corner.START_START, value: Corner.START_START},
{label: Corner.START_END, value: Corner.START_END},
{label: Corner.END_START, value: Corner.END_START},
{label: Corner.END_END, value: Corner.END_END},
]
}),
}),
new Knob('menuCorner', {
defaultValue: 'START_START' as Corner,
defaultValue: Corner.START_START as Corner,
ui: selectDropdown<Corner>({
options: [
{label: 'START_START', value: 'START_START'},
{label: 'START_END', value: 'START_END'},
{label: 'END_START', value: 'END_START'},
{label: 'END_END', value: 'END_END'},
{label: Corner.START_START, value: Corner.START_START},
{label: Corner.START_END, value: Corner.START_END},
{label: Corner.END_START, value: Corner.END_START},
{label: Corner.END_END, value: Corner.END_END},
]
}),
}),
new Knob('defaultFocus', {
defaultValue: 'FIRST_ITEM' as const,
ui: selectDropdown<DefaultFocusState>({
defaultValue: FocusState.FIRST_ITEM as FocusState,
ui: selectDropdown<FocusState>({
options: [
{label: 'FIRST_ITEM', value: 'FIRST_ITEM'},
{label: 'LAST_ITEM', value: 'LAST_ITEM'},
{label: 'LIST_ROOT', value: 'LIST_ROOT'},
{label: 'NONE', value: 'NONE'},
{label: FocusState.FIRST_ITEM, value: FocusState.FIRST_ITEM},
{label: FocusState.LAST_ITEM, value: FocusState.LAST_ITEM},
{label: FocusState.LIST_ROOT, value: FocusState.LIST_ROOT},
{label: FocusState.NONE, value: FocusState.NONE},
]
}),
}),
@ -125,24 +125,24 @@ const collection =
// sub-menu-item knobs
new Knob('sub-menu-item', {ui: title()}),
new Knob('submenu.anchorCorner', {
defaultValue: 'START_END' as Corner,
defaultValue: Corner.START_END as Corner,
ui: selectDropdown<Corner>({
options: [
{label: 'START_START', value: 'START_START'},
{label: 'START_END', value: 'START_END'},
{label: 'END_START', value: 'END_START'},
{label: 'END_END', value: 'END_END'},
{label: Corner.START_START, value: Corner.START_START},
{label: Corner.START_END, value: Corner.START_END},
{label: Corner.END_START, value: Corner.END_START},
{label: Corner.END_END, value: Corner.END_END},
]
}),
}),
new Knob('submenu.menuCorner', {
defaultValue: 'START_START' as Corner,
defaultValue: Corner.START_START as Corner,
ui: selectDropdown<Corner>({
options: [
{label: 'START_START', value: 'START_START'},
{label: 'START_END', value: 'START_END'},
{label: 'END_START', value: 'END_START'},
{label: 'END_END', value: 'END_END'},
{label: Corner.START_START, value: Corner.START_START},
{label: Corner.START_END, value: Corner.START_END},
{label: Corner.END_START, value: Corner.END_START},
{label: Corner.END_END, value: Corner.END_END},
]
}),
}),

View File

@ -14,7 +14,7 @@ import '@material/web/icon/icon.js';
import {MaterialStoryInit} from './material-collection.js';
import {CloseMenuEvent} from '@material/web/menu/internal/shared.js';
import {Corner, DefaultFocusState, MdMenu, MenuItem} from '@material/web/menu/menu.js';
import {Corner, FocusState, MdMenu, MenuItem} from '@material/web/menu/menu.js';
import {css, html} from 'lit';
/** Knob types for Menu stories. */
@ -22,7 +22,7 @@ export interface StoryKnobs {
menu: void;
anchorCorner: Corner|undefined;
menuCorner: Corner|undefined;
defaultFocus: DefaultFocusState|undefined;
defaultFocus: FocusState|undefined;
open: boolean;
fixed: boolean;
quick: boolean;

View File

@ -32,7 +32,18 @@ export const DEFAULT_TYPEAHEAD_BUFFER_TIME = 200;
/**
* Element to focus on when menu is first opened.
*/
export type DefaultFocusState = 'NONE'|'LIST_ROOT'|'FIRST_ITEM'|'LAST_ITEM';
// tslint:disable-next-line:enforce-name-casing We are mimicking enum style
export const FocusState = {
NONE: 'none',
LIST_ROOT: 'list-root',
FIRST_ITEM: 'first-item',
LAST_ITEM: 'last-item'
} as const;
/**
* Element to focus on when menu is first opened.
*/
export type FocusState = typeof FocusState[keyof typeof FocusState];
/**
* Gets the currently focused element on the page.
@ -143,7 +154,8 @@ export abstract class Menu extends LitElement {
* NOTE: This value may not be respected by the menu positioning algorithm
* if the menu would render outisde the viewport.
*/
@property({attribute: 'anchor-corner'}) anchorCorner: Corner = 'END_START';
@property({attribute: 'anchor-corner'})
anchorCorner: Corner = Corner.END_START;
/**
* The corner of the menu which to align the anchor in the standard logical
* property style of <block>_<inline>.
@ -151,7 +163,7 @@ export abstract class Menu extends LitElement {
* NOTE: This value may not be respected by the menu positioning algorithm
* if the menu would render outisde the viewport.
*/
@property({attribute: 'menu-corner'}) menuCorner: Corner = 'START_START';
@property({attribute: 'menu-corner'}) menuCorner: Corner = Corner.START_START;
/**
* Keeps the user clicks outside the menu.
*
@ -181,7 +193,7 @@ export abstract class Menu extends LitElement {
* `list-tabindex` to `0` when necessary.
*/
@property({attribute: 'default-focus'})
defaultFocus: DefaultFocusState = 'FIRST_ITEM';
defaultFocus: FocusState = FocusState.FIRST_ITEM;
@state() private typeaheadActive = true;
@ -398,7 +410,7 @@ export abstract class Menu extends LitElement {
const items = this.listElement.items;
const activeItemRecord = List.getActiveItem(items);
if (activeItemRecord && this.defaultFocus !== 'NONE') {
if (activeItemRecord && this.defaultFocus !== FocusState.NONE) {
activeItemRecord.item.tabIndex = -1;
}
@ -414,7 +426,7 @@ export abstract class Menu extends LitElement {
// the items before the animation has begun and causes the list to slide
// (block-padding-of-the-menu)px at the end of the animation
switch (this.defaultFocus) {
case 'FIRST_ITEM':
case FocusState.FIRST_ITEM:
const first = List.getFirstActivatableItem(items);
if (first) {
first.tabIndex = 0;
@ -422,7 +434,7 @@ export abstract class Menu extends LitElement {
await (first as LitElement & MenuItem).updateComplete;
}
break;
case 'LAST_ITEM':
case FocusState.LAST_ITEM:
const last = List.getLastActivatableItem(items);
if (last) {
last.tabIndex = 0;
@ -430,11 +442,11 @@ export abstract class Menu extends LitElement {
await (last as LitElement & MenuItem).updateComplete;
}
break;
case 'LIST_ROOT':
case FocusState.LIST_ROOT:
this.listElement?.focus();
break;
default:
case 'NONE':
case FocusState.NONE:
// Do nothing.
break;
}

View File

@ -28,11 +28,12 @@ export class SubMenuItem extends MenuItemEl {
/**
* The anchorCorner to set on the submenu.
*/
@property({attribute: 'anchor-corner'}) anchorCorner: Corner = 'START_END';
@property({attribute: 'anchor-corner'})
anchorCorner: Corner = Corner.START_END;
/**
* The menuCorner to set on the submenu.
*/
@property({attribute: 'menu-corner'}) menuCorner: Corner = 'START_START';
@property({attribute: 'menu-corner'}) menuCorner: Corner = Corner.START_START;
/**
* The delay between mouseenter and submenu opening.
*/
@ -267,7 +268,7 @@ export class SubMenuItem extends MenuItemEl {
// We manually set focus with `active` on keyboard navigation. And we
// want to focus the root on hover, so the user can pick up navigation with
// keyboard after hover.
menu.defaultFocus = 'LIST_ROOT';
menu.defaultFocus = 'list-root';
// This is required in the case where we have a leaf menu open and and the
// user hovers a parent menu's item which is not an md-sub-menu item.
// If this were set to true, then the menu would close and focus would be

View File

@ -7,10 +7,21 @@
import {ReactiveController, ReactiveControllerHost} from 'lit';
import {StyleInfo} from 'lit/directives/style-map.js';
/**
* An enum of supported Menu corners
*/
// tslint:disable-next-line:enforce-name-casing We are mimicking enum style
export const Corner = {
END_START: 'end-start',
END_END: 'end-end',
START_START: 'start-start',
START_END: 'start-end',
} as const;
/**
* A corner of a box in the standard logical property style of <block>_<inline>
*/
export type Corner = 'END_START'|'END_END'|'START_START'|'START_END';
export type Corner = typeof Corner[keyof typeof Corner];
/**
* An interface that provides a method to customize the rect from which to
@ -147,8 +158,8 @@ export class SurfacePositionController implements ReactiveController {
yOffset,
repositionStrategy,
} = this.getProperties();
const anchorCorner = anchorCornerRaw.toUpperCase().trim();
const surfaceCorner = surfaceCornerRaw.toUpperCase().trim();
const anchorCorner = anchorCornerRaw.toLowerCase().trim();
const surfaceCorner = surfaceCornerRaw.toLowerCase().trim();
if (!surfaceEl || !anchorEl) {
return;
@ -172,9 +183,9 @@ export class SurfacePositionController implements ReactiveController {
anchorEl.getSurfacePositionClientRect() :
anchorEl.getBoundingClientRect();
const [surfaceBlock, surfaceInline] =
surfaceCorner.split('_') as Array<'START'|'END'>;
surfaceCorner.split('-') as Array<'start'|'end'>;
const [anchorBlock, anchorInline] =
anchorCorner.split('_') as Array<'START'|'END'>;
anchorCorner.split('-') as Array<'start'|'end'>;
// LTR depends on the direction of the SURFACE not the anchor.
const isLTR =
@ -226,8 +237,8 @@ export class SurfacePositionController implements ReactiveController {
// If the surface should be out of bounds in the block direction, flip the
// surface and anchor corner block values and recalculate
if (blockOutOfBoundsCorrection) {
const flippedSurfaceBlock = surfaceBlock === 'START' ? 'END' : 'START';
const flippedAnchorBlock = anchorBlock === 'START' ? 'END' : 'START';
const flippedSurfaceBlock = surfaceBlock === 'start' ? 'end' : 'start';
const flippedAnchorBlock = anchorBlock === 'start' ? 'end' : 'start';
const flippedBlock = this.calculateBlock({
surfaceRect,
@ -263,8 +274,8 @@ export class SurfacePositionController implements ReactiveController {
// If the surface should be out of bounds in the inline direction, flip the
// surface and anchor corner inline values and recalculate
if (inlineOutOfBoundsCorrection) {
const flippedSurfaceInline = surfaceInline === 'START' ? 'END' : 'START';
const flippedAnchorInline = anchorInline === 'START' ? 'END' : 'START';
const flippedSurfaceInline = surfaceInline === 'start' ? 'end' : 'start';
const flippedAnchorInline = anchorInline === 'start' ? 'end' : 'start';
const flippedInline = this.calculateInline({
surfaceRect,
@ -326,8 +337,8 @@ export class SurfacePositionController implements ReactiveController {
private calculateBlock(config: {
surfaceRect: DOMRect,
anchorRect: DOMRect,
anchorBlock: 'START'|'END',
surfaceBlock: 'START'|'END',
anchorBlock: 'start'|'end',
surfaceBlock: 'start'|'end',
yOffset: number,
isTopLayer: boolean,
}) {
@ -342,8 +353,8 @@ export class SurfacePositionController implements ReactiveController {
// We use number booleans to multiply values rather than `if` / ternary
// statements because it _heavily_ cuts down on nesting and readability
const isTopLayer = isTopLayerBool ? 1 : 0;
const isSurfaceBlockStart = surfaceBlock === 'START' ? 1 : 0;
const isSurfaceBlockEnd = surfaceBlock === 'END' ? 1 : 0;
const isSurfaceBlockStart = surfaceBlock === 'start' ? 1 : 0;
const isSurfaceBlockEnd = surfaceBlock === 'end' ? 1 : 0;
const isOneBlockEnd = anchorBlock !== surfaceBlock ? 1 : 0;
// Whether or not to apply the height of the anchor
@ -363,7 +374,7 @@ export class SurfacePositionController implements ReactiveController {
const blockInset = isTopLayer * blockTopLayerOffset + blockAnchorOffset;
const surfaceBlockProperty =
surfaceBlock === 'START' ? 'inset-block-start' : 'inset-block-end';
surfaceBlock === 'start' ? 'inset-block-start' : 'inset-block-end';
return {blockInset, blockOutOfBoundsCorrection, surfaceBlockProperty};
}
@ -374,8 +385,8 @@ export class SurfacePositionController implements ReactiveController {
*/
private calculateInline(config: {
isLTR: boolean,
surfaceInline: 'START'|'END',
anchorInline: 'START'|'END',
surfaceInline: 'start'|'end',
anchorInline: 'start'|'end',
anchorRect: DOMRect,
surfaceRect: DOMRect,
xOffset: number,
@ -395,8 +406,8 @@ export class SurfacePositionController implements ReactiveController {
const isTopLayer = isTopLayerBool ? 1 : 0;
const isLTR = isLTRBool ? 1 : 0;
const isRTL = isLTRBool ? 0 : 1;
const isSurfaceInlineStart = surfaceInline === 'START' ? 1 : 0;
const isSurfaceInlineEnd = surfaceInline === 'END' ? 1 : 0;
const isSurfaceInlineStart = surfaceInline === 'start' ? 1 : 0;
const isSurfaceInlineEnd = surfaceInline === 'end' ? 1 : 0;
const isOneInlineEnd = anchorInline !== surfaceInline ? 1 : 0;
// Whether or not to apply the width of the anchor
@ -424,7 +435,7 @@ export class SurfacePositionController implements ReactiveController {
const inlineInset = isTopLayer * inlineTopLayerOffset + inlineAnchorOffset;
const surfaceInlineProperty =
surfaceInline === 'START' ? 'inset-inline-start' : 'inset-inline-end';
surfaceInline === 'start' ? 'inset-inline-start' : 'inset-inline-end';
return {
inlineInset,

View File

@ -11,7 +11,7 @@ import {Menu} from './internal/menu.js';
import {styles} from './internal/menu-styles.css.js';
export {ListItem} from '../list/internal/listitem/list-item.js';
export {Corner, DefaultFocusState} from './internal/menu.js';
export {Corner, FocusState} from './internal/menu.js';
export {CloseMenuEvent, MenuItem} from './internal/shared.js';
declare global {

View File

@ -467,7 +467,7 @@ export abstract class Select extends LitElement {
return html`
<md-menu
id="listbox"
default-focus="NONE"
default-focus="none"
list-tabindex="-1"
type="listbox"
stay-open-on-focusout