'use client'; import {IconButton} from '@astryxdesign/core/IconButton'; import {Icon} from '@astryxdesign/core/Icon'; import {ICONS} from '@/shared/utils/icons'; import {useSidebar} from './SidebarProvider'; /** * The one control that is never absent. * * It renders in the top bar's leading slot at EVERY width — the header is the * only region of the shell that survives all three navigation states, so it is * the only place a control can live and still be reachable when the nav it * governs is collapsed or gone. Anything mounted inside the sidebar disappears * with the sidebar, which is exactly how the rail became unreopenable. * * Three states, one button: * drawer closed ☰ → open the overlay * drawer open ☰ → close it (aria-expanded carries the state) * rail collapsed panel-open → expand to 260px * rail expanded panel-close → collapse to 84px * * 44px square below the breakpoint: IconButton's `lg` is 36px, which clears * neither the WCAG 2.2 target-size minimum nor a thumb. `size-11` is the * spacing-11 token (44px) through the Tailwind bridge, and it sits in the * utilities layer so it wins over Astryx's own sizing without !important. */ export function NavMenuButton() { const {isDrawer, isDrawerOpen, isCollapsed, toggle, controlsId} = useSidebar(); const label = isDrawer ? isDrawerOpen ? 'Close navigation menu' : 'Open navigation menu' : isCollapsed ? 'Expand navigation' : 'Collapse navigation'; const icon = isDrawer ? ICONS.menu : isCollapsed ? ICONS.sidebarOpen : ICONS.sidebarClose; return ( } label={label} tooltip={label} variant="ghost" size={isDrawer ? 'lg' : 'md'} onClick={toggle} // Expanded/collapsed is the drawer's state; above the breakpoint the rail // is always present, so only its width changes and aria-expanded would be // a lie. aria-controls still points at the rail so the relationship holds. aria-expanded={isDrawer ? isDrawerOpen : undefined} aria-controls={controlsId} className={isDrawer ? 'size-11' : undefined} data-testid="nav-menu-button" /> ); }