Skip to content

✨ feat: responsive collapse and drawer behavior for Sidebar#626

Merged
futjesus merged 3 commits intomainfrom
feat/sidebar-responsive-collapse-drawer
Apr 28, 2026
Merged

✨ feat: responsive collapse and drawer behavior for Sidebar#626
futjesus merged 3 commits intomainfrom
feat/sidebar-responsive-collapse-drawer

Conversation

@futjesus
Copy link
Copy Markdown
Member

Summary

Makes the Sidebar fully responsive with three viewport-driven modes:

Viewport Mode Behavior
>= 1024px expanded Current behavior — labels and group titles visible.
640 – 1023px collapsed Icon-only, group titles hidden, NavigationSeparator auto-injected between groups.
< 640px drawer The <aside> is replaced by a hamburger trigger that opens the sidebar content inside a left Drawer in expanded form.

Design reference (Figma):

What changed

New public API

  • useMediaQuery(query) — SSR-safe hook, exported from the library.
  • <Sidebar.Label> — auto-hides in collapsed mode, replacing the manual hidden md:block pattern consumers had to repeat on every label.
  • mode?: 'auto' | 'expanded' | 'collapsed' | 'drawer' prop on Sidebar (default auto = viewport-driven; the others are manual overrides for tests, stories, or forced layouts).

Internal additions

  • SidebarContext + useSidebarContext for distributing the active mode to descendants.
  • useSidebarMode hook that resolves the mode from the viewport or the mode prop.
  • HamburgerTrigger component for the drawer mode.

Behavior changes on existing components

  • NavigationGroup hides its title when collapsed.
  • Navigation auto-injects a NavigationSeparator between NavigationGroup siblings when collapsed (without duplicating separators the consumer added manually).
  • Wrapper now resolves the mode and renders either <aside> or HamburgerTrigger + Drawer accordingly.

Styling (minimal and targeted)

  • NavigationSeparator.variants.ts: updated to match the thin horizontal line in the Figma designs (only stylistic change in this PR).
  • Logo.variants.ts and NavigationOption.variants.ts: the padding rules previously tied to the md: viewport breakpoint now use group-data-[mode=expanded]/sidebar:* selectors. Values are unchanged — they just follow the sidebar's mode instead of the viewport, which fixes an alignment bug where the 768–1023px range applied desktop padding inside the collapsed (w-18) aside.
  • Sidebar.variants.ts: width moved from w-18 md:w-64 to a mode CVA variant (w-18 / w-64).

Story

  • Sidebar.stories.tsx refactored to use <Sidebar.Label> and group-data-[mode=expanded]/sidebar:* selectors. Added CollapsedMode and DrawerMode stories for manual inspection.

Tests

  • tests/setup.ts: added a default window.matchMedia mock (required by the new hook).
  • Sidebar.test.tsx: new coverage for the three modes — labels/titles visibility, auto-injected separators, hamburger trigger, drawer opening with expanded content.

Test plan

  • npm run check:types passes.
  • npm run lint passes.
  • npm test passes (426 tests).
  • npm run build succeeds.
  • Storybook story In Review/SidebarSidebar:
    • At >= 1024px viewport: sidebar is expanded, labels and group titles visible.
    • At 640–1023px: sidebar collapses to icons only, a thin line separates groups, no group titles.
    • At < 640px: the <aside> disappears, a hamburger button shows in the top-left.
  • Storybook Sidebar at < 640px: click the hamburger → a Drawer opens from the left with labels and group titles visible. Escape / overlay click / X close it.
  • Storybook CollapsedMode story: icons only, separators between groups.
  • Storybook DrawerMode story: only the hamburger trigger is visible; clicking it opens the drawer.

Adapts the Sidebar to three viewport-driven modes:
- `>= 1024px`: expanded (current behavior).
- `640-1023px`: collapsed icon-only with auto-injected NavigationSeparator
  between groups and group titles hidden.
- `< 640px`: the aside is replaced by a hamburger trigger that opens the
  sidebar content inside a left Drawer in expanded form.

Introduces:
- useMediaQuery hook (SSR-safe) exported from the library.
- useSidebarMode + SidebarContext to distribute the active mode to
  descendants.
- Sidebar.Label - auto-hides text labels when collapsed, replacing the
  manual hidden md:block pattern consumers had to repeat.
- HamburgerTrigger button for the drawer mode.
- Optional mode prop on Sidebar (auto | expanded | collapsed | drawer)
  for manual override, tests and stories.

Fixes an alignment bug where md: padding on Logo and NavigationOption
was driven by the viewport and clashed with the collapsed mode in the
768-1023px range: the paddings are now driven by
group-data-[mode=expanded]/sidebar:* selectors so they stay tied to the
sidebar mode instead of the viewport.
@futjesus futjesus changed the title ✨ feat: responsive collapse and drawer behavior for Sidebar [🚧 WIP] ✨ feat: responsive collapse and drawer behavior for Sidebar Apr 23, 2026
…n hover reveal

- Drag-to-resize: disable transition during drag, set body cursor and
  prevent text selection, clear inline width when leaving expanded mode.
- Expose minWith / maxWith / initialWidth as optional props (defaults
  match prior hardcoded values: 240 / 300 / 256).
- Add expandOnHover (default true) and animateOnHover (default true)
  props. In collapsed mode, hovering a NavigationOption reveals its
  Label as an absolute-positioned overlay anchored to the right edge,
  animating max-width and opacity. The icon stays in place and the
  auto-injected separator between groups remains unobstructed.
- Update Sidebar.test.tsx: split the collapsed-mode label test into a
  strict "expandOnHover disabled" case and a clipped-in-DOM case for
  the new default.
…classNames

- drawerMaxWidth: cap the drawer panel width on mobile (default 280;
  width is min(viewport, drawerMaxWidth) so it shrinks on narrow phones).
- drawerBreakpoint / expandedBreakpoint: configurable viewport
  thresholds for auto mode (defaults 640 / 1024).
- triggerClassName: forward custom classes to the HamburgerTrigger
  button rendered in drawer mode.
- separatorClassName: applied to the auto-injected NavigationSeparator
  between groups in collapsed mode (passed via SidebarContext).
- Drop the slate-200 border-r the Drawer renders in left position by
  forcing border-r-0 on the panel — that border was the visible "white
  line" along the right edge of the mobile drawer.
@futjesus futjesus marked this pull request as ready for review April 28, 2026 21:27
@futjesus futjesus changed the title [🚧 WIP] ✨ feat: responsive collapse and drawer behavior for Sidebar ✨ feat: responsive collapse and drawer behavior for Sidebar Apr 28, 2026
@futjesus futjesus merged commit e340b5c into main Apr 28, 2026
1 check passed
@futjesus futjesus deleted the feat/sidebar-responsive-collapse-drawer branch April 28, 2026 21:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant