pull/4886/head
pushkine 5 years ago
commit 25a631a78f

@ -9,7 +9,7 @@ title: Template syntax
A lowercase tag, like `<div>`, denotes a regular HTML element. A capitalised tag, such as `<Widget>` or `<Namespace.Widget>`, indicates a *component*. A lowercase tag, like `<div>`, denotes a regular HTML element. A capitalised tag, such as `<Widget>` or `<Namespace.Widget>`, indicates a *component*.
```sv ```html
<script> <script>
import Widget from './Widget.svelte'; import Widget from './Widget.svelte';
</script> </script>
@ -26,7 +26,7 @@ A lowercase tag, like `<div>`, denotes a regular HTML element. A capitalised tag
By default, attributes work exactly like their HTML counterparts. By default, attributes work exactly like their HTML counterparts.
```sv ```html
<div class="foo"> <div class="foo">
<button disabled>can't touch this</button> <button disabled>can't touch this</button>
</div> </div>
@ -36,7 +36,7 @@ By default, attributes work exactly like their HTML counterparts.
As in HTML, values may be unquoted. As in HTML, values may be unquoted.
```sv ```html
<input type=checkbox> <input type=checkbox>
``` ```
@ -44,7 +44,7 @@ As in HTML, values may be unquoted.
Attribute values can contain JavaScript expressions. Attribute values can contain JavaScript expressions.
```sv ```html
<a href="page/{p}">page {p}</a> <a href="page/{p}">page {p}</a>
``` ```
@ -52,26 +52,15 @@ Attribute values can contain JavaScript expressions.
Or they can *be* JavaScript expressions. Or they can *be* JavaScript expressions.
```sv
<button disabled={!clickable}>...</button>
```
---
Boolean attributes are included on the element if their value is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) and excluded if it's [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy).
All other attributes are included unless their value is [nullish](https://developer.mozilla.org/en-US/docs/Glossary/Nullish) (`null` or `undefined`).
```html ```html
<input required={false} placeholder="This input field is not required"> <button disabled={!clickable}>...</button>
<div title={null}>This div has no title attribute</div>
``` ```
--- ---
An expression might include characters that would cause syntax highlighting to fail in regular HTML, so quoting the value is permitted. The quotes do not affect how the value is parsed: An expression might include characters that would cause syntax highlighting to fail in regular HTML, so quoting the value is permitted. The quotes do not affect how the value is parsed:
```sv ```html
<button disabled="{number !== 42}">...</button> <button disabled="{number !== 42}">...</button>
``` ```
@ -79,7 +68,7 @@ An expression might include characters that would cause syntax highlighting to f
When the attribute name and value match (`name={name}`), they can be replaced with `{name}`. When the attribute name and value match (`name={name}`), they can be replaced with `{name}`.
```sv ```html
<!-- These are equivalent --> <!-- These are equivalent -->
<button disabled={disabled}>...</button> <button disabled={disabled}>...</button>
<button {disabled}>...</button> <button {disabled}>...</button>
@ -91,7 +80,7 @@ By convention, values passed to components are referred to as *properties* or *p
As with elements, `name={name}` can be replaced with the `{name}` shorthand. As with elements, `name={name}` can be replaced with the `{name}` shorthand.
```sv ```html
<Widget foo={bar} answer={42} text="hello"/> <Widget foo={bar} answer={42} text="hello"/>
``` ```
@ -101,7 +90,7 @@ As with elements, `name={name}` can be replaced with the `{name}` shorthand.
An element or component can have multiple spread attributes, interspersed with regular ones. An element or component can have multiple spread attributes, interspersed with regular ones.
```sv ```html
<Widget {...things}/> <Widget {...things}/>
``` ```
@ -109,19 +98,10 @@ An element or component can have multiple spread attributes, interspersed with r
*`$$props`* references all props that are passed to a component including ones that are not declared with `export`. It is useful in rare cases, but not generally recommended, as it is difficult for Svelte to optimise. *`$$props`* references all props that are passed to a component including ones that are not declared with `export`. It is useful in rare cases, but not generally recommended, as it is difficult for Svelte to optimise.
```sv
<Widget {...$$props}/>
```
---
*`$$restProps`* contains only the props which are *not* declared with `export`. It can be used to pass down other unknown attributes to an element in a component.
```html ```html
<input {...$$restProps}> <Widget {...$$props}/>
``` ```
---
### Text expressions ### Text expressions
@ -133,7 +113,7 @@ An element or component can have multiple spread attributes, interspersed with r
Text can also contain JavaScript expressions: Text can also contain JavaScript expressions:
```sv ```html
<h1>Hello {name}!</h1> <h1>Hello {name}!</h1>
<p>{a} + {b} = {a + b}.</p> <p>{a} + {b} = {a + b}.</p>
``` ```
@ -145,7 +125,7 @@ Text can also contain JavaScript expressions:
You can use HTML comments inside components. You can use HTML comments inside components.
```sv ```html
<!-- this is a comment! --> <!-- this is a comment! -->
<h1>Hello world</h1> <h1>Hello world</h1>
``` ```
@ -154,7 +134,7 @@ You can use HTML comments inside components.
Comments beginning with `svelte-ignore` disable warnings for the next block of markup. Usually these are accessibility warnings; make sure that you're disabling them for a good reason. Comments beginning with `svelte-ignore` disable warnings for the next block of markup. Usually these are accessibility warnings; make sure that you're disabling them for a good reason.
```sv ```html
<!-- svelte-ignore a11y-autofocus --> <!-- svelte-ignore a11y-autofocus -->
<input bind:value={name} autofocus> <input bind:value={name} autofocus>
``` ```
@ -176,7 +156,7 @@ Comments beginning with `svelte-ignore` disable warnings for the next block of m
Content that is conditionally rendered can be wrapped in an if block. Content that is conditionally rendered can be wrapped in an if block.
```sv ```html
{#if answer === 42} {#if answer === 42}
<p>what was the question?</p> <p>what was the question?</p>
{/if} {/if}
@ -186,7 +166,7 @@ Content that is conditionally rendered can be wrapped in an if block.
Additional conditions can be added with `{:else if expression}`, optionally ending in an `{:else}` clause. Additional conditions can be added with `{:else if expression}`, optionally ending in an `{:else}` clause.
```sv ```html
{#if porridge.temperature > 100} {#if porridge.temperature > 100}
<p>too hot!</p> <p>too hot!</p>
{:else if 80 > porridge.temperature} {:else if 80 > porridge.temperature}
@ -206,9 +186,6 @@ Additional conditions can be added with `{:else if expression}`, optionally endi
{#each expression as name, index}...{/each} {#each expression as name, index}...{/each}
``` ```
```sv ```sv
{#each expression as name (key)}...{/each}
```
```sv
{#each expression as name, index (key)}...{/each} {#each expression as name, index (key)}...{/each}
``` ```
```sv ```sv
@ -219,7 +196,7 @@ Additional conditions can be added with `{:else if expression}`, optionally endi
Iterating over lists of values can be done with an each block. Iterating over lists of values can be done with an each block.
```sv ```html
<h1>Shopping list</h1> <h1>Shopping list</h1>
<ul> <ul>
{#each items as item} {#each items as item}
@ -234,7 +211,7 @@ You can use each blocks to iterate over any array or array-like value — that i
An each block can also specify an *index*, equivalent to the second argument in an `array.map(...)` callback: An each block can also specify an *index*, equivalent to the second argument in an `array.map(...)` callback:
```sv ```html
{#each items as item, i} {#each items as item, i}
<li>{i + 1}: {item.name} x {item.qty}</li> <li>{i + 1}: {item.name} x {item.qty}</li>
{/each} {/each}
@ -244,12 +221,7 @@ An each block can also specify an *index*, equivalent to the second argument in
If a *key* expression is provided — which must uniquely identify each list item — Svelte will use it to diff the list when data changes, rather than adding or removing items at the end. The key can be any object, but strings and numbers are recommended since they allow identity to persist when the objects themselves change. If a *key* expression is provided — which must uniquely identify each list item — Svelte will use it to diff the list when data changes, rather than adding or removing items at the end. The key can be any object, but strings and numbers are recommended since they allow identity to persist when the objects themselves change.
```sv ```html
{#each items as item (item.id)}
<li>{item.name} x {item.qty}</li>
{/each}
<!-- or with additional index value -->
{#each items as item, i (item.id)} {#each items as item, i (item.id)}
<li>{i + 1}: {item.name} x {item.qty}</li> <li>{i + 1}: {item.name} x {item.qty}</li>
{/each} {/each}
@ -259,7 +231,7 @@ If a *key* expression is provided — which must uniquely identify each list ite
You can freely use destructuring and rest patterns in each blocks. You can freely use destructuring and rest patterns in each blocks.
```sv ```html
{#each items as { id, name, qty }, i (id)} {#each items as { id, name, qty }, i (id)}
<li>{i + 1}: {name} x {qty}</li> <li>{i + 1}: {name} x {qty}</li>
{/each} {/each}
@ -277,7 +249,7 @@ You can freely use destructuring and rest patterns in each blocks.
An each block can also have an `{:else}` clause, which is rendered if the list is empty. An each block can also have an `{:else}` clause, which is rendered if the list is empty.
```sv ```html
{#each todos as todo} {#each todos as todo}
<p>{todo.text}</p> <p>{todo.text}</p>
{:else} {:else}
@ -302,7 +274,7 @@ An each block can also have an `{:else}` clause, which is rendered if the list i
Await blocks allow you to branch on the three possible states of a Promise — pending, fulfilled or rejected. Await blocks allow you to branch on the three possible states of a Promise — pending, fulfilled or rejected.
```sv ```html
{#await promise} {#await promise}
<!-- promise is pending --> <!-- promise is pending -->
<p>waiting for the promise to resolve...</p> <p>waiting for the promise to resolve...</p>
@ -319,7 +291,7 @@ Await blocks allow you to branch on the three possible states of a Promise — p
The `catch` block can be omitted if you don't need to render anything when the promise rejects (or no error is possible). The `catch` block can be omitted if you don't need to render anything when the promise rejects (or no error is possible).
```sv ```html
{#await promise} {#await promise}
<!-- promise is pending --> <!-- promise is pending -->
<p>waiting for the promise to resolve...</p> <p>waiting for the promise to resolve...</p>
@ -333,7 +305,7 @@ The `catch` block can be omitted if you don't need to render anything when the p
If you don't care about the pending state, you can also omit the initial block. If you don't care about the pending state, you can also omit the initial block.
```sv ```html
{#await promise then value} {#await promise then value}
<p>The value is {value}</p> <p>The value is {value}</p>
{/await} {/await}
@ -354,7 +326,7 @@ The expression should be valid standalone HTML — `{@html "<div>"}content{@html
> Svelte does not sanitize expressions before injecting HTML. If the data comes from an untrusted source, you must sanitize it, or you are exposing your users to an XSS vulnerability. > Svelte does not sanitize expressions before injecting HTML. If the data comes from an untrusted source, you must sanitize it, or you are exposing your users to an XSS vulnerability.
```sv ```html
<div class="blog-post"> <div class="blog-post">
<h1>{post.title}</h1> <h1>{post.title}</h1>
{@html post.content} {@html post.content}
@ -377,7 +349,7 @@ The `{@debug ...}` tag offers an alternative to `console.log(...)`. It logs the
It accepts a comma-separated list of variable names (not arbitrary expressions). It accepts a comma-separated list of variable names (not arbitrary expressions).
```sv ```html
<script> <script>
let user = { let user = {
firstname: 'Ada', firstname: 'Ada',
@ -394,7 +366,7 @@ It accepts a comma-separated list of variable names (not arbitrary expressions).
`{@debug ...}` accepts a comma-separated list of variable names (not arbitrary expressions). `{@debug ...}` accepts a comma-separated list of variable names (not arbitrary expressions).
```sv ```html
<!-- Compiles --> <!-- Compiles -->
{@debug user} {@debug user}
{@debug user1, user2, user3} {@debug user1, user2, user3}
@ -428,7 +400,7 @@ on:eventname|modifiers={handler}
Use the `on:` directive to listen to DOM events. Use the `on:` directive to listen to DOM events.
```sv ```html
<script> <script>
let count = 0; let count = 0;
@ -446,7 +418,7 @@ Use the `on:` directive to listen to DOM events.
Handlers can be declared inline with no performance penalty. As with attributes, directive values may be quoted for the sake of syntax highlighters. Handlers can be declared inline with no performance penalty. As with attributes, directive values may be quoted for the sake of syntax highlighters.
```sv ```html
<button on:click="{() => count += 1}"> <button on:click="{() => count += 1}">
count: {count} count: {count}
</button> </button>
@ -456,7 +428,7 @@ Handlers can be declared inline with no performance penalty. As with attributes,
Add *modifiers* to DOM events with the `|` character. Add *modifiers* to DOM events with the `|` character.
```sv ```html
<form on:submit|preventDefault={handleSubmit}> <form on:submit|preventDefault={handleSubmit}>
<!-- the `submit` event's default is prevented, <!-- the `submit` event's default is prevented,
so the page won't reload --> so the page won't reload -->
@ -470,7 +442,6 @@ The following modifiers are available:
* `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so) * `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
* `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase * `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase
* `once` — remove the handler after the first time it runs * `once` — remove the handler after the first time it runs
* `self` — only trigger handler if event.target is the element itself
Modifiers can be chained together, e.g. `on:click|once|capture={...}`. Modifiers can be chained together, e.g. `on:click|once|capture={...}`.
@ -478,7 +449,7 @@ Modifiers can be chained together, e.g. `on:click|once|capture={...}`.
If the `on:` directive is used without a value, the component will *forward* the event, meaning that a consumer of the component can listen for it. If the `on:` directive is used without a value, the component will *forward* the event, meaning that a consumer of the component can listen for it.
```sv ```html
<button on:click> <button on:click>
The component itself will emit the click event The component itself will emit the click event
</button> </button>
@ -488,7 +459,7 @@ If the `on:` directive is used without a value, the component will *forward* the
It's possible to have multiple event listeners for the same event: It's possible to have multiple event listeners for the same event:
```sv ```html
<script> <script>
let counter = 0; let counter = 0;
function increment() { function increment() {
@ -515,7 +486,7 @@ Data ordinarily flows down, from parent to child. The `bind:` directive allows d
The simplest bindings reflect the value of a property, such as `input.value`. The simplest bindings reflect the value of a property, such as `input.value`.
```sv ```html
<input bind:value={name}> <input bind:value={name}>
<textarea bind:value={text}></textarea> <textarea bind:value={text}></textarea>
@ -526,7 +497,7 @@ The simplest bindings reflect the value of a property, such as `input.value`.
If the name matches the value, you can use a shorthand. If the name matches the value, you can use a shorthand.
```sv ```html
<!-- These are equivalent --> <!-- These are equivalent -->
<input bind:value={value}> <input bind:value={value}>
<input bind:value> <input bind:value>
@ -536,7 +507,7 @@ If the name matches the value, you can use a shorthand.
Numeric input values are coerced; even though `input.value` is a string as far as the DOM is concerned, Svelte will treat it as a number. If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`. Numeric input values are coerced; even though `input.value` is a string as far as the DOM is concerned, Svelte will treat it as a number. If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`.
```sv ```html
<input type="number" bind:value={num}> <input type="number" bind:value={num}>
<input type="range" bind:value={num}> <input type="range" bind:value={num}>
``` ```
@ -548,7 +519,7 @@ Numeric input values are coerced; even though `input.value` is a string as far a
A `<select>` value binding corresponds to the `value` property on the selected `<option>`, which can be any value (not just strings, as is normally the case in the DOM). A `<select>` value binding corresponds to the `value` property on the selected `<option>`, which can be any value (not just strings, as is normally the case in the DOM).
```sv ```html
<select bind:value={selected}> <select bind:value={selected}>
<option value={a}>a</option> <option value={a}>a</option>
<option value={b}>b</option> <option value={b}>b</option>
@ -560,7 +531,7 @@ A `<select>` value binding corresponds to the `value` property on the selected `
A `<select multiple>` element behaves similarly to a checkbox group. A `<select multiple>` element behaves similarly to a checkbox group.
```sv ```html
<select multiple bind:value={fillings}> <select multiple bind:value={fillings}>
<option value="Rice">Rice</option> <option value="Rice">Rice</option>
<option value="Beans">Beans</option> <option value="Beans">Beans</option>
@ -573,7 +544,7 @@ A `<select multiple>` element behaves similarly to a checkbox group.
When the value of an `<option>` matches its text content, the attribute can be omitted. When the value of an `<option>` matches its text content, the attribute can be omitted.
```sv ```html
<select multiple bind:value={fillings}> <select multiple bind:value={fillings}>
<option>Rice</option> <option>Rice</option>
<option>Beans</option> <option>Beans</option>
@ -586,7 +557,7 @@ When the value of an `<option>` matches its text content, the attribute can be o
Elements with the `contenteditable` attribute support `innerHTML` and `textContent` bindings. Elements with the `contenteditable` attribute support `innerHTML` and `textContent` bindings.
```sv ```html
<div contenteditable="true" bind:innerHTML={html}></div> <div contenteditable="true" bind:innerHTML={html}></div>
``` ```
@ -603,17 +574,16 @@ Media elements (`<audio>` and `<video>`) have their own set of bindings — six
* `seeking` (readonly) — boolean * `seeking` (readonly) — boolean
* `ended` (readonly) — boolean * `ended` (readonly) — boolean
...and five *two-way* bindings: ...and four *two-way* bindings:
* `currentTime` — the current point in the video, in seconds * `currentTime` — the current point in the video, in seconds
* `playbackRate` — how fast to play the video, where 1 is 'normal' * `playbackRate` — how fast to play the video, where 1 is 'normal'
* `paused` — this one should be self-explanatory * `paused` — this one should be self-explanatory
* `volume` — a value between 0 and 1 * `volume` — a value between 0 and 1
* `muted` — a boolean value where true is muted
Videos additionally have readonly `videoWidth` and `videoHeight` bindings. Videos additionally have readonly `videoWidth` and `videoHeight` bindings.
```sv ```html
<video <video
src={clip} src={clip}
bind:duration bind:duration
@ -625,7 +595,6 @@ Videos additionally have readonly `videoWidth` and `videoHeight` bindings.
bind:currentTime bind:currentTime
bind:paused bind:paused
bind:volume bind:volume
bind:muted
bind:videoWidth bind:videoWidth
bind:videoHeight bind:videoHeight
></video> ></video>
@ -642,7 +611,7 @@ Block-level elements have 4 readonly bindings, measured using a technique simila
* `offsetWidth` * `offsetWidth`
* `offsetHeight` * `offsetHeight`
```sv ```html
<div <div
bind:offsetWidth={width} bind:offsetWidth={width}
bind:offsetHeight={height} bind:offsetHeight={height}
@ -661,7 +630,7 @@ bind:group={variable}
Inputs that work together can use `bind:group`. Inputs that work together can use `bind:group`.
```sv ```html
<script> <script>
let tortilla = 'Plain'; let tortilla = 'Plain';
let fillings = []; let fillings = [];
@ -689,7 +658,7 @@ bind:this={dom_node}
To get a reference to a DOM node, use `bind:this`. To get a reference to a DOM node, use `bind:this`.
```sv ```html
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
@ -718,7 +687,7 @@ class:name
A `class:` directive provides a shorter way of toggling a class on an element. A `class:` directive provides a shorter way of toggling a class on an element.
```sv ```html
<!-- These are equivalent --> <!-- These are equivalent -->
<div class="{active ? 'active' : ''}">...</div> <div class="{active ? 'active' : ''}">...</div>
<div class:active={active}>...</div> <div class:active={active}>...</div>
@ -751,7 +720,7 @@ action = (node: HTMLElement, parameters: any) => {
Actions are functions that are called when an element is created. They can return an object with a `destroy` method that is called after the element is unmounted: Actions are functions that are called when an element is created. They can return an object with a `destroy` method that is called after the element is unmounted:
```sv ```html
<script> <script>
function foo(node) { function foo(node) {
// the node has been mounted in the DOM // the node has been mounted in the DOM
@ -773,7 +742,7 @@ An action can have parameters. If the returned value has an `update` method, it
> Don't worry about the fact that we're redeclaring the `foo` function for every component instance — Svelte will hoist any functions that don't depend on local state out of the component definition. > Don't worry about the fact that we're redeclaring the `foo` function for every component instance — Svelte will hoist any functions that don't depend on local state out of the component definition.
```sv ```html
<script> <script>
export let bar; export let bar;
@ -826,11 +795,11 @@ transition = (node: HTMLElement, params: any) => {
A transition is triggered by an element entering or leaving the DOM as a result of a state change. A transition is triggered by an element entering or leaving the DOM as a result of a state change.
When a block is transitioning out, all elements inside the block, including those that do not have their own transitions, are kept in the DOM until every transition in the block has completed. Elements inside an *outroing* block are kept in the DOM until all current transitions have completed.
The `transition:` directive indicates a *bidirectional* transition, which means it can be smoothly reversed while the transition is in progress. The `transition:` directive indicates a *bidirectional* transition, which means it can be smoothly reversed while the transition is in progress.
```sv ```html
{#if visible} {#if visible}
<div transition:fade> <div transition:fade>
fades in and out fades in and out
@ -848,7 +817,7 @@ Like actions, transitions can have parameters.
(The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.) (The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.)
```sv ```html
{#if visible} {#if visible}
<div transition:fade="{{ duration: 2000 }}"> <div transition:fade="{{ duration: 2000 }}">
flies in, fades out over two seconds flies in, fades out over two seconds
@ -866,7 +835,7 @@ The `t` argument passed to `css` is a value between `0` and `1` after the `easin
The function is called repeatedly *before* the transition begins, with different `t` and `u` arguments. The function is called repeatedly *before* the transition begins, with different `t` and `u` arguments.
```sv ```html
<script> <script>
import { elasticOut } from 'svelte/easing'; import { elasticOut } from 'svelte/easing';
@ -897,14 +866,14 @@ A custom transition function can also return a `tick` function, which is called
> If it's possible to use `css` instead of `tick`, do so — CSS animations can run off the main thread, preventing jank on slower devices. > If it's possible to use `css` instead of `tick`, do so — CSS animations can run off the main thread, preventing jank on slower devices.
```sv ```html
<script> <script>
export let visible = false; export let visible = false;
function typewriter(node, { speed = 50 }) { function typewriter(node, { speed = 50 }) {
const valid = ( const valid = (
node.childNodes.length === 1 && node.childNodes.length === 1 &&
node.childNodes[0].nodeType === Node.TEXT_NODE node.childNodes[0].nodeType === 3
); );
if (!valid) return {}; if (!valid) return {};
@ -943,7 +912,7 @@ An element with transitions will dispatch the following events in addition to an
* `outrostart` * `outrostart`
* `outroend` * `outroend`
```sv ```html
{#if visible} {#if visible}
<p <p
transition:fly="{{ y: 200, duration: 2000 }}" transition:fly="{{ y: 200, duration: 2000 }}"
@ -961,7 +930,7 @@ An element with transitions will dispatch the following events in addition to an
Local transitions only play when the block they belong to is created or destroyed, *not* when parent blocks are created or destroyed. Local transitions only play when the block they belong to is created or destroyed, *not* when parent blocks are created or destroyed.
```sv ```html
{#if x} {#if x}
{#if y} {#if y}
<p transition:fade> <p transition:fade>
@ -1010,7 +979,9 @@ Similar to `transition:`, but only applies to elements entering (`in:`) or leavi
Unlike with `transition:`, transitions applied with `in:` and `out:` are not bidirectional — an in transition will continue to 'play' alongside the out transition, rather than reversing, if the block is outroed while the transition is in progress. If an out transition is aborted, transitions will restart from scratch. Unlike with `transition:`, transitions applied with `in:` and `out:` are not bidirectional — an in transition will continue to 'play' alongside the out transition, rather than reversing, if the block is outroed while the transition is in progress. If an out transition is aborted, transitions will restart from scratch.
```sv If an `out:` custom transition function returns a promise instead of a transition object, svelte will simply await its completion before unmounting the node.
```html
{#if visible} {#if visible}
<div in:fly out:fade> <div in:fly out:fade>
flies in, fades out flies in, fades out
@ -1059,7 +1030,7 @@ An animation is triggered when the contents of a [keyed each block](docs#each) a
Animations can be used with Svelte's [built-in animation functions](docs#svelte_animate) or [custom animation functions](docs#Custom_animation_functions). Animations can be used with Svelte's [built-in animation functions](docs#svelte_animate) or [custom animation functions](docs#Custom_animation_functions).
```sv ```html
<!-- When `list` is reordered the animation will run--> <!-- When `list` is reordered the animation will run-->
{#each list as item, index (item)} {#each list as item, index (item)}
<li animate:flip>{item}</li> <li animate:flip>{item}</li>
@ -1074,7 +1045,7 @@ As with actions and transitions, animations can have parameters.
(The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.) (The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.)
```sv ```html
{#each list as item, index (item)} {#each list as item, index (item)}
<li animate:flip="{{ delay: 500 }}">{item}</li> <li animate:flip="{{ delay: 500 }}">{item}</li>
{/each} {/each}
@ -1093,7 +1064,7 @@ The `t` argument passed to `css` is a value that goes from `0` and `1` after the
The function is called repeatedly *before* the animation begins, with different `t` and `u` arguments. The function is called repeatedly *before* the animation begins, with different `t` and `u` arguments.
```sv ```html
<script> <script>
import { cubicOut } from 'svelte/easing'; import { cubicOut } from 'svelte/easing';
@ -1126,7 +1097,7 @@ A custom animation function can also return a `tick` function, which is called *
> If it's possible to use `css` instead of `tick`, do so — CSS animations can run off the main thread, preventing jank on slower devices. > If it's possible to use `css` instead of `tick`, do so — CSS animations can run off the main thread, preventing jank on slower devices.
```sv ```html
<script> <script>
import { cubicOut } from 'svelte/easing'; import { cubicOut } from 'svelte/easing';
@ -1166,7 +1137,7 @@ on:eventname={handler}
Components can emit events using [createEventDispatcher](docs#createEventDispatcher), or by forwarding DOM events. Listening for component events looks the same as listening for DOM events: Components can emit events using [createEventDispatcher](docs#createEventDispatcher), or by forwarding DOM events. Listening for component events looks the same as listening for DOM events:
```sv ```html
<SomeComponent on:whatever={handler}/> <SomeComponent on:whatever={handler}/>
``` ```
@ -1174,7 +1145,7 @@ Components can emit events using [createEventDispatcher](docs#createEventDispatc
As with DOM events, if the `on:` directive is used without a value, the component will *forward* the event, meaning that a consumer of the component can listen for it. As with DOM events, if the `on:` directive is used without a value, the component will *forward* the event, meaning that a consumer of the component can listen for it.
```sv ```html
<SomeComponent on:whatever/> <SomeComponent on:whatever/>
``` ```
@ -1189,7 +1160,7 @@ bind:property={variable}
You can bind to component props using the same syntax as for elements. You can bind to component props using the same syntax as for elements.
```sv ```html
<Keypad bind:value={pin}/> <Keypad bind:value={pin}/>
``` ```
@ -1205,7 +1176,7 @@ Components also support `bind:this`, allowing you to interact with component ins
> Note that we can't do `{cart.empty}` since `cart` is `undefined` when the button is first rendered and throws an error. > Note that we can't do `{cart.empty}` since `cart` is `undefined` when the button is first rendered and throws an error.
```sv ```html
<ShoppingCart bind:this={cart}/> <ShoppingCart bind:this={cart}/>
<button on:click={() => cart.empty()}> <button on:click={() => cart.empty()}>
@ -1233,7 +1204,7 @@ Components can have child content, in the same way that elements can.
The content is exposed in the child component using the `<slot>` element, which can contain fallback content that is rendered if no children are provided. The content is exposed in the child component using the `<slot>` element, which can contain fallback content that is rendered if no children are provided.
```sv ```html
<!-- App.svelte --> <!-- App.svelte -->
<Widget></Widget> <Widget></Widget>
@ -1255,7 +1226,7 @@ The content is exposed in the child component using the `<slot>` element, which
Named slots allow consumers to target specific areas. They can also have fallback content. Named slots allow consumers to target specific areas. They can also have fallback content.
```sv ```html
<!-- App.svelte --> <!-- App.svelte -->
<Widget> <Widget>
<h1 slot="header">Hello</h1> <h1 slot="header">Hello</h1>
@ -1278,17 +1249,17 @@ Slots can be rendered zero or more times, and can pass values *back* to the pare
The usual shorthand rules apply — `let:item` is equivalent to `let:item={item}`, and `<slot {item}>` is equivalent to `<slot item={item}>`. The usual shorthand rules apply — `let:item` is equivalent to `let:item={item}`, and `<slot {item}>` is equivalent to `<slot item={item}>`.
```sv ```html
<!-- App.svelte --> <!-- App.svelte -->
<FancyList {items} let:prop={thing}> <FancyList {items} let:item={item}>
<div>{thing.text}</div> <div>{item.text}</div>
</FancyList> </FancyList>
<!-- FancyList.svelte --> <!-- FancyList.svelte -->
<ul> <ul>
{#each items as item} {#each items as item}
<li class="fancy"> <li class="fancy">
<slot prop={item}></slot> <slot item={item}></slot>
</li> </li>
{/each} {/each}
</ul> </ul>
@ -1298,10 +1269,10 @@ The usual shorthand rules apply — `let:item` is equivalent to `let:item={item}
Named slots can also expose values. The `let:` directive goes on the element with the `slot` attribute. Named slots can also expose values. The `let:` directive goes on the element with the `slot` attribute.
```sv ```html
<!-- App.svelte --> <!-- App.svelte -->
<FancyList {items}> <FancyList {items}>
<div slot="item" let:item>{item.text}</div> <div slot="item" let:item={item}>{item.text}</div>
<p slot="footer">Copyright (c) 2019 Svelte Industries</p> <p slot="footer">Copyright (c) 2019 Svelte Industries</p>
</FancyList> </FancyList>
@ -1309,7 +1280,7 @@ Named slots can also expose values. The `let:` directive goes on the element wit
<ul> <ul>
{#each items as item} {#each items as item}
<li class="fancy"> <li class="fancy">
<slot name="item" {item}></slot> <slot name="item" item={item}></slot>
</li> </li>
{/each} {/each}
</ul> </ul>
@ -1326,7 +1297,7 @@ The `<svelte:self>` element allows a component to include itself, recursively.
It cannot appear at the top level of your markup; it must be inside an if or each block to prevent an infinite loop. It cannot appear at the top level of your markup; it must be inside an if or each block to prevent an infinite loop.
```sv ```html
<script> <script>
export let count; export let count;
</script> </script>
@ -1351,7 +1322,7 @@ The `<svelte:component>` element renders a component dynamically, using the comp
If `this` is falsy, no component is rendered. If `this` is falsy, no component is rendered.
```sv ```html
<svelte:component this={currentSelection.component} foo={bar}/> <svelte:component this={currentSelection.component} foo={bar}/>
``` ```
@ -1369,7 +1340,7 @@ If `this` is falsy, no component is rendered.
The `<svelte:window>` element allows you to add event listeners to the `window` object without worrying about removing them when the component is destroyed, or checking for the existence of `window` when server-side rendering. The `<svelte:window>` element allows you to add event listeners to the `window` object without worrying about removing them when the component is destroyed, or checking for the existence of `window` when server-side rendering.
```sv ```html
<script> <script>
function handleKeydown(event) { function handleKeydown(event) {
alert(`pressed the ${event.key} key`); alert(`pressed the ${event.key} key`);
@ -1393,7 +1364,7 @@ You can also bind to the following properties:
All except `scrollX` and `scrollY` are readonly. All except `scrollX` and `scrollY` are readonly.
```sv ```html
<svelte:window bind:scrollY={y}/> <svelte:window bind:scrollY={y}/>
``` ```
@ -1408,7 +1379,7 @@ All except `scrollX` and `scrollY` are readonly.
As with `<svelte:window>`, this element allows you to add listeners to events on `document.body`, such as `mouseenter` and `mouseleave` which don't fire on `window`. As with `<svelte:window>`, this element allows you to add listeners to events on `document.body`, such as `mouseenter` and `mouseleave` which don't fire on `window`.
```sv ```html
<svelte:body <svelte:body
on:mouseenter={handleMouseenter} on:mouseenter={handleMouseenter}
on:mouseleave={handleMouseleave} on:mouseleave={handleMouseleave}
@ -1426,7 +1397,7 @@ As with `<svelte:window>`, this element allows you to add listeners to events on
This element makes it possible to insert elements into `document.head`. During server-side rendering, `head` content is exposed separately to the main `html` content. This element makes it possible to insert elements into `document.head`. During server-side rendering, `head` content is exposed separately to the main `html` content.
```sv ```html
<svelte:head> <svelte:head>
<link rel="stylesheet" href="tutorial/dark-theme.css"> <link rel="stylesheet" href="tutorial/dark-theme.css">
</svelte:head> </svelte:head>
@ -1450,6 +1421,6 @@ The `<svelte:options>` element provides a place to specify per-component compile
* `namespace="..."` — the namespace where this component will be used, most commonly "svg" * `namespace="..."` — the namespace where this component will be used, most commonly "svg"
* `tag="..."` — the name to use when compiling this component as a custom element * `tag="..."` — the name to use when compiling this component as a custom element
```sv ```html
<svelte:options tag="my-custom-element"/> <svelte:options tag="my-custom-element"/>
``` ```

@ -68,6 +68,7 @@ export function transition_out(block, local: 0 | 1, detach: 0 | 1, callback) {
const null_transition: TransitionConfig = { duration: 0 }; const null_transition: TransitionConfig = { duration: 0 };
type TransitionFn = (node: Element, params: any) => TransitionConfig; type TransitionFn = (node: Element, params: any) => TransitionConfig;
type PromiseFn = (node: Element, params: any) => Promise<any>
export function create_in_transition(node: Element & ElementCSSInlineStyle, fn: TransitionFn, params: any) { export function create_in_transition(node: Element & ElementCSSInlineStyle, fn: TransitionFn, params: any) {
let config = fn(node, params); let config = fn(node, params);
@ -150,7 +151,7 @@ export function create_in_transition(node: Element & ElementCSSInlineStyle, fn:
}; };
} }
export function create_out_transition(node: Element & ElementCSSInlineStyle, fn: TransitionFn, params: any) { export function create_out_transition(node: Element & ElementCSSInlineStyle, fn: TransitionFn | PromiseFn, params: any) {
let config = fn(node, params); let config = fn(node, params);
let running = true; let running = true;
let animation_name; let animation_name;
@ -159,6 +160,19 @@ export function create_out_transition(node: Element & ElementCSSInlineStyle, fn:
group.r += 1; group.r += 1;
function started() {
add_render_callback(() => dispatch(node, false, 'start'));
}
function ended() {
dispatch(node, false, 'end');
if (!--group.r) {
// this will result in `end()` being called,
// so we don't need to clean up here
run_all(group.c);
}
}
function go() { function go() {
const { const {
delay = 0, delay = 0,
@ -166,27 +180,21 @@ export function create_out_transition(node: Element & ElementCSSInlineStyle, fn:
easing = linear, easing = linear,
tick = noop, tick = noop,
css css
} = config || null_transition; } = config as TransitionConfig || null_transition;
if (css) animation_name = create_rule(node, 1, 0, duration, delay, easing, css); if (css) animation_name = create_rule(node, 1, 0, duration, delay, easing, css);
const start_time = now() + delay; const start_time = now() + delay;
const end_time = start_time + duration; const end_time = start_time + duration;
add_render_callback(() => dispatch(node, false, 'start')); started();
loop(now => { loop(now => {
if (running) { if (running) {
if (now >= end_time) { if (now >= end_time) {
tick(0, 1); tick(0, 1);
dispatch(node, false, 'end'); ended();
if (!--group.r) {
// this will result in `end()` being called,
// so we don't need to clean up here
run_all(group.c);
}
return false; return false;
} }
@ -207,13 +215,16 @@ export function create_out_transition(node: Element & ElementCSSInlineStyle, fn:
config = config(); config = config();
go(); go();
}); });
} else if (config && 'then' in config) {
started();
config.then(ended).catch(ended);
} else { } else {
go(); go();
} }
return { return {
end(reset) { end(reset) {
if (reset && config.tick) { if (reset && 'tick' in config) {
config.tick(1, 0); config.tick(1, 0);
} }

@ -0,0 +1,14 @@
export default {
props: {
visible: true,
},
test({ assert, component, target }) {
component.visible = false;
assert.notEqual(target.querySelector('span'), undefined);
component.resolve();
setTimeout(() => {
assert.equal(target.querySelector('span'), undefined);
});
},
};

@ -0,0 +1,14 @@
<script>
export let visible;
export let resolve
function foo(node, params) {
return new Promise(r => {
resolve = r
});
}
</script>
{#if visible}
<span out:foo>hello</span>
{/if}
Loading…
Cancel
Save