Skip to content

Commit a5fd28a

Browse files
authored
fix: inline pointer events now correctly work in Chrome (#11695)
* fix: inline pointer events now correctly work in Chrome * fix more
1 parent e6f8e95 commit a5fd28a

File tree

3 files changed

+42
-11
lines changed

3 files changed

+42
-11
lines changed

.changeset/quiet-cobras-smile.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: inline pointer events now correctly work in Chrome

packages/svelte/src/internal/client/dom/elements/attributes.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { DEV } from 'esm-env';
22
import { hydrating } from '../hydration.js';
33
import { get_descriptors, get_prototype_of, map_get, map_set } from '../../utils.js';
44
import { AttributeAliases, DelegatedEvents, namespace_svg } from '../../../../constants.js';
5-
import { delegate } from './events.js';
5+
import { create_event, delegate } from './events.js';
66
import { autofocus } from './misc.js';
77
import { effect, effect_root } from '../../reactivity/effects.js';
88
import * as w from '../../warnings.js';
@@ -151,9 +151,13 @@ export function set_attributes(element, prev, next, lowercase_attributes, css_ha
151151
if (!delegated) {
152152
// we use `addEventListener` here because these events are not delegated
153153
if (!prev) {
154-
events.push([key, value, () => element.addEventListener(event_name, value, opts)]);
154+
events.push([
155+
key,
156+
value,
157+
() => (next[key] = create_event(event_name, element, value, opts))
158+
]);
155159
} else {
156-
element.addEventListener(event_name, value, opts);
160+
next[key] = create_event(event_name, element, value, opts);
157161
}
158162
} else {
159163
// @ts-ignore

packages/svelte/src/internal/client/dom/elements/events.js

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { render_effect } from '../../reactivity/effects.js';
22
import { all_registered_events, root_event_handles } from '../../render.js';
33
import { define_property, is_array } from '../../utils.js';
44
import { hydrating } from '../hydration.js';
5+
import { queue_task } from '../task.js';
56

67
/**
78
* SSR adds onload and onerror attributes to catch those events before the hydration.
@@ -34,18 +35,14 @@ export function replay_events(dom) {
3435
* @param {string} event_name
3536
* @param {Element} dom
3637
* @param {EventListener} handler
37-
* @param {boolean} capture
38-
* @param {boolean} [passive]
39-
* @returns {void}
38+
* @param {AddEventListenerOptions} options
4039
*/
41-
export function event(event_name, dom, handler, capture, passive) {
42-
var options = { capture, passive };
43-
40+
export function create_event(event_name, dom, handler, options) {
4441
/**
4542
* @this {EventTarget}
4643
*/
4744
function target_handler(/** @type {Event} */ event) {
48-
if (!capture) {
45+
if (!options.capture) {
4946
// Only call in the bubble phase, else delegated events would be called before the capturing events
5047
handle_event_propagation(dom, event);
5148
}
@@ -54,7 +51,32 @@ export function event(event_name, dom, handler, capture, passive) {
5451
}
5552
}
5653

57-
dom.addEventListener(event_name, target_handler, options);
54+
// Chrome has a bug where pointer events don't work when attached to a DOM element that has been cloned
55+
// with cloneNode() and the DOM element is disconnected from the document. To ensure the event works, we
56+
// defer the attachment till after it's been appended to the document. TODO: remove this once Chrome fixes
57+
// this bug.
58+
if (event_name.startsWith('pointer')) {
59+
queue_task(() => {
60+
dom.addEventListener(event_name, target_handler, options);
61+
});
62+
} else {
63+
dom.addEventListener(event_name, target_handler, options);
64+
}
65+
66+
return target_handler;
67+
}
68+
69+
/**
70+
* @param {string} event_name
71+
* @param {Element} dom
72+
* @param {EventListener} handler
73+
* @param {boolean} capture
74+
* @param {boolean} [passive]
75+
* @returns {void}
76+
*/
77+
export function event(event_name, dom, handler, capture, passive) {
78+
var options = { capture, passive };
79+
var target_handler = create_event(event_name, dom, handler, options);
5880

5981
// @ts-ignore
6082
if (dom === document.body || dom === window || dom === document) {

0 commit comments

Comments
 (0)