mirror of
https://github.com/block/buzz.git
synced 2026-11-04 08:21:48 +00:00
Fix thread reply pill behavior
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -265,6 +265,23 @@ export function ChannelScreen({
|
||||
(messageId: string) => directReplyIdsByParentId.get(messageId)?.[0] ?? null,
|
||||
[directReplyIdsByParentId],
|
||||
);
|
||||
const getReplyDescendantIdsForMessage = React.useCallback(
|
||||
(messageId: string) => {
|
||||
const descendantIds: string[] = [];
|
||||
const pendingIds = [...(directReplyIdsByParentId.get(messageId) ?? [])];
|
||||
|
||||
while (pendingIds.length > 0) {
|
||||
const currentId = pendingIds.pop();
|
||||
if (!currentId) continue;
|
||||
|
||||
descendantIds.push(currentId);
|
||||
pendingIds.push(...(directReplyIdsByParentId.get(currentId) ?? []));
|
||||
}
|
||||
|
||||
return descendantIds;
|
||||
},
|
||||
[directReplyIdsByParentId],
|
||||
);
|
||||
const threadPanelData = React.useMemo(
|
||||
() =>
|
||||
buildThreadPanelData(
|
||||
@@ -309,6 +326,7 @@ export function ChannelScreen({
|
||||
editTargetId,
|
||||
expandedThreadReplyIds,
|
||||
getFirstReplyIdForMessage,
|
||||
getReplyDescendantIdsForMessage,
|
||||
openThreadHeadId,
|
||||
sendMessageMutation,
|
||||
setExpandedThreadReplyIds,
|
||||
|
||||
@@ -21,6 +21,7 @@ export function useChannelPaneHandlers({
|
||||
editTargetId,
|
||||
expandedThreadReplyIds,
|
||||
getFirstReplyIdForMessage,
|
||||
getReplyDescendantIdsForMessage,
|
||||
openThreadHeadId,
|
||||
sendMessageMutation,
|
||||
setExpandedThreadReplyIds,
|
||||
@@ -36,6 +37,7 @@ export function useChannelPaneHandlers({
|
||||
editTargetId: string | null;
|
||||
expandedThreadReplyIds: ReadonlySet<string>;
|
||||
getFirstReplyIdForMessage: (messageId: string) => string | null;
|
||||
getReplyDescendantIdsForMessage: (messageId: string) => string[];
|
||||
openThreadHeadId: string | null;
|
||||
sendMessageMutation: ReturnType<typeof useSendMessageMutation>;
|
||||
setExpandedThreadReplyIds: React.Dispatch<React.SetStateAction<Set<string>>>;
|
||||
@@ -158,21 +160,33 @@ export function useChannelPaneHandlers({
|
||||
|
||||
const handleExpandThreadReplies = React.useCallback(
|
||||
(message: { id: string }) => {
|
||||
const firstReplyId = getFirstReplyIdForMessage(message.id);
|
||||
if (!expandedThreadReplyIdsRef.current.has(message.id)) {
|
||||
if (expandedThreadReplyIdsRef.current.has(message.id)) {
|
||||
const descendantIds = getReplyDescendantIdsForMessage(message.id);
|
||||
setExpandedThreadReplyIds((current) => {
|
||||
const next = new Set(current);
|
||||
next.add(message.id);
|
||||
next.delete(message.id);
|
||||
for (const descendantId of descendantIds) {
|
||||
next.delete(descendantId);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const firstReplyId = getFirstReplyIdForMessage(message.id);
|
||||
setExpandedThreadReplyIds((current) => {
|
||||
const next = new Set(current);
|
||||
next.add(message.id);
|
||||
return next;
|
||||
});
|
||||
|
||||
if (firstReplyId) {
|
||||
setThreadScrollTargetId(firstReplyId);
|
||||
}
|
||||
},
|
||||
[
|
||||
getFirstReplyIdForMessage,
|
||||
getReplyDescendantIdsForMessage,
|
||||
setExpandedThreadReplyIds,
|
||||
setThreadScrollTargetId,
|
||||
],
|
||||
|
||||
@@ -220,10 +220,6 @@ export function MessageThreadPanel({
|
||||
{threadReplies.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
{threadReplies.map((entry, index) => {
|
||||
const nextDepth =
|
||||
threadReplies[index + 1]?.message.depth ?? -1;
|
||||
const isExpanded = nextDepth > entry.message.depth;
|
||||
|
||||
return (
|
||||
<div key={entry.message.id}>
|
||||
<MessageRow
|
||||
@@ -246,9 +242,10 @@ export function MessageThreadPanel({
|
||||
onToggleReaction={onToggleReaction}
|
||||
profiles={profiles}
|
||||
/>
|
||||
{entry.summary && !isExpanded ? (
|
||||
{entry.summary ? (
|
||||
<MessageThreadSummaryRow
|
||||
depth={entry.message.depth}
|
||||
layoutVariant="thread-reply"
|
||||
message={entry.message}
|
||||
onOpenThread={onExpandReplies}
|
||||
summary={entry.summary}
|
||||
|
||||
@@ -30,17 +30,19 @@ function ParticipantAvatar({
|
||||
|
||||
export function MessageThreadSummaryRow({
|
||||
depth = 0,
|
||||
layoutVariant = "default",
|
||||
message,
|
||||
onOpenThread,
|
||||
summary,
|
||||
}: {
|
||||
depth?: number;
|
||||
layoutVariant?: "default" | "thread-reply";
|
||||
message: TimelineMessage;
|
||||
onOpenThread: (message: TimelineMessage) => void;
|
||||
summary: TimelineThreadSummary;
|
||||
}) {
|
||||
const visibleDepth = Math.min(Math.max(depth, 0), 6);
|
||||
const messageTextOffsetPx = 50;
|
||||
const messageTextOffsetPx = layoutVariant === "thread-reply" ? 8 : 50;
|
||||
const marginLeftPx = visibleDepth * 28 + messageTextOffsetPx;
|
||||
const depthGuideOffsets = Array.from(
|
||||
{ length: visibleDepth },
|
||||
|
||||
@@ -104,6 +104,7 @@ export const TimelineMessageList = React.memo(function TimelineMessageList({
|
||||
profiles={profiles}
|
||||
/>
|
||||
<MessageThreadSummaryRow
|
||||
depth={message.depth}
|
||||
message={message}
|
||||
onOpenThread={onReply}
|
||||
summary={summary}
|
||||
|
||||
Reference in New Issue
Block a user