Skip to content
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

refactor(web-components): refactor menu to popover #31674

Merged
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ef8ab6a
wip: refactor menu to popover
davatron5000 Jun 11, 2024
75aa28e
refactor menu-list and menu-item
davatron5000 Jun 14, 2024
1c558c1
refactor menu item template and styles
davatron5000 Jun 17, 2024
0281d02
add changefile
davatron5000 Jun 17, 2024
4bad9b6
refactor indent function to move reduce outside of forEach
davatron5000 Jun 18, 2024
8e44984
rm floating-ui from package.json
davatron5000 Jun 18, 2024
d3251e4
prevent popover from throwing
davatron5000 Jun 18, 2024
4842974
handle contextmenu event
davatron5000 Jun 19, 2024
9011279
doc fixes
davatron5000 Jun 19, 2024
1706463
fix focus-visible styles in safari
davatron5000 Jun 19, 2024
7f60ef1
rm floating-ui from tensile config
davatron5000 Jun 19, 2024
6961b1b
fix formatting
davatron5000 Jun 19, 2024
27c31d1
flatten menu-item template
davatron5000 Jun 19, 2024
8d6c44b
add docs for max-height css property
davatron5000 Jun 20, 2024
77fa151
reorganize menu-item styles and fix forced-colors bug
davatron5000 Jun 20, 2024
382ff3a
fix focus and tabindex bugs
davatron5000 Jun 21, 2024
bf4684d
improve positioning on viewport collision with better fallbacks
davatron5000 Jun 21, 2024
38adb86
update api report
davatron5000 Jun 21, 2024
3d988bf
Update packages/web-components/src/menu-item/menu-item.ts
davatron5000 Jun 21, 2024
576edf7
Update packages/web-components/src/menu-item/menu-item.ts
davatron5000 Jun 21, 2024
1955ed1
fix nits, improve stories
davatron5000 Jun 21, 2024
cf8b66a
fix forced-colors disabled state
davatron5000 Jun 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Refactor Menu, MenuList, and MenuItem components",
"packageName": "@fluentui/web-components",
"email": "rupertdavid@microsoft.com",
"dependentChangeType": "patch"
}
36 changes: 8 additions & 28 deletions packages/web-components/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -2290,35 +2290,27 @@ export type MediaQueryListListener = (this: MediaQueryList, ev?: MediaQueryListE

// @public
export class Menu extends FASTElement {
cleanup?: () => void;
closeMenu: () => void;
closeOnScroll?: boolean;
closeOnScrollChanged(oldValue: boolean, newValue: boolean): void;
connectedCallback(): void;
disconnectedCallback(): void;
focusMenuList(): void;
focusTrigger(): void;
handleMenuKeydown(e: KeyboardEvent): boolean | void;
handleTriggerKeydown: (e: KeyboardEvent) => boolean | void;
open: boolean;
openChanged(oldValue: boolean, newValue: boolean): void;
menuKeydownHandler(e: KeyboardEvent): boolean | void;
openMenu: (e?: Event) => void;
openOnContext?: boolean;
openOnContextChanged(oldValue: boolean, newValue: boolean): void;
openOnHover?: boolean;
openOnHoverChanged(oldValue: boolean, newValue: boolean): void;
persistOnItemClick?: boolean;
persistOnItemClickChanged(oldValue: boolean, newValue: boolean): void;
// @internal
positioningContainer?: HTMLElement;
setComponent(): void;
// @internal
protected setPositioning(): void;
// @internal
protected setPositioningTask: () => void;
slottedMenuList: MenuList[];
slottedTriggers: HTMLElement[];
toggleHandler: (e: Event | ToggleEvent) => void;
toggleMenu: () => void;
triggerKeydownHandler: (e: KeyboardEvent) => boolean | void;
}

// @public
Expand Down Expand Up @@ -2373,36 +2365,27 @@ export class MenuItem extends FASTElement {
checked: boolean;
// (undocumented)
protected checkedChanged(oldValue: boolean, newValue: boolean): void;
cleanup: () => void;
disabled: boolean;
// @internal (undocumented)
disconnectedCallback(): void;
expanded: boolean;
// (undocumented)
protected expandedChanged(prev: boolean | undefined, next: boolean): void;
// @internal (undocumented)
handleMenuItemClick: (e: MouseEvent) => boolean;
// @internal (undocumented)
handleMenuItemKeyDown: (e: KeyboardEvent) => boolean;
// @internal (undocumented)
handleMouseOut: (e: MouseEvent) => boolean;
// @internal (undocumented)
handleMouseOver: (e: MouseEvent) => boolean;
// @internal (undocumented)
get hasSubmenu(): boolean;
hidden: boolean;
role: MenuItemRole;
// @internal
setSubmenuPosition: () => void;
// @internal
slottedSubmenu: HTMLElement[];
// @internal
protected slottedSubmenuChanged(prev: HTMLElement[] | undefined, next: HTMLElement[]): void;
// @internal (undocumented)
submenu: HTMLElement | undefined;
// @internal
submenuContainer: HTMLDivElement;
// @internal (undocumented)
submenuLoaded: () => void;
updateSubmenu(): void;
toggleHandler: (e: ToggleEvent | Event) => void;
}

// @internal
Expand All @@ -2419,9 +2402,8 @@ export const MenuItemDefinition: FASTElementDefinition<typeof MenuItem>;

// @public
export type MenuItemOptions = StartEndOptions<MenuItem> & {
checkboxIndicator?: StaticallyComposableHTML<MenuItem>;
expandCollapseGlyph?: StaticallyComposableHTML<MenuItem>;
radioIndicator?: StaticallyComposableHTML<MenuItem>;
indicator?: StaticallyComposableHTML<MenuItem>;
submenuGlyph?: StaticallyComposableHTML<MenuItem>;
};

// @public
Expand All @@ -2444,13 +2426,11 @@ export const MenuItemTemplate: ElementViewTemplate<MenuItem>;

// @public
export class MenuList extends FASTElement {
collapseExpandedItem(): void;
// @internal (undocumented)
connectedCallback(): void;
// @internal (undocumented)
disconnectedCallback(): void;
focus(): void;
// (undocumented)
handleChange(source: any, propertyName: string): void;
// @internal
handleFocusOut: (e: FocusEvent) => void;
Expand Down
1 change: 0 additions & 1 deletion packages/web-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@
},
"dependencies": {
"@microsoft/fast-web-utilities": "^6.0.0",
"@floating-ui/dom": "^1.2.0",
"@fluentui/tokens": "1.0.0-alpha.16",
"tabbable": "^6.2.0",
"tslib": "^2.1.0"
Expand Down
193 changes: 79 additions & 114 deletions packages/web-components/src/menu-item/menu-item.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import {
colorNeutralForeground2Pressed,
colorNeutralForeground3,
colorNeutralForegroundDisabled,
colorStrokeFocus2,
fontFamilyBase,
fontSizeBase200,
fontSizeBase300,
fontSizeBase500,
fontWeightRegular,
lineHeightBase200,
lineHeightBase300,
Expand All @@ -29,76 +29,25 @@ export const styles = css`
${display('grid')}

:host {
grid-template-columns: 20px 20px auto 20px;
--indent: 0;
align-items: center;
grid-gap: 4px;
height: 32px;
background: ${colorNeutralBackground1};
font: ${fontWeightRegular} ${fontSizeBase300} / ${lineHeightBase300} ${fontFamilyBase};
border-radius: ${borderRadiusMedium};
color: ${colorNeutralForeground2};
padding: 0 10px;
contain: layout;
cursor: pointer;
/* Prevent shrinking of MenuItems when max-height is applied to MenuList */
flex-shrink: 0;
font: ${fontWeightRegular} ${fontSizeBase300} / ${lineHeightBase300} ${fontFamilyBase};
grid-gap: 4px;
grid-template-columns: 20px 20px auto 20px;
height: 32px;
overflow: visible;
contain: layout;
padding: 0 10px;
}

:host(:hover) {
background: ${colorNeutralBackground1Hover};
}

.content {
white-space: nowrap;
flex-grow: 1;
grid-column: auto / span 2;
padding: 0 2px;
}

.checkbox,
.radio {
display: none;
}

.input-container,
.expand-collapse-glyph-container,
::slotted([slot='start']),
::slotted([slot='end']),
:host([checked]) .checkbox,
:host([checked]) .radio {
display: inline-flex;
justify-content: center;
align-items: center;
color: ${colorNeutralForeground2};
}

.expand-collapse-glyph-container,
::slotted([slot='start']),
::slotted([slot='end']) {
height: 32px;
font-size: ${fontSizeBase500};
width: fit-content;
}

.input-container {
width: 20px;
}

::slotted([slot='end']) {
color: ${colorNeutralForeground3};
font: ${fontWeightRegular} ${fontSizeBase200} / ${lineHeightBase200} ${fontFamilyBase};
white-space: nowrap;
grid-column: 4 / span 1;
justify-self: flex-end;
}

.expand-collapse-glyph-container {
grid-column: 4 / span 1;
justify-self: flex-end;
}

:host(:hover) .input-container,
:host(:hover) .expand-collapse-glyph-container,
:host(:hover) .content {
color: ${colorNeutralForeground2Hover};
}

Expand All @@ -108,11 +57,6 @@ export const styles = css`

:host(:active) {
background-color: ${colorNeutralBackground1Selected};
}

:host(:active) .input-container,
:host(:active) .expand-collapse-glyph-container,
:host(:active) .content {
color: ${colorNeutralForeground2Pressed};
}

Expand All @@ -122,67 +66,47 @@ export const styles = css`

:host([disabled]) {
background-color: ${colorNeutralBackgroundDisabled};
}

:host([disabled]) .content,
:host([disabled]) .expand-collapse-glyph-container,
:host([disabled]) ::slotted([slot='end']),
:host([disabled]) ::slotted([slot='start']) {
color: ${colorNeutralForegroundDisabled};
}

:host([data-indent]) {
display: grid;
}

:host([data-indent='1']) .content {
grid-column: 2 / span 1;
}

:host([data-indent='1'][role='menuitemcheckbox']) {
display: grid;
:host([disabled]) ::slotted([slot='end']) {
color: ${colorNeutralForegroundDisabled};
}

:host([data-indent='2'][aria-haspopup='menu']) ::slotted([slot='end']) {
grid-column: 4 / span 1;
:host(:focus-visible) {
border-radius: ${borderRadiusMedium};
outline: 2px solid ${colorStrokeFocus2};
}

:host([data-indent='2'][aria-haspopup='menu']) .expand-collapse-glyph-container {
grid-column: 5 / span 1;
.content {
white-space: nowrap;
flex-grow: 1;
grid-column: auto / span 2;
padding: 0 2px;
}

:host([data-indent='1']) .content {
grid-column: 2 / span 1;
:host(:not([checked])) .indicator,
:host(:not([checked])) ::slotted([slot='indicator']),
:host(:not([aria-haspopup='menu'])) .submenu-glyph,
:host(:not([aria-haspopup='menu'])) ::slotted([slot='submenu-glyph']) {
display: none;
}

:host([data-indent='1'][role='menuitemcheckbox']) .content,
:host([data-indent='1'][role='menuitemradio']) .content {
grid-column: auto / span 1;
::slotted([slot='end']) {
color: ${colorNeutralForeground3};
font: ${fontWeightRegular} ${fontSizeBase200} / ${lineHeightBase200} ${fontFamilyBase};
white-space: nowrap;
}

:host([icon]) ::slotted([slot='end']),
:host([data-indent='1']) ::slotted([slot='end']) {
grid-column: 4 / span 1;
justify-self: flex-end;
:host([data-indent='1']) {
--indent: 1;
}

:host([data-indent='2']) {
display: grid;
--indent: 2;
grid-template-columns: 20px 20px auto auto;
}

:host([data-indent='2']) .content {
grid-column: 3 / span 1;
}

:host([data-indent='2']) .input-container {
grid-column: 1 / span 1;
}

:host([data-indent='2']) ::slotted([slot='start']) {
grid-column: 2 / span 1;
}

:host([aria-haspopup='menu']) {
grid-template-columns: 20px auto auto 20px;
}
Expand All @@ -191,13 +115,54 @@ export const styles = css`
grid-template-columns: 20px 20px auto auto 20px;
}

:host([aria-haspopup='menu']) ::slotted([slot='end']) {
grid-column: 3 / span 1;
justify-self: flex-end;
.indicator,
::slotted([slot='indicator']) {
grid-column: 1 / span 1;
width: 20px;
}

::slotted([slot='start']) {
display: inline-flex;
grid-column: calc(var(--indent)) / span 1;
}

:host([data-indent='2'][aria-haspopup='menu']) ::slotted([slot='end']) {
grid-column: 4 / span 1;
justify-self: flex-end;
.content {
grid-column: calc(var(--indent) + 1) / span 1;
}

::slotted([slot='end']) {
grid-column: calc(var(--indent) + 2) / span 1;
justify-self: end;
}

.submenu-glyph,
::slotted([slot='submenu-glyph']) {
grid-column: -2 / span 1;
justify-self: end;
}

@layer popover {
:host {
anchor-name: --menu-trigger;
position: relative;
}

::slotted([popover]) {
inset-area: inline-end span-block-end;
margin: 0;
max-height: var(--menu-max-height, auto);
position: absolute;
position-anchor: --menu-trigger;
position-try-options: flip-inline, inset-area(block-start);
z-index: 1;
}

::slotted([popover]:not(:popover-open)) {
display: none;
}

::slotted([popover]:popover-open) {
inset: unset;
}
}
`;
Loading
Loading