Skip to content

feat!: externalize sidebar toggle and remove navOpen state from the SDK#3088

Merged
oliverlaz merged 10 commits intomasterfrom
fix/hide-toggle-sidebar-without-channel-list
Apr 8, 2026
Merged

feat!: externalize sidebar toggle and remove navOpen state from the SDK#3088
oliverlaz merged 10 commits intomasterfrom
fix/hide-toggle-sidebar-without-channel-list

Conversation

@oliverlaz
Copy link
Copy Markdown
Member

@oliverlaz oliverlaz commented Apr 2, 2026

🎯 Goal

The SDK currently couples itself to a specific layout pattern (collapsible sidebar) by owning navOpen state in ChatContext. This creates problems — e.g., the sidebar toggle renders even when no sidebar exists — and prevents apps from fully controlling their own layout.

This PR removes all sidebar state management from the SDK and makes the app fully responsible for sidebar visibility.

🛠 Implementation details

Sidebar toggle externalized (commit 1-3):

  • Removed ToggleSidebarButton component from the SDK
  • Added SidebarToggle slot to ComponentContext — apps provide their own toggle via WithComponents
  • All 4 headers (ChannelHeader, ChannelListHeader, ThreadHeader, ThreadListHeader) render the slot when provided
  • Removed IconSidebar (moved to vite example), MenuIcon prop, ToggleButtonIcon prop

navOpen state removed (commit 4):

  • Removed navOpen, closeMobileNav, openMobileNav from ChatContextValue
  • Removed initialNavOpen from ChatProps
  • Removed NAV_SIDEBAR_DESKTOP_BREAKPOINT constant, useMobileNavigation hook, useIsMobileViewport hook
  • Removed auto-close-on-channel-selection (mobile) from setActiveChannel
  • Removed auto-close-on-thread-click from ThreadListItemUI
  • Removed openMobileNav calls from ChatViewSelector buttons
  • Removed all 7 navOpen-dependent CSS classes and their SCSS rules from 6 files

Vite example updated:

  • New SidebarContext (SidebarProvider + useSidebar) replaces SDK nav state
  • SidebarToggle uses app-level sidebar state
  • Layout panels read sidebarOpen from app context
  • Resize handle toggles app-level sidebar state
  • CSS rules hide the expand toggle when sidebar is visible (mutual exclusivity)

🎨 UI Changes

No visual changes in the vite example — sidebar toggle behavior is identical. Apps that don't provide a SidebarToggle will have no toggle button in any header.

⚠️ Breaking changes

Removed API Migration
ChatContextValue.navOpen Own your sidebar state
ChatContextValue.closeMobileNav / openMobileNav Own your toggle functions
ChatProps.initialNavOpen Move to own state initializer
NAV_SIDEBAR_DESKTOP_BREAKPOINT Define own constant
useMobileNavigation hook Implement own click-outside logic
ToggleSidebarButton component Provide SidebarToggle via WithComponents
MenuIcon / ToggleButtonIcon props Use SidebarToggle slot instead
7 navOpen CSS classes Apply own classes from own state

… rendered

The expand button in ChannelHeader is pointless when there is no
ChannelList in the component tree. Use the existing ChannelListContext
to detect whether a ChannelList is present and conditionally render
the button.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 2, 2026

Size Change: -3.36 kB (-0.55%)

Total Size: 606 kB

📦 View Changed
Filename Size Change
dist/cjs/emojis.js 2.96 kB -1 B (-0.03%)
dist/cjs/index.js 234 kB -1.21 kB (-0.52%)
dist/cjs/WithAudioPlayback.js 42.4 kB -125 B (-0.29%)
dist/css/index.css 44.9 kB -604 B (-1.33%)
dist/es/index.mjs 232 kB -1.28 kB (-0.55%)
dist/es/WithAudioPlayback.mjs 42.2 kB -136 B (-0.32%)
ℹ️ View Unchanged
Filename Size
dist/cjs/audioProcessing.js 1.32 kB
dist/cjs/mp3-encoder.js 1.27 kB
dist/css/emoji-replacement.css 456 B
dist/es/audioProcessing.mjs 1.31 kB
dist/es/emojis.mjs 2.47 kB
dist/es/mp3-encoder.mjs 756 B

compressed-size-action

Verify the button is hidden without ChannelList and shown with it.
Update existing tests to provide ChannelListContext where needed.
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 2, 2026

Codecov Report

❌ Patch coverage is 85.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.45%. Comparing base (8317b73) to head (0bc0dbd).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/components/ChatView/ChatView.tsx 60.00% 2 Missing ⚠️
...components/Threads/ThreadList/ThreadListItemUI.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3088      +/-   ##
==========================================
+ Coverage   80.44%   80.45%   +0.01%     
==========================================
  Files         414      411       -3     
  Lines       11975    11901      -74     
  Branches     3862     3835      -27     
==========================================
- Hits         9633     9575      -58     
+ Misses       2342     2326      -16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…nent

Remove ToggleSidebarButton from the SDK and replace it with a
SidebarToggle slot in ComponentContext. Apps provide their own toggle
component via WithComponents; the SDK renders it in the appropriate
header slots with conditional visibility:

- ChannelHeader/ThreadHeader: render when sidebar is collapsed
- ChannelListHeader: render when a channel is active
- ThreadListHeader: render when a thread is active

Also removes IconSidebar (moved to vite example), MenuIcon prop
from ChannelHeader/ThreadHeader, and ToggleButtonIcon prop from
ChannelListHeader/ThreadListHeader.
@oliverlaz oliverlaz changed the title fix(ChannelHeader): hide toggle sidebar button when no ChannelList is rendered feat: make sidebar toggle an externally-provided component via ComponentContext Apr 3, 2026
@oliverlaz oliverlaz changed the title feat: make sidebar toggle an externally-provided component via ComponentContext fix: make sidebar toggle an externally-provided component via ComponentContext Apr 3, 2026
BREAKING CHANGE: The SDK no longer manages sidebar visibility. The
following public APIs have been removed:

- `ChatContextValue.navOpen`, `closeMobileNav`, `openMobileNav`
- `ChatProps.initialNavOpen`
- `NAV_SIDEBAR_DESKTOP_BREAKPOINT` exported constant
- `useMobileNavigation` exported hook

Sidebar toggle is now fully app-owned. Apps provide a `SidebarToggle`
component via `WithComponents` and manage their own open/close state.

The vite example app demonstrates this with a new `SidebarContext`
that replaces the SDK's nav state.

Also removes all navOpen-dependent CSS classes and SCSS rules from
the SDK, and deletes `useMobileNavigation` and `useIsMobileViewport`
hooks.
@oliverlaz oliverlaz changed the title fix: make sidebar toggle an externally-provided component via ComponentContext feat!: externalize sidebar toggle and remove navOpen state from the SDK Apr 7, 2026
…Content

Split the single SidebarToggle slot into two generic slots:

- HeaderStartContent: rendered at the start of content headers
  (ChannelHeader, ThreadHeader)
- HeaderEndContent: rendered at the end of sidebar headers
  (ChannelListHeader, ThreadListHeader)

These are position-aware, generic slots that can serve any purpose
(sidebar toggle, breadcrumbs, back button, etc.).
@oliverlaz oliverlaz merged commit dc16bb5 into master Apr 8, 2026
8 checks passed
@oliverlaz oliverlaz deleted the fix/hide-toggle-sidebar-without-channel-list branch April 8, 2026 09:53
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.

2 participants