Skip to content

Commit c53d1d3

Browse files
committed
fix(app): less auto-expand/collapse
1 parent f386137 commit c53d1d3

3 files changed

Lines changed: 29 additions & 74 deletions

File tree

packages/ui/src/components/context-tool-results.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,9 @@ export function ContextToolGroupHeader(props: {
5858
<ToolCall
5959
variant="row"
6060
icon="magnifying-glass-menu"
61-
open={!props.pending && props.open}
62-
showArrow={!props.pending}
63-
onOpenChange={(v) => {
64-
if (!props.pending) props.onOpenChange(v)
65-
}}
61+
open={props.open}
62+
showArrow
63+
onOpenChange={props.onOpenChange}
6664
trigger={
6765
<div data-component="context-tool-group-trigger" data-pending={props.pending || undefined}>
6866
<span

packages/ui/src/components/message-part.tsx

Lines changed: 15 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { usePageVisibility } from "@solid-primitives/page-visibility"
21
import { Component, createEffect, createMemo, createSignal, For, Match, on, Show, Switch, type JSX } from "solid-js"
32
import stripAnsi from "strip-ansi"
43
import { createStore } from "solid-js/store"
@@ -39,7 +38,7 @@ import { TextShimmer } from "./text-shimmer"
3938
import { list } from "./text-utils"
4039
import { GrowBox } from "./grow-box"
4140
import { COLLAPSIBLE_SPRING } from "./motion"
42-
import { busy, hold, createThrottledValue, useToolFade, useContextToolPending } from "./tool-utils"
41+
import { busy, createThrottledValue, useToolFade, useContextToolPending } from "./tool-utils"
4342
import { ContextToolGroupHeader, ContextToolExpandedList, ContextToolRollingResults } from "./context-tool-results"
4443
import { ShellRollingResults } from "./shell-rolling-results"
4544

@@ -273,19 +272,6 @@ function createGroupOpenState() {
273272
return { read, controlled, write }
274273
}
275274

276-
function shouldCollapseGroup(
277-
statuses: (string | undefined)[],
278-
opts: { afterTool?: boolean; groupTail?: boolean; working?: boolean },
279-
pageVisible: () => boolean,
280-
) {
281-
if (opts.afterTool) return true
282-
if (opts.groupTail === false) return true
283-
if (!pageVisible()) return false
284-
if (opts.working) return false
285-
if (!statuses.length) return false
286-
return !statuses.some((s) => busy(s))
287-
}
288-
289275
function renderable(part: PartType, showReasoningSummaries = true) {
290276
if (part.type === "tool") {
291277
if (HIDDEN_TOOLS.has(part.tool)) return false
@@ -363,7 +349,6 @@ export function AssistantParts(props: {
363349
}) {
364350
const data = useData()
365351
const emptyParts: PartType[] = []
366-
const pageVisible = usePageVisibility()
367352
const groupState = createGroupOpenState()
368353
const grouped = createMemo(() => {
369354
const keys: string[] = []
@@ -481,24 +466,9 @@ export function AssistantParts(props: {
481466
return COLLAPSIBLE_SPRING
482467
})
483468
const contextOpen = createMemo(() => {
484-
const collapse = (
485-
afterTool?: boolean,
486-
groupTail?: boolean,
487-
group?: { part: ToolPart; message: AssistantMessage }[],
488-
) =>
489-
shouldCollapseGroup(
490-
group?.map((item) => item.part.state.status) ?? [],
491-
{
492-
afterTool,
493-
groupTail,
494-
working: props.working,
495-
},
496-
pageVisible,
497-
)
498469
const value = ctx()
499-
if (value) return groupState.read(value.groupKey, collapse(value.afterTool, value.tail, value.parts))
500-
const entry = part()
501-
return groupState.read(entry?.groupKey, collapse(entry?.afterTool, entry?.groupTail, entry?.groupParts))
470+
if (value) return groupState.read(value.groupKey, true)
471+
return groupState.read(part()?.groupKey, true)
502472
})
503473
const visible = createMemo(() => {
504474
if (!context()) return true
@@ -544,9 +514,7 @@ export function AssistantParts(props: {
544514
ctxPartsPrev = result
545515
return result
546516
})
547-
const ctxPendingRaw = useContextToolPending(ctxParts, () => !!(props.working && ctx()?.tail))
548-
const ctxPending = ctxPendingRaw
549-
const ctxHoldOpen = hold(ctxPendingRaw)
517+
const ctxPending = useContextToolPending(ctxParts, () => !!(props.working && ctx()?.tail))
550518
const shell = createMemo(() => {
551519
const value = part()
552520
if (!value) return
@@ -598,12 +566,20 @@ export function AssistantParts(props: {
598566
onOpenChange={(value: boolean) => groupState.write(entry().groupKey, value)}
599567
/>
600568
</PartGrow>
601-
<ContextToolExpandedList parts={ctxParts()} expanded={!ctxPending() && contextOpen()} />
602-
<ContextToolRollingResults parts={ctxParts()} pending={ctxHoldOpen()} />
569+
<ContextToolExpandedList parts={ctxParts()} expanded={contextOpen() && !ctxPending()} />
570+
<ContextToolRollingResults parts={ctxParts()} pending={contextOpen() && ctxPending()} />
603571
</>
604572
)}
605573
</Show>
606-
<Show when={shell()}>{(value) => <ShellRollingResults part={value()} animate={props.animate} />}</Show>
574+
<Show when={shell()}>
575+
{(value) => (
576+
<ShellRollingResults
577+
part={value()}
578+
animate={props.animate}
579+
defaultOpen={props.shellToolDefaultOpen}
580+
/>
581+
)}
582+
</Show>
607583
<Show when={!shell() ? part() : undefined}>
608584
{(entry) => (
609585
<Show when={!entry().context}>

packages/ui/src/components/shell-rolling-results.tsx

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,7 @@ import { TextShimmer } from "./text-shimmer"
1010
import { Tooltip } from "./tooltip"
1111
import { GROW_SPRING } from "./motion"
1212
import { useSpring } from "./motion-spring"
13-
import {
14-
busy,
15-
createThrottledValue,
16-
hold,
17-
updateScrollMask,
18-
useCollapsible,
19-
useRowWipe,
20-
useToolFade,
21-
} from "./tool-utils"
13+
import { busy, createThrottledValue, updateScrollMask, useCollapsible, useRowWipe, useToolFade } from "./tool-utils"
2214

2315
function ShellRollingSubtitle(props: { text: string; animate?: boolean }) {
2416
let ref: HTMLSpanElement | undefined
@@ -176,24 +168,17 @@ function ShellExpanded(props: { cmd: string; out: string; open: boolean }) {
176168
)
177169
}
178170

179-
export function ShellRollingResults(props: { part: ToolPart; animate?: boolean }) {
171+
export function ShellRollingResults(props: { part: ToolPart; animate?: boolean; defaultOpen?: boolean }) {
180172
const i18n = useI18n()
181173
const reduce = useReducedMotion()
182174
const wiped = new Set<string>()
183175
const [mounted, setMounted] = createSignal(false)
184-
const [userToggled, setUserToggled] = createSignal(false)
185-
const [userOpen, setUserOpen] = createSignal(false)
176+
const [open, setOpen] = createSignal(props.defaultOpen ?? true)
186177
onMount(() => setMounted(true))
187178
const state = createMemo(() => props.part.state as Record<string, any>)
188179
const pending = createMemo(() => busy(props.part.state.status))
189-
const autoOpen = hold(pending, 2000)
190-
const effectiveOpen = createMemo(() => {
191-
if (pending()) return true
192-
if (userToggled()) return userOpen()
193-
return autoOpen()
194-
})
195-
const expanded = createMemo(() => !pending() && !autoOpen() && userToggled() && userOpen())
196-
const previewOpen = createMemo(() => effectiveOpen() && !expanded())
180+
const expanded = createMemo(() => open() && !pending())
181+
const previewOpen = createMemo(() => open() && pending())
197182
const command = createMemo(() => {
198183
const value = state().input?.command ?? state().metadata?.command
199184
if (typeof value === "string") return value
@@ -217,12 +202,10 @@ export function ShellRollingResults(props: { part: ToolPart; animate?: boolean }
217202
const headerHeight = useSpring(() => (mounted() ? 37 : 0), GROW_SPRING)
218203
let headerClipRef: HTMLDivElement | undefined
219204
const handleHeaderClick = () => {
220-
if (pending()) return
221205
const el = headerClipRef
222206
const viewport = el?.closest(".scroll-view__viewport") as HTMLElement | null
223207
const beforeY = el?.getBoundingClientRect().top ?? 0
224-
setUserToggled(true)
225-
setUserOpen((prev) => !prev)
208+
setOpen((prev) => !prev)
226209
if (viewport && el) {
227210
requestAnimationFrame(() => {
228211
const afterY = el.getBoundingClientRect().top
@@ -249,7 +232,7 @@ export function ShellRollingResults(props: { part: ToolPart; animate?: boolean }
249232
ref={headerClipRef}
250233
data-slot="shell-rolling-header-clip"
251234
data-scroll-preserve
252-
data-clickable={!pending() ? "true" : "false"}
235+
data-clickable="true"
253236
onClick={handleHeaderClick}
254237
style={{ height: `${skip() ? (mounted() ? 37 : 0) : headerHeight()}px`, overflow: "clip" }}
255238
>
@@ -258,13 +241,11 @@ export function ShellRollingResults(props: { part: ToolPart; animate?: boolean }
258241
<TextShimmer text={i18n.t("ui.tool.shell")} active={pending()} />
259242
</span>
260243
<Show when={subtitle()}>{(text) => <ShellRollingSubtitle text={text()} animate={props.animate} />}</Show>
261-
<Show when={!pending()}>
262-
<span data-slot="shell-rolling-actions">
263-
<span data-slot="shell-rolling-arrow" data-open={effectiveOpen() ? "true" : "false"}>
264-
<Icon name="chevron-down" size="small" />
265-
</span>
244+
<span data-slot="shell-rolling-actions">
245+
<span data-slot="shell-rolling-arrow" data-open={open() ? "true" : "false"}>
246+
<Icon name="chevron-down" size="small" />
266247
</span>
267-
</Show>
248+
</span>
268249
</div>
269250
</div>
270251
<div

0 commit comments

Comments
 (0)