From 9315bfbf44f31a11607999ec8e26035a72eb04a0 Mon Sep 17 00:00:00 2001 From: mnajdova Date: Fri, 10 Jan 2025 13:57:40 +0100 Subject: [PATCH 01/10] [experiments] Fluent UI submenus --- .../experiments/menu-fluent-ui.module.css | 151 ++++++++++++++++++ .../(private)/experiments/menu-fluent-ui.tsx | 130 +++++++++++++++ 2 files changed, 281 insertions(+) create mode 100644 docs/src/app/(private)/experiments/menu-fluent-ui.module.css create mode 100644 docs/src/app/(private)/experiments/menu-fluent-ui.tsx diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css new file mode 100644 index 0000000000..d23fd4a18f --- /dev/null +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css @@ -0,0 +1,151 @@ +.Button { + box-sizing: border-box; + font-size: 0.875rem; + display: flex; + align-items: center; + justify-content: center; + gap: 0.375rem; + height: 2rem; + padding: 0 1rem; + margin: 0; + outline: 0; + border: 1px solid oklch(12% 9% 264 / 8%); + background-color: oklch(98% 0.25% 264); + font-family: inherit; + font-weight: 500; + line-height: 1.5rem; + color: oklch(12% 5% 264 / 90%); + user-select: none; + + @media (hover: hover) { + &:hover { + background-color: oklch(12% 9.5% 264 / 5%); + } + } + + &:active { + background-color: oklch(12% 9.5% 264 / 5%); + } + + &[data-popup-open] { + background-color: oklch(12% 9.5% 264 / 5%); + } + + &:focus-visible { + outline: 2px solid oklch(45% 50% 264); + outline-offset: -1px; + } +} + +.Positioner { + outline: 0; +} + +.Popup { + box-sizing: border-box; + padding-block: 0.25rem; + background-color: canvas; + color: oklch(12% 5% 264 / 90%); + transform-origin: var(--transform-origin); + transition: + transform 150ms, + opacity 150ms; + + &[data-starting-style], + &[data-ending-style] { + opacity: 0; + transform: scale(0.9); + } + + outline: 1px solid oklch(12% 9% 264 / 8%); + box-shadow: + 0px 4px 6px -3px oklch(12% 9% 264 / 8%), + 0px 4px 6px -4px oklch(12% 9% 264 / 8%); +} + +.Arrow { + display: flex; + + &[data-side='top'] { + bottom: -8px; + rotate: 180deg; + } + &[data-side='bottom'] { + top: -8px; + rotate: 0deg; + } + &[data-side='left'] { + right: -13px; + rotate: 90deg; + } + &[data-side='right'] { + left: -13px; + rotate: -90deg; + } +} + +.ArrowFill { + fill: canvas; +} + +.ArrowOuterStroke { + fill: oklch(12% 9% 264 / 8%); +} + +.Item, +.ItemWithSubmenu, +.SubmenuTrigger, +.SubmenuTriggerInsideItem, +.SplitButtonRoot, +.SplitButtonItem, +.SplitButtonSubemnuTrigger { + outline: 0; + cursor: default; + user-select: none; + padding-block: 0.5rem; + padding-left: 1rem; + padding-right: 2rem; + display: flex; + font-size: 0.875rem; + line-height: 1rem; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding-right: 1rem; + + &:hover { + background: oklch(12% 9.5% 264 / 5%); + } + + &[data-highlighted] { + z-index: 0; + position: relative; + background: oklch(12% 9.5% 264 / 5%); + } +} + +.ItemWithSubmenu { + padding-right: 0; + padding-block: 0; +} + +.SplitButtonRoot { + padding: 0; + padding-left: 1rem; +} + +.SubmenuTrigger { + padding: 0.75rem 1rem; + margin-left: auto; +} + +.SplitButtonItem { + display: inline-flex; + padding-left: 1rem; +} + +.SplitButtonSubemnuTrigger { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + display: inline-flex; +} diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx new file mode 100644 index 0000000000..8abfef6fa6 --- /dev/null +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx @@ -0,0 +1,130 @@ +import * as React from 'react'; +import { Menu } from '@base-ui-components/react/menu'; +import styles from './menu-fluent-ui.module.css'; + +export default function ExampleMenu() { + return ( +
+
+ Reference:{' '} + + ContextualMenu with subemnus + {' '} +
+ + + Contextual menu + + + + + {/* Submenu */} + + + New{' '} + + + + + + + + Email message + Calendar event + + + + + + {/* Submenu */} + + + Share{' '} + + + + + + + + Share to Twitter + + Share to Facebook + + + + + + + {/* + * First try, using MenuItem as the wrapper of the SubmenuTrigger + * Issues: + * ❌ MenuItem is never highlighted, we assume that only SubmenuTrigger can be used, as triggers and there never be a MenuItem added here (which kind of makes sense) + * ❌ There are two navigation stops for both the MenuItem and the SubmenuTrigger + */} + + + Share w/ split + + + + + + + + Share to Twitter + + Share to Facebook + + + + + + + {/* + * Second try, using MenuItem independently, style them as one element + * Issues: + * ✅ MenuItem is never highlighted, we assume that only SubmenuTrigger can be used, as triggers and there never be a MenuItem added here (which kind of makes sense) + * ❌ There are two navigation stops for both the MenuItem and the SubmenuTrigger + */} + + Share w/ split + + + + + + + + + Share to Twitter + + Share to Facebook + + + + + + + + + +
+ ); +} + +function ChevronDownIcon(props: React.ComponentProps<'svg'>) { + return ( + + + + ); +} + +function ChevronRightIcon(props: React.ComponentProps<'svg'>) { + return ( + + + + ); +} From 3e09c9a56b7acc1a79d038524aac1394bb77aac4 Mon Sep 17 00:00:00 2001 From: mnajdova Date: Fri, 10 Jan 2025 13:59:44 +0100 Subject: [PATCH 02/10] add aria labels --- docs/src/app/(private)/experiments/menu-fluent-ui.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx index 8abfef6fa6..af2a6502f7 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx @@ -65,7 +65,7 @@ export default function ExampleMenu() { Share w/ split - + @@ -91,7 +91,7 @@ export default function ExampleMenu() { Share w/ split - + From 26ba62b3d37fb0d585152bbf38921e964156ee6c Mon Sep 17 00:00:00 2001 From: mnajdova Date: Mon, 13 Jan 2025 10:03:13 +0100 Subject: [PATCH 03/10] cleanup demo --- .../experiments/menu-fluent-ui.module.css | 6 --- .../(private)/experiments/menu-fluent-ui.tsx | 37 ++----------------- 2 files changed, 4 insertions(+), 39 deletions(-) diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css index d23fd4a18f..0ef65f567c 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css @@ -96,7 +96,6 @@ .ItemWithSubmenu, .SubmenuTrigger, .SubmenuTriggerInsideItem, -.SplitButtonRoot, .SplitButtonItem, .SplitButtonSubemnuTrigger { outline: 0; @@ -129,11 +128,6 @@ padding-block: 0; } -.SplitButtonRoot { - padding: 0; - padding-left: 1rem; -} - .SubmenuTrigger { padding: 0.75rem 1rem; margin-left: auto; diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx index af2a6502f7..77541fe14d 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx @@ -55,43 +55,14 @@ export default function ExampleMenu() { - - {/* - * First try, using MenuItem as the wrapper of the SubmenuTrigger - * Issues: - * ❌ MenuItem is never highlighted, we assume that only SubmenuTrigger can be used, as triggers and there never be a MenuItem added here (which kind of makes sense) - * ❌ There are two navigation stops for both the MenuItem and the SubmenuTrigger - */} - - - Share w/ split - - - - - - - - Share to Twitter - - Share to Facebook - - - - - - - {/* - * Second try, using MenuItem independently, style them as one element - * Issues: - * ✅ MenuItem is never highlighted, we assume that only SubmenuTrigger can be used, as triggers and there never be a MenuItem added here (which kind of makes sense) - * ❌ There are two navigation stops for both the MenuItem and the SubmenuTrigger - */} Share w/ split - + From 56fde06b0c7de37ba2a65a00ec7864e173913806 Mon Sep 17 00:00:00 2001 From: mnajdova Date: Mon, 13 Jan 2025 13:28:04 +0100 Subject: [PATCH 04/10] wip --- .../experiments/composite.module.css | 46 +++++++++++ .../app/(private)/experiments/composite.tsx | 81 +++++++++++++++++++ .../experiments/menu-fluent-ui.module.css | 7 ++ .../(private)/experiments/menu-fluent-ui.tsx | 42 +++++++++- packages/react/package.json | 1 + packages/react/src/composite/index.parts.ts | 3 + packages/react/src/composite/index.ts | 1 + 7 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 docs/src/app/(private)/experiments/composite.module.css create mode 100644 docs/src/app/(private)/experiments/composite.tsx create mode 100644 packages/react/src/composite/index.parts.ts create mode 100644 packages/react/src/composite/index.ts diff --git a/docs/src/app/(private)/experiments/composite.module.css b/docs/src/app/(private)/experiments/composite.module.css new file mode 100644 index 0000000000..1ba9a65f80 --- /dev/null +++ b/docs/src/app/(private)/experiments/composite.module.css @@ -0,0 +1,46 @@ +.Grid { + display: flex; + flex-direction: column; + box-sizing: border-box; + padding-block: 0.25rem; + background-color: canvas; + color: oklch(12% 5% 264 / 90%); + transform-origin: var(--transform-origin); + transition: + transform 150ms, + opacity 150ms; + + &[data-starting-style], + &[data-ending-style] { + opacity: 0; + transform: scale(0.9); + } + + outline: 1px solid oklch(12% 9% 264 / 8%); + box-shadow: + 0px 4px 6px -3px oklch(12% 9% 264 / 8%), + 0px 4px 6px -4px oklch(12% 9% 264 / 8%); +} + +.GridRow { + display: flex; +} + +.GridItem { + outline: 0; + cursor: default; + display: flex; + align-items: center; + justify-content: center; + width: 48px; + height: 48px; + &:hover { + background: oklch(12% 9.5% 264 / 5%); + } + + &[data-highlighted] { + z-index: 0; + position: relative; + background: oklch(12% 9.5% 264 / 5%); + } +} diff --git a/docs/src/app/(private)/experiments/composite.tsx b/docs/src/app/(private)/experiments/composite.tsx new file mode 100644 index 0000000000..af0b114e35 --- /dev/null +++ b/docs/src/app/(private)/experiments/composite.tsx @@ -0,0 +1,81 @@ +'use client'; +import * as React from 'react'; +import { Composite } from '@base-ui-components/react/composite'; +import styles from './composite.module.css'; + +export default function ExampleGrid() { + const [column, setColumn] = React.useState(0); + const [row, setRow] = React.useState(0); + + const rootHandleHighligtedIndexChange = (index: number) => { + setRow(index); + }; + + const handleHighligtedIndexChange = (index: number) => { + setColumn(index); + }; + + return ( + + + + A + B + C + D + + + + + E + F + G + H + + + + + I + J + K + L + + + + + M + N + + + + ); +} diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css index 0ef65f567c..3e5240f83f 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css @@ -1,4 +1,5 @@ .Button { + width: fit-content; box-sizing: border-box; font-size: 0.875rem; display: flex; @@ -92,6 +93,12 @@ fill: oklch(12% 9% 264 / 8%); } +.Separator { + margin: 0.375rem 0; + height: 1px; + background-color: oklch(12% 9% 264 / 8%); +} + .Item, .ItemWithSubmenu, .SubmenuTrigger, diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx index 77541fe14d..9da3fdc8e1 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx @@ -4,8 +4,8 @@ import styles from './menu-fluent-ui.module.css'; export default function ExampleMenu() { return ( -
-
+
+
Reference:{' '} ContextualMenu with subemnus @@ -80,6 +80,44 @@ export default function ExampleMenu() { + + + + Contextual menu + + + + + New + Upload + + + + Categorized + + + + + + + + Share to Twitter + + Share to Facebook + + + + + + + + +
); } diff --git a/packages/react/package.json b/packages/react/package.json index 274aa9a180..1f47effc77 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -56,6 +56,7 @@ "./tooltip": "./src/tooltip/index.ts", "./unstable-no-ssr": "./src/unstable-no-ssr/index.ts", "./unstable-use-media-query": "./src/unstable-use-media-query/index.ts", + "./composite": "./src/composite/index.ts", "./utils": "./src/utils/index.ts" }, "imports": { diff --git a/packages/react/src/composite/index.parts.ts b/packages/react/src/composite/index.parts.ts new file mode 100644 index 0000000000..e42456f7d9 --- /dev/null +++ b/packages/react/src/composite/index.parts.ts @@ -0,0 +1,3 @@ +export { CompositeRoot as Root } from './root/CompositeRoot'; +export { CompositeList as List } from './list/CompositeList'; +export { CompositeItem as Item } from './item/CompositeItem'; diff --git a/packages/react/src/composite/index.ts b/packages/react/src/composite/index.ts new file mode 100644 index 0000000000..5709e5228e --- /dev/null +++ b/packages/react/src/composite/index.ts @@ -0,0 +1 @@ +export * as Composite from './index.parts'; From 00db429e7468e3aa49340850205244981bc6cde4 Mon Sep 17 00:00:00 2001 From: mnajdova Date: Mon, 13 Jan 2025 18:03:22 +0100 Subject: [PATCH 05/10] grid like example --- .../experiments/menu-fluent-ui.module.css | 29 ++++++++++++ .../(private)/experiments/menu-fluent-ui.tsx | 46 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css index 3e5240f83f..adee24d079 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css @@ -150,3 +150,32 @@ padding-bottom: 0.75rem; display: inline-flex; } + +.Grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 0.25rem; +} + +.GridRow { + display: flex; +} + +.GridItem { + outline: 0; + cursor: default; + display: flex; + align-items: center; + justify-content: center; + width: 48px; + height: 48px; + &:hover { + background: oklch(12% 9.5% 264 / 5%); + } + + &[data-highlighted] { + z-index: 0; + position: relative; + background: oklch(12% 9.5% 264 / 5%); + } +} diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx index 9da3fdc8e1..c579e23543 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx @@ -1,8 +1,12 @@ +'use client'; import * as React from 'react'; import { Menu } from '@base-ui-components/react/menu'; +import { Composite } from '@base-ui-components/react/composite'; import styles from './menu-fluent-ui.module.css'; export default function ExampleMenu() { + const [complexMenuOpen, setComplexMenuOpen] = React.useState(false); + return (
@@ -96,6 +100,48 @@ export default function ExampleMenu() { New Upload + { + setComplexMenuOpen(open); + }} + > + + Charm + + + + + + + + + {[...Array(16).keys()].map((i) => ( + { + if (e.key === 'ArrowLeft') + setComplexMenuOpen(false); + }, + } + : {})} + > + {i + 1} + + ))} + + + + + Categorized From 4626b6e2277facd0a5cf855f870b262e5fdac02d Mon Sep 17 00:00:00 2001 From: mnajdova Date: Mon, 13 Jan 2025 18:12:01 +0100 Subject: [PATCH 06/10] render as Menu.Item --- docs/src/app/(private)/experiments/menu-fluent-ui.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx index c579e23543..f67de91926 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx @@ -133,6 +133,7 @@ export default function ExampleMenu() { }, } : {})} + render={(props) => } > {i + 1} From 8a884ad097c177d6bf04faf4098a9d021e3afcb8 Mon Sep 17 00:00:00 2001 From: mnajdova Date: Tue, 14 Jan 2025 09:53:10 +0100 Subject: [PATCH 07/10] lint issues --- docs/src/app/(private)/experiments/menu-fluent-ui.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx index f67de91926..0682096a09 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx @@ -127,9 +127,10 @@ export default function ExampleMenu() { key={i} {...(i === 0 ? { - onKeyDown: (e) => { - if (e.key === 'ArrowLeft') + onKeyDown: (event) => { + if (event.key === 'ArrowLeft') { setComplexMenuOpen(false); + } }, } : {})} From 1fef36f49e36d272253f1b54ae4fa592aa7bd9be Mon Sep 17 00:00:00 2001 From: mnajdova Date: Tue, 14 Jan 2025 10:03:16 +0100 Subject: [PATCH 08/10] styles fixes --- docs/src/app/(private)/experiments/menu-fluent-ui.module.css | 5 ++--- docs/src/app/(private)/experiments/menu-fluent-ui.tsx | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css index adee24d079..ec08db90a3 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css @@ -101,10 +101,9 @@ .Item, .ItemWithSubmenu, -.SubmenuTrigger, .SubmenuTriggerInsideItem, .SplitButtonItem, -.SplitButtonSubemnuTrigger { +.SplitButtonSubmenuTrigger { outline: 0; cursor: default; user-select: none; @@ -145,7 +144,7 @@ padding-left: 1rem; } -.SplitButtonSubemnuTrigger { +.SplitButtonSubmenuTrigger { padding-top: 0.75rem; padding-bottom: 0.75rem; display: inline-flex; diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx index 0682096a09..09daca48e6 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx @@ -64,7 +64,7 @@ export default function ExampleMenu() { From 13270b2f2685b04181a8f8e4585a0f54cf627245 Mon Sep 17 00:00:00 2001 From: mnajdova Date: Wed, 15 Jan 2025 12:02:33 +0100 Subject: [PATCH 09/10] Depend on useListNavigation --- .../experiments/menu-fluent-ui.module.css | 10 +---- .../(private)/experiments/menu-fluent-ui.tsx | 42 ++++--------------- packages/react/package.json | 1 - packages/react/src/menu/root/MenuRoot.tsx | 3 ++ packages/react/src/menu/root/useMenuRoot.ts | 3 ++ 5 files changed, 15 insertions(+), 44 deletions(-) diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css index ec08db90a3..9b3d9da892 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.module.css +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.module.css @@ -42,7 +42,8 @@ outline: 0; } -.Popup { +.Popup, +.Grid { box-sizing: border-box; padding-block: 0.25rem; background-color: canvas; @@ -118,10 +119,6 @@ gap: 1rem; padding-right: 1rem; - &:hover { - background: oklch(12% 9.5% 264 / 5%); - } - &[data-highlighted] { z-index: 0; position: relative; @@ -168,9 +165,6 @@ justify-content: center; width: 48px; height: 48px; - &:hover { - background: oklch(12% 9.5% 264 / 5%); - } &[data-highlighted] { z-index: 0; diff --git a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx index 09daca48e6..ad1e84011f 100644 --- a/docs/src/app/(private)/experiments/menu-fluent-ui.tsx +++ b/docs/src/app/(private)/experiments/menu-fluent-ui.tsx @@ -1,12 +1,9 @@ 'use client'; import * as React from 'react'; import { Menu } from '@base-ui-components/react/menu'; -import { Composite } from '@base-ui-components/react/composite'; import styles from './menu-fluent-ui.module.css'; export default function ExampleMenu() { - const [complexMenuOpen, setComplexMenuOpen] = React.useState(false); - return (
@@ -100,12 +97,7 @@ export default function ExampleMenu() { New Upload - { - setComplexMenuOpen(open); - }} - > + Charm @@ -114,32 +106,12 @@ export default function ExampleMenu() { - - - {[...Array(16).keys()].map((i) => ( - { - if (event.key === 'ArrowLeft') { - setComplexMenuOpen(false); - } - }, - } - : {})} - render={(props) => } - > - {i + 1} - - ))} - + + {[...Array(16).keys()].map((i) => ( + + {i + 1} + + ))} diff --git a/packages/react/package.json b/packages/react/package.json index 1f47effc77..274aa9a180 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -56,7 +56,6 @@ "./tooltip": "./src/tooltip/index.ts", "./unstable-no-ssr": "./src/unstable-no-ssr/index.ts", "./unstable-use-media-query": "./src/unstable-use-media-query/index.ts", - "./composite": "./src/composite/index.ts", "./utils": "./src/utils/index.ts" }, "imports": { diff --git a/packages/react/src/menu/root/MenuRoot.tsx b/packages/react/src/menu/root/MenuRoot.tsx index ce482cfe37..a7245ca58e 100644 --- a/packages/react/src/menu/root/MenuRoot.tsx +++ b/packages/react/src/menu/root/MenuRoot.tsx @@ -26,6 +26,7 @@ const MenuRoot: React.FC = function MenuRoot(props) { orientation = 'vertical', delay = 100, openOnHover: openOnHoverProp, + cols, } = props; const direction = useDirection(); @@ -54,6 +55,7 @@ const MenuRoot: React.FC = function MenuRoot(props) { delay, onTypingChange, modal, + cols, }); const context: MenuRootContext = React.useMemo( @@ -141,6 +143,7 @@ namespace MenuRoot { * Defaults to `true` for nested menus. */ openOnHover?: boolean; + cols?: number; } } diff --git a/packages/react/src/menu/root/useMenuRoot.ts b/packages/react/src/menu/root/useMenuRoot.ts index 058d927800..b5f910dd4a 100644 --- a/packages/react/src/menu/root/useMenuRoot.ts +++ b/packages/react/src/menu/root/useMenuRoot.ts @@ -44,6 +44,7 @@ export function useMenuRoot(parameters: useMenuRoot.Parameters): useMenuRoot.Ret openOnHover, onTypingChange, modal, + cols, } = parameters; const [triggerElement, setTriggerElement] = React.useState(null); @@ -192,6 +193,7 @@ export function useMenuRoot(parameters: useMenuRoot.Parameters): useMenuRoot.Ret rtl: direction === 'rtl', disabledIndices: EMPTY_ARRAY, onNavigate: setActiveIndex, + cols, }); const typeahead = useTypeahead(floatingRootContext, { @@ -347,6 +349,7 @@ export namespace useMenuRoot { */ onTypingChange: (typing: boolean) => void; modal: boolean; + cols?: number; } export interface ReturnValue { From cce58e8473ad610a2d5b94a3f39276d5d6a6eca7 Mon Sep 17 00:00:00 2001 From: mnajdova Date: Wed, 15 Jan 2025 12:03:30 +0100 Subject: [PATCH 10/10] allow both navigation --- packages/react/src/menu/root/useMenuRoot.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/menu/root/useMenuRoot.ts b/packages/react/src/menu/root/useMenuRoot.ts index b5f910dd4a..4844b5f3ed 100644 --- a/packages/react/src/menu/root/useMenuRoot.ts +++ b/packages/react/src/menu/root/useMenuRoot.ts @@ -289,7 +289,7 @@ export function useMenuRoot(parameters: useMenuRoot.Parameters): useMenuRoot.Ret ); } -export type MenuOrientation = 'horizontal' | 'vertical'; +export type MenuOrientation = 'horizontal' | 'vertical' | 'both'; export namespace useMenuRoot { export interface Parameters {