From d2f5f530e01e4f011e82723853af28d3e17128c1 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Tue, 26 May 2026 20:24:15 +0200 Subject: [PATCH] fix(frontend): Outbound submit crash on non-mux protocols + tab a11y (B21) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two issues surfaced on Outbound save: 1. Crash: `Cannot read properties of undefined (reading 'enabled')` at formValuesToWirePayload. The modal hides the Mux switch entirely for non-stream protocols (dns/freedom/blackhole/loopback) and for stream protocols when isMuxAllowed gates it out (xhttp, vless+flow). With the field never registered, validateFields() returns no `mux` key — `values.mux.enabled` then dereferences undefined. Fix: optional chain `values.mux?.enabled` so missing mux skips the mux clause silently. Documented why mux can be absent. 2. Chrome a11y warning: "Blocked aria-hidden on an element because its descendant retained focus" — when the user has an input focused inside one Tab panel and switches to another tab, AntD marks the outgoing panel aria-hidden while focus is still inside. The browser warns, but the focused control is now invisible to AT users. Fix: blur the active element before setActiveKey in onTabChange. --- frontend/src/lib/xray/outbound-form-adapter.ts | 5 ++++- frontend/src/pages/xray/OutboundFormModal.tsx | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/xray/outbound-form-adapter.ts b/frontend/src/lib/xray/outbound-form-adapter.ts index 3dd5852d..bf331fca 100644 --- a/frontend/src/lib/xray/outbound-form-adapter.ts +++ b/frontend/src/lib/xray/outbound-form-adapter.ts @@ -620,7 +620,10 @@ export function formValuesToWirePayload(values: OutboundFormValues): WireOutboun } if (values.sendThrough) result.sendThrough = values.sendThrough; - if (values.mux.enabled && muxAllowed(values)) { + // mux may be absent when the modal didn't render the Mux switch (non- + // stream protocols or when isMuxAllowed gated it out). validateFields() + // only returns registered fields, so values.mux can be undefined. + if (values.mux?.enabled && muxAllowed(values)) { result.mux = values.mux; } return result; diff --git a/frontend/src/pages/xray/OutboundFormModal.tsx b/frontend/src/pages/xray/OutboundFormModal.tsx index 362efdfa..fee094f7 100644 --- a/frontend/src/pages/xray/OutboundFormModal.tsx +++ b/frontend/src/pages/xray/OutboundFormModal.tsx @@ -372,6 +372,13 @@ export default function OutboundFormModal({ if (key === '1' && activeKey === '2') { if (!applyJsonToForm()) return; } + // Blur the currently focused element before AntD marks the outgoing + // tab panel aria-hidden. Without this, a focused input inside the + // hidden panel triggers a Chrome a11y warning ("Blocked aria-hidden + // on an element because its descendant retained focus"). + if (typeof document !== 'undefined') { + (document.activeElement as HTMLElement | null)?.blur?.(); + } setActiveKey(key); }