Skip to content

Commit 2cd2646

Browse files
committed
feat: bind activeElement and pointerLockElement in <svelte:document>
1 parent 14ddb87 commit 2cd2646

File tree

9 files changed

+49
-2
lines changed

9 files changed

+49
-2
lines changed

.changeset/lovely-bugs-sneeze.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+
feat: bind `activeElement` and `pointerLockElement` in `<svelte:document>`

documentation/docs/02-template-syntax/07-special-elements.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,9 @@ As with `<svelte:window>`, this element may only appear the top level of your co
268268

269269
You can also bind to the following properties:
270270

271+
- `activeElement`
271272
- `fullscreenElement`
273+
- `pointerLockElement`
272274
- `visibilityState`
273275

274276
All are readonly.

packages/svelte/elements.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,9 @@ export interface SvelteMediaTimeRange {
13641364
}
13651365

13661366
export interface SvelteDocumentAttributes extends HTMLAttributes<Document> {
1367+
readonly 'bind:activeElement'?: Document['activeElement'] | undefined | null;
13671368
readonly 'bind:fullscreenElement'?: Document['fullscreenElement'] | undefined | null;
1369+
readonly 'bind:pointerLockElement'?: Document['pointerLockElement'] | undefined | null;
13681370
readonly 'bind:visibilityState'?: Document['visibilityState'] | undefined | null;
13691371
}
13701372

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2773,6 +2773,11 @@ export const template_visitors = {
27732773
call_expr = b.call('$.bind_window_size', b.literal(node.name), setter);
27742774
break;
27752775

2776+
// document
2777+
case 'activeElement':
2778+
call_expr = b.call('$.bind_active_element', setter);
2779+
break;
2780+
27762781
// media
27772782
case 'muted':
27782783
call_expr = b.call(`$.bind_muted`, state.node, getter, setter);

packages/svelte/src/compiler/phases/bindings.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,20 @@ export const binding_properties = {
8686
omit_in_ssr: true
8787
},
8888
// document
89+
activeElement: {
90+
valid_elements: ['svelte:document'],
91+
omit_in_ssr: true
92+
},
8993
fullscreenElement: {
9094
valid_elements: ['svelte:document'],
9195
event: 'fullscreenchange',
9296
omit_in_ssr: true
9397
},
98+
pointerLockElement: {
99+
valid_elements: ['svelte:document'],
100+
event: 'pointerlockchange',
101+
omit_in_ssr: true
102+
},
94103
visibilityState: {
95104
valid_elements: ['svelte:document'],
96105
event: 'visibilitychange',
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { render_effect } from '../../../reactivity/effects.js';
2+
3+
/**
4+
* @param {(activeElement: Element | null) => void} update
5+
* @returns {void}
6+
*/
7+
export function bind_active_element(update) {
8+
var handler = () => {
9+
update(document.activeElement);
10+
};
11+
12+
handler();
13+
14+
document.addEventListener('focus', handler, true);
15+
document.addEventListener('blur', handler, true);
16+
17+
render_effect(() => {
18+
return () => {
19+
document.removeEventListener('focus', handler);
20+
document.removeEventListener('blur', handler);
21+
};
22+
});
23+
}

packages/svelte/src/internal/client/dom/elements/bindings/shared.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { add_form_reset_listener } from '../misc.js';
44
/**
55
* Fires the handler once immediately (unless corresponding arg is set to `false`),
66
* then listens to the given events until the render effect context is destroyed
7-
* @param {Element | Window} target
7+
* @param {EventTarget} target
88
* @param {Array<string>} events
99
* @param {() => void} handler
1010
* @param {any} call_handler_immediately

packages/svelte/src/internal/client/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export { event, delegate, replay_events } from './dom/elements/events.js';
3636
export { autofocus, remove_textarea_child } from './dom/elements/misc.js';
3737
export { set_style } from './dom/elements/style.js';
3838
export { animation, transition } from './dom/elements/transitions.js';
39+
export { bind_active_element } from './dom/elements/bindings/document.js';
3940
export { bind_checked, bind_files, bind_group, bind_value } from './dom/elements/bindings/input.js';
4041
export {
4142
bind_buffered,

packages/svelte/tests/validator/samples/document-binding-invalid-dimensions/errors.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
33
"code": "bind_invalid_name",
4-
"message": "`bind:clientWidth` is not a valid binding. Possible bindings for <svelte:document> are focused, fullscreenElement, visibilityState, this",
4+
"message": "`bind:clientWidth` is not a valid binding. Possible bindings for <svelte:document> are focused, activeElement, fullscreenElement, pointerLockElement, visibilityState, this",
55
"start": {
66
"line": 5,
77
"column": 17

0 commit comments

Comments
 (0)