Merge branch 'sites' into feat/ts-in-docs

pull/8452/head
Puru Vijay 3 years ago
commit 5a36085e76

@ -1,5 +1,10 @@
# Svelte changelog
## Unreleased
* Handle `width`/`height` attributes when spreading ([#6752](https://github.com/sveltejs/svelte/issues/6752))
* Add support for resize observer bindings (`<div bind:contentRect|contentBoxSize|borderBoxSize|devicePixelContentBoxSize>`) ([#8022](https://github.com/sveltejs/svelte/pull/8022))
## 3.58.0
- Add `bind:innerText` for `contenteditable` elements ([#3311](https://github.com/sveltejs/svelte/issues/3311))

@ -546,6 +546,11 @@ export interface HTMLAttributes<T extends EventTarget> extends AriaAttributes, D
*/
'bind:innerText'?: string | undefined | null;
readonly 'bind:contentRect'?: DOMRectReadOnly | undefined | null;
readonly 'bind:contentBoxSize'?: Array<{ blockSize: number; inlineSize: number }> | undefined | null; // TODO make this ResizeObserverSize once we require TS>=4.4
readonly 'bind:borderBoxSize'?: Array<{ blockSize: number; inlineSize: number }> | undefined | null; // TODO make this ResizeObserverSize once we require TS>=4.4
readonly 'bind:devicePixelContentBoxSize'?: Array<{ blockSize: number; inlineSize: number }> | undefined | null; // TODO make this ResizeObserverSize once we require TS>=4.4
// SvelteKit
'data-sveltekit-keepfocus'?: true | '' | 'off' | undefined | null;
'data-sveltekit-noscroll'?: true | '' | 'off' | undefined | null;

14
package-lock.json generated

@ -10,7 +10,7 @@
"license": "MIT",
"devDependencies": {
"@ampproject/remapping": "^0.3.0",
"@jridgewell/sourcemap-codec": "^1.4.14",
"@jridgewell/sourcemap-codec": "^1.4.15",
"@rollup/plugin-commonjs": "^11.0.0",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^11.2.1",
@ -185,9 +185,9 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"node_modules/@nodelib/fs.scandir": {
@ -5526,9 +5526,9 @@
"dev": true
},
"@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"@nodelib/fs.scandir": {

@ -120,7 +120,7 @@
"homepage": "https://svelte.dev",
"devDependencies": {
"@ampproject/remapping": "^0.3.0",
"@jridgewell/sourcemap-codec": "^1.4.14",
"@jridgewell/sourcemap-codec": "^1.4.15",
"@rollup/plugin-commonjs": "^11.0.0",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^11.2.1",

@ -266,7 +266,7 @@ You cannot `export default`, since the default export is the component itself.
<script context="module">
let totalComponents = 0;
// this allows an importer to do e.g.
// the export keyword allows this function to imported with e.g.
// `import Example, { alertTotal } from './Example.svelte'`
export function alertTotal() {
alert(totalComponents);

File diff suppressed because it is too large Load Diff

@ -18,7 +18,7 @@
},
"dependencies": {
"@supabase/supabase-js": "^2.20.0",
"@sveltejs/repl": "^0.2.0",
"@sveltejs/repl": "^0.4.0",
"cookie": "^0.5.0",
"devalue": "^4.3.0",
"do-not-zip": "^1.0.0",
@ -28,9 +28,9 @@
},
"devDependencies": {
"@resvg/resvg-js": "^2.4.1",
"@sveltejs/adapter-vercel": "^2.4.1",
"@sveltejs/kit": "^1.15.4",
"@sveltejs/site-kit": "^4.1.1",
"@sveltejs/adapter-vercel": "^2.4.2",
"@sveltejs/kit": "^1.15.7",
"@sveltejs/site-kit": "^5.0.3",
"@types/marked": "^4.0.8",
"@types/node": "^18.15.11",
"@types/prismjs": "^1.26.0",
@ -46,7 +46,7 @@
"rollup": "^3.20.2",
"rollup-plugin-dts": "^5.3.0",
"sass": "^1.62.0",
"satori": "^0.4.7",
"satori": "^0.4.11",
"satori-html": "^0.3.2",
"shelljs": "^0.8.5",
"shiki": "^0.14.1",
@ -56,6 +56,6 @@
"ts-morph": "^18.0.0",
"typescript": "^5.0.4",
"vite": "^4.2.1",
"vite-imagetools": "^4.0.18"
"vite-imagetools": "^4.0.19"
}
}

@ -42,7 +42,7 @@
left: 0;
top: 0;
height: 100%;
background-color: var(--prime);
background-color: var(--sk-theme-1);
transition: width 0.4s;
}

@ -42,7 +42,7 @@
return {
name: file.slice(0, dot),
type: file.slice(dot + 1),
source,
source
};
})
.filter((x) => x.type === 'svelte' || x.type === 'js')
@ -63,7 +63,7 @@
);
repl.set({
components,
components
});
}
}
@ -80,10 +80,8 @@
browser && version === 'local'
? `${location.origin}/repl/local`
: `https://unpkg.com/svelte@${version}`;
const rollupUrl = `https://unpkg.com/rollup@1/dist/rollup.browser.js`;
</script>
{#if browser}
<Repl bind:this={repl} {svelteUrl} {rollupUrl} embedded relaxed />
<Repl bind:this={repl} {svelteUrl} embedded relaxed />
{/if}

@ -26,11 +26,11 @@
const res = await fetch(`/apps/destroy`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'content-type': 'application/json'
},
body: JSON.stringify({
ids: selected,
}),
ids: selected
})
});
if (res.ok) {
@ -142,8 +142,8 @@
<style>
.apps {
padding: var(--top-offset) var(--side-nav) 6rem var(--side-nav);
max-width: var(--main-width);
padding: var(--sk-page-padding-top) var(--sk-page-padding-side) 6rem var(--sk-page-padding-side);
max-width: var(--sk-page-main-width);
margin: 0 auto;
}
@ -161,7 +161,7 @@
padding: 0 0 0 3.2rem;
position: relative;
margin: 1rem 0;
color: var(--text);
color: var(--sk-text-2);
}
.avatar {
@ -217,7 +217,7 @@
line-height: 1;
display: flex;
border: 1px solid #eee;
border-radius: var(--border-r);
border-radius: var(--sk-border-radius);
z-index: 2;
}
@ -226,7 +226,7 @@
gap: 1rem;
padding: 0 1rem;
height: 100%;
border-radius: var(--border-r);
border-radius: var(--sk-border-radius);
align-items: center;
}
@ -247,8 +247,8 @@
}
h2 {
color: var(--text);
font-size: var(--h5);
color: var(--sk-text-2);
font-size: var(--sk-text-s);
font-weight: 400;
overflow: hidden;
text-overflow: ellipsis;
@ -256,11 +256,11 @@
li a {
display: block;
background: var(--back-light);
background: var(--sk-back-3);
padding: 1rem 3rem 1rem 1rem;
height: 100%;
line-height: 1;
border-radius: var(--border-r);
border-radius: var(--sk-border-radius);
text-decoration: none;
}
@ -282,7 +282,7 @@
}
ul:not(.selecting) li:hover a {
background-color: var(--second);
background-color: var(--sk-theme-2);
color: white;
}

@ -6,7 +6,6 @@
import { mapbox_setup } from '../../../../config.js';
import AppControls from './AppControls.svelte';
/** @type {import('./$types').PageData} */
export let data;
let version = data.version;
@ -41,7 +40,7 @@
afterNavigate(() => {
repl.set({
components: data.gist.components,
components: data.gist.components
});
});
@ -99,11 +98,11 @@
<style>
.repl-outer {
position: relative;
height: calc(100vh - var(--nav-h));
height: calc(100vh - var(--sk-nav-height));
--app-controls-h: 5.6rem;
--pane-controls-h: 4.2rem;
overflow: hidden;
background-color: var(--back);
background-color: var(--sk-back-1);
padding: var(--app-controls-h) 0 0 0;
/* margin: 0 calc(var(--side-nav) * -1); */
box-sizing: border-box;

@ -45,15 +45,15 @@
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name,
files: components.map((component) => ({
name: `${component.name}.${component.type}`,
source: component.source,
})),
}),
source: component.source
}))
})
});
if (r.status < 200 || r.status >= 300) {
@ -110,15 +110,15 @@
method: 'PUT',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name,
files: components.map((component) => ({
name: `${component.name}.${component.type}`,
source: component.source,
})),
}),
source: component.source
}))
})
});
if (r.status < 200 || r.status >= 300) {
@ -164,7 +164,7 @@
files.push(
...components.map((component) => ({
path: `src/${component.name}.${component.type}`,
data: component.source,
data: component.source
}))
);
files.push({
@ -175,7 +175,7 @@ var app = new App({
target: document.body
});
export default app;`,
export default app;`
});
downloadBlob(doNotZip.toBlob(files), 'svelte-app.zip');
@ -242,7 +242,7 @@ export default app;`,
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.6rem var(--side-nav);
padding: 0.6rem var(--sk-page-padding-side);
background-color: var(--sk-back-4);
color: var(--sk-text-1);
white-space: nowrap;

@ -47,7 +47,7 @@
/* position: relative; padding: 0 2em 0 0; */
line-height: 1;
display: none;
font-family: var(--font);
font-family: var(--sk-font);
font-size: 1.6rem;
opacity: 0.7;
}
@ -72,7 +72,7 @@
min-width: 10em;
top: 3rem;
right: -1.6rem;
background-color: var(--second);
background-color: var(--sk-theme-2);
padding: 0.8rem 1.6rem;
z-index: 99;
text-align: left;
@ -84,7 +84,7 @@
.menu button,
.menu a {
background-color: transparent;
font-family: var(--font);
font-family: var(--sk-font);
font-size: 1.6rem;
opacity: 0.7;
padding: 0.4rem 0;

@ -26,7 +26,7 @@
left: 0;
width: 100%;
height: 100%;
background-color: var(--back);
background-color: var(--sk-back-1);
overflow: hidden;
box-sizing: border-box;
--pane-controls-h: 4.2rem;

@ -45,7 +45,7 @@
<style>
.container {
padding: var(--top-offset) var(--side-nav) 6rem var(--side-nav);
padding: var(--sk-page-padding-top) var(--sk-page-padding-side) 6rem var(--sk-page-padding-side);
}
h1,
@ -64,10 +64,10 @@
}
.error {
background-color: var(--second);
background-color: var(--sk-theme-2);
color: white;
padding: 12px 16px;
font: 600 16px/1.7 var(--font);
font: 600 16px/1.7 var(--sk-font);
border-radius: 2px;
}
</style>

@ -123,12 +123,12 @@ npm run dev
section {
position: relative;
margin: 10rem auto;
padding: 0 var(--side-nav);
padding: 0 var(--sk-page-padding-side);
max-width: 120rem;
}
.blurb-shifter {
margin-top: calc(-10rem + var(--side-nav));
margin-top: calc(-10rem + var(--sk-page-padding-side));
}
footer {
@ -139,7 +139,7 @@ npm run dev
}
footer a {
color: var(--text);
color: var(--sk-text-2);
padding: 0.5rem 1rem;
display: block;
}

@ -6,26 +6,26 @@
{
id: 'hello-world',
title: 'Hello World',
description: 'Svelte components are built on top of HTML. Just add data.',
description: 'Svelte components are built on top of HTML. Just add data.'
},
{
id: 'nested-components',
title: 'Scoped CSS',
description:
'CSS is component-scoped by default — no more style collisions or specificity wars. Or you can <a href="/blog/svelte-css-in-js">use your favourite CSS-in-JS library</a >.',
'CSS is component-scoped by default — no more style collisions or specificity wars. Or you can <a href="/blog/svelte-css-in-js">use your favourite CSS-in-JS library</a >.'
},
{
id: 'reactive-assignments',
title: 'Reactivity',
description:
'Trigger efficient, granular updates by assigning to local variables. The compiler does the rest.',
'Trigger efficient, granular updates by assigning to local variables. The compiler does the rest.'
},
{
id: 'svg-transitions',
title: 'Transitions',
description:
'Build beautiful UIs with a powerful, performant transition engine built right into the framework.',
},
'Build beautiful UIs with a powerful, performant transition engine built right into the framework.'
}
];
let selected = examples[0];
@ -80,14 +80,14 @@
grid-template-columns: 4fr 1fr;
color: white;
align-items: center;
font-size: var(--h5);
font-size: var(--sk-text-s);
}
.tabs {
display: grid;
grid-template-columns: repeat(4, 1fr);
height: 100%;
border-radius: var(--border-r) var(--border-r) 0 0;
border-radius: var(--sk-border-radius) var(--sk-border-radius) 0 0;
background-color: rgba(255, 255, 255, 0.1);
}
@ -98,7 +98,7 @@
height: 100%;
align-items: center;
justify-content: center;
border-radius: var(--border-r) var(--border-r) 0 0;
border-radius: var(--sk-border-radius) var(--sk-border-radius) 0 0;
}
button:hover {
@ -143,7 +143,7 @@
@media (min-width: 960px) {
.controls {
font-size: var(--h4);
font-size: var(--sk-text-s);
}
.large-show {

@ -17,7 +17,7 @@
.repl-container {
width: 100%;
height: 420px;
border-radius: var(--border-r);
border-radius: var(--sk-border-radius);
overflow: hidden;
}
</style>

@ -6,7 +6,11 @@
<div class="hero">
<strong>Cybernetically enhanced web apps</strong>
<Image src={Machine} alt="The Svelte compiler packaging up your component code" --max-height="65vh" />
<Image
src={Machine}
alt="The Svelte compiler packaging up your component code"
--max-height="65vh"
/>
<img alt="Svelte logotype" class="logotype" src={SvelteLogotype} />
</div>
@ -22,13 +26,13 @@
strong {
position: absolute;
font-size: min(4vw, var(--h4));
font-size: min(4vw, var(--sk-text-s));
max-width: 10em;
text-transform: uppercase;
font-weight: 700;
color: var(--sk-text-2);
letter-spacing: 0.05em;
left: max(var(--side-nav), 10%);
left: max(var(--sk-page-padding-side), 10%);
top: 25%;
}
@ -55,15 +59,14 @@
.logotype,
strong {
left: calc(var(--side-nav) + 4rem);
/* left: calc(50% - 56rem + var(--side-nav)); */
left: calc(var(--sk-page-padding-side) + 4rem);
}
}
@media (min-width: 1200px) {
strong,
.logotype {
left: calc(50% - 56rem + var(--side-nav));
left: calc(50% - 56rem + var(--sk-page-padding-side));
}
}

@ -10,7 +10,7 @@
.inner {
max-width: 120rem;
padding: 0 var(--side-nav);
padding: 0 var(--sk-page-padding-side);
margin: 0 auto;
}
</style>

@ -36,7 +36,7 @@
grid-gap: 1em;
min-height: calc(100vh - var(--sk-nav-height));
padding: var(--sk-page-padding-top) var(--sk-page-padding-side) 6rem var(--sk-page-padding-side);
max-width: var(--main-width);
max-width: var(--sk-page-main-width);
margin: 0 auto;
}
@ -52,7 +52,7 @@
.post:first-child {
margin: 0 0 2rem 0;
padding: 0 0 4rem 0;
border-bottom: var(--border-w) solid #6767785b; /* based on --second */
border-bottom: var(--sk-thick-border-width) solid #6767785b; /* based on --second */
}
.post:first-child h2 {

@ -36,7 +36,7 @@
<style>
.post {
padding: var(--sk-page-padding-top) var(--sk-page-padding-side) 6rem var(--sk-page-padding-side);
max-width: var(--main-width);
max-width: var(--sk-page-main-width);
margin: 0 auto;
}
@ -155,7 +155,7 @@
@media (min-width: 910px) {
.post :global(.max) {
width: calc(100vw - 2 * var(--sk-page-padding-side));
margin: 0 calc(var(--main-width) / 2 - 50vw);
margin: 0 calc(var(--sk-page-main-width) / 2 - 50vw);
text-align: center;
}

@ -18,7 +18,7 @@
const clone = (file) => ({
name: file.name.replace(/.\w+$/, ''),
type: file.type,
source: file.content,
source: file.content
});
$: mobile = width < 768; // note: same as per media query below
@ -112,7 +112,7 @@
height: 100%;
display: grid;
/* TODO */
grid-template-columns: var(--sidebar-mid-w) auto;
grid-template-columns: 36rem auto;
grid-auto-rows: 100%;
transition: none;
}

@ -50,7 +50,7 @@
overflow-y: auto;
height: 100%;
border-right: 1px solid var(--sk-back-4);
background-color: var(--sk-back-4);
background-color: var(--sk-back-3);
color: var(--sk-text-2);
padding: 3rem 3rem 0 3rem;
margin: 0;

@ -34,8 +34,7 @@
grid-gap: 1em;
min-height: calc(100vh - var(--sk-nav-height));
padding: var(--sk-page-padding-top) var(--sk-page-padding-side) 6rem var(--sk-page-padding-side);
/* TODO: REMOVE */
max-width: var(--main-width);
max-width: var(--sk-page-main-width);
margin: 0 auto;
tab-size: 2;
}

@ -1,10 +1,9 @@
<script>
import Repl from '@sveltejs/repl';
import ScreenToggle from '$lib/components/ScreenToggle.svelte';
import TableOfContents from './TableOfContents.svelte';
import { browser } from '$app/environment';
import ScreenToggle from '$lib/components/ScreenToggle.svelte';
import Repl from '@sveltejs/repl';
import { mapbox_setup, svelteUrl } from '../../../config.js';
import TableOfContents from './TableOfContents.svelte';
import '@sveltejs/site-kit/styles/code.css';
@ -32,7 +31,7 @@
slug: chapter.slug,
section,
chapter,
prev,
prev
};
lookup.set(chapter.slug, obj);
@ -54,13 +53,13 @@
const clone = (file) => ({
name: file.name.replace(/.\w+$/, ''),
type: file.type,
source: file.content,
source: file.content
});
$: if (repl) {
completed = false;
repl.set({
components: data.tutorial.initial.map(clone),
components: data.tutorial.initial.map(clone)
});
}
@ -68,13 +67,13 @@
function reset() {
repl.update({
components: data.tutorial.initial.map(clone),
components: data.tutorial.initial.map(clone)
});
}
function complete() {
repl.update({
components: data.tutorial.complete.map(clone),
components: data.tutorial.complete.map(clone)
});
}
@ -188,7 +187,7 @@
height: 100%;
display: grid;
/* TODO */
grid-template-columns: minmax(33.333%, var(--sidebar-large-w)) auto;
grid-template-columns: minmax(33.333%, 48rem) auto;
grid-auto-rows: 100%;
transition: none;
}
@ -204,7 +203,7 @@
flex-direction: column;
height: 100%;
border-right: 1px solid var(--sk-back-4);
background-color: var(--sk-back-4);
background-color: var(--sk-back-3);
color: var(--sk-text-2);
}
@ -287,6 +286,7 @@
padding: 1rem 1rem;
box-shadow: inset 1px 1px 6px hsla(205.7, 63.6%, 30.8%, 0.06);
border-radius: 0.5rem;
--shiki-color-background: var(--sk-back-1);
}
.controls {

@ -3,7 +3,7 @@ import get_object from '../utils/get_object';
import Expression from './shared/Expression';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { regex_dimensions } from '../../utils/patterns';
import { regex_dimensions, regex_box_size } from '../../utils/patterns';
import { Node as ESTreeNode } from 'estree';
import { TemplateNode } from '../../interfaces';
import Element from './Element';
@ -92,6 +92,7 @@ export default class Binding extends Node {
this.is_readonly =
regex_dimensions.test(this.name) ||
regex_box_size.test(this.name) ||
(isElement(parent) &&
((parent.is_media_node() && read_only_media_attributes.has(this.name)) ||
(parent.name === 'input' && type === 'file')) /* TODO others? */);

@ -12,7 +12,7 @@ import Text from './Text';
import { namespaces } from '../../utils/namespaces';
import map_children from './shared/map_children';
import { is_name_contenteditable, get_contenteditable_attr } from '../utils/contenteditable';
import { regex_dimensions, regex_starts_with_newline, regex_non_whitespace_character } from '../../utils/patterns';
import { regex_dimensions, regex_starts_with_newline, regex_non_whitespace_character, regex_box_size } from '../../utils/patterns';
import fuzzymatch from '../../utils/fuzzymatch';
import list from '../../utils/list';
import Let from './Let';
@ -1090,7 +1090,10 @@ export default class Element extends Node {
} else if (contenteditable && !contenteditable.is_static) {
return component.error(contenteditable, compiler_errors.dynamic_contenteditable_attribute);
}
} else if (name !== 'this') {
} else if (
name !== 'this' &&
!regex_box_size.test(name)
) {
return component.error(binding, compiler_errors.invalid_binding(binding.name));
}
});

@ -11,6 +11,7 @@ import { Node, Identifier } from 'estree';
import add_to_set from '../../../utils/add_to_set';
import mark_each_block_bindings from '../shared/mark_each_block_bindings';
import handle_select_value_binding from './handle_select_value_binding';
import { regex_box_size } from '../../../../utils/patterns';
export default class BindingWrapper {
node: Binding;
@ -455,7 +456,12 @@ function get_value_from_dom(
return x`$$value`;
}
// <select bind:value='selected'>
// <div bind:contentRect|contentBoxSize|borderBoxSize|devicePixelContentBoxSize>
if (regex_box_size.test(name)) {
return x`@ResizeObserverSingleton.entries.get(this)?.${name}`;
}
// <select bind:value='selected>
if (node.name === 'select') {
return node.get_static_attribute_value('multiple') === true ?
x`@select_multiple_value(this)` :

@ -12,7 +12,7 @@ import { namespaces } from '../../../../utils/namespaces';
import AttributeWrapper from './Attribute';
import StyleAttributeWrapper from './StyleAttribute';
import SpreadAttributeWrapper from './SpreadAttribute';
import { regex_dimensions, regex_starts_with_newline, regex_backslashes } from '../../../../utils/patterns';
import { regex_dimensions, regex_starts_with_newline, regex_backslashes, regex_border_box_size, regex_content_box_size, regex_device_pixel_content_box_size, regex_content_rect } from '../../../../utils/patterns';
import Binding from './Binding';
import add_to_set from '../../../utils/add_to_set';
import { add_event_handler } from '../shared/add_event_handlers';
@ -64,11 +64,29 @@ const events = [
filter: (node: Element, _name: string) =>
node.name === 'input' && node.get_static_attribute_value('type') === 'range'
},
// resize events
{
event_names: ['elementresize'],
filter: (_node: Element, name: string) =>
regex_dimensions.test(name)
},
{
event_names: ['elementresizecontentbox'],
filter: (_node: Element, name: string) =>
regex_content_rect.test(name) ?? regex_content_box_size.test(name)
},
{
event_names: ['elementresizeborderbox'],
filter: (_node: Element, name: string) =>
regex_border_box_size.test(name)
},
{
event_names: ['elementresizedevicepixelcontentbox'],
filter: (_node: Element, name: string) =>
regex_device_pixel_content_box_size.test(name)
},
// media events
{
event_names: ['timeupdate'],
@ -747,14 +765,33 @@ export default class ElementWrapper extends Wrapper {
`);
binding_group.events.forEach(name => {
if (name === 'elementresize') {
// special case
if (['elementresize', 'elementresizecontentbox', 'elementresizeborderbox', 'elementresizedevicepixelcontentbox'].indexOf(name) !== -1) {
const resize_listener = block.get_unique_name(`${this.var.name}_resize_listener`);
block.add_variable(resize_listener);
// Can't dynamically do `@fn[name]`, code-red doesn't know how to resolve it
switch (name) {
case 'elementresize':
block.chunks.mount.push(
b`${resize_listener} = @add_resize_listener(${this.var}, ${callee}.bind(${this.var}));`
b`${resize_listener} = @add_iframe_resize_listener(${this.var}, ${callee}.bind(${this.var}));`
);
break;
case 'elementresizecontentbox':
block.chunks.mount.push(
b`${resize_listener} = @resize_observer_content_box.observe(${this.var}, ${callee}.bind(${this.var}));`
);
break;
case 'elementresizeborderbox':
block.chunks.mount.push(
b`${resize_listener} = @resize_observer_border_box.observe(${this.var}, ${callee}.bind(${this.var}));`
);
break;
case 'elementresizedevicepixelcontentbox':
block.chunks.mount.push(
b`${resize_listener} = @resize_observer_device_pixel_content_box.observe(${this.var}, ${callee}.bind(${this.var}));`
);
break;
}
block.chunks.destroy.push(
b`${resize_listener}();`

@ -22,3 +22,9 @@ export const regex_ends_with_underscore = /_$/;
export const regex_invalid_variable_identifier_characters = /[^a-zA-Z0-9_$]/g;
export const regex_dimensions = /^(?:offset|client)(?:Width|Height)$/;
export const regex_content_rect = /^(?:contentRect)$/;
export const regex_content_box_size = /^(?:contentBoxSize)$/;
export const regex_border_box_size = /^(?:borderBoxSize)$/;
export const regex_device_pixel_content_box_size = /^(?:devicePixelContentBoxSize)$/;
export const regex_box_size = /^(?:contentRect|contentBoxSize|borderBoxSize|devicePixelContentBoxSize)$/;

@ -0,0 +1,69 @@
import { globals } from './globals';
/**
* Resize observer singleton.
* One listener per element only!
* https://groups.google.com/a/chromium.org/g/blink-dev/c/z6ienONUb5A/m/F5-VcUZtBAAJ
*/
export class ResizeObserverSingleton {
constructor(readonly options?: ResizeObserverOptions) {}
observe(element: Element, listener: Listener) {
this._listeners.set(element, listener);
this._getObserver().observe(element, this.options);
return () => {
this._listeners.delete(element);
this._observer.unobserve(element); // this line can probably be removed
};
}
private readonly _listeners: WeakMap<Element, Listener> = 'WeakMap' in globals ? new WeakMap() : undefined;
private _observer?: ResizeObserver;
private _getObserver() {
return this._observer ?? (this._observer = new ResizeObserver((entries) => {
for (const entry of entries) {
(ResizeObserverSingleton as any).entries.set(entry.target, entry);
this._listeners.get(entry.target)?.(entry);
}
}));
}
}
// Needs to be written like this to pass the tree-shake-test
(ResizeObserverSingleton as any).entries = 'WeakMap' in globals ? new WeakMap() : undefined;
type Listener = (entry: ResizeObserverEntry)=>any;
// TODO: Remove this
interface ResizeObserverSize {
readonly blockSize: number;
readonly inlineSize: number;
}
interface ResizeObserverEntry {
readonly borderBoxSize: readonly ResizeObserverSize[];
readonly contentBoxSize: readonly ResizeObserverSize[];
readonly contentRect: DOMRectReadOnly;
readonly devicePixelContentBoxSize: readonly ResizeObserverSize[];
readonly target: Element;
}
type ResizeObserverBoxOptions = 'border-box' | 'content-box' | 'device-pixel-content-box';
interface ResizeObserverOptions {
box?: ResizeObserverBoxOptions;
}
interface ResizeObserver {
disconnect(): void;
observe(target: Element, options?: ResizeObserverOptions): void;
unobserve(target: Element): void;
}
interface ResizeObserverCallback {
(entries: ResizeObserverEntry[], observer: ResizeObserver): void;
}
declare let ResizeObserver: {
prototype: ResizeObserver;
new(callback: ResizeObserverCallback): ResizeObserver;
};

@ -1,3 +1,4 @@
import { ResizeObserverSingleton } from './ResizeObserverSingleton';
import { contenteditable_truthy_values, has_prop } from './utils';
// Track which nodes are claimed during hydration. Unclaimed nodes can then be removed from the DOM
@ -306,6 +307,15 @@ export function attr(node: Element, attribute: string, value?: string) {
else if (node.getAttribute(attribute) !== value) node.setAttribute(attribute, value);
}
/**
* List of attributes that should always be set through the attr method,
* because updating them through the property setter doesn't work reliably.
* In the example of `width`/`height`, the problem is that the setter only
* accepts numeric values, but the attribute can also be set to a string like `50%`.
* If this list becomes too big, rethink this approach.
*/
const always_set_through_set_attribute = ['width', 'height'];
export function set_attributes(node: Element & ElementCSSInlineStyle, attributes: { [x: string]: string }) {
// @ts-ignore
const descriptors = Object.getOwnPropertyDescriptors(node.__proto__);
@ -316,7 +326,7 @@ export function set_attributes(node: Element & ElementCSSInlineStyle, attributes
node.style.cssText = attributes[key];
} else if (key === '__value') {
(node as any).value = node[key] = attributes[key];
} else if (descriptors[key] && descriptors[key].set) {
} else if (descriptors[key] && descriptors[key].set && always_set_through_set_attribute.indexOf(key) === -1) {
node[key] = attributes[key];
} else {
attr(node, key, attributes[key]);
@ -689,7 +699,7 @@ export function is_crossorigin() {
return crossorigin;
}
export function add_resize_listener(node: HTMLElement, fn: () => void) {
export function add_iframe_resize_listener(node: HTMLElement, fn: () => void) {
const computed_style = getComputedStyle(node);
if (computed_style.position === 'static') {
@ -737,6 +747,11 @@ export function add_resize_listener(node: HTMLElement, fn: () => void) {
};
}
export const resize_observer_content_box = /* @__PURE__ */ new ResizeObserverSingleton({ box: 'content-box' });
export const resize_observer_border_box = /* @__PURE__ */ new ResizeObserverSingleton({ box: 'border-box' });
export const resize_observer_device_pixel_content_box = /* @__PURE__ */ new ResizeObserverSingleton({ box: 'device-pixel-content-box' });
export { ResizeObserverSingleton };
export function toggle_class(element, name, toggle) {
element.classList[toggle ? 'add' : 'remove'](name);
}

@ -1,8 +1,8 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
add_iframe_resize_listener,
add_render_callback,
add_resize_listener,
detach,
element,
init,
@ -23,7 +23,7 @@ function create_fragment(ctx) {
},
m(target, anchor) {
insert(target, div, anchor);
div_resize_listener = add_resize_listener(div, /*div_elementresize_handler*/ ctx[2].bind(div));
div_resize_listener = add_iframe_resize_listener(div, /*div_elementresize_handler*/ ctx[2].bind(div));
},
p: noop,
i: noop,

@ -1,8 +1,8 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
add_iframe_resize_listener,
add_render_callback,
add_resize_listener,
detach,
element,
init,
@ -42,7 +42,7 @@ function create_fragment(ctx) {
},
m(target, anchor) {
insert(target, video, anchor);
video_resize_listener = add_resize_listener(video, /*video_elementresize_handler*/ ctx[7].bind(video));
video_resize_listener = add_iframe_resize_listener(video, /*video_elementresize_handler*/ ctx[7].bind(video));
if (!mounted) {
dispose = [

@ -0,0 +1,4 @@
export default {
// https://github.com/sveltejs/svelte/issues/6752
html: '<img height="100%" width="100%" alt="" />'
};

@ -0,0 +1 @@
<img height="100%" width="100%" alt="" {...$$restProps} />
Loading…
Cancel
Save