mirror of
https://github.com/material-components/material-web.git
synced 2026-01-09 07:21:09 +08:00
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:
parent
ff3073a280
commit
6e54048f1e
@ -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}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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},
|
||||
]
|
||||
}),
|
||||
}),
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user