feat: PiPelement binding

fix: undefined properties
feat: tests
pull/8507/head
ThaUnknown 3 years ago
parent 43ab54bc4e
commit 17a3d509be

@ -1081,6 +1081,7 @@ export interface SvelteMediaTimeRange {
export interface SvelteDocumentAttributes extends HTMLAttributes<Document> {
readonly 'bind:fullscreenElement'?: Document['fullscreenElement'] | undefined | null;
readonly 'bind:visibilityState'?: Document['visibilityState'] | undefined | null;
readonly 'bind:pictureInPictureElement'?: Document['pictureInPictureElement'] | undefined | null;
}
export interface SvelteWindowAttributes extends HTMLAttributes<Window> {

@ -1777,10 +1777,11 @@ As with `<svelte:window>`, this element may only appear the top level of your co
You can also bind to the following properties:
* `visibilityState`
* `fullscreenElement`
* `pictureInPictureElement`
* `visibilityState`
All except are readonly.
All are readonly.
### `<svelte:body>`

@ -9,6 +9,7 @@ import { TemplateNode } from '../../interfaces';
import Element from './Element';
import InlineComponent from './InlineComponent';
import Window from './Window';
import Document from './Document';
import { clone } from '../../utils/clone';
import compiler_errors from '../compiler_errors';
import compiler_warnings from '../compiler_warnings';
@ -36,7 +37,7 @@ export default class Binding extends Node {
is_contextual: boolean;
is_readonly: boolean;
constructor(component: Component, parent: Element | InlineComponent | Window, scope: TemplateScope, info: TemplateNode) {
constructor(component: Component, parent: Element | InlineComponent | Window | Document, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
if (info.expression.type !== 'Identifier' && info.expression.type !== 'MemberExpression') {

@ -4,6 +4,7 @@ import EventHandler from './EventHandler';
import fuzzymatch from '../../utils/fuzzymatch';
import Action from './Action';
import Component from '../Component';
import list from '../../utils/list';
import TemplateScope from './shared/TemplateScope';
import { Element } from '../../interfaces';
import compiler_warnings from '../compiler_warnings';
@ -11,6 +12,7 @@ import compiler_errors from '../compiler_errors';
const valid_bindings = [
'fullscreenElement',
'pictureInPictureElement',
'visibilityState'
];
@ -28,7 +30,8 @@ export default class Document extends Node {
this.handlers.push(new EventHandler(component, this, scope, node));
} else if (node.type === 'Binding') {
if (!~valid_bindings.indexOf(node.name)) {
if (fuzzymatch(node.name, valid_bindings)) {
const match = fuzzymatch(node.name, valid_bindings);
if (match) {
return component.error(node, compiler_errors.invalid_binding_on(node.name, '<svelte:document>', ` (did you mean '${match}'?)`));
} else {
return component.error(node, compiler_errors.invalid_binding_on(node.name, '<svelte:document>', ` — valid bindings are ${list(valid_bindings)}`));

@ -10,12 +10,14 @@ import Renderer from '../Renderer';
import add_actions from './shared/add_actions';
const associated_events = {
fullscreenElement: 'fullscreenchange',
visibilityState: 'visibilitychange'
fullscreenElement: ['fullscreenchange'],
pictureInPictureElement: ['enterpictureinpicture', 'leavepictureinpicture'],
visibilityState: ['visibilitychange']
};
const readonly = new Set([
'fullscreenElement',
'pictureInPictureElement',
'visibilityState'
]);
@ -49,13 +51,15 @@ export default class DocumentWrapper extends Wrapper {
bindings[binding.name] = binding_name;
const associated_event = associated_events[binding.name];
const binding_events = associated_events[binding.name];
const property = binding.name;
if (!events[associated_event]) events[associated_event] = [];
events[associated_event].push({
name: binding_name,
value: property
binding_events.forEach(associated_event => {
if (!events[associated_event]) events[associated_event] = [];
events[associated_event].push({
name: binding_name,
value: property
});
});
});

@ -0,0 +1,31 @@
export default {
before_test() {
Object.defineProperties(window.document, {
fullscreenElement: {
value: null,
configurable: true
}
});
},
// copied from window-binding
// there's some kind of weird bug with this test... it compiles with the wrong require.extensions hook for some bizarre reason
skip_if_ssr: true,
async test({ assert, target, window, component }) {
const event = new window.Event('fullscreenchange');
const div = target.querySelector('div');
Object.defineProperties(window.document, {
fullscreenElement: {
value: div,
configurable: true
}
});
window.document.dispatchEvent(event);
assert.equal(component.fullscreen, div);
}
};

@ -0,0 +1,7 @@
<script>
export let fullscreen;
</script>
<svelte:document bind:fullscreenElement={fullscreen}/>
<div />

@ -0,0 +1,44 @@
export default {
before_test() {
Object.defineProperties(document, {
pictureInPictureElement: {
value: null,
configurable: true
}
});
},
// copied from window-binding
// there's some kind of weird bug with this test... it compiles with the wrong require.extensions hook for some bizarre reason
skip_if_ssr: true,
async test({ assert, target, window, component }) {
const enter = new window.Event('enterpictureinpicture');
const div = target.querySelector('div');
Object.defineProperties(window.document, {
pictureInPictureElement: {
value: div,
configurable: true
}
});
window.document.dispatchEvent(enter);
assert.equal(component.pip, div);
const leave = new window.Event('leavepictureinpicture');
Object.defineProperties(window.document, {
pictureInPictureElement: {
value: null,
configurable: true
}
});
window.document.dispatchEvent(leave);
assert.equal(component.pip, null);
}
};

@ -0,0 +1,7 @@
<script>
export let pip;
</script>
<svelte:document bind:pictureInPictureElement={pip}/>
<div />
Loading…
Cancel
Save