Skip to content

Commit a1651ca

Browse files
tanhauhau98mux
andauthored
add nonpassive event modifier (#5442)
Co-authored-by: filipot <filipot@stud.ntnu.no>
1 parent 41d1656 commit a1651ca

File tree

10 files changed

+64
-20
lines changed

10 files changed

+64
-20
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44

5+
* Add `|nonpassive` event modifier, explicitly passing `passive: false` ([#2068](https://github.com/sveltejs/svelte/issues/2068))
56
* Fix keyed `{#each}` not reacting to key changing ([#5444](https://github.com/sveltejs/svelte/issues/5444))
67
* Fix destructuring into store values ([#5449](https://github.com/sveltejs/svelte/issues/5449))
78
* Fix erroneous `missing-declaration` warning with `use:obj.method` ([#5451](https://github.com/sveltejs/svelte/issues/5451))

site/content/docs/02-template-syntax.md

+1
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ The following modifiers are available:
471471
* `preventDefault` — calls `event.preventDefault()` before running the handler
472472
* `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element
473473
* `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
474+
* `nonpassive` — explicitly set `passive: false`
474475
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase
475476
* `once` — remove the handler after the first time it runs
476477
* `self` — only trigger handler if event.target is the element itself

site/content/tutorial/05-events/03-event-modifiers/text.md

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ The full list of modifiers:
2121
* `preventDefault` — calls `event.preventDefault()` before running the handler. Useful for client-side form handling, for example.
2222
* `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element
2323
* `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
24+
* `nonpassive` — explicitly set `passive: false`
2425
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase ([MDN docs](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture))
2526
* `once` — remove the handler after the first time it runs
2627
* `self` — only trigger handler if event.target is the element itself

src/compiler/compile/nodes/Element.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ const valid_modifiers = new Set([
8080
'capture',
8181
'once',
8282
'passive',
83+
'nonpassive',
8384
'self'
8485
]);
8586

@@ -770,6 +771,13 @@ export default class Element extends Node {
770771
});
771772
}
772773

774+
if (handler.modifiers.has('passive') && handler.modifiers.has('nonpassive')) {
775+
component.error(handler, {
776+
code: 'invalid-event-modifier',
777+
message: `The 'passive' and 'nonpassive' modifiers cannot be used together`
778+
});
779+
}
780+
773781
handler.modifiers.forEach(modifier => {
774782
if (!valid_modifiers.has(modifier)) {
775783
component.error(handler, {
@@ -804,7 +812,7 @@ export default class Element extends Node {
804812
}
805813
});
806814

807-
if (passive_events.has(handler.name) && handler.can_make_passive && !handler.modifiers.has('preventDefault')) {
815+
if (passive_events.has(handler.name) && handler.can_make_passive && !handler.modifiers.has('preventDefault') && !handler.modifiers.has('nonpassive')) {
808816
// touch/wheel events should be passive by default
809817
handler.modifiers.add('passive');
810818
}

src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,17 @@ export default class EventHandlerWrapper {
4545

4646
const args = [];
4747

48-
const opts = ['passive', 'once', 'capture'].filter(mod => this.node.modifiers.has(mod));
48+
const opts = ['nonpassive', 'passive', 'once', 'capture'].filter(mod => this.node.modifiers.has(mod));
4949
if (opts.length) {
50-
args.push((opts.length === 1 && opts[0] === 'capture')
51-
? TRUE
52-
: x`{ ${opts.map(opt => p`${opt}: true`)} }`);
50+
if (opts.length === 1 && opts[0] === 'capture') {
51+
args.push(TRUE);
52+
} else {
53+
args.push(x`{ ${ opts.map(opt =>
54+
opt === 'nonpassive'
55+
? p`passive: false`
56+
: p`${opt}: true`
57+
) } }`);
58+
}
5359
} else if (block.renderer.options.dev) {
5460
args.push(FALSE);
5561
}

test/js/samples/event-modifiers/expected.js

+22-14
Original file line numberDiff line numberDiff line change
@@ -16,41 +16,49 @@ import {
1616
} from "svelte/internal";
1717

1818
function create_fragment(ctx) {
19-
let div;
20-
let button0;
19+
let div1;
20+
let div0;
2121
let t1;
22-
let button1;
22+
let button0;
2323
let t3;
24+
let button1;
25+
let t5;
2426
let button2;
2527
let mounted;
2628
let dispose;
2729

2830
return {
2931
c() {
30-
div = element("div");
32+
div1 = element("div");
33+
div0 = element("div");
34+
div0.textContent = "touch me";
35+
t1 = space();
3136
button0 = element("button");
3237
button0.textContent = "click me";
33-
t1 = space();
38+
t3 = space();
3439
button1 = element("button");
3540
button1.textContent = "or me";
36-
t3 = space();
41+
t5 = space();
3742
button2 = element("button");
3843
button2.textContent = "or me!";
3944
},
4045
m(target, anchor) {
41-
insert(target, div, anchor);
42-
append(div, button0);
43-
append(div, t1);
44-
append(div, button1);
45-
append(div, t3);
46-
append(div, button2);
46+
insert(target, div1, anchor);
47+
append(div1, div0);
48+
append(div1, t1);
49+
append(div1, button0);
50+
append(div1, t3);
51+
append(div1, button1);
52+
append(div1, t5);
53+
append(div1, button2);
4754

4855
if (!mounted) {
4956
dispose = [
57+
listen(div0, "touchstart", handleTouchstart, { passive: false }),
5058
listen(button0, "click", stop_propagation(prevent_default(handleClick))),
5159
listen(button1, "click", handleClick, { once: true, capture: true }),
5260
listen(button2, "click", handleClick, true),
53-
listen(div, "touchstart", handleTouchstart, { passive: true })
61+
listen(div1, "touchstart", handleTouchstart, { passive: true })
5462
];
5563

5664
mounted = true;
@@ -60,7 +68,7 @@ function create_fragment(ctx) {
6068
i: noop,
6169
o: noop,
6270
d(detaching) {
63-
if (detaching) detach(div);
71+
if (detaching) detach(div1);
6472
mounted = false;
6573
run_all(dispose);
6674
}

test/js/samples/event-modifiers/input.svelte

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
</script>
1010

1111
<div on:touchstart={handleTouchstart}>
12+
<div on:touchstart|nonpassive={handleTouchstart}>touch me</div>
1213
<button on:click|stopPropagation|preventDefault={handleClick}>click me</button>
1314
<button on:click|once|capture={handleClick}>or me</button>
1415
<button on:click|capture={handleClick}>or me!</button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[{
2+
"message": "The 'passive' and 'nonpassive' modifiers cannot be used together",
3+
"code": "invalid-event-modifier",
4+
"start": {
5+
"line": 1,
6+
"column": 5,
7+
"character": 5
8+
},
9+
"end": {
10+
"line": 1,
11+
"column": 51,
12+
"character": 51
13+
},
14+
"pos": 5
15+
}]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div on:touchstart|nonpassive|passive={handleWheel}>
2+
oops
3+
</div>

test/validator/samples/event-modifiers-invalid/errors.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[{
2-
"message": "Valid event modifiers are preventDefault, stopPropagation, capture, once, passive or self",
2+
"message": "Valid event modifiers are preventDefault, stopPropagation, capture, once, passive, nonpassive or self",
33
"code": "invalid-event-modifier",
44
"start": {
55
"line": 1,

0 commit comments

Comments
 (0)