don't hoist identifiers when one of them is used in an event that is not delegateable

pull/9433/head
Simon Holthausen 3 years ago
parent 59e26bfda0
commit 42ce088c53

@ -104,19 +104,28 @@ function get_delegated_event(node, context) {
return non_hoistable;
}
const element =
parent.type === 'OnDirective'
? path.at(-2)
: parent.type === 'ExpressionTag' &&
is_event_attribute(/** @type {import('#compiler').Attribute} */ (path.at(-2)))
? path.at(-3)
: null;
if (element) {
/** @type {import('#compiler').RegularElement | null} */
let element = null;
/** @type {string | null} */
let event_name = null;
if (parent.type === 'OnDirective') {
element = /** @type {import('#compiler').RegularElement} */ (path.at(-2));
event_name = parent.name;
} else if (
parent.type === 'ExpressionTag' &&
is_event_attribute(/** @type {import('#compiler').Attribute} */ (path.at(-2)))
) {
element = /** @type {import('#compiler').RegularElement} */ (path.at(-3));
const attribute = /** @type {import('#compiler').Attribute} */ (path.at(-2));
event_name = get_attribute_event_name(attribute.name);
}
if (element && event_name) {
if (
element.type !== 'RegularElement' ||
!determine_element_spread_and_delegatable(element).metadata.can_delegate_events ||
(element.metadata.has_spread && node.type === 'Attribute')
(element.metadata.has_spread && node.type === 'Attribute') ||
!DelegatedEvents.includes(event_name)
) {
return non_hoistable;
}
@ -1036,10 +1045,7 @@ function determine_element_spread_and_delegatable(node) {
) {
let event_name = attribute.name;
if (attribute.type === 'Attribute') {
if (is_capture_event(event_name)) {
event_name = event_name.slice(0, -7);
}
event_name = event_name.slice(2);
event_name = get_attribute_event_name(event_name);
}
events.set(event_name, (events.get(event_name) || 0) + 1);
if (!has_on && attribute.type === 'OnDirective') {
@ -1066,6 +1072,17 @@ function determine_element_spread_and_delegatable(node) {
return node;
}
/**
* @param {string} event_name
*/
function get_attribute_event_name(event_name) {
if (is_capture_event(event_name)) {
event_name = event_name.slice(0, -7);
}
event_name = event_name.slice(2);
return event_name;
}
/**
* @param {string} name
* @returns boolean

@ -0,0 +1,18 @@
import { test } from '../../test';
// Checks that event handlers are not hoisted when one of them is not delegateable
export default test({
html: `<button>0</button>`,
async test({ assert, target }) {
const [button] = target.querySelectorAll('button');
button.click();
await Promise.resolve();
assert.htmlEqual(target.innerHTML, '<button>1</button>');
button.dispatchEvent(new MouseEvent('mouseenter'));
await Promise.resolve();
assert.htmlEqual(target.innerHTML, '<button>2</button>');
}
});

@ -0,0 +1,11 @@
<script>
let count = $state(0)
function increment() {
count += 1
}
</script>
<button onclick={increment} onmouseenter={increment}>
{count}
</button>
Loading…
Cancel
Save