Update examples and thumbnails

pull/2425/head
Rich Harris 6 years ago committed by GitHub
parent df75e0c6d9
commit c5b401254c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,281 +0,0 @@
---
title: Template syntax
---
Rather than reinventing the wheel, Svelte templates are built on foundations that have stood the test of time: HTML, CSS and JavaScript. There's very little extra stuff to learn.
### Tags
Tags allow you to bind data to your template. Whenever your data changes (for example after `component.a = 3`), the DOM updates automatically. You can use any JavaScript expression in templates, and it will also automatically update:
```html
<!-- { title: 'Template tags' } -->
<p>{a} + {b} = {a + b}</p>
```
```json
/* { hidden: true } */
{
"a": 1,
"b": 2
}
```
You can also use tags in attributes:
```html
<!-- { title: 'Tags in attributes' } -->
<h1 style="color: {color};">{color}</h1>
<p hidden={hideParagraph}>You can hide this paragraph.</p>
```
```json
/* { hidden: true } */
{
color: "steelblue",
hideParagraph: false
}
```
[Boolean attributes](https://www.w3.org/TR/html5/infrastructure.html#sec-boolean-attributes) like `hidden` will be omitted if the tag expression evaluates to false. Attributes will be removed from the element if their value is `undefined` or `null`.
### HTML
Ordinary tags render expressions as plain text. If you need your expression interpreted as HTML, wrap it in a special `@html` tag:
```html
<!-- { title: 'Triple tags' } -->
<p>This HTML: {content}</p>
<p>Renders as: {@html content}</p>
```
```json
/* { hidden: true } */
{
content: "Some <b>bold</b> text."
}
```
As with regular tags, you can use any JavaScript expression in HTML tags, and it will automatically update the document when your data changes.
> HTML is **not** sanitized before it is rendered! If you are displaying user input, you are responsible for first sanitizing it. Not doing so potentially opens you up to XSS attacks.
### If blocks
Control whether or not part of your template is rendered by wrapping it in an if block.
```html
<!-- { repl: false } -->
{#if user.loggedIn}
<a href="/logout">log out</a>
{/if}
{#if !user.loggedIn}
<a href="/login">log in</a>
{/if}
```
You can combine the two blocks above with `{:else}`:
```html
<!-- { repl: false } -->
{#if user.loggedIn}
<a href="/logout">log out</a>
{:else}
<a href="/login">log in</a>
{/if}
```
You can also use `{:else if ...}`:
```html
<!--{ title: 'If, else and else if' }-->
{#if x > 10}
<p>{x} is greater than 10</p>
{:else if 5 > x}
<p>{x} is less than 5</p>
{:else}
<p>{x} is between 5 and 10</p>
{/if}
```
```json
/* { hidden: true } */
{
x: 7
}
```
### Each blocks
Iterate over lists of data:
```html
<!--{ title: 'Each blocks' }-->
<h1>Cats of YouTube</h1>
<ul>
{#each cats as cat}
<li><a target="_blank" href={cat.video}>{cat.name}</a></li>
{:else}
<li>No cats :(</li>
{/each}
</ul>
```
```json
/* { hidden: true } */
{
cats: [
{
name: "Keyboard Cat",
video: "https://www.youtube.com/watch?v=J---aiyznGQ"
},
{
name: "Maru",
video: "https://www.youtube.com/watch?v=z_AbfPXTKms"
},
{
name: "Henri The Existential Cat",
video: "https://www.youtube.com/watch?v=OUtn3pvWmpg"
}
]
}
```
Else is triggered when the list is empty.
You can access the index of the current element with *expression* as *name*, *index*:
```html
<!--{ title: 'Each block indexes' }-->
<div class="grid">
{#each rows as row, y}
<div class="row">
{#each columns as column, x}
<code class="cell">
{x + 1},{y + 1}:
<strong>{row[column]}</strong>
</code>
{/each}
</div>
{/each}
</div>
```
```json
/* { hidden: true } */
{
columns: ["foo", "bar", "baz"],
rows: [
{ foo: "a", bar: "b", baz: "c" },
{ foo: "d", bar: "e", baz: "f" },
{ foo: "g", bar: "h", baz: "i" }
]
}
```
> By default, if the list `a, b, c` becomes `a, c`, Svelte will *remove* the third block and *change* the second from `b` to `c`, rather than removing `b`. If that's not what you want, use a [keyed each block](docs#keyed-each-blocks).
You can use destructuring patterns on the elements of the array:
```html
<!--{ title: 'Each block destructuring' }-->
<h1>It's the cats of YouTube again</h1>
<ul>
{#each cats as {name, video} }
<li><a target="_blank" href={video}>{name}</a></li>
{/each}
</ul>
```
```json
/* { hidden: true } */
{
cats: [
{
name: "Keyboard Cat",
video: "https://www.youtube.com/watch?v=J---aiyznGQ"
},
{
name: "Maru",
video: "https://www.youtube.com/watch?v=z_AbfPXTKms"
},
{
name: "Henri The Existential Cat",
video: "https://www.youtube.com/watch?v=OUtn3pvWmpg"
}
]
}
```
### Await blocks
You can represent the three states of a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — pending, fulfilled and rejected — with an `await` block:
```html
<!--{ title: 'Await blocks' }-->
<script>
const promise = new Promise(fulfil => {
setTimeout(() => fulfil(42), 3000);
});
</script>
{#await promise}
<p>wait for it...</p>
{:then answer}
<p>the answer is {answer}!</p>
{:catch error}
<p>well that's odd</p>
{/await}
```
If the expression in `{#await expression}` *isn't* a promise, Svelte skips ahead to the `then` section.
### Directives
Directives allow you to add special instructions for adding [event handlers](docs#event-handlers), [bindings](docs#bindings), [transitions](docs#transitions) and so on. We'll cover each of those in later stages of this guide for now, all you need to know is that directives can be identified by the `:` character:
```html
<!--{ title: 'Element directives' }-->
<p>Count: {count}</p>
<button on:click="{() => count += 1}">+1</button>
```
```json
/* { hidden: true } */
{
count: 0
}
```
> Technically, the `:` character is used to denote namespaced attributes in HTML. These will *not* be treated as directives, if encountered.
### Debug tags
To inspect data as it changes and flows through your app, use a `{@debug ...}` tag:
```html
<!--{ title: 'Debug tags' }-->
<input bind:value={name}>
{@debug name}
<h1>Hello {name}!</h1>
```
```json
/* { hidden: true } */
{
name: 'world'
}
```
This will log the value of `name` whenever it changes. If your devtools are open, changing `name` will pause execution and open the debugger.
You can debug multiple values simultaneously (`{@debug foo, bar, baz}`), or use `{@debug}` to pause execution whenever the surrounding markup is updated.
> Debug tags only have an effect when compiling with the `dev: true` compiler option.

@ -1,118 +0,0 @@
---
title: Scoped styles
---
One of Svelte's key tenets is that components should be self-contained and reusable in different contexts. Because of that, it has a mechanism for *scoping* your CSS, so that you don't accidentally clobber other selectors on the page.
### Adding styles
Your component template can have a `<style>` tag, like so:
```html
<!--{ title: 'Scoped styles' }-->
<style>
.foo {
color: red;
font-size: 2em;
font-family: 'Comic Sans MS';
}
</style>
<div class="foo">
Big red Comic Sans
</div>
```
### How it works
Open the example above in the REPL and inspect the element to see what has happened Svelte has added a `svelte-[uniqueid]` class to the element, and transformed the CSS selector accordingly. Since no other element on the page can share that selector, anything else on the page with `class="foo"` will be unaffected by our styles.
This is vastly simpler than achieving the same effect via [Shadow DOM](http://caniuse.com/#search=shadow%20dom) and works everywhere without polyfills.
> Svelte will add a `<style>` tag to the page containing your scoped styles. Dynamically adding styles may be impossible if your site has a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). If that's the case, you can use scoped styles by [server-rendering your CSS](docs#rendering-css) and using the `css: false` compiler option (or `--no-css` with the CLI).
### Cascading rules
Styles will *only* apply to the current component, unless you opt in to cascading with the `:global(...)` modifier:
<!-- TODO `cascade: false` in the REPL -->
```html
<!-- { repl: false } -->
<script>
import Widget from './Widget.html';
</script>
<style>
p {
/* this block will be disregarded, since
there are no <p> elements here */
color: red;
}
div :global(p) {
/* this block will be applied to any <p> elements
inside the <div>, i.e. in <Widget> */
font-weight: bold;
}
</style>
<div>
<Widget/>
</div>
```
> Scoped styles are *not* dynamic  they are shared between all instances of a component. In other words you can't use `{tags}` inside your CSS.
### Unused style removal
Svelte will identify and remove styles that are not being used in your app. It will also emit a warning so that you can remove them from the source.
For rules *not* to be removed, they must apply to the component's markup. As far as Svelte is concerned `.bold` is unused in the following code and should be removed:
```html
<!-- { repl: false } -->
<div>
<p bind:this={paragraph}>this text is not bold</p>
</div>
<style>
.bold {
color: bold;
}
</style>
<script>
import { onMount } from 'svelte';
let paragraph;
onMount(() => {
paragraph.classList.add('bold');
});
</script>
```
Instead of manually manipulating the DOM, you should always use the `class` attribute (or the [class directive](https://svelte.technology/docs#classes)):
```html
<!-- { repl: false } -->
<div>
<p class:bold={bold}>this text is bold</p>
</div>
```
If that's impossible for some reason, you can use `:global(...)`:
```html
<!-- { repl: false } -->
<style>
div :global(.bold) {
color: bold;
}
</style>
```
The same applies to the contents of `{@html ...}` tags.

@ -1,122 +0,0 @@
---
title: Behaviours
---
As well as scoped styles and a template, components can encapsulate *behaviours*. For that, we add a `<script>` element:
```html
<!-- { title: 'Behaviours' } -->
<script>
// behaviours go here
</script>
<div>
<!-- template goes here -->
</div>
```
### Internal state
Often, it makes sense for a component to have internal state that isn't visible to the outside world.
```html
<!-- { title: 'Internal state' } -->
<script>
let count = 0;
</script>
<p>Count: {count}</p>
<button on:click="{() => count += 1}">+1</button>
```
### External properties
On the other hand, for the component to form part of a system, it needs to expose certain values so that they can be set from outside. These are called *props*, and we use the `export` keyword to differentiate them from internal state:
```html
<!-- { title: 'External properties' } -->
<script>
export let count = 0;
</script>
<p>Count: {count}</p>
<button on:click="{() => count += 1}">+1</button>
```
> Effectively, we're exporting a *contract* with the outside world. The `export` keyword normally means something different in JavaScript, so you might be surprised to see it used like this. Just roll with it for now!
The `= 0` sets a default value for `count`, if none is provided.
```js
const counter = new Counter({
target: document.body,
props: {
count: 99
}
});
counter.count; // 99
counter.count += 1; // 100
```
Props declared with `const` or `function` are *read-only* — they cannot be set from outside. This allows you to, for example, attach custom methods to your component:
```js
component.doSomethingFun();
```
### Lifecycle hooks
There are four 'hooks' provided by Svelte for adding control logic — `onMount`, `beforeUpdate`, `afterUpdate` and `onDestroy`. Import them directly from `svelte`:
```html
<!-- { title: 'Lifecycle hooks' } -->
<script>
import { onMount, beforeUpdate, afterUpdate, onDestroy } from 'svelte';
beforeUpdate(() => {
// this function is called immediately before
// the component updates to reflect new data
console.log(`beforeUpdate`);
});
afterUpdate(() => {
// this function is called immediately *after*
// the component updates to reflect new data.
// if you need to do anything that assumes the
// DOM is up-to-date — such as measuring the
// size of an element — do it here
console.log(`afterUpdate`);
});
onMount(() => {
// this function is called once, after the
// `afterUpdate` function (if there is one)
// runs for the first time
console.log(`onMount`);
return () => {
// this function runs when the
// component is destroyed
console.log(`onMount cleanup`);
};
});
onDestroy(() => {
// this function runs when the
// component is destroyed
console.log(`onDestroy`);
});
let count = 0;
</script>
<button on:click="{() => count += 1}">
Trigger an update ({count})
</button>
```
> Lifecycle hooks do *not* run in server-side rendering (SSR) mode, with the exception of `onDestroy`. More on SSR later.

@ -1,147 +0,0 @@
---
title: Nested components
---
As well as containing elements (and `if` blocks and `each` blocks), Svelte components can contain *other* Svelte components.
```html
<!-- { title: 'Nested components' } -->
<script>
import Widget from './Widget.html';
</script>
<div class='widget-container'>
<Widget answer={42}/>
</div>
```
```html
<!--{ filename: 'Widget.html' }-->
<p>I am a nested component. The answer is {answer}</p>
```
That's similar to doing this...
```js
import Widget from './Widget.html';
const widget = new Widget({
target: document.querySelector('.widget-container'),
props: {
answer: 42
}
});
```
...except that Svelte takes care of destroying the child component when the parent is destroyed, and keeps props in sync if they change.
> Component names must be capitalised, following the widely-used JavaScript convention of capitalising constructor names. It's also an easy way to distinguish components from elements in your template.
### Props
Props, short for 'properties', are the means by which you pass data down from a parent to a child component — in other words, they're just like attributes on an element. As with element attributes, prop values can contain any valid JavaScript expression.
Often, the name of the property will be the same as the value, in which case we can use a shorthand:
```html
<!-- { repl: false } -->
<!-- these are equivalent -->
<Widget foo={foo}/>
<Widget {foo}/>
```
> Note that props are *one-way* — to get data from a child component into a parent component, use [bindings](docs#bindings).
### Composing with `<slot>`
A component can contain a `<slot></slot>` element, which allows the parent component to inject content:
```html
<!-- { title: 'Using <slot>' } -->
<script>
import Box from './Box.html';
</script>
<Box>
<h2>Hello!</h2>
<p>This is a box. It can contain anything.</p>
</Box>
```
```html
<!--{ filename: 'Box.html' }-->
<style>
.box {
border: 2px solid black;
padding: 0.5em;
}
</style>
<div class="box">
<slot><!-- content is injected here --></slot>
</div>
```
The `<slot>` element can contain 'fallback content', which will be used if no children are provided for the component:
```html
<!-- { title: 'Default slot content' } -->
<script>
import Box from './Box.html';
</script>
<Box></Box>
```
```html
<!--{ filename: 'Box.html' }-->
<style>
.box {
border: 2px solid black;
padding: 0.5em;
}
.fallback {
color: #999;
}
</style>
<div class="box">
<slot>
<p class="fallback">the box is empty!</p>
</slot>
</div>
```
You can also have *named* slots. Any elements with a corresponding `slot` attribute will fill these slots:
```html
<!-- { title: 'Named slots' } -->
<script>
import ContactCard from './ContactCard.html';
</script>
<ContactCard>
<span slot="name">P. Sherman</span>
<span slot="address">42 Wallaby Way, Sydney</span>
</ContactCard>
```
```html
<!--{ filename: 'ContactCard.html' }-->
<style>
.contact-card {
border: 2px solid black;
padding: 0.5em;
}
</style>
<div class="contact-card">
<h2><slot name="name"></slot></h2>
<slot name="address">Unknown address</slot>
<br>
<slot name="email">Unknown email</slot>
</div>
```

@ -1,135 +0,0 @@
---
title: Special elements
---
Svelte includes a handful of built-in elements with special behaviour.
### `<svelte:self>`
Sometimes, a component needs to embed itself recursively — for example if you have a tree-like data structure. In Svelte, that's accomplished with the `<svelte:self>` tag:
```html
<!-- { title: '<svelte:self> tags' } -->
{#if countdown > 0}
<p>{countdown}</p>
<svelte:self countdown="{countdown - 1}"/>
{:else}
<p>liftoff!</p>
{/if}
```
```json
/* { hidden: true } */
{
countdown: 5
}
```
### `<svelte:component>`
If you don't know what kind of component to render until the app runs — in other words, it's driven by state (aka a dynamic component) — you can use `<svelte:component>`:
```html
<!-- { title: '<svelte:component> tags' } -->
<script>
import Red from './Red.html';
import Blue from './Blue.html';
let foo = true;
</script>
<input type=checkbox bind:checked={foo}> foo
<svelte:component this="{foo ? Red : Blue}" name="thing"/>
```
```html
<!--{ hidden: true, filename: 'Red.html' }-->
<p style="color: red">Red {name}</p>
```
```html
<!--{ hidden: true, filename: 'Blue.html' }-->
<p style="color: blue">Blue {name}</p>
```
The expression inside the `this="{...}"` can be any valid JavaScript expression.
### `<svelte:window>`
The `<svelte:window>` tag gives you a convenient way to declaratively add event listeners to `window`. Event listeners are automatically removed when the component is destroyed.
```html
<!-- { title: '<svelte:window> tags' } -->
<svelte:window on:keydown="{e => (key = event.key, keyCode = e.keyCode)}"/>
<style>
kbd {
background-color: #eee;
border: 2px solid #f4f4f4;
border-right-color: #ddd;
border-bottom-color: #ddd;
font-size: 2em;
margin: 0 0.5em 0 0;
padding: 0.5em 0.8em;
font-family: Inconsolata;
}
</style>
{#if key}
<p><kbd>{key === ' ' ? 'Space' : key}</kbd> (code {keyCode})</p>
{:else}
<p>click in this window and press any key</p>
{/if}
```
You can also bind to certain values — so far `innerWidth`, `outerWidth`, `innerHeight`, `outerHeight`, `scrollX`, `scrollY` and `online`:
```html
<!-- { title: '<svelte:window> bindings' } -->
<svelte:window bind:scrollY={y}/>
<style>
.background {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 9999px;
background: linear-gradient(to bottom, #7db9e8 0%,#0a1d33 100%);
}
.fixed {
position: fixed;
top: 1em;
left: 1em;
color: white;
}
</style>
<div class="background"></div>
<p class="fixed">user has scrolled {y} pixels</p>
```
### `<svelte:body>`
The `<svelte:body>` tag, just like `<svelte:window>`, gives you a convenient way to declaratively add event listeners to the `document.body` object. This is useful for listening to events that don't fire on `window`, such as `mouseenter` and `mouseleave`.
### `<svelte:head>`
If you're building an application with Svelte — particularly if you're using [Sapper](https://sapper.svelte.technology) — then it's likely you'll need to add some content to the `<head>` of your page, such as adding a `<title>` element.
You can do that with the `<svelte:head>` tag:
```html
<!-- { title: '<svelte:head> tags' } -->
<svelte:head>
<title>{post.title} • My blog</title>
</svelte:head>
```
When [server rendering](docs#server-side-rendering), the `<head>` contents can be extracted separately to the rest of the markup.

@ -1,180 +0,0 @@
---
title: Events
---
In most applications, you'll need to respond to the user's actions. In Svelte, this is done with the `on:[event]` directive.
### Element events
When used on an element, `on:click={handler}` is equivalent to calling `element.addEventListener('click', handler)`. When the element is removed, Svelte calls `removeEventListener` automatically.
```html
<!-- { title: 'Inline event handlers' } -->
<p>Count: {count}</p>
<button on:click="{() => count += 1}">+1</button>
```
```json
/* { hidden: true } */
{
count: 0
}
```
For more complicated behaviours, you'll probably want to declare an event handler in your `<script>` block:
```html
<!-- { title: 'Event handlers' } -->
<script>
let count = 0;
function incrementOrDecrement(event) {
const d = event.shiftKey
? -1
: +1;
count += d;
}
</script>
<p>Count: {count}</p>
<button on:click={incrementOrDecrement}>update</button>
```
```json
/* { hidden: true } */
{
count: 0
}
```
### Event handler modifiers
While you can invoke methods like `event.stopPropagation` directly...
```html
<!-- { repl: false } -->
<div on:click="{e => e.stopPropagation()}">...</div>
```
...it gets annoying if you want to combine that with some other behaviour:
```html
<!-- { repl: false } -->
<script>
let foo = false;
function toggleFoo(event) {
event.stopPropagation();
event.preventDefault();
foo = !foo;
}
</script>
<div on:click={toggleFoo}>...</div>
```
For that reason, Svelte lets you use *event modifiers*:
- [`preventDefault`](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
- [`stopPropagation`](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation)
- [`passive`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters) — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
- [`once`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters) — removes the listener after the first invocation
- [`capture`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameter)
> `passive` and `once` are not implemented in `legacy` mode
The example above can be achieved with modifiers — no need for a separate event handler:
```html
<!-- { repl: false } -->
<div on:click|stopPropagation|preventDefault="{() => foo = !foo}">...</div>
```
### Component events
Events are an excellent way for [nested components](docs#nested-components) to communicate with their parents. Let's revisit our earlier example, but turn it into a `<CategoryChooser>` component:
```html
<!-- { filename: 'CategoryChooser.html', repl: false } -->
<p>Select a category:</p>
{#each categories as category}
<button on:click="fire('select', { category })">select {category}</button>
{/each}
<script>
export default {
data() {
return {
categories: [
'animal',
'vegetable',
'mineral'
]
}
}
};
</script>
```
When the user clicks a button, the component will fire a `select` event, where the `event` object has a `category` property. Any component that nests `<CategoryChooser>` can listen for events like so:
```html
<!--{ title: 'Component events' }-->
<CategoryChooser on:select="playTwentyQuestions(event.category)"/>
<script>
import CategoryChooser from './CategoryChooser.html';
export default {
components: {
CategoryChooser
},
methods: {
playTwentyQuestions(category) {
alert(`ok! you chose ${category}`);
}
}
};
</script>
```
```html
<!--{ filename: 'CategoryChooser.html', hidden: true }-->
<p>Select a category:</p>
{#each categories as category}
<button on:click="fire('select', { category })">select {category}</button>
{/each}
<script>
export default {
data() {
return {
categories: [
'animal',
'vegetable',
'mineral'
]
}
}
};
</script>
```
Just as `this` in an element's event handler refers to the element itself, in a component event handler `this` refers to the component firing the event.
There is also a shorthand for listening for and re-firing an event unchanged.
```html
<!-- { repl: false } -->
<!-- these are equivalent -->
<Widget on:foo="fire('foo', event)"/>
<Widget on:foo/>
```
Since component events do not propagate as DOM events do, this can be used to pass events through intermediate components. This shorthand technique also applies to element events (`on:click` is equivalent to `on:click="fire('click', event)"`).

@ -1,161 +0,0 @@
---
title: Bindings
---
### Bindings
As we've seen, data can be passed down to elements and components with attributes and [props](docs#props). Occasionally, you need to get data back *up*; for that we use bindings.
#### Component bindings
Component bindings keep values in sync between a parent and a child:
```html
<!-- { repl: false } -->
<Widget bind:childValue=parentValue/>
```
Whenever `childValue` changes in the child component, `parentValue` will be updated in the parent component and vice versa.
If the names are the same, you can shorten the declaration:
```html
<!-- { repl: false } -->
<Widget bind:value/>
```
> Use component bindings judiciously. They can save you a lot of boilerplate, but will make it harder to reason about data flow within your application if you overuse them.
#### Element bindings
Element bindings make it easy to respond to user interactions:
```html
<!-- { title: 'Element bindings' } -->
<h1>Hello {name}!</h1>
<input bind:value={name}>
```
```json
/* { hidden: true } */
{
name: 'world'
}
```
Some bindings are *one-way*, meaning that the values are read-only. Most are *two-way* — changing the data programmatically will update the DOM. The following bindings are available:
| Name | Applies to | Kind |
|-----------------------------------------------------------------|----------------------------------------------|----------------------|
| `value` | `<input>` `<textarea>` `<select>` | <span>Two-way</span> |
| `checked` `indeterminate` | `<input type=checkbox>` | <span>Two-way</span> |
| `group` (see note) | `<input type=checkbox>` `<input type=radio>` | <span>Two-way</span> |
| `currentTime` `paused` `played` `volume` | `<audio>` `<video>` | <span>Two-way</span> |
| `buffered` `duration` `seekable` | `<audio>` `<video>` | <span>One-way</span> |
| `offsetWidth` `offsetHeight` `clientWidth` `clientHeight` | All block-level elements | <span>One-way</span> |
| `scrollX` `scrollY` | `<svelte:window>` | <span>Two-way</span> |
| `online` `innerWidth` `innerHeight` `outerWidth` `outerHeight` | `<svelte:window>` | <span>One-way</span> |
> 'group' bindings allow you to capture the current value of a [set of radio inputs](repl?demo=binding-input-radio), or all the selected values of a [set of checkbox inputs](repl?demo=binding-input-checkbox-group).
Here is a complete example of using two way bindings with a form:
```html
<!-- { title: 'Form bindings' } -->
<form on:submit="handleSubmit(event)">
<input bind:value=name type=text>
<button type=submit>Say hello</button>
</form>
<script>
export default {
methods: {
handleSubmit(event) {
// prevent the page from reloading
event.preventDefault();
const { name } = this.get();
alert(`Hello ${name}!`);
}
}
};
</script>
```
```json
/* { hidden: true } */
{
name: "world"
}
```
> 'two way' bindings allow you to update a value in a nested property as seen in [this checkbox input example](repl?demo=binding-input-checkbox).
### bind:this
There's a special binding that exists on all elements and components — `this`. It allows you to store a reference to a DOM node or component instance so that you can interact with it programmatically:
```html
<!-- { title: 'Refs' } -->
<canvas bind:this={canvas} width={200} height={200}></canvas>
<script>
import { onMount } from 'svelte';
import createRenderer from './createRenderer.js';
let canvas;
onMount(() => {
const ctx = canvas.getContext('2d');
const renderer = createRenderer(canvas, ctx);
// stop updating the canvas when
// the component is destroyed
return renderer.stop;
});
</script>
```
```js
/* { filename: 'createRenderer.js', hidden: true } */
export default function createRenderer(canvas, ctx) {
let running = true;
loop();
return {
stop: () => {
running = false;
}
};
function loop() {
if (!running) return;
requestAnimationFrame(loop);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
for (let p = 0; p < imageData.data.length; p += 4) {
const i = p / 4;
const x = i % canvas.width;
const y = i / canvas.height >>> 0;
const t = window.performance.now();
const r = 64 + (128 * x / canvas.width) + (64 * Math.sin(t / 1000));
const g = 64 + (128 * y / canvas.height) + (64 * Math.cos(t / 1000));
const b = 128;
imageData.data[p + 0] = r;
imageData.data[p + 1] = g;
imageData.data[p + 2] = b;
imageData.data[p + 3] = 255;
}
ctx.putImageData(imageData, 0, 0);
}
}
```

@ -1,110 +0,0 @@
---
title: Transitions
---
Transitions allow elements to enter and leave the DOM gracefully, rather than suddenly appearing and disappearing.
```html
<!-- { title: 'Transitions' } -->
<script>
import { fade } from 'svelte/transition';
let visible = false;
</script>
<input type=checkbox bind:checked={visible}> visible
{#if visible}
<p transition:fade>fades in and out</p>
{/if}
```
Transitions can have parameters — typically `delay` and `duration`, but often others, depending on the transition in question. For example, here's the `fly` transition:
```html
<!-- { title: 'Transition with parameters' } -->
<script>
import { fly } from 'svelte/transition';
let visible = false;
</script>
<input type=checkbox bind:checked={visible}> visible
{#if visible}
<p transition:fly="{{y: 200, duration: 1000}}">flies 200 pixels up, slowly</p>
{/if}
```
### In and out
An element can have separate `in` and `out` transitions:
```html
<!-- { title: 'Transition in/out' } -->
<script>
import { fade, fly } from 'svelte-transitions';
let visible = false;
</script>
<input type=checkbox bind:checked={visible}> visible
{#if visible}
<p in:fly="{y: 50}" out:fade>flies up, fades out</p>
{/if}
```
### Built-in transitions
Svelte comes with a handful of ready-to-use transitions:
```html
<!-- { repl: false } -->
<script>
import {
fade,
fly,
slide,
draw
} from 'svelte/transition';
</script>
```
### Custom transitions
You can also make your own. Transitions are simple functions that take a `node` and any provided `parameters` and return an object with the following properties:
* `duration` — how long the transition takes in milliseconds
* `delay` — milliseconds before the transition starts
* `easing` — an [easing function](https://github.com/rollup/eases-jsnext)
* `css` — a function that accepts an argument `t` between 0 and 1 and returns the styles that should be applied at that moment
* `tick` — a function that will be called on every frame, with the same `t` argument, while the transition is in progress
Of these, `duration` is required, as is *either* `css` or `tick`. The rest are optional. Here's how the `fade` transition is implemented, for example:
```html
<!-- { title: 'Fade transition' } -->
<script>
function fade(node, { delay = 0, duration = 400 }) {
const o = +getComputedStyle(node).opacity;
return {
delay,
duration,
css: t => `opacity: ${t * o}`
};
}
let visible = false;
</script>
<input type=checkbox bind:checked={visible}> visible
{#if visible}
<p transition:fade>fades in and out</p>
{/if}
```
> If the `css` option is used, Svelte will create a CSS animation that runs efficiently off the main thread. Therefore if you can achieve an effect using `css` rather than `tick`, you should.

@ -1,103 +0,0 @@
---
title: Actions
---
### Actions
Actions let you decorate elements with additional functionality. Actions are functions which may return an object with lifecycle methods, `update` and `destroy`. The action will be called when its element is added to the DOM.
Use actions for things like:
* tooltips
* lazy loading images as the page is scrolled, e.g. `<img use:lazyload data-src='giant-photo.jpg'/>`
* capturing link clicks for your client router
* adding drag and drop
```html
<!-- { title: 'Actions' } -->
<button on:click={toggleLanguage} use:tooltip={translations[language].tooltip}>
{language}
</button>
<script>
export default {
actions: {
tooltip(node, text) {
const tooltip = document.createElement('div');
tooltip.textContent = text;
Object.assign(tooltip.style, {
position: 'absolute',
background: 'black',
color: 'white',
padding: '0.5em 1em',
fontSize: '12px',
pointerEvents: 'none',
transform: 'translate(5px, -50%)',
borderRadius: '2px',
transition: 'opacity 0.4s'
});
function position() {
const { top, right, bottom } = node.getBoundingClientRect();
tooltip.style.top = `${(top + bottom) / 2}px`;
tooltip.style.left = `${right}px`;
}
function append() {
document.body.appendChild(tooltip);
tooltip.style.opacity = 0;
setTimeout(() => tooltip.style.opacity = 1);
position();
}
function remove() {
tooltip.remove();
}
node.addEventListener('mouseenter', append);
node.addEventListener('mouseleave', remove);
return {
update(text) {
tooltip.textContent = text;
position();
},
destroy() {
tooltip.remove();
node.removeEventListener('mouseenter', append);
node.removeEventListener('mouseleave', remove);
}
}
}
},
methods: {
toggleLanguage() {
const { language } = this.get();
this.set({
language: language === 'english' ? 'latin' : 'english'
});
}
}
};
</script>
```
```json
/* { hidden: true } */
{
language: "english",
translations: {
english: {
tooltip: "Switch Languages",
},
latin: {
tooltip: "Itchsway Anguageslay",
},
}
}
```

@ -1,70 +0,0 @@
---
title: Classes
---
Like any attribute, the `class` attribute can be set using regular JavaScript. Suppose we had an `active` class that we wanted to apply to an element when `isActive` is true — we could do it like this:
```html
<!-- { title: 'Dynamic classes using ternaries' } -->
<script>
let isActive = false;
</script>
<style>
.active {
color: red;
}
</style>
<h1 class="{isActive ? 'active' : ''}">red if active</h1>
<label>
<input type=checkbox bind:checked={isActive}> isActive
</label>
```
That's a little verbose though, so the `class:` directive gives you a simpler way to achieve the same thing:
```html
<!-- { title: 'Dynamic classes using directives' } -->
<script>
let isActive = false;
</script>
<style>
.active {
color: red;
}
</style>
-<h1 class="{isActive ? 'active' : ''}">red if active</h1>
+<h1 class:active={isActive}>red if active</h1>
<label>
<input type=checkbox bind:checked={isActive}> isActive
</label>
```
As with any directive, you can use any JavaScript expression. If it's a variable name that matches the class name, you can use a shorthand:
```html
<!-- { title: 'Dynamic classes using directives' } -->
<script>
- let isActive = false;
+ let active = false;
</script>
<style>
.active {
color: red;
}
</style>
-<h1 class:active={isActive}>red if active</h1>
+<h1 class:active>red if active</h1>
<label>
- <input type=checkbox bind:checked={isActive}> isActive
+ <input type=checkbox bind:checked={active}> active
</label>
```

@ -1,67 +0,0 @@
---
title: Module context
---
So far, our `<script>` tags have been running in the context of a component *instance*. In other words, if you have two components like this...
```html
<!-- { title: 'Counter' } -->
<script>
import Counter from './Counter.html';
</script>
<Counter/>
<Counter/>
```
```html
<!--{ filename: 'Counter.html' }-->
<script>
let count = 0;
</script>
<button on:click="{() => count += 1}">+1</button>
```
...each counter has its own `count` variable. The code runs once per instance.
Occasionally, you want code to run once *per module* instead. For that, we use `context="module"`:
```html
<!-- { title: 'Module context' } -->
<script context="module">
console.log(`this will run once`);
const answer = 42;
</script>
<script>
console.log(`this will run once per instance`);
console.log(`we can 'see' module-level variables like ${answer}`);
</script>
```
> Don't worry about manually hoisting functions from instance context to module context to avoid creating multiple copies of them — Svelte will do that for you
### Module exports
Any named exports from a `context="module"` script become part of the module's static exports. For example, to define a `preload` function for use with [Sapper](https://sapper.svelte.technology):
```html
<!-- { title: 'Module exports', repl: false } -->
<script context="module">
export async function preload({ params }) {
const res = await this.fetch(`/blog/${params.slug}.json`);
return {
post: await res.json()
};
}
</script>
```
```js
import BlogPost, { preload } from './BlogPost.html';
```
You can only have named exports — no `export default` — because the component *is* the default export.

@ -1,78 +0,0 @@
---
title: Server-side rendering
---
So far, we've discussed creating Svelte components *on the client*, which is to say the browser. But you can also render Svelte components in Node.js. This can result in better perceived performance as it means the application starts rendering while the page is still downloading, before any JavaScript executes. It also has SEO advantages in some cases, and can be beneficial for people running older browsers that can't or won't run your JavaScript for whatever reason.
### Using the compiler
If you're using the Svelte compiler, whether directly or via an integration like [rollup-plugin-svelte](https://github.com/rollup/rollup-plugin-svelte) or [svelte-loader](https://github.com/sveltejs/svelte-loader), you can tell it to generate a server-side component by passing the `generate: 'ssr'` option:
```js
const { js } = svelte.compile(source, {
generate: 'ssr' // as opposed to 'dom', the default
});
```
### Registering Svelte
Alternatively, an easy way to use the server-side renderer is to *register* it:
```js
require('svelte/register.js');
```
Now you can `require` your components:
```js
const Thing = require('./components/Thing.html');
```
If you prefer to use a different file extension, you can pass options like so:
```js
require('svelte/register.js')({
extensions: ['.svelte']
});
```
### Server-side API
Components have a different API in Node.js rather than being a constructor that you use with the `new` keyword, a component is an object with a `render(data, options)` method:
```js
require('svelte/register.js');
const Thing = require('./components/Thing.html');
const props = { answer: 42 };
const { html, css, head } = Thing.render(props);
```
[Lifecycle hooks](docs#lifecycle-hooks) will *not* run, with the exception of `onDestroy`, because the component is never 'mounted'.
> The SSR compiler will generate a CommonJS module for each of your components meaning that `import` and `export` statements are converted into their `require` and `module.exports` equivalents. If your components have non-component dependencies, they must also work as CommonJS modules in Node. If you're using ES2015 modules, we recommend the [`esm`](https://github.com/standard-things/esm) module for automatically converting them to CommonJS.
#### Rendering styles
You can also extract any [scoped styles](docs#scoped-styles) that are used by the component or its children:
```js
const { css } = Thing.render(data);
```
You could put the resulting `css` in a separate stylesheet, or include them in the page inside a `<style>` tag. If you do this, you will probably want to prevent the client-side compiler from including the CSS again. For the CLI, use the `--no-css` flag. In build tool integrations like `rollup-plugin-svelte`, pass the `css: false` option.
#### Rendering `<head>` contents
If your component, any of its children, use the `<svelte:head>` [component](docs#-head-tags), you can extract the contents:
```js
const { head } = Thing.render(data);
```

@ -1,304 +0,0 @@
---
title: State management
---
Svelte components have built-in state management via the `get` and `set` methods. But as your application grows beyond a certain size, you may find that passing data between components becomes laborious.
For example, you might have an `<Options>` component inside a `<Sidebar>` component that allows the user to control the behaviour of a `<MainView>` component. You could use bindings or events to 'send' information up from `<Options>` through `<Sidebar>` to a common ancestor — say `<App>` — which would then have the responsibility of sending it back down to `<MainView>`. But that's cumbersome, especially if you decide you want to break `<MainView>` up into a set of smaller components.
Instead, a popular solution to this problem is to use a *global store* of data that cuts across your component hierarchy. React has [Redux](https://redux.js.org/) and [MobX](https://mobx.js.org/index.html) (though these libraries can be used anywhere, including with Svelte), and Vue has [Vuex](https://vuex.vuejs.org/en/).
Svelte has `Store`. `Store` can be used in any JavaScript app, but it's particularly well-suited to Svelte apps.
### The basics
Import `Store` from `svelte/store.js` (remember to include the curly braces, as it's a *named import*), then create a new store with some (optional) data:
```js
import { Store } from 'svelte/store.js';
const store = new Store({
name: 'world'
});
```
Each instance of `Store` has `get`, `set`, `on` and `fire` methods that behave identically to their counterparts on a Svelte component:
```js
const { name } = store.get(); // 'world'
store.on('state', ({ current, changed, previous }) => {
console.log(`hello ${current.name}`);
});
store.set({ name: 'everybody' }); // 'hello everybody'
```
### Creating components with stores
Let's adapt our [very first example](docs#understanding-svelte-components):
```html
<!-- { repl: false } -->
<h1>Hello {$name}!</h1>
<Greeting/>
<script>
import Greeting from './Greeting.html';
export default {
components: { Greeting }
};
</script>
```
```html
<!--{ filename: 'Greeting.html' }-->
<p>It's nice to see you, {$name}</p>
```
```js
/* { filename: 'main.js' } */
import App from './App.html';
import { Store } from 'svelte/store.js';
const store = new Store({
name: 'world'
});
const app = new App({
target: document.querySelector('main'),
store
});
window.store = store; // useful for debugging!
```
There are three important things to notice:
* We're passing `store` to `new App(...)` instead of `data`
* The template refers to `$name` instead of `name`. The `$` prefix tells Svelte that `name` is a *store property*
* Because `<Greeting>` is a child of `<App>`, it also has access to the store. Without it, `<App>` would have to pass the `name` property down as a component property (`<Greeting name={name}/>`)
Components that depend on store properties will re-render whenever they change.
### Declarative stores
As an alternative to adding the `store` option when instantiating, the component itself can declare a dependency on a store:
```html
<!-- { title: 'Declarative stores' } -->
<h1>Hello {$name}!</h1>
<Greeting/>
<script>
import Greeting from './Greeting.html';
import store from './store.js';
export default {
store: () => store,
components: { Greeting }
};
</script>
```
```html
<!--{ filename: 'Greeting.html' }-->
<p>It's nice to see you, {$name}</p>
```
```js
/* { filename: 'store.js' } */
import { Store } from 'svelte/store.js';
export default new Store({ name: 'world' });
```
Note that the `store` option is a function that *returns* a store, rather than the store itself — this provides greater flexibility.
### Computed store properties
Just like components, stores can have computed properties:
```js
store = new Store({
width: 10,
height: 10,
depth: 10,
density: 3
});
store.compute(
'volume',
['width', 'height', 'depth'],
(width, height, depth) => width * height * depth
);
store.get().volume; // 1000
store.set({ width: 20 });
store.get().volume; // 2000
store.compute(
'mass',
['volume', 'density'],
(volume, density) => volume * density
);
store.get().mass; // 6000
```
The first argument is the name of the computed property. The second is an array of *dependencies* — these can be data properties or other computed properties. The third argument is a function that recomputes the value whenever the dependencies change.
A component that was connected to this store could reference `{$volume}` and `{$mass}`, just like any other store property.
### Accessing the store inside components
Each component gets a reference to `this.store`. This allows you to attach behaviours in `oncreate`...
```html
<!-- { repl: false } -->
<script>
export default {
oncreate() {
const listener = this.store.on('state', ({ current }) => {
// ...
});
// listeners are not automatically removed — cancel
// them to prevent memory leaks
this.on('destroy', listener.cancel);
}
};
</script>
```
...or call store methods in your event handlers, using the same `$` prefix as data properties:
```html
<!-- { repl: false } -->
<button on:click="$set({ muted: true })">
Mute audio
</button>
```
### Custom store methods
`Store` doesn't have a concept of *actions* or *commits*, like Redux and Vuex. Instead, state is always updated with `store.set(...)`.
You can implement custom logic by subclassing `Store`:
```js
class TodoStore extends Store {
addTodo(description) {
const todo = {
id: generateUniqueId(),
done: false,
description
};
const todos = this.get().todos.concat(todo);
this.set({ todos });
}
toggleTodo(id) {
const todos = this.get().todos.map(todo => {
if (todo.id === id) {
return {
id,
done: !todo.done,
description: todo.description
};
}
return todo;
});
this.set({ todos });
}
}
const store = new TodoStore({
todos: []
});
store.addTodo('Finish writing this documentation');
```
Methods can update the store asynchronously:
```js
class NasdaqTracker extends Store {
async fetchStockPrices(ticker) {
const token = this.token = {};
const prices = await fetch(`/api/prices/${ticker}`).then(r => r.json());
if (token !== this.token) return; // invalidated by subsequent request
this.set({ prices });
}
}
const store = new NasdaqTracker();
store.fetchStockPrices('AMZN');
```
You can call these methods in your components, just like the built-in methods:
```html
<!-- { repl: false } -->
<input
placeholder="Enter a stock ticker"
on:change="$fetchStockPrices(this.value)"
>
```
### Store bindings
You can bind to store values just like you bind to component values — just add the `$` prefix:
```html
<!-- { repl: false } -->
<!-- global audio volume control -->
<input bind:value=$volume type=range min=0 max=1 step=0.01>
```
### Using store properties in computed properties
Just as in templates, you can access store properties in component computed properties by prefixing them with `$`:
```html
<!-- { repl: false } -->
{#if isVisible}
<div class="todo {todo.done ? 'done': ''}">
{todo.description}
</div>
{/if}
<script>
export default {
computed: {
// `todo` is a component property, `$filter` is
// a store property
isVisible: ({ todo, $filter }) => {
if ($filter === 'all') return true;
if ($filter === 'done') return todo.done;
if ($filter === 'pending') return !todo.done;
}
}
};
</script>
```
### Built-in optimisations
The Svelte compiler knows which store properties your components are interested in (because of the `$` prefix), and writes code that only listens for changes to those properties. Because of that, you needn't worry about having many properties on your store, even ones that update frequently — components that don't use them will be unaffected.

@ -1,61 +0,0 @@
---
title: Preprocessing
---
Some developers like to use non-standard languages such as [Pug](https://pugjs.org/api/getting-started.html), [Sass](http://sass-lang.com/) or [CoffeeScript](http://coffeescript.org/).
It's possible to use these languages, or anything else that can be converted to HTML, CSS and JavaScript, using *preprocessors*.
### svelte.preprocess
Svelte exports a `preprocess` function that takes some input source code and returns a Promise for a standard Svelte component, ready to be used with `svelte.compile`:
```js
const svelte = require('svelte');
const input = fs.readFileSync('App.html', 'utf-8');
svelte.preprocess(input, {
filename: 'App.html', // this is passed to each preprocessor
markup: ({ content, filename }) => {
return {
code: '<!-- some HTML -->',
map: {...}
};
},
style: ({ content, attributes, filename }) => {
return {
code: '/* some CSS */',
map: {...}
};
},
script: ({ content, attributes, filename }) => {
return {
code: '// some JavaScript',
map: {...}
};
}
}).then(preprocessed => {
fs.writeFileSync('preprocessed/App.html', preprocessed.toString());
const { js } = svelte.compile(preprocessed);
fs.writeFileSync('compiled/App.js', js.code);
});
```
The `markup` preprocessor, if specified, runs first. The `content` property represents the entire input string.
The `style` and `script` preprocessors receive the contents of the `<style>` and `<script>` elements respectively, along with any `attributes` on those elements (e.g. `<style lang='scss'>`).
All three preprocessors are optional. Each should return a `{ code, map }` object or a Promise that resolves to a `{ code, map }` object, where `code` is the resulting string and `map` is a sourcemap representing the transformation.
> The returned `map` objects are not currently used by Svelte, but will be in future versions
### Using build tools
Many build tool plugins, such as [rollup-plugin-svelte](https://github.com/rollup/rollup-plugin-svelte) and [svelte-loader](https://github.com/sveltejs/svelte-loader), allow you to specify `preprocess` options, in which case the build tool will do the grunt work.

@ -1,142 +0,0 @@
---
title: Advanced
---
### Keyed each blocks
Associating a *key* with a block allows Svelte to be smarter about how it adds and removes items to and from a list. To do so, add an `(expression)` that uniquely identifies each member of the list:
```html
<!-- { repl: false } -->
{#each people as person (person.name)}
<div>{person.name}</div>
{/each}
```
It's easier to show the effect of this than to describe it. Open the following example in the REPL:
```html
<!-- { title: 'Keyed each blocks' } -->
<button on:click="{update}">update</button>
<section>
<h2>Keyed</h2>
{#each people as person (person.name)}
<div transition:slide>{person.name}</div>
{/each}
</section>
<section>
<h2>Non-keyed</h2>
{#each people as person}
<div transition:slide>{person.name}</div>
{/each}
</section>
<style>
button {
display: block;
}
section {
width: 10em;
float: left;
}
</style>
<script>
import { slide } from 'svelte/transition';
const names = ['Alice', 'Barry', 'Cecilia', 'Douglas', 'Eleanor', 'Felix', 'Grace', 'Horatio', 'Isabelle'];
function random() {
return names
.filter(() => Math.random() < 0.5)
.map(name => ({ name }));
}
let people = random();
function update() {
people = random();
}
</script>
```
### Hydration
If you're using [server-side rendering](docs#server-side-rendering), it's likely that you'll need to create a client-side version of your app *on top of* the server-rendered version. A naive way to do that would involve removing all the existing DOM and rendering the client-side app in its place:
```js
import App from './App.html';
const target = document.querySelector('#element-with-server-rendered-html');
// avoid doing this!
target.innerHTML = '';
new App({
target
});
```
Ideally, we want to reuse the existing DOM instead. This process is called *hydration*. First, we need to tell the compiler to include the code necessary for hydration to work by passing the `hydratable: true` option:
```js
const { js } = svelte.compile(source, {
hydratable: true
});
```
(Most likely, you'll be passing this option to [rollup-plugin-svelte](https://github.com/rollup/rollup-plugin-svelte) or [svelte-loader](https://github.com/sveltejs/svelte-loader).)
Then, when we instantiate the client-side component, we tell it to use the existing DOM with `hydrate: true`:
```js
import App from './App.html';
const target = document.querySelector('#element-with-server-rendered-html');
new App({
target,
hydrate: true
});
```
> It doesn't matter if the client-side app doesn't perfectly match the server-rendered HTML — Svelte will repair the DOM as it goes.
### Immutable
Because arrays and objects are *mutable*, Svelte must err on the side of caution when deciding whether or not to update things that refer to them.
But if all your data is [immutable](https://en.wikipedia.org/wiki/Immutable_object), you can use the `{ immutable: true }` compiler option to use strict object comparison (using `===`) everywhere in your app. If you have one component that uses immutable data you can set it to use the strict comparison for just that component.
In the example below, `searchResults` would normally be recalculated whenever `items` *might* have changed, but with `immutable: true` it will only update when `items` has *definitely* changed. This can improve the performance of your app.
```html
<!-- { repl: false } -->
{#each searchResults as item}
<div>{item.name}</div>
{/each}
<script>
import FuzzySearch from 'fuzzy-search';
export default {
immutable: true,
computed: {
searchResults: ({ searchString, items }) => {
if (!searchString) return items;
const searcher = new FuzzySearch(items, ['name', 'location']);
return searcher.search(searchString);
}
}
}
</script>
```
[Here's a live example](repl?demo=immutable) showing the effect of `immutable: true`.

@ -1,109 +0,0 @@
---
title: Custom elements
---
[Custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements) are an emerging web standard for creating DOM elements that encapsulate styles and behaviours, much like Svelte components. They are part of the [web components](https://developer.mozilla.org/en-US/docs/Web/Web_Components) family of specifications.
> Most browsers need [polyfills](https://www.webcomponents.org/polyfills) for custom elements. See [caniuse](https://caniuse.com/#feat=custom-elementsv1) for more details
Svelte components can be used as custom elements by doing the following:
1. Declaring a `tag` name. The value must contain a hyphen (`hello-world` in the example below)
2. Specifying `customElement: true` in the compiler configuration
```html
<!-- { filename: 'HelloWorld.html', repl: false } -->
<h1>Hello {name}!</h1>
<script>
export default {
tag: 'hello-world'
};
</script>
```
Importing this file will now register a globally-available `<hello-world>` custom element that accepts a `name` property:
```js
import './HelloWorld.html';
document.body.innerHTML = `<hello-world name="world"/>`;
const el = document.querySelector('hello-world');
el.name = 'everybody';
```
See [svelte-custom-elements.surge.sh](http://svelte-custom-elements.surge.sh/) ([source here](https://github.com/sveltejs/template-custom-element)) for a larger example.
The compiled custom elements are still full-fledged Svelte components and can be used as such:
```js
el.get().name === el.name; // true
el.set({ name: 'folks' }); // equivalent to el.name = 'folks'
```
One crucial difference is that styles are *fully encapsulated* — whereas Svelte will prevent component styles from leaking *out*, custom elements use [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM) which also prevents styles from leaking *in*.
### Using `<slot>`
Custom elements can use [slots](docs#composing-with-slot) to place child elements, just like regular Svelte components.
### Firing events
You can dispatch events inside custom elements to pass data out:
```js
// inside a component method
const event = new CustomEvent('message', {
detail: 'Hello parent!',
bubbles: true,
cancelable: true,
composed: true // makes the event jump shadow DOM boundary
});
this.dispatchEvent(event);
```
Other parts of the application can listen for these events with `addEventListener`:
```js
const el = document.querySelector('hello-world');
el.addEventListener('message', event => {
alert(event.detail);
});
```
> Note the `composed: true` attribute of the custom event. It enables the custom DOM event to cross the shadow DOM boundary and enter into main DOM tree.
### Observing properties
Svelte will determine, from the template and `computed` values, which properties the custom element has — for example, `name` in our `<hello-world>` example. You can specify this list of properties manually, for example to restrict which properties are 'visible' to the rest of your app:
```js
export default {
tag: 'my-thing',
props: ['foo', 'bar']
};
```
### Compiler options
Earlier, we saw the use of `customElement: true` to instruct the Svelte compiler to generate a custom element using the `tag` and (optional) `props` declared inside the component file.
Alternatively, you can pass `tag` and `props` direct to the compiler:
```js
const { js } = svelte.compile(source, {
customElement: {
tag: 'overridden-tag-name',
props: ['yar', 'boo']
}
});
```
These options will override the component's own settings, if any.
### Transpiling
* Custom elements use ES2015 classes (`MyThing extends HTMLElement`). Make sure you don't transpile the custom element code to ES5, and use a ES2015-aware minifier such as [uglify-es](https://www.npmjs.com/package/uglify-es).
* If you do need ES5 support, make sure to use `Reflect.construct` aware transpiler plugin such as [babel-plugin-transform-builtin-classes](https://github.com/WebReflection/babel-plugin-transform-builtin-classes) and a polyfill like [custom-elements-es5-adapterjs](https://github.com/webcomponents/webcomponentsjs#custom-elements-es5-adapterjs).

@ -1,8 +0,0 @@
---
title: Miscellaneous
---
### `<noscript>`
If you use `<noscript>` tags in a component, Svelte will only render them in SSR mode. The DOM compiler will strip them out, since you can't create the component without JavaScript, and `<noscript>` has no effect if JavaScript is available.

@ -1,155 +0,0 @@
---
title: API reference
---
## TODO MAKE THIS CURRENT, INCLUDE svelte, svelte/store, ETC ETC
As we saw above, you create a component instance with the `new` keyword:
```js
/* { filename: 'main.js' } */
import App from './App.html';
const component = new App({
// `target` is the only required option. This is the
// DOM element your component will be appended to
target: document.querySelector('main'),
// `anchor` is optional.
// The component is inserted immediately before this
// DOM element, which must be a child of `target`
anchor: document.querySelector('main #child'),
// `props` is optional. A component can also have
// default props we'll learn about that later.
props: {
questions: [
'life',
'the universe',
'everything'
],
answer: 42
}
});
```
Normally, you'd interact with a component by getting and setting *props*:
```js
console.log(component.answer); // 42
component.answer = 420;
```
Every Svelte component instance has three built-in methods:
### component.$set(props)
This updates the component's state with the new values provided and causes the DOM to update. `state` must be a plain old JavaScript object (POJO). Any properties *not* included in `state` will remain as they were.
```js
component.set({
questions: [
'why is the sky blue?',
'how do planes fly?',
'where do babies come from?'
],
answer: 'ask your mother'
});
```
### component.get()
Returns the component's current state:
```js
const { questions, answer } = component.get();
console.log(answer); // 'ask your mother'
```
This will also retrieve the value of [computed properties](docs#computed-properties).
> Previous versions of Svelte allowed you to specify a key to retrieve a specific value — this was removed in version 2.
### component.on(eventName, callback)
Allows you to respond to *events*:
```js
const listener = component.on('thingHappened', event => {
console.log(`A thing happened: ${event.thing}`);
});
// some time later...
listener.cancel();
```
Each component has three built-in events, corresponding to their [lifecycle hooks](docs#lifecycle-hooks):
```js
component.on('state', ({ changed, current, previous }) => {
console.log('state changed', current);
});
component.on('update', ({ changed, current, previous }) => {
console.log('DOM updated after state change', current);
});
component.on('destroy', () => {
console.log('this component is being destroyed');
});
```
### component.fire(eventName, event)
The companion to `component.on(...)`:
```js
component.fire('thingHappened', {
thing: 'this event was fired'
});
```
At first glance `component.on(...)` and `component.fire(...)` aren't particularly useful, but it'll become more so when we learn about [nested components](docs#nested-components) and [component events](docs#component-events).
### component.destroy()
Removes the component from the DOM and removes any event listeners that were created. This will also fire a `destroy` event:
```js
component.on('destroy', () => {
alert('goodbye!'); // please don't do this
});
component.destroy();
```
### component.options
The options used to instantiate the component are available in `component.options`.
```html
<!-- { title: 'component.options' } -->
Check the console.
<script>
export default {
oncreate() {
console.log(this.options);
}
};
</script>
```
This gives you access to standard options like `target` and `data`, but can also be used to access any other custom options you may choose to implement for your component.
### component.root
In [nested components](docs#nested-components), each component has a `root` property pointing to the top-level root component that is, the one instantiated with `new MyComponent({...})`.
> Earlier versions of Svelte had a `component.observe(...)` method. This was removed in version 2, in favour of the `onstate` [lifecycle hook](docs#lifecycle-hooks), but is still available via [svelte-extras](https://github.com/sveltejs/svelte-extras).

@ -1,5 +0,0 @@
---
title: TODO...
---
This documentation is still a work-in-progress, like Svelte itself. If there are particular things that are missing or could be improved, then [please raise an issue on GitHub](https://github.com/sveltejs/svelte.technology)!

@ -18,6 +18,18 @@
Remove first thing
</button>
{#each things as thing (thing.id)}
<Thing value={thing.value}/>
{/each}
<div style="display: grid; grid-template-columns: 1fr 1fr; grip-gap: 1em">
<div>
<h2>Keyed</h2>
{#each things as thing (thing.id)}
<Thing value={thing.value}/>
{/each}
</div>
<div>
<h2>Unkeyed</h2>
{#each things as thing}
<Thing value={thing.value}/>
{/each}
</div>
</div>

@ -12,12 +12,20 @@
function clear() {
todos = todos.filter(t => !t.done);
}
$: remaining = todos.filter(t => !t.done).length;
</script>
<style>
.done {
opacity: 0.4;
}
</style>
<h1>Todos</h1>
{#each todos as todo}
<div>
<div class:done={todo.done}>
<input
type=checkbox
bind:checked={todo.done}
@ -30,6 +38,8 @@
</div>
{/each}
<p>{remaining} remaining</p>
<button on:click={add}>
Add new
</button>

@ -34,6 +34,10 @@
</script>
<style>
h2 {
text-align: center;
}
.chart {
width: 100%;
max-width: 500px;
@ -77,9 +81,10 @@
}
</style>
<div class="chart">
<h2>US birthrate by year</h2>
<svg bind:clientWidth={width} bind:clientHeight={height}>
<h2>US birthrate by year</h2>
<div class="chart" bind:clientWidth={width} bind:clientHeight={height}>
<svg>
<!-- y axis -->
<g class="axis y-axis" transform="translate(0,{padding.top})">
{#each yTicks as tick}

@ -1,5 +1,4 @@
<script>
import { onMount } from 'svelte';
import { scaleLinear } from 'd3-scale';
import points from './data.js';
@ -26,21 +25,12 @@
function formatMobile (tick) {
return "'" + tick % 100;
}
let svg;
function resize() {
({ width, height } = svg.getBoundingClientRect());
}
onMount(resize);
</script>
<svelte:window on:resize='{resize}'/>
<h2>Arctic sea ice minimum</h2>
<div class="chart">
<h2>Arctic sea ice minimum</h2>
<svg bind:this={svg}>
<div class="chart" bind:clientWidth={width} bind:clientHeight={height}>
<svg>
<!-- y axis -->
<g class="axis y-axis" transform="translate(0, {padding.top})">
{#each yTicks as tick}
@ -65,21 +55,23 @@
<path class="path-area" d={area}></path>
<path class="path-line" d={path}></path>
</svg>
<p>Average September extent. Source: <a href='https://climate.nasa.gov/vital-signs/arctic-sea-ice/'>NSIDC/NASA</a>
</div>
<p>Average September extent. Source: <a href='https://climate.nasa.gov/vital-signs/arctic-sea-ice/'>NSIDC/NASA</a></p>
<style>
.chart {
.chart, h2, p {
width: 100%;
max-width: 500px;
margin: 0 auto;
margin-left: auto;
margin-right: auto;
}
svg {
position: relative;
width: 100%;
height: 200px;
overflow: visible;
}
.tick {

@ -45,5 +45,7 @@
on:panstart={handlePanStart}
on:panmove={handlePanMove}
on:panend={handlePanEnd}
style="transform: translate({$coords.x}px,{$coords.y}px)"
style="transform:
translate({$coords.x}px,{$coords.y}px)
rotate({$coords.x * 0.2}deg)"
></div>

@ -1,5 +1,5 @@
<script>
import ContactCard from './ContactCard.html';
import ContactCard from './ContactCard.svelte';
</script>
<ContactCard>

@ -30,7 +30,10 @@
$: selected = filteredPeople[i];
$: reset_inputs(selected);
$: {
first = selected ? selected.first : '';
last = selected ? selected.last : '';
}
function create() {
people = people.concat({ first, last });

@ -6,10 +6,6 @@
let item;
let page;
onMount(() => {
hashchange();
});
async function hashchange() {
// the poor man's router!
const path = window.location.hash.slice(1);
@ -26,6 +22,8 @@
window.location.hash = '/top/1';
}
}
onMount(hashchange);
</script>
<style>
@ -52,7 +50,7 @@
<main>
{#if item}
<Item {item}/>
<Item {item} returnTo="#/top/{page}"/>
{:else if page}
<List {page}/>
{/if}

@ -1,3 +1,7 @@
<script>
export let comment;
</script>
<style>
article {
border-top: 1px solid #eee;

@ -1,12 +1,8 @@
<script>
import Comment from "./Comment.html";
import Comment from "./Comment.svelte";
export let item;
function back(event) {
event.preventDefault();
window.history.back();
}
export let returnTo;
</script>
<style>
@ -25,7 +21,7 @@
}
</style>
<a href="#/top/1" on:click={back}>&laquo; back</a>
<a href={returnTo}>&laquo; back</a>
<article>
<a href="{item.url}">

@ -1,24 +1,21 @@
<script>
import { beforeUpdate } from "svelte";
import Summary from "./Summary.html";
import Summary from "./Summary.svelte";
const PAGE_SIZE = 20;
export let items;
export let offset;
export let page;
let previous_page;
let items;
let offset;
beforeUpdate(async () => {
if (page !== previous_page) {
previous_page = page;
items = await fetch(`https://node-hnapi.herokuapp.com/news?page=${page}`).then(r => r.json())
$: fetch(`https://node-hnapi.herokuapp.com/news?page=${page}`)
.then(r => r.json())
.then(data => {
items = data;
offset = PAGE_SIZE * (page - 1);
window.scrollTo(0, 0);
}
});
});
</script>
<style>

@ -12,12 +12,20 @@
function clear() {
todos = todos.filter(t => !t.done);
}
$: remaining = todos.filter(t => !t.done).length;
</script>
<style>
.done {
opacity: 0.4;
}
</style>
<h1>Todos</h1>
{#each todos as todo}
<div>
<div class:done={todo.done}>
<input
type=checkbox
checked={todo.done}
@ -30,6 +38,8 @@
</div>
{/each}
<p>{remaining} remaining</p>
<button on:click={add}>
Add new
</button>

@ -12,12 +12,20 @@
function clear() {
todos = todos.filter(t => !t.done);
}
$: remaining = todos.filter(t => !t.done).length;
</script>
<style>
.done {
opacity: 0.4;
}
</style>
<h1>Todos</h1>
{#each todos as todo}
<div>
<div class:done={todo.done}>
<input
type=checkbox
bind:checked={todo.done}
@ -30,6 +38,8 @@
</div>
{/each}
<p>{remaining} remaining</p>
<button on:click={add}>
Add new
</button>

@ -43,5 +43,7 @@
on:panstart={handlePanStart}
on:panmove={handlePanMove}
on:panend={handlePanEnd}
style="transform: translate({$coords.x}px,{$coords.y}px)"
style="transform:
translate({$coords.x}px,{$coords.y}px)
rotate({$coords.x * 0.2}deg)"
></div>

@ -45,5 +45,7 @@
on:panstart={handlePanStart}
on:panmove={handlePanMove}
on:panend={handlePanEnd}
style="transform: translate({$coords.x}px,{$coords.y}px)"
style="transform:
translate({$coords.x}px,{$coords.y}px)
rotate({$coords.x * 0.2}deg)"
></div>

@ -1,5 +1,5 @@
<script>
import ContactCard from './ContactCard.html';
import ContactCard from './ContactCard.svelte';
</script>
<ContactCard>

@ -1,5 +1,5 @@
<script>
import ContactCard from './ContactCard.html';
import ContactCard from './ContactCard.svelte';
</script>
<ContactCard>

@ -15,8 +15,8 @@ fs.readdirSync(`content/examples`).forEach(group_dir => {
async function main() {
const browser = await puppeteer.launch({
defaultViewport: {
width: 1280,
height: 960,
width: 600 * 10 / 4,
height: 400 + 42,
deviceScaleFactor: 2
}
});
@ -32,7 +32,7 @@ async function main() {
}
console.log(slug);
await page.goto(`http://localhost:3000/repl?example=${slug}`);
await page.goto(`http://localhost:3000/repl/embed?example=${slug}`);
await page.waitForSelector('iframe.inited[title=Result]');
await page.waitFor(1500);
@ -40,8 +40,10 @@ async function main() {
const buffer = await iframe.screenshot();
const image = await Jimp.read(buffer);
console.log(image.bitmap.width, image.bitmap.height);
image.crop(3, 3, image.bitmap.width - 6, image.bitmap.height - 6);
image.autocrop();
// image.scale(0.25);
if (image.bitmap.width > 300 || image.bitmap.width > 200) {
const scale = Math.min(
@ -55,6 +57,7 @@ async function main() {
await image.write(output_file);
} catch (err) {
console.log(c.bold().red(`failed to screenshot ${slug}`));
console.log(err);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 842 B

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 883 B

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1021 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save