fix(frontend): Outbound submit crash on non-mux protocols + tab a11y (B21)

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.
This commit is contained in:
MHSanaei 2026-05-26 20:24:15 +02:00
parent f910bfbcda
commit d2f5f530e0
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A
2 changed files with 11 additions and 1 deletions

View file

@ -620,7 +620,10 @@ export function formValuesToWirePayload(values: OutboundFormValues): WireOutboun
} }
if (values.sendThrough) result.sendThrough = values.sendThrough; 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; result.mux = values.mux;
} }
return result; return result;

View file

@ -372,6 +372,13 @@ export default function OutboundFormModal({
if (key === '1' && activeKey === '2') { if (key === '1' && activeKey === '2') {
if (!applyJsonToForm()) return; 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); setActiveKey(key);
} }