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