diff --git a/packages/tui/src/component/dialog-open.tsx b/packages/tui/src/component/dialog-open.tsx
index 62cf0adbb32..65798ef29eb 100644
--- a/packages/tui/src/component/dialog-open.tsx
+++ b/packages/tui/src/component/dialog-open.tsx
@@ -1,6 +1,7 @@
import { createMemo, createResource, createSignal } from "solid-js"
import type { SessionInfo } from "@opencode-ai/client"
import { useTerminalDimensions } from "@opentui/solid"
+import type { RGBA } from "@opentui/core"
import { dialogWidth, useDialog } from "../ui/dialog"
import { DialogSelect, dialogSelectContentWidth } from "../ui/dialog-select"
import { useRoute } from "../context/route"
@@ -105,7 +106,7 @@ export function DialogOpen(props: { sessions: SessionInfo[] }) {
footer: `${name ? `${Locale.truncate(name, 20)} · ` : ""}${timeAgo(session.time.updated)}`,
onSelect: () => location.set(session.location),
gutter: running
- ? () =>
+ ? (color: RGBA) =>
: tabs.has(session.id)
? () => ▪
: undefined,
diff --git a/packages/tui/src/component/dialog-session-list.tsx b/packages/tui/src/component/dialog-session-list.tsx
index 200ed7ccb7f..08cee7a5a9f 100644
--- a/packages/tui/src/component/dialog-session-list.tsx
+++ b/packages/tui/src/component/dialog-session-list.tsx
@@ -2,6 +2,7 @@ import { createMemo, createResource, createSignal, onMount, Show } from "solid-j
import path from "path"
import type { SessionInfo } from "@opencode-ai/client"
import { TextAttributes } from "@opentui/core"
+import type { RGBA } from "@opentui/core"
import { useDialog } from "../ui/dialog"
import { DialogSelect } from "../ui/dialog-select"
import { useRoute } from "../context/route"
@@ -161,7 +162,7 @@ export function DialogSessionList() {
gutter:
data.session.status(session.id) === "running" ||
data.session.family(session.id).some((id) => data.session.status(id) === "running")
- ? () =>
+ ? (color: RGBA) =>
: slot === undefined
? undefined
: () => {slot},
diff --git a/packages/tui/src/ui/dialog-select.tsx b/packages/tui/src/ui/dialog-select.tsx
index 03b10e3d2d3..f851dc667ad 100644
--- a/packages/tui/src/ui/dialog-select.tsx
+++ b/packages/tui/src/ui/dialog-select.tsx
@@ -80,7 +80,7 @@ export interface DialogSelectOption {
disabled?: boolean
bg?: RGBA
fg?: RGBA
- gutter?: () => JSX.Element
+ gutter?: (color: RGBA) => JSX.Element
margin?: JSX.Element
onSelect?: (ctx: DialogContext) => void
}
@@ -816,7 +816,7 @@ function Option(props: {
footerColor?: RGBA
titleWidth?: number
truncateTitle?: boolean | "left"
- gutter?: () => JSX.Element
+ gutter?: (color: RGBA) => JSX.Element
activeColor?: RGBA
onMouseOver?: () => void
}) {
@@ -837,7 +837,7 @@ function Option(props: {
- {props.gutter?.()}
+ {props.gutter?.(text())}
{
}
})
+test("passes the row foreground color to gutters", async () => {
+ await using tmp = await tmpdir()
+ const colors = new Map()
+ const gutter = (item: string) => (color: RGBA) => {
+ colors.set(item, color)
+ return *
+ }
+ const select = await mountSelect(tmp.path, [
+ { title: "Alpha", value: "alpha", gutter: gutter("alpha") },
+ { title: "Beta", value: "beta", gutter: gutter("beta") },
+ ])
+
+ try {
+ await select.app.waitFor(() => colors.size === 2)
+ const selected = colors.get("alpha")!.toInts()
+ const idle = colors.get("beta")!.toInts()
+ expect(selected).not.toEqual(idle)
+
+ select.app.mockInput.pressArrow("down")
+ await select.app.waitFor(() => colors.get("alpha")!.toInts().every((value, index) => value === idle[index]))
+ expect(colors.get("beta")!.toInts()).toEqual(selected)
+ } finally {
+ select.app.renderer.destroy()
+ }
+})
+
test("dialog actions run without options while row actions still require a selection", async () => {
await using tmp = await tmpdir()
let global = 0