Skip to content

Commit 70f3175

Browse files
committed
feat: add reveal intent to the slot geometry
1 parent 4fade8b commit 70f3175

11 files changed

Lines changed: 754 additions & 134 deletions

File tree

β€Žexamples/vite/src/App.tsxβ€Ž

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ import {
5353
OPTIONAL_THREAD_SLOT,
5454
} from './ChatLayout/constants.ts';
5555
import { ChatSkipNavigation } from './AccessibilityNavigation/ChatSkipNavigation.tsx';
56+
import { SlotGeometryProvider } from 'stream-chat-react/slot-geometry';
57+
import { AlsoSentInChannelIndicator } from './ChatLayout/AlsoSentInChannelIndicator.tsx';
5658
import { ChannelsPanels, ThreadsPanels } from './ChatLayout/Panels.tsx';
5759
import { SidebarProvider } from './ChatLayout/SidebarContext.tsx';
5860
import {
@@ -481,7 +483,6 @@ const App = () => {
481483
[initialPanelLayout.leftPanel.width, initialPanelLayout.threadPanel.width],
482484
);
483485

484-
// Memoized so the ChatView `views` map keeps a stable reference across renders.
485486
const chatViews = useMemo(
486487
() => ({
487488
channels: (
@@ -531,6 +532,10 @@ const App = () => {
531532
return (
532533
<WithComponents
533534
overrides={{
535+
// Coverage-aware "Also sent in channel β†’ View": records a reveal intent that a
536+
// channels-view effect resolves after navigation (works across the threads β†’ channels
537+
// switch; closes the covering thread only when it actually covers).
538+
MessageAlsoSentInChannelIndicator: AlsoSentInChannelIndicator,
534539
emojiSearchIndex: SearchIndex,
535540
EmojiPicker: EmojiPickerWithCustomOptions,
536541
NotificationList: ConfigurableNotificationList,
@@ -566,16 +571,22 @@ const App = () => {
566571
iconOnly={chatView.iconOnly}
567572
layoutRef={appLayoutRef}
568573
/>
569-
<ChatView
570-
dialogManagerId={globalDialogManager}
571-
layouts={chatViewLayouts}
572-
maxSlots={2}
573-
minSlots={2}
574-
views={chatViews}
575-
>
576-
<ChatStateSync initialChatView={initialChatView} />
577-
<SidebarLayoutSync />
578-
</ChatView>
574+
{/* Geometry provider spans the whole ChatView so slot-coverage state and the reveal
575+
intent are shared across views (the "Also sent in channel β†’ View" indicator sets
576+
the intent in the threads view; the channels panels resolve it after navigating).
577+
Instance-scoped β€” not a module singleton β€” so other chat surfaces don't collide. */}
578+
<SlotGeometryProvider>
579+
<ChatView
580+
dialogManagerId={globalDialogManager}
581+
layouts={chatViewLayouts}
582+
maxSlots={2}
583+
minSlots={2}
584+
views={chatViews}
585+
>
586+
<ChatStateSync initialChatView={initialChatView} />
587+
<SidebarLayoutSync />
588+
</ChatView>
589+
</SlotGeometryProvider>
579590
</div>
580591
</div>
581592
{/* The single-channel scenario floats over the full app in a draggable modal (the full

β€Žexamples/vite/src/ChatLayout/AlsoSentInChannelIndicator.tsxβ€Ž

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
import {
22
MessageAlsoSentInChannelIndicator,
3-
useChatViewNavigation,
43
useMessageAlsoSentInChannelNavigation,
54
} from 'stream-chat-react';
65
import { useSlotGeometry } from 'stream-chat-react/slot-geometry';
76

8-
import { CHANNEL_THREAD_SLOT, MAIN_CHANNEL_SLOT } from './constants';
7+
import { MAIN_CHANNEL_SLOT } from './constants';
98

109
/**
1110
* Coverage-aware "Also sent in channel" indicator. It reuses the SDK default component and its
12-
* navigation hook β€” no logic or markup is copied β€” and only augments the click: when jumping to the
13-
* channel from inside the reply thread, it first releases the thread slot **if** the geometry module
14-
* reports the channel column is actually obscured (collapsed under / covered by the thread) right
15-
* now. On wide side-by-side layouts the channel isn't obscured, so the thread stays open.
11+
* navigation hook β€” no logic or markup is copied β€” and only records a one-shot intent (on the
12+
* geometry provider) to reveal the channel column when jumping to it from inside a reply thread.
1613
*
17-
* Coverage is app-layout knowledge (this example's responsive CSS), so it lives here rather than in
18-
* the SDK β€” measured from real DOM rects, no breakpoint or class-name coupling.
14+
* The actual "close the covering thread" decision is deferred to a channels-view effect
15+
* (in `ResponsiveChannelPanels`), because it must run *after* navigation: in the cross-view
16+
* case (threads β†’ channels) the channel isn't mounted or measurable at click time. The effect closes
17+
* the thread only when the geometry plugin reports the channel is actually obscured, so wide
18+
* side-by-side layouts keep the thread. This scopes the behavior to this navigation only β€” it does
19+
* not change global channel-open semantics.
1920
*/
2021
export const AlsoSentInChannelIndicator = () => {
2122
const { isInThread, viewReference } = useMessageAlsoSentInChannelNavigation();
22-
const { close } = useChatViewNavigation();
23-
const { isObscured } = useSlotGeometry();
23+
const { requestReveal } = useSlotGeometry();
2424

2525
const onView = async () => {
26-
if (isInThread && isObscured(MAIN_CHANNEL_SLOT)) close(CHANNEL_THREAD_SLOT);
26+
if (isInThread) requestReveal(MAIN_CHANNEL_SLOT);
2727
await viewReference();
2828
};
2929

0 commit comments

Comments
Β (0)