From f4c06355490b34673db3381bcdd12e8135b08dc5 Mon Sep 17 00:00:00 2001 From: Jake Date: Thu, 7 May 2026 11:27:42 +0100 Subject: [PATCH] fix(a11y): guard sidebar-toggle keypress against custom widgets and scope transcript font-size effect - Extend isInputFocused to also bail when document.activeElement sits inside a custom widget with role combobox/listbox/radio/switch/menuitem/tab so single-letter shortcuts like '[' do not collapse the sidebar while focused on SegmentedButton, ZonePicker, etc. - Move the transcript font-size CSS variable write from documentElement to document.body. Consumers inherit body styles, and scoping the write there avoids invalidating root-level styles every time fontSize changes. --- src/routes/+layout.svelte | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index a2fb70c..006adc3 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -182,15 +182,31 @@ } }); - // Apply font size setting as CSS variable (legacy — kept for backwards compat) + // Apply font size setting as CSS variable (legacy, kept for backwards compat). + // Scoped to rather than documentElement so the write only invalidates + // styles on the body subtree (transcript surfaces inherit from body anyway). $effect(() => { - document.documentElement.style.setProperty("--font-size-transcript", `${settings.fontSize}px`); + document.body.style.setProperty("--font-size-transcript", `${settings.fontSize}px`); }); - // Check whether the keydown originates from a text input (avoid triggering while typing) + // Custom widgets that should swallow single-letter shortcuts so they don't + // accidentally trigger global hotkeys while focused. + const CUSTOM_WIDGET_SELECTOR = + '[role="combobox"], [role="listbox"], [role="radio"], [role="switch"], [role="menuitem"], [role="tab"]'; + + // Check whether the keydown originates from a text input or custom widget + // (avoid triggering shortcuts while typing or while focus sits in a + // SegmentedButton, ZonePicker, or similar ARIA-roled control). function isInputFocused(e) { const tag = e.target?.tagName; - return tag === "INPUT" || tag === "TEXTAREA" || e.target?.isContentEditable; + if (tag === "INPUT" || tag === "TEXTAREA" || e.target?.isContentEditable) { + return true; + } + const active = document.activeElement; + if (active && typeof active.closest === "function" && active.closest(CUSTOM_WIDGET_SELECTOR)) { + return true; + } + return false; } function handleKeydown(e) {