fix(csr): deliver focus and blur outputs from inside a component
A parent writing @focus on a component tag never heard that component's own input or button take focus. The runtime bound every output-named DOM fallback listener in the bubble phase, and focus and blur do not bubble, so the event fired on the descendant and stopped there. Nothing errored -- the binding simply did nothing. That made a whole class of declared outputs undeliverable: button.focus, button.blur, TextLink.focus, TextLink.blur, WysiwygEditor.focus and WysiwygEditor.blur all advertised events they could never send. The ui ratchet for outputs nothing emits excluded natively-named outputs on the grounds that a native event reaches the root anyway. That holds for click and change, which bubble, and was wrong for focus and blur. Binding those two in the capture phase makes the exclusion honest rather than convenient; the ratchet's comment now says so. Also documents WysiwygEditor as the chrome shell it is: it emits none of its four outputs itself, it forwards whatever the slotted control raises. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2724,9 +2724,17 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
);
|
||||
}
|
||||
};
|
||||
node.addEventListener(outName, domListener);
|
||||
/*
|
||||
* focus and blur do not bubble, so a bubble-phase listener on the
|
||||
* component root never hears its own input or button take focus --
|
||||
* the binding silently did nothing. Capture reaches the descendant.
|
||||
* The same flag must be passed to removeEventListener or the
|
||||
* listener outlives the component.
|
||||
*/
|
||||
var capture = outName === "focus" || outName === "blur";
|
||||
node.addEventListener(outName, domListener, capture);
|
||||
cleanupCallbacks.push(function () {
|
||||
node.removeEventListener(outName, domListener);
|
||||
node.removeEventListener(outName, domListener, capture);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user