diff --git a/src/components/SistentNavigation/content.js b/src/components/SistentNavigation/content.js index b18cfd87b0594..c64188a92ab80 100644 --- a/src/components/SistentNavigation/content.js +++ b/src/components/SistentNavigation/content.js @@ -79,59 +79,63 @@ export const content = [ { id: 57, link: "/projects/sistent/components/list/guidance", text: "List" }, { id: 58, link: "/projects/sistent/components/list/code", text: "List" }, - { id: 59, link: "/projects/sistent/components/modal", text: "Modal" }, - { id: 60, link: "/projects/sistent/components/modal/guidance", text: "Modal" }, - { id: 61, link: "/projects/sistent/components/modal/code", text: "Modal" }, + { id: 59, link: "/projects/sistent/components/menu", text: "Menu" }, + { id: 60, link: "/projects/sistent/components/menu/guidance", text: "Menu" }, + { id: 61, link: "/projects/sistent/components/menu/code", text: "Menu" }, - { id: 62, link: "/projects/sistent/components/pagination", text: "Pagination" }, - { id: 63, link: "/projects/sistent/components/pagination/guidance", text: "Pagination" }, - { id: 64, link: "/projects/sistent/components/pagination/code", text: "Pagination" }, + { id: 62, link: "/projects/sistent/components/modal", text: "Modal" }, + { id: 63, link: "/projects/sistent/components/modal/guidance", text: "Modal" }, + { id: 64, link: "/projects/sistent/components/modal/code", text: "Modal" }, - { id: 65, link: "/projects/sistent/components/paper", text: "Paper" }, - { id: 66, link: "/projects/sistent/components/paper/guidance", text: "Paper" }, - { id: 67, link: "/projects/sistent/components/paper/code", text: "Paper" }, + { id: 65, link: "/projects/sistent/components/pagination", text: "Pagination" }, + { id: 66, link: "/projects/sistent/components/pagination/guidance", text: "Pagination" }, + { id: 67, link: "/projects/sistent/components/pagination/code", text: "Pagination" }, - { id: 68, link: "/projects/sistent/components/popper", text: "Popper" }, - { id: 69, link: "/projects/sistent/components/popper/guidance", text: "Popper" }, - { id: 70, link: "/projects/sistent/components/popper/code", text: "Popper" }, + { id: 68, link: "/projects/sistent/components/paper", text: "Paper" }, + { id: 69, link: "/projects/sistent/components/paper/guidance", text: "Paper" }, + { id: 70, link: "/projects/sistent/components/paper/code", text: "Paper" }, - { id: 71, link: "/projects/sistent/components/radiogroup", text: "RadioGroup" }, - { id: 72, link: "/projects/sistent/components/radiogroup/guidance", text: "RadioGroup" }, - { id: 73, link: "/projects/sistent/components/radiogroup/code", text: "RadioGroup" }, + { id: 71, link: "/projects/sistent/components/popper", text: "Popper" }, + { id: 72, link: "/projects/sistent/components/popper/guidance", text: "Popper" }, + { id: 73, link: "/projects/sistent/components/popper/code", text: "Popper" }, - { id: 74, link: "/projects/sistent/components/select", text: "Select" }, - { id: 75, link: "/projects/sistent/components/select/guidance", text: "Select" }, - { id: 76, link: "/projects/sistent/components/select/code", text: "Select" }, + { id: 74, link: "/projects/sistent/components/radiogroup", text: "RadioGroup" }, + { id: 75, link: "/projects/sistent/components/radiogroup/guidance", text: "RadioGroup" }, + { id: 76, link: "/projects/sistent/components/radiogroup/code", text: "RadioGroup" }, - { id: 77, link: "/projects/sistent/components/stack", text: "Stack" }, - { id: 78, link: "/projects/sistent/components/stack/guidance", text: "Stack" }, - { id: 79, link: "/projects/sistent/components/stack/code", text: "Stack" }, + { id: 77, link: "/projects/sistent/components/select", text: "Select" }, + { id: 78, link: "/projects/sistent/components/select/guidance", text: "Select" }, + { id: 79, link: "/projects/sistent/components/select/code", text: "Select" }, - { id: 80, link: "/projects/sistent/components/stepper", text: "Stepper" }, - { id: 81, link: "/projects/sistent/components/stepper/guidance", text: "Stepper" }, - { id: 82, link: "/projects/sistent/components/stepper/code", text: "Stepper" }, + { id: 80, link: "/projects/sistent/components/stack", text: "Stack" }, + { id: 81, link: "/projects/sistent/components/stack/guidance", text: "Stack" }, + { id: 82, link: "/projects/sistent/components/stack/code", text: "Stack" }, - { id: 83, link: "/projects/sistent/components/switch", text: "Switch" }, - { id: 84, link: "/projects/sistent/components/switch/guidance", text: "Switch" }, - { id: 85, link: "/projects/sistent/components/switch/code", text: "Switch" }, + { id: 83, link: "/projects/sistent/components/stepper", text: "Stepper" }, + { id: 84, link: "/projects/sistent/components/stepper/guidance", text: "Stepper" }, + { id: 85, link: "/projects/sistent/components/stepper/code", text: "Stepper" }, - { id: 86, link: "/projects/sistent/components/tabs", text: "Tabs" }, - { id: 87, link: "/projects/sistent/components/tabs/guidance", text: "Tabs" }, - { id: 88, link: "/projects/sistent/components/tabs/code", text: "Tabs" }, + { id: 86, link: "/projects/sistent/components/switch", text: "Switch" }, + { id: 87, link: "/projects/sistent/components/switch/guidance", text: "Switch" }, + { id: 88, link: "/projects/sistent/components/switch/code", text: "Switch" }, - { id: 89, link: "/projects/sistent/components/text-field", text: "Text Field" }, - { id: 90, link: "/projects/sistent/components/text-field/guidance", text: "Text Field" }, - { id: 91, link: "/projects/sistent/components/text-field/code", text: "Text Field" }, + { id: 89, link: "/projects/sistent/components/tabs", text: "Tabs" }, + { id: 90, link: "/projects/sistent/components/tabs/guidance", text: "Tabs" }, + { id: 91, link: "/projects/sistent/components/tabs/code", text: "Tabs" }, - { id: 92, link: "/projects/sistent/components/text-input", text: "Text Input" }, - { id: 93, link: "/projects/sistent/components/text-input/guidance", text: "Text Input" }, - { id: 94, link: "/projects/sistent/components/text-input/code", text: "Text Input" }, + { id: 92, link: "/projects/sistent/components/text-field", text: "Text Field" }, + { id: 93, link: "/projects/sistent/components/text-field/guidance", text: "Text Field" }, + { id: 94, link: "/projects/sistent/components/text-field/code", text: "Text Field" }, - { id: 95, link: "/projects/sistent/components/toolbar", text: "Toolbar" }, - { id: 96, link: "/projects/sistent/components/toolbar/guidance", text: "Toolbar" }, - { id: 97, link: "/projects/sistent/components/toolbar/code", text: "Toolbar" }, + { id: 95, link: "/projects/sistent/components/text-input", text: "Text Input" }, + { id: 96, link: "/projects/sistent/components/text-input/guidance", text: "Text Input" }, + { id: 97, link: "/projects/sistent/components/text-input/code", text: "Text Input" }, - { id: 98, link: "/projects/sistent/components/tooltip", text: "Tooltip" }, - { id: 99, link: "/projects/sistent/components/tooltip/guidance", text: "Tooltip" }, - { id: 100, link: "/projects/sistent/components/tooltip/code", text: "Tooltip" }, + { id: 98, link: "/projects/sistent/components/toolbar", text: "Toolbar" }, + { id: 99, link: "/projects/sistent/components/toolbar/guidance", text: "Toolbar" }, + { id: 100, link: "/projects/sistent/components/toolbar/code", text: "Toolbar" }, + + { id: 101, link: "/projects/sistent/components/tooltip", text: "Tooltip" }, + { id: 102, link: "/projects/sistent/components/tooltip/guidance", text: "Tooltip" }, + { id: 103, link: "/projects/sistent/components/tooltip/code", text: "Tooltip" }, ]; diff --git a/src/sections/Projects/Sistent/components/content.js b/src/sections/Projects/Sistent/components/content.js index a7fcf0e32e2af..6a79dc721a6a7 100644 --- a/src/sections/Projects/Sistent/components/content.js +++ b/src/sections/Projects/Sistent/components/content.js @@ -246,6 +246,13 @@ const componentsData = [ }, { id: 32, + name: "Menu", + description: "Menu provides a way to display a list of options to the user.", + url: "/projects/sistent/components/menu", + src: "/menu", + }, + { + id: 33, name: "Stack", description: "Stack is a layout component that arranges elements in a one-dimensional flow with customizable spacing and direction.", url: "/projects/sistent/components/stack", diff --git a/src/sections/Projects/Sistent/components/menu/code.js b/src/sections/Projects/Sistent/components/menu/code.js new file mode 100644 index 0000000000000..23d1ade008506 --- /dev/null +++ b/src/sections/Projects/Sistent/components/menu/code.js @@ -0,0 +1,277 @@ +import React from "react"; +import { navigate } from "gatsby"; +import { useLocation } from "@reach/router"; + +import { SistentLayout } from "../../sistent-layout"; +import TabButton from "../../../../../reusecore/Button"; +import { useStyledDarkMode } from "../../../../../theme/app/useStyledDarkMode"; +import { SistentThemeProvider, Menu, MenuItem, MenuList, Button } from "@sistent/sistent"; +import { CodeBlock } from "../button/code-block"; + +const codes = [ + // Basic menu + ` + + + Profile + My account + Logout + + `, + // Positioned menu + ` + + + Settings + Help + + `, + // Menu item states + ` + + + + Selected + + + Disabled + + Regular + + `, + // Long menu with max height and auto focus item + ` + + + {["Profile","My account","Dashboard","Settings","Billing","Support","Sign out"].map((label) => ( + {label} + ))} + + `, + // Standalone MenuList + ` + + Selected + Regular + Disabled + + `, + // MenuItem as link + ` + + Profile + My account + + `, +]; + +const MenuCode = () => { + const location = useLocation(); + const { isDark } = useStyledDarkMode(); + + // Example 1 + const [anchorEl, setAnchorEl] = React.useState(null); + const open = Boolean(anchorEl); + const handleOpen = (e) => setAnchorEl(e.currentTarget); + const handleClose = () => setAnchorEl(null); + + // Example 2 (positioned) + const [anchorEl2, setAnchorEl2] = React.useState(null); + const open2 = Boolean(anchorEl2); + const handleOpen2 = (e) => setAnchorEl2(e.currentTarget); + const handleClose2 = () => setAnchorEl2(null); + + // Example 3 (states) + const [anchorEl3, setAnchorEl3] = React.useState(null); + const open3 = Boolean(anchorEl3); + const handleOpen3 = (e) => setAnchorEl3(e.currentTarget); + const handleClose3 = () => setAnchorEl3(null); + + // Example 4 (long) + const [anchorEl4, setAnchorEl4] = React.useState(null); + const open4 = Boolean(anchorEl4); + const handleOpen4 = (e) => setAnchorEl4(e.currentTarget); + const handleClose4 = () => setAnchorEl4(null); + + return ( + +
+ +

Menu

+
+

+ Menu is the anchored container that manages positioning, anchoring, focus, and + open/close behavior. It typically wraps a MenuList, which renders the list of + MenuItem options and handles keyboard navigation. +

+ +
+ navigate("/projects/sistent/components/menu")} + title="Overview" + /> + navigate("/projects/sistent/components/menu/guidance")} + title="Guidance" + /> + navigate("/projects/sistent/components/menu/code")} + title="Code" + /> +
+ +
+ {/* Basic Menu */} + +

Basic Menu

+
+

Attach the menu to a trigger using anchorEl and control its visibility with open.

+
+
+ + + + Profile + My account + Logout + + +
+ +
+ + {/* Positioned Menu */} + +

Positioned Menu

+
+

Control menu placement with anchorOrigin and transformOrigin.

+
+
+ + + + Settings + Help + + +
+ +
+ + {/* Menu Item States */} + +

Menu Item States

+
+

Communicate state with selected and disabled props on MenuItem.

+
+
+ + + + + Selected + + + Disabled + + Regular + + +
+ +
+ + {/* Long Menu */} + +

Long Menu

+
+

Constrain menu size with PaperProps and enable keyboard focus with MenuListProps.autoFocusItem.

+
+
+ + + + {["Profile","My account","Dashboard","Settings","Billing","Support","Sign out"].map((label) => ( + {label} + ))} + + +
+ +
+ + {/* Standalone MenuList */} + +

Standalone MenuList

+
+

Use MenuList directly to manage keyboard focus and selection among items without an anchored surface.

+
+
+ + + Selected + Regular + Disabled + + +
+ +
+ + {/* MenuItem as link */} + +

MenuItem as Link

+
+

Render MenuItem as an anchor by setting component="a" and href.

+
+
+ + + Profile + My account + + +
+ +
+
+
+
+ ); +}; + +export default MenuCode; + diff --git a/src/sections/Projects/Sistent/components/menu/guidance.js b/src/sections/Projects/Sistent/components/menu/guidance.js new file mode 100644 index 0000000000000..511848526fa74 --- /dev/null +++ b/src/sections/Projects/Sistent/components/menu/guidance.js @@ -0,0 +1,128 @@ +import React from "react"; +import { navigate } from "gatsby"; +import { useLocation } from "@reach/router"; + +import TabButton from "../../../../../reusecore/Button"; +import { SistentLayout } from "../../sistent-layout"; + +const MenuGuidance = () => { + const location = useLocation(); + + return ( + +
+ +

Menu

+
+

+ Menu is the anchored container that manages positioning, anchoring, focus, and + open/close behavior. It typically wraps a MenuList, which renders the list of + MenuItem options and manages their keyboard navigation and accessibility roles. +

+ +
+ navigate("/projects/sistent/components/menu")} + title="Overview" + /> + navigate("/projects/sistent/components/menu/guidance")} + title="Guidance" + /> + navigate("/projects/sistent/components/menu/code")} + title="Code" + /> +
+ +
+ +

Usage

+
+
    +
  • Contextual actions: Offer actions related to a selected item.
  • +
  • Navigation: Provide quick navigation choices within a workflow.
  • +
  • Dense choices: Present multiple related options without overwhelming the UI.
  • +
+ + +

Behavior

+
+
    +
  • Anchoring and visibility (Menu): Use anchorEl and open; handle dismissal via onClose.
  • +
  • Positioning (Menu): Control placement with anchorOrigin and transformOrigin; uses Popover internally.
  • +
  • Keyboard navigation (MenuList): Arrow keys and Home/End move focus across items; Enter/Space selects; Esc closes via Menu.
  • +
  • Dismissal: Clicking outside or selecting an item should close the menu and return focus to the trigger.
  • +
+ + +

Design Guidelines

+
+
    +
  • Anchoring (Menu): Align to the trigger using anchorOrigin and transformOrigin.
  • +
  • Content (MenuList): Keep item labels concise; avoid deep nesting; communicate selected/disabled states.
  • +
  • Responsiveness (Menu): Ensure the surface doesn’t overflow the viewport; constrain with PaperProps.
  • +
+ + +

Accessibility

+
+
    +
  • Provide an accessible trigger with appropriate labeling and aria-haspopup="menu"/aria-controls when applicable.
  • +
  • Roles: Menu surface hosts a MenuList with role="menu"; items use role="menuitem".
  • +
  • Ensure focus is moved into the menu on open and returned to the trigger on close.
  • +
  • Use clear, descriptive text in MenuItem labels; avoid ambiguous wording.
  • +
+ + +

When to use

+
+
    +
  • When a user needs to pick from a short list of related actions.
  • +
  • When actions are secondary and should not be permanently visible.
  • +
+ + +

When not to use

+
+
    +
  • For primary navigation across the site (use Tabs, Sidebar, or Navigation components instead).
  • +
  • For long or scrollable lists of options; consider a Select or Dialog instead.
  • +
+ + +

MenuItem

+
+
    +
  • Purpose: Actionable item inside a menu or menu-like list.
  • +
  • Common props: selected, disabled, autoFocus, dense, divider, disableGutters.
  • +
  • Navigation: Render as a link using component="a" with href.
  • +
  • Accessibility: Uses appropriate ARIA roles when inside a menu; ensure meaningful labels.
  • +
+ + +

MenuList

+
+
    +
  • Purpose: Manages keyboard focus and selection among nested MenuItem elements.
  • +
  • Common props: autoFocus, autoFocusItem, dense, disableListWrap, variant.
  • +
  • Usage: Used internally by Menu, or standalone when you don't need an anchored surface. Does not handle positioning or anchoring.
  • +
  • Accessibility: Typically uses role="menu"; ensure correct context and focus return to trigger.
  • +
+
+
+
+ ); +}; + +export default MenuGuidance; + diff --git a/src/sections/Projects/Sistent/components/menu/index.js b/src/sections/Projects/Sistent/components/menu/index.js new file mode 100644 index 0000000000000..c95a2fa7d7303 --- /dev/null +++ b/src/sections/Projects/Sistent/components/menu/index.js @@ -0,0 +1,126 @@ +import React from "react"; +import { navigate } from "gatsby"; +import { useLocation } from "@reach/router"; + +import { + SistentThemeProvider, + Menu, + MenuItem, + Button, +} from "@sistent/sistent"; +import TabButton from "../../../../../reusecore/Button"; +import { SistentLayout } from "../../sistent-layout"; +import { Row } from "../../../../../reusecore/Layout"; +import { useStyledDarkMode } from "../../../../../theme/app/useStyledDarkMode"; + +const SistentMenu = () => { + const location = useLocation(); + const { isDark } = useStyledDarkMode(); + + const [anchorEl, setAnchorEl] = React.useState(null); + const open = Boolean(anchorEl); + const handleOpen = (event) => setAnchorEl(event.currentTarget); + const handleClose = () => setAnchorEl(null); + + return ( + +
+ +

Menu

+
+

+ Menu is the anchored container (shell) that manages positioning, anchoring, + opening/closing, focus management, and transitions. It typically wraps a + MenuList, which renders the list of MenuItem options and handles + keyboard navigation. +

+ +
+ navigate("/projects/sistent/components/menu")} + title="Overview" + /> + + navigate("/projects/sistent/components/menu/guidance") + } + title="Guidance" + /> + navigate("/projects/sistent/components/menu/code")} + title="Code" + /> +
+ +
+ +

Basic Menu

+
+

+ Menus are anchored to a control (usually a button). Clicking the + control opens the menu. Select an item to perform an action or close + the menu. +

+ + + + + Profile + My account + Logout + + + + + +

Positioning

+
+

+ Use anchorEl and origin props to control where the Menu appears + relative to its trigger. Menu uses Popover internally and manages focus + and dismissal via open and onClose. +

+ + +

MenuItem

+
+

+ MenuItem represents an actionable option within a menu. Use props like + selected, disabled, and autoFocus to communicate state, or render as a link with + component="a" and href. +

+ + +

MenuList

+
+

+ MenuList renders the list of options and manages keyboard navigation (Arrow keys, Home/End) and roles + (e.g., role="menu"). It does not handle positioning or anchoring—that is the responsibility of Menu. + Use it standalone when you need menu-like behavior without a floating surface. +

+
+
+
+ ); +}; + +export default SistentMenu; +