Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
b1ee200
Stubs
michaldudak Feb 7, 2025
092edd1
Create a working experiment
michaldudak Apr 1, 2025
446aea6
Basic keyboard navigation
michaldudak Apr 2, 2025
e7647a5
Simplify
michaldudak Apr 2, 2025
c006d20
Simplify more
michaldudak Apr 2, 2025
28f8b2a
Title
michaldudak Apr 3, 2025
c505040
Do not render Menu.Root
michaldudak Apr 3, 2025
ba050a0
Remove unnecessary fields from context
michaldudak Apr 3, 2025
73e96f2
Fix keyboard navigation
michaldudak Apr 4, 2025
f259ec7
Fix focus management issue with keyboard navigation
michaldudak Apr 7, 2025
ea107da
Almost there
michaldudak Apr 8, 2025
f779dfe
Improvements
michaldudak Apr 8, 2025
f31bf82
Fix the build
michaldudak Apr 8, 2025
3c05bc2
Fix highlight jumping
michaldudak Apr 8, 2025
b100c12
Fix menu opening randomly on hover
michaldudak Apr 8, 2025
f4cbe0c
Tests
michaldudak Apr 9, 2025
435ed55
Update tests
michaldudak Apr 10, 2025
ef08508
Change implemenation to Composite
michaldudak Apr 10, 2025
0a07509
Fix keyboard navigation
michaldudak Apr 10, 2025
fbcfd44
Open on hover
michaldudak Apr 10, 2025
d8e55b5
Modality
michaldudak Apr 10, 2025
e7080ca
Better modality
michaldudak Apr 10, 2025
3a88019
Revert temporary edits
michaldudak Apr 10, 2025
670cd55
Demos
michaldudak Apr 10, 2025
32731f9
API docs
michaldudak Apr 10, 2025
fef2c0a
More tests
michaldudak Apr 11, 2025
99221c0
Revert tests back to RTL
michaldudak Apr 11, 2025
0da8ac4
Make tests less flaky
michaldudak Apr 11, 2025
707d43a
Update the docs
michaldudak Apr 14, 2025
9722a04
Styles
michaldudak Apr 14, 2025
6acc15b
Data attributes docs
michaldudak Apr 14, 2025
4b01543
Remove the unnecessary hook
michaldudak Apr 14, 2025
7d40712
Remove the Root part
michaldudak Apr 14, 2025
00e25ed
Fix navigation in vertical menubar
michaldudak Apr 15, 2025
31f6256
Merge branch 'master' into menubar
michaldudak Apr 15, 2025
10a3f2b
Fix horizontal menu
michaldudak Apr 15, 2025
c782f46
API reference
michaldudak Apr 15, 2025
10e5a1d
Use CompositeRoot
michaldudak Apr 16, 2025
f582e4b
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak Apr 16, 2025
d7d05f5
Fix navigation with CompositeRoot
michaldudak Apr 16, 2025
e767e05
Fix navigation to the left
michaldudak Apr 16, 2025
449c8f3
Correct the vertical menu layout
michaldudak Apr 16, 2025
b2409c7
Remove hover delay
michaldudak Apr 16, 2025
b5479c7
Demo styles
michaldudak Apr 16, 2025
dfab3cd
Update the docs
michaldudak Apr 16, 2025
7db0cd2
proptypes
michaldudak Apr 16, 2025
d890dda
data-instant
michaldudak Apr 16, 2025
0d9066e
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak Apr 17, 2025
eb21218
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak Apr 17, 2025
36b28ce
Focus menu triggers on hover
michaldudak Apr 17, 2025
d0e49af
Place the menus below the menubar
michaldudak Apr 17, 2025
67aa55d
Update the experiment styles
michaldudak Apr 18, 2025
d9e69a4
Fix menu triggers tabIndex
michaldudak Apr 18, 2025
cc24704
TS fixes
michaldudak Apr 18, 2025
b57b317
Proptypes
michaldudak Apr 18, 2025
79181ba
Open on mouseenter instead of mousemove
michaldudak Apr 18, 2025
5454846
Centralize MenuRoot logic in its hook
michaldudak Apr 18, 2025
95c68a8
Unify parent access
michaldudak Apr 18, 2025
a28af12
Improve data-instant
michaldudak Apr 18, 2025
a25c630
Remove console.log
michaldudak Apr 18, 2025
5fa337f
Fix nested menu not fading out on exit
michaldudak Apr 18, 2025
0bddb80
Add missing role
michaldudak Apr 22, 2025
08f2cd5
Correct placing of the disabled prop in demos
michaldudak Apr 22, 2025
789d845
Fix styling of disabled triggers
michaldudak Apr 22, 2025
acda591
Wait for focus in tests
michaldudak Apr 22, 2025
f87b52b
Correct prop merging order
michaldudak Apr 22, 2025
db6a9d9
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak Apr 22, 2025
c117be1
Revert `ignoreNavigationFromPopups`
michaldudak Apr 22, 2025
7252f6a
Run more tests on JSDOM
michaldudak Apr 22, 2025
2411a47
cleanup
michaldudak Apr 18, 2025
faf82fd
proptypes
michaldudak Apr 22, 2025
44c4593
Do not run keyboard interaction tests in browsers
michaldudak Apr 22, 2025
8c3adb9
Skip loop tests in the browser
michaldudak Apr 22, 2025
f95170f
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak Apr 22, 2025
94d67a6
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak Apr 23, 2025
efbdc37
Update transitions
michaldudak Apr 23, 2025
9ffec0f
Re-add missing type
michaldudak Apr 23, 2025
33b2298
Merge branch 'master' into menubar
atomiks Apr 25, 2025
4e3fa15
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak Apr 25, 2025
5d6117e
Update the lockfile
michaldudak Apr 25, 2025
f4f6563
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak Apr 28, 2025
a29e86c
Restore focus
michaldudak Apr 28, 2025
a3a27b7
Fix data-instant not applied correctly
michaldudak Apr 28, 2025
ac34f48
Lint
michaldudak Apr 29, 2025
265fa6a
Merge branch 'master' into menubar
michaldudak Apr 30, 2025
f4be79d
Update Floating UI to canary version
michaldudak Apr 30, 2025
6c98393
Fix initial focus
michaldudak May 1, 2025
c2ee03f
Use vitest browser interactions for some tests
michaldudak May 1, 2025
4969c6f
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak May 1, 2025
83dd07e
Dedupe
michaldudak May 1, 2025
2860b25
Dedupe again
michaldudak May 1, 2025
dc05242
Fix the exit animation not appearing at times
michaldudak May 1, 2025
dd22e5d
Focus styles
michaldudak May 2, 2025
36d9ffb
Do not restore focus on outside click
michaldudak May 2, 2025
ab1c38e
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak May 2, 2025
aed1e77
Fix tests
michaldudak May 2, 2025
ef55ab8
Fix data-instant during keyboard navigation
michaldudak May 2, 2025
78c7c8c
Apply data-instant when using keyboard to click a menu item
michaldudak May 5, 2025
28c27d9
Disable waiting for patient clicks to close menus
michaldudak May 5, 2025
d2f1352
New export pattern
michaldudak May 5, 2025
48f71c7
Cleanup
michaldudak May 5, 2025
052901c
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak May 5, 2025
95f3a49
parens in wrong places
michaldudak May 5, 2025
c1de1c3
Simplify
michaldudak May 5, 2025
6822f24
Use vitest browser utils for flaky tests
michaldudak May 5, 2025
0098a97
Open on mousedown, close on click
michaldudak May 5, 2025
04be19c
Styles
michaldudak May 5, 2025
274ed37
Fix mixed modality data-instant application
michaldudak May 5, 2025
e66d87d
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak May 6, 2025
4ae8743
Fix press-drag-release interaction across menus
michaldudak May 6, 2025
6179d67
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak May 6, 2025
036bd11
Fix pnpm issues?
michaldudak May 6, 2025
d4e3f2e
Fix menu closing immediately after opening in devtools
michaldudak May 8, 2025
29a359a
Clear timeouts
michaldudak May 8, 2025
6849ffc
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak May 8, 2025
0c8af10
Fix highlighted chevron color
michaldudak May 8, 2025
ce3917d
Set pnpm to stable version
michaldudak May 8, 2025
d291242
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak May 8, 2025
9f90abb
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak May 8, 2025
c965252
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak May 9, 2025
354785e
Fix tests
michaldudak May 9, 2025
2aa858c
Fix more tests
michaldudak May 9, 2025
a6b6450
Fix more tests
michaldudak May 9, 2025
2c39e5a
Fix next tests
michaldudak May 9, 2025
66fd1f3
Fix positioner tests
michaldudak May 9, 2025
0e3df20
Merge remote-tracking branch 'upstream/master' into menubar
michaldudak May 9, 2025
a478546
Lint
michaldudak May 9, 2025
6862170
Do not make RAF sync in tests
michaldudak May 9, 2025
c5ba0a0
tests
michaldudak May 9, 2025
5e089a6
tests
michaldudak May 9, 2025
10de21f
docs:api
michaldudak May 9, 2025
4bae43d
Fix remaining tests
michaldudak May 9, 2025
2ac8e7d
use timeout hooks
michaldudak May 9, 2025
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
2 changes: 1 addition & 1 deletion docs/reference/generated/menu-popup.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
},
"data-instant": {
"description": "Present if animations should be instant.",
"type": "'click' | 'dismiss'"
"type": "'click' | 'dismiss' | 'group'"
},
"data-side": {
"description": "Indicates which side the popup is positioned relative to the trigger.",
Expand Down
36 changes: 36 additions & 0 deletions docs/reference/generated/menubar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "Menubar",
"description": "The container for menus.",
"props": {
"modal": {
"type": "boolean",
"default": "true",
"description": "Whether the menubar is modal."
},
"disabled": {
"type": "boolean",
"default": "false",
"description": "Whether the whole menubar is disabled."
},
"loop": {
"type": "boolean",
"default": "true",
"description": "Whether to loop keyboard focus back to the first item\nwhen the end of the list is reached while using the arrow keys."
},
"orientation": {
"type": "MenuOrientation",
"default": "'horizontal'",
"description": "The orientation of the menubar."
},
"className": {
"type": "string | ((state: Menubar.State) => string)",
"description": "CSS class applied to the element, or a function that\nreturns a class based on the component’s state."
},
"render": {
"type": "ReactElement | ((props: HTMLProps, state: Menubar.State) => ReactElement)",
"description": "Allows you to replace the component’s HTML element\nwith a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
}
},
"dataAttributes": {},
"cssVariables": {}
}
285 changes: 285 additions & 0 deletions docs/src/app/(private)/experiments/menu/menu-horizontal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
'use client';
import * as React from 'react';
import { Menu } from '@base-ui-components/react/menu';
import { styled } from '@mui/system';

export default function NestedMenu() {
const createHandleMenuClick = (menuItem: string) => {
return () => {
console.log(`Clicked on ${menuItem}`);
};
};

const containerRef = React.useRef<HTMLDivElement>(null);

return (
<Container>
<div ref={containerRef} />
<Menu.Root orientation="horizontal" open modal={false}>
<Menu.Portal>
<Menu.Positioner
side="bottom"
align="start"
sideOffset={6}
anchor={containerRef}
>
<MenuRootPopup>
<Menu.Root openOnHover={false}>
<SubmenuTrigger>Text color</SubmenuTrigger>
<Menu.Portal>
<Menu.Positioner align="start" side="bottom" sideOffset={12}>
<MenuPopup>
<MenuItem onClick={createHandleMenuClick('Text color/Black')}>
Black
</MenuItem>
<MenuItem
onClick={createHandleMenuClick('Text color/Dark grey')}
>
Dark grey
</MenuItem>
<MenuItem onClick={createHandleMenuClick('Text color/Accent')}>
Accent
</MenuItem>
</MenuPopup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>

<Menu.Root openOnHover={false}>
<SubmenuTrigger>Style</SubmenuTrigger>
<Menu.Portal>
<Menu.Positioner align="start" side="bottom" sideOffset={12}>
<MenuPopup>
<Menu.Root>
<SubmenuTrigger>Heading</SubmenuTrigger>
<Menu.Portal>
<Menu.Positioner
align="start"
side="right"
sideOffset={12}
>
<MenuPopup>
<MenuItem
onClick={createHandleMenuClick(
'Style/Heading/Level 1',
)}
>
Level 1
</MenuItem>
<MenuItem
onClick={createHandleMenuClick(
'Style/Heading/Level 2',
)}
>
Level 2
</MenuItem>
<MenuItem
onClick={createHandleMenuClick(
'Style/Heading/Level 3',
)}
>
Level 3
</MenuItem>
</MenuPopup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
<MenuItem onClick={createHandleMenuClick('Style/Paragraph')}>
Paragraph
</MenuItem>
<Menu.Root disabled>
<SubmenuTrigger>List</SubmenuTrigger>
<Menu.Portal>
<Menu.Positioner
align="start"
side="bottom"
sideOffset={12}
>
<MenuPopup>
<MenuItem
onClick={createHandleMenuClick('Style/List/Ordered')}
>
Ordered
</MenuItem>
<MenuItem
onClick={createHandleMenuClick(
'Style/List/Unordered',
)}
>
Unordered
</MenuItem>
</MenuPopup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
</MenuPopup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
</MenuRootPopup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
</Container>
);
}

const grey = {
50: '#F3F6F9',
100: '#E5EAF2',
200: '#DAE2ED',
300: '#C7D0DD',
400: '#B0B8C4',
500: '#9DA8B7',
600: '#6B7A90',
700: '#434D5B',
800: '#303740',
900: '#1C2025',
};

const MenuPopup = styled(Menu.Popup)(
({ theme }) => `
font-family: 'IBM Plex Sans', sans-serif;
font-size: 0.875rem;
box-sizing: border-box;
padding: 6px;
min-width: 200px;
border-radius: 12px;
overflow: visible;
outline: 0;
background: ${theme.palette.mode === 'dark' ? grey[900] : '#fff'};
border: 1px solid ${theme.palette.mode === 'dark' ? grey[700] : grey[200]};
color: ${theme.palette.mode === 'dark' ? grey[300] : grey[900]};
box-shadow: 0 4px 30px ${theme.palette.mode === 'dark' ? grey[900] : grey[200]};
z-index: 1;
transform-origin: var(--transform-origin);
opacity: 1;
transform: scale(1, 1);
transition: opacity 100ms ease-in, transform 100ms ease-in;

&[data-nested] {
margin-top: -6px;
}

&[data-starting-style] {
opacity: 0;
transform: scale(0.8);
}

&[data-ending-style] {
opacity: 0;
transform: scale(0.8);
transition: opacity 200ms ease-in, transform 200ms ease-in;
}
`,
);

const MenuRootPopup = styled(Menu.Popup)(`
font-family: 'IBM Plex Sans', sans-serif;
font-size: 0.875rem;
box-sizing: border-box;
padding: 6px;
min-width: 200px;
border-radius: 12px;
overflow: visible;
outline: 0;
background: '#fff';
border: 1px solid grey[200];
color: grey[900];
box-shadow: 0 4px 30px grey[200];
z-index: 1;
transform-origin: var(--transform-origin);
opacity: 1;
transform: scale(1, 1);
transition: opacity 100ms ease-in, transform 100ms ease-in;
display: flex;

&[data-nested] {
margin-top: -6px;
}

&[data-starting-style] {
opacity: 0;
transform: scale(0.8);
}

&[data-ending-style] {
opacity: 0;
transform: scale(0.8);
transition: opacity 200ms ease-in, transform 200ms ease-in;
}
`);

const MenuItem = styled(Menu.Item)(
({ theme }) => `
list-style: none;
padding: 8px;
border-radius: 8px;
cursor: default;
user-select: none;

&:last-of-type {
border-bottom: none;
}

&:focus,
&:hover {
background-color: ${theme.palette.mode === 'dark' ? grey[800] : grey[100]};
color: ${theme.palette.mode === 'dark' ? grey[300] : grey[900]};
}

&:focus-visible {
outline: none;
}

&[data-disabled] {
color: ${theme.palette.mode === 'dark' ? grey[700] : grey[400]};
}
`,
);

const SubmenuTrigger = styled(Menu.SubmenuTrigger)(
({ theme }) => `
list-style: none;
padding: 8px;
border-radius: 8px;
cursor: default;
user-select: none;

&:last-of-type {
border-bottom: none;
}

&::after {
content: '›';
float: right;
}

&[data-popup-open] {
background-color: ${theme.palette.mode === 'dark' ? grey[900] : grey[50]};
color: ${theme.palette.mode === 'dark' ? grey[300] : grey[900]};
}

&:focus,
&:hover {
background-color: ${theme.palette.mode === 'dark' ? grey[800] : grey[100]};
color: ${theme.palette.mode === 'dark' ? grey[300] : grey[900]};
}

&:focus-visible {
outline: none;
}

&[data-disabled] {
color: ${theme.palette.mode === 'dark' ? grey[700] : grey[400]};
}
`,
);

const Container = styled('div')`
display: flex;
min-height: 110vh;
box-sizing: border-box;
align-items: center;
gap: 20px;
`;
8 changes: 4 additions & 4 deletions docs/src/app/(private)/experiments/menu/menu.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,13 @@
rotate: 0deg;
}

&[data-side='left'] {
right: -13px;
&[data-side='inline-start'] {
inset-inline-end: -13px;
rotate: 90deg;
}

&[data-side='right'] {
left: -13px;
&[data-side='inline-end'] {
inset-inline-start: -13px;
rotate: -90deg;
}
}
Expand Down
Loading