From 44e6cf5fa9163cc979c20c63edc70cef944e9db6 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Sat, 14 Mar 2026 02:40:38 -0400 Subject: [PATCH 1/2] feat: Add experimental.dialog_background_overlay setting Adds a new experimental configuration option to control dialog background overlay behavior: - 'full' (default): Semi-transparent overlay covers entire screen (current behavior) - 'limited': No overlay outside dialog window bounds - 'none': No overlay at all This allows users to work around the TUI renderer bug where emojis disappear when semi-transparent overlays are applied. Changes: - Added dialog_background_overlay to Config.Experimental schema - Updated SDK types to include the new field - Modified Dialog component to conditionally render overlay based on setting --- packages/opencode/src/cli/cmd/tui/ui/dialog.tsx | 17 +++++++++++------ packages/opencode/src/config/config.ts | 4 ++++ packages/sdk/js/src/v2/gen/types.gen.ts | 4 ++++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx index 8cebd9cba54..9aea8a438b9 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx @@ -6,6 +6,7 @@ import { createStore } from "solid-js/store" import { useToast } from "./toast" import { Flag } from "@/flag/flag" import { Selection } from "@tui/util/selection" +import { useSync } from "@tui/context/sync" export function Dialog( props: ParentProps<{ @@ -16,6 +17,10 @@ export function Dialog( const dimensions = useTerminalDimensions() const { theme } = useTheme() const renderer = useRenderer() + const sync = useSync() + + const overlayMode = () => sync.data.config.experimental?.dialog_background_overlay ?? "full" + const showFullOverlay = () => overlayMode() === "full" let dismiss = false @@ -31,14 +36,14 @@ export function Dialog( } props.onClose?.() }} - width={dimensions().width} - height={dimensions().height} + width={showFullOverlay() ? dimensions().width : props.size === "large" ? 80 : 60} + height={showFullOverlay() ? dimensions().height : undefined} alignItems="center" position="absolute" - paddingTop={dimensions().height / 4} - left={0} - top={0} - backgroundColor={RGBA.fromInts(0, 0, 0, 150)} + paddingTop={showFullOverlay() ? dimensions().height / 4 : undefined} + left={showFullOverlay() ? 0 : undefined} + top={showFullOverlay() ? 0 : undefined} + backgroundColor={showFullOverlay() ? RGBA.fromInts(0, 0, 0, 150) : undefined} > { diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 27ba4e18671..27771c512c8 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -1220,6 +1220,10 @@ export namespace Config { .positive() .optional() .describe("Timeout in milliseconds for model context protocol (MCP) requests"), + dialog_background_overlay: z + .enum(["full", "limited", "none"]) + .optional() + .describe("Control dialog background overlay: 'full' = semi-transparent overlay (default), 'limited' = overlay only within dialog bounds, 'none' = no overlay"), }) .optional(), }) diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 2629015eb34..dcbef4da4e0 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1500,6 +1500,10 @@ export type Config = { * Timeout in milliseconds for model context protocol (MCP) requests */ mcp_timeout?: number + /** + * Control dialog background overlay: 'full' = semi-transparent overlay (default), 'limited' = overlay only within dialog bounds, 'none' = no overlay + */ + dialog_background_overlay?: 'full' | 'limited' | 'none' } } From 418b3f5d644ca7b600f85db66ce5e3e1de1224b2 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Sat, 14 Mar 2026 02:52:12 -0400 Subject: [PATCH 2/2] fix: Keep dialog centered in limited/none overlay modes The dialog window was appearing in the top-left when overlay mode was set to 'limited' or 'none'. This was because the outer positioning box was being resized to match the dialog window instead of staying full screen. Now the outer box always uses full screen dimensions for proper centering, and only the backgroundColor is conditionally applied. --- packages/opencode/src/cli/cmd/tui/ui/dialog.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx index 9aea8a438b9..9ac942d3c89 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx @@ -20,7 +20,7 @@ export function Dialog( const sync = useSync() const overlayMode = () => sync.data.config.experimental?.dialog_background_overlay ?? "full" - const showFullOverlay = () => overlayMode() === "full" + const showOverlay = () => overlayMode() === "full" let dismiss = false @@ -36,14 +36,14 @@ export function Dialog( } props.onClose?.() }} - width={showFullOverlay() ? dimensions().width : props.size === "large" ? 80 : 60} - height={showFullOverlay() ? dimensions().height : undefined} + width={dimensions().width} + height={dimensions().height} alignItems="center" position="absolute" - paddingTop={showFullOverlay() ? dimensions().height / 4 : undefined} - left={showFullOverlay() ? 0 : undefined} - top={showFullOverlay() ? 0 : undefined} - backgroundColor={showFullOverlay() ? RGBA.fromInts(0, 0, 0, 150) : undefined} + paddingTop={dimensions().height / 4} + left={0} + top={0} + backgroundColor={showOverlay() ? RGBA.fromInts(0, 0, 0, 150) : undefined} > {