mirror of https://github.com/sveltejs/svelte
commit
4026fb00ec
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
title: What's new in Svelte: November 2020
|
||||||
|
description: Slot forwarding fixes, SvelteKit for faster local development, and more from Svelte Summit
|
||||||
|
author: Daniel Sandoval
|
||||||
|
authorURL: https://desandoval.net
|
||||||
|
---
|
||||||
|
|
||||||
|
Welcome back to the "What's new in Svelte" series! This month, we're covering new features & bug fixes, last month's Svelte Summit and some stand-out sites and libraries...
|
||||||
|
|
||||||
|
## New features & impactful bug fixes
|
||||||
|
|
||||||
|
1. Destructuring Promises now works as expected by using the `{#await}` syntax
|
||||||
|
(**3.29.3**, [Example](https://svelte.dev/repl/3fd4e2cecfa14d629961478f1dac2445?version=3.29.3))
|
||||||
|
2. Slot forwarding (released in 3.29.0) should no longer hang during compilation (**3.29.3**, [Example](https://svelte.dev/repl/29959e70103f4868a6525c0734934936?version=3.29.3))
|
||||||
|
3. Better typings for the `get` function in `svelte/store` and on lifecycle hooks (**3.29.1**)
|
||||||
|
|
||||||
|
**What's going on in Sapper?**
|
||||||
|
|
||||||
|
Sapper got some new types in its `preload` function, which will make typing easier if you are using TypeScript. See the [Sapper docs](https://sapper.svelte.dev/docs#Typing_the_function) on how to use them. There also were fixes to `preload` links in exported sites. Route layouts got a few fixes too - including ensuring CSS is applied to nested route layouts. You can also better organize your files now that extensions with multiple dots are supported. (**0.28.10**)
|
||||||
|
|
||||||
|
|
||||||
|
For all the features and bugfixes see the CHANGELOGs for [Svelte](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md) and [Sapper](https://github.com/sveltejs/sapper/blob/master/CHANGELOG.md).
|
||||||
|
|
||||||
|
|
||||||
|
## [Svelte Summit](https://sveltesummit.com/) was Svelte-tacular!
|
||||||
|
- Rich Harris demoed the possible future of Svelte development in a talk titled "Futuristic Web Development". The not-yet-public project is called SvelteKit (name may change) and will bring a first-class developer experience and more flexibility for build outputs. If you want to get the full sneak-peek, [check out the video](https://www.youtube.com/watch?v=qSfdtmcZ4d0).
|
||||||
|
- 17 speakers made the best of the conference's virtual format... From floating heads to seamless demos, Svelte developers from every skill level will find something of interest in this year's [YouTube playlist](https://www.youtube.com/playlist?list=PL8bMgX1kyZThM1sbYCoWdTcpiYysJsSeu)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Community Showcase
|
||||||
|
- [Svelte Lab](https://sveltelab.app/) showcases a variety of components, visualizations and interactions that can be achieved in Svelte. You can click into any component to see its source or edit it, using the site's built-in REPL
|
||||||
|
- [svelte-electron-boilerplate](https://github.com/hjalmar/svelte-electron-boilerplate) is a fast way to get up and running with a Svelte app built in the desktop javascript framework, Electron
|
||||||
|
- [React Hooks in Svelte](https://github.com/joshnuss/react-hooks-in-svelte) showcases examples of common React Hooks ported to Svelte.
|
||||||
|
- [gurlic](https://gurlic.com/) is a social network and internet experiment that is super snappy thanks to Svelte
|
||||||
|
- [Interference 2020](https://interference2020.org/) visualizes reported foreign interference in the 2020 U.S. elections. You can learn more about how it was built in [YYY's talk at Svelte Summit]()
|
||||||
|
- [jitsi-svelte](https://github.com/relm-us/jitsi-svelte) lets you easily create your own custom Jitsi client by providing out-of-the-box components built with Svelte
|
||||||
|
- [Ellx](https://ellx.io/) is part spreadsheet, part notebook and part IDE. It's super smooth thanks to Svelte 😎
|
||||||
|
- [This New Zealand news site](https://www.nzherald.co.nz/nz/election-2020-latest-results-party-vote-electorate-vote-and-full-data/5CFVO4ENKNQDE3SICRRNPU5GZM/) breaks down the results of the 2020 Parliamentary elections using Svelte
|
||||||
|
- [Budibase](https://github.com/Budibase/budibase) is a no-code app builder, powered by Svelte
|
||||||
|
- [Svelt-yjs](https://github.com/relm-us/svelt-yjs) combines the collaborative, local-first technology of Yjs with the power of Svelte to enable multiple users across the internet to stay in sync.
|
||||||
|
- [tabler-icons-svelte](https://github.com/benflap/tabler-icons-svelte) is a Svelte wrapper for over 850 free MIT-licensed high-quality SVG icons for you to use in your web projects.
|
||||||
|
|
||||||
|
## See you next month!
|
||||||
|
|
||||||
|
Got an idea for something to add to the Showcase? Want to get involved more with Svelte? We're always looking for maintainers, contributors and fanatics... Check out the [Svelte Society](https://sveltesociety.dev/), [Reddit](https://www.reddit.com/r/sveltejs/) and [Discord](https://discord.com/invite/yy75DKs) to get involved!
|
@ -0,0 +1,57 @@
|
|||||||
|
<script>
|
||||||
|
import Project from './Project.svelte'
|
||||||
|
import Comment from './Comment.svelte'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
font-weight: 300;
|
||||||
|
margin: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
ul {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding: 0.5rem;
|
||||||
|
flex: 1 1 50%;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
Projects
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<Project
|
||||||
|
title="Add Typescript support"
|
||||||
|
tasksCompleted={25}
|
||||||
|
totalTasks={57}
|
||||||
|
>
|
||||||
|
<div slot="comments">
|
||||||
|
<Comment name="Ecma Script" postedAt={new Date('2020-08-17T14:12:23')}>
|
||||||
|
<p>Those interface tests are now passing.</p>
|
||||||
|
</Comment>
|
||||||
|
</div>
|
||||||
|
</Project>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Project
|
||||||
|
title="Update documentation"
|
||||||
|
tasksCompleted={18}
|
||||||
|
totalTasks={21}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
@ -0,0 +1,56 @@
|
|||||||
|
<script>
|
||||||
|
export let name;
|
||||||
|
export let postedAt;
|
||||||
|
|
||||||
|
$: avatar = `https://ui-avatars.com/api/?name=${name.replace(/ /g, '+')}&rounded=true&background=ff3e00&color=fff&bold=true`;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
article {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px #ccc solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
margin-left: 0.5rem
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
time {
|
||||||
|
color: #777;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body :global(p) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<div class="header">
|
||||||
|
<img src={avatar} alt="" height="32" width="32">
|
||||||
|
<div class="details">
|
||||||
|
<h4>{name}</h4>
|
||||||
|
<time datetime={postedAt.toISOString()}>{postedAt.toLocaleDateString()}</time>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="body">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</article>
|
@ -0,0 +1,62 @@
|
|||||||
|
<script>
|
||||||
|
export let title;
|
||||||
|
export let tasksCompleted = 0;
|
||||||
|
export let totalTasks = 0;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
article {
|
||||||
|
border: 1px #ccc solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > div {
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article.has-discussion::after {
|
||||||
|
content: '';
|
||||||
|
background-color: #ff3e00;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||||
|
height: 20px;
|
||||||
|
position: absolute;
|
||||||
|
right: -10px;
|
||||||
|
top: -10px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
margin: 0 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #777;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discussion {
|
||||||
|
background-color: #eee;
|
||||||
|
border-top: 1px #ccc solid;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<article class:has-discussion={true}>
|
||||||
|
<div>
|
||||||
|
<h2>{title}</h2>
|
||||||
|
<p>{tasksCompleted}/{totalTasks} tasks completed</p>
|
||||||
|
</div>
|
||||||
|
<div class="discussion">
|
||||||
|
<h3>Comments</h3>
|
||||||
|
<slot name="comments"></slot>
|
||||||
|
</div>
|
||||||
|
</article>
|
@ -0,0 +1,57 @@
|
|||||||
|
<script>
|
||||||
|
import Project from './Project.svelte'
|
||||||
|
import Comment from './Comment.svelte'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
font-weight: 300;
|
||||||
|
margin: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
ul {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding: 0.5rem;
|
||||||
|
flex: 1 1 50%;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
Projects
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<Project
|
||||||
|
title="Add Typescript support"
|
||||||
|
tasksCompleted={25}
|
||||||
|
totalTasks={57}
|
||||||
|
>
|
||||||
|
<div slot="comments">
|
||||||
|
<Comment name="Ecma Script" postedAt={new Date('2020-08-17T14:12:23')}>
|
||||||
|
<p>Those interface tests are now passing.</p>
|
||||||
|
</Comment>
|
||||||
|
</div>
|
||||||
|
</Project>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Project
|
||||||
|
title="Update documentation"
|
||||||
|
tasksCompleted={18}
|
||||||
|
totalTasks={21}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
@ -0,0 +1,56 @@
|
|||||||
|
<script>
|
||||||
|
export let name;
|
||||||
|
export let postedAt;
|
||||||
|
|
||||||
|
$: avatar = `https://ui-avatars.com/api/?name=${name.replace(/ /g, '+')}&rounded=true&background=ff3e00&color=fff&bold=true`;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
article {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px #ccc solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.details {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
margin-left: 0.5rem
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
time {
|
||||||
|
color: #777;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body :global(p) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<div class="header">
|
||||||
|
<img src={avatar} alt="" height="32" width="32">
|
||||||
|
<div class="details">
|
||||||
|
<h4>{name}</h4>
|
||||||
|
<time datetime={postedAt.toISOString()}>{postedAt.toLocaleDateString()}</time>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="body">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</article>
|
@ -0,0 +1,64 @@
|
|||||||
|
<script>
|
||||||
|
export let title;
|
||||||
|
export let tasksCompleted = 0;
|
||||||
|
export let totalTasks = 0;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
article {
|
||||||
|
border: 1px #ccc solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
article > div {
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
article.has-discussion::after {
|
||||||
|
content: '';
|
||||||
|
background-color: #ff3e00;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||||
|
height: 20px;
|
||||||
|
position: absolute;
|
||||||
|
right: -10px;
|
||||||
|
top: -10px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
margin: 0 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #777;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.discussion {
|
||||||
|
background-color: #eee;
|
||||||
|
border-top: 1px #ccc solid;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<article class:has-discussion={$$slots.comments}>
|
||||||
|
<div>
|
||||||
|
<h2>{title}</h2>
|
||||||
|
<p>{tasksCompleted}/{totalTasks} tasks completed</p>
|
||||||
|
</div>
|
||||||
|
{#if $$slots.comments}
|
||||||
|
<div class="discussion">
|
||||||
|
<h3>Comments</h3>
|
||||||
|
<slot name="comments"></slot>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</article>
|
@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
title: Checking for slot content
|
||||||
|
---
|
||||||
|
|
||||||
|
In some cases, you may want to control parts of your component based on whether the parent passes in content for a certain slot. Perhaps you have a wrapper around that slot, and you don't want to render it if the slot is empty. Or perhaps you'd like to apply a class only if the slot is present. You can do this by checking the properties of the special `$$slots` variable.
|
||||||
|
|
||||||
|
`$$slots` is an object whose keys are the names of the slots passed in by the parent component. If the parent leaves a slot empty, then `$$slots` will not have an entry for that slot.
|
||||||
|
|
||||||
|
Notice that both instances of `<Project>` in this example render a container for comments and a notification dot, even though only one has comments. We want to use `$$slots` to make sure we only render these elements when the parent `<App>` passes in content for the `comments` slot.
|
||||||
|
|
||||||
|
In `Project.svelte`, update the `class:has-discussion` directive on the `<article>`:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<article class:has-discussion={$$slots.comments}>
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, wrap the `comments` slot and its wrapping `<div>` in an `if` block that checks `$$slots`:
|
||||||
|
|
||||||
|
```html
|
||||||
|
{#if $$slots.comments}
|
||||||
|
<div class="discussion">
|
||||||
|
<h3>Comments</h3>
|
||||||
|
<slot name="comments"></slot>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now the comments container and the notification dot won't render when `<App>` leaves the `comments` slot empty.
|
@ -0,0 +1,10 @@
|
|||||||
|
<svelte:options tag="custom-element"/>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export let name;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>name: {name}</p>
|
||||||
|
<p>$$props: {JSON.stringify($$props)}</p>
|
||||||
|
<p>$$restProps: {JSON.stringify($$restProps)}</p>
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
import * as assert from 'assert';
|
||||||
|
import './main.svelte';
|
||||||
|
|
||||||
|
export default function (target) {
|
||||||
|
target.innerHTML = '<custom-element name="world" answer="42" test="svelte"></custom-element>';
|
||||||
|
const el = target.querySelector('custom-element');
|
||||||
|
|
||||||
|
assert.htmlEqual(el.shadowRoot.innerHTML, `
|
||||||
|
<p>name: world</p>
|
||||||
|
<p>$$props: {"name":"world","answer":"42","test":"svelte"}</p>
|
||||||
|
<p>$$restProps: {"answer":"42","test":"svelte"}</p>
|
||||||
|
`);
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
<script>
|
||||||
|
let keys = ['a', 'b'];
|
||||||
|
let items = ['c', 'd'];
|
||||||
|
export let log;
|
||||||
|
function setKey(key, value, item) {
|
||||||
|
log.push(`setKey(${key}, ${value}, ${item})`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each items as item (item)}
|
||||||
|
{#each keys as key (key)}
|
||||||
|
<slot {key} {item} set={(value) => setKey(key, value, item)} />
|
||||||
|
{/each}
|
||||||
|
{/each}
|
@ -0,0 +1,36 @@
|
|||||||
|
export default {
|
||||||
|
html: `
|
||||||
|
<button type="button">Set a-c</button>
|
||||||
|
<button type="button">Set b-c</button>
|
||||||
|
<button type="button">Set a-d</button>
|
||||||
|
<button type="button">Set b-d</button>
|
||||||
|
`,
|
||||||
|
async test({ assert, target, window, component }) {
|
||||||
|
const [btn1, btn2, btn3, btn4] = target.querySelectorAll('button');
|
||||||
|
const click = new window.MouseEvent('click');
|
||||||
|
|
||||||
|
await btn1.dispatchEvent(click);
|
||||||
|
assert.deepEqual(component.log, ['setKey(a, value-a-c, c)']);
|
||||||
|
|
||||||
|
await btn2.dispatchEvent(click);
|
||||||
|
assert.deepEqual(component.log, [
|
||||||
|
'setKey(a, value-a-c, c)',
|
||||||
|
'setKey(b, value-b-c, c)'
|
||||||
|
]);
|
||||||
|
|
||||||
|
await btn3.dispatchEvent(click);
|
||||||
|
assert.deepEqual(component.log, [
|
||||||
|
'setKey(a, value-a-c, c)',
|
||||||
|
'setKey(b, value-b-c, c)',
|
||||||
|
'setKey(a, value-a-d, d)'
|
||||||
|
]);
|
||||||
|
|
||||||
|
await btn4.dispatchEvent(click);
|
||||||
|
assert.deepEqual(component.log, [
|
||||||
|
'setKey(a, value-a-c, c)',
|
||||||
|
'setKey(b, value-b-c, c)',
|
||||||
|
'setKey(a, value-a-d, d)',
|
||||||
|
'setKey(b, value-b-d, d)'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
import Nested from './Nested.svelte';
|
||||||
|
export let log = [];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Nested {log} let:set let:key let:item>
|
||||||
|
<button type="button" on:click={() => set(`value-${key}-${item}`)}>Set {key}-{item}</button>
|
||||||
|
</Nested>
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
let keys = ['a', 'b'];
|
||||||
|
export let log;
|
||||||
|
function setKey(key, value) {
|
||||||
|
log.push(`setKey(${key}, ${value})`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each keys as key (key)}
|
||||||
|
<slot {key} set={(value) => setKey(key, value)} />
|
||||||
|
{/each}
|
@ -0,0 +1,19 @@
|
|||||||
|
export default {
|
||||||
|
html: `
|
||||||
|
<button type="button">Set a</button>
|
||||||
|
<button type="button">Set b</button>
|
||||||
|
`,
|
||||||
|
async test({ assert, target, window, component }) {
|
||||||
|
const [btn1, btn2] = target.querySelectorAll('button');
|
||||||
|
const click = new window.MouseEvent('click');
|
||||||
|
|
||||||
|
await btn1.dispatchEvent(click);
|
||||||
|
assert.deepEqual(component.log, ['setKey(a, value-a)']);
|
||||||
|
|
||||||
|
await btn2.dispatchEvent(click);
|
||||||
|
assert.deepEqual(component.log, [
|
||||||
|
'setKey(a, value-a)',
|
||||||
|
'setKey(b, value-b)'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
import Nested from './Nested.svelte';
|
||||||
|
export let log = [];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Nested {log} let:set let:key>
|
||||||
|
<button type="button" on:click={() => set(`value-${key}`)}>Set {key}</button>
|
||||||
|
</Nested>
|
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
export let log;
|
||||||
|
function setKey(key, value) {
|
||||||
|
log.push(`setKey(${key}, ${value})`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<slot key="a" set={setKey} />
|
||||||
|
<slot key="b" set={setKey} />
|
@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
import Inner from './Inner.svelte';
|
||||||
|
export let log;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Inner {log} let:key let:set>
|
||||||
|
<slot {key} set={(value) => set(key, value)} />
|
||||||
|
</Inner>
|
@ -0,0 +1,19 @@
|
|||||||
|
export default {
|
||||||
|
html: `
|
||||||
|
<button type="button">Set a</button>
|
||||||
|
<button type="button">Set b</button>
|
||||||
|
`,
|
||||||
|
async test({ assert, target, window, component }) {
|
||||||
|
const [btn1, btn2] = target.querySelectorAll('button');
|
||||||
|
const click = new window.MouseEvent('click');
|
||||||
|
|
||||||
|
await btn1.dispatchEvent(click);
|
||||||
|
assert.deepEqual(component.log, ['setKey(a, value-a)']);
|
||||||
|
|
||||||
|
await btn2.dispatchEvent(click);
|
||||||
|
assert.deepEqual(component.log, [
|
||||||
|
'setKey(a, value-a)',
|
||||||
|
'setKey(b, value-b)'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
import Nested from './Nested.svelte';
|
||||||
|
export let log = [];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Nested {log} let:set let:key>
|
||||||
|
<button type="button" on:click={() => set(`value-${key}`)}>Set {key}</button>
|
||||||
|
</Nested>
|
@ -0,0 +1,31 @@
|
|||||||
|
// expect aborting halfway through outro transition
|
||||||
|
// to behave the same in `{#if}` block as in `{:else}` block
|
||||||
|
export default {
|
||||||
|
html: `
|
||||||
|
<div>a</div>
|
||||||
|
|
||||||
|
<div>a</div>
|
||||||
|
`,
|
||||||
|
|
||||||
|
async test({ assert, component, target, window, raf }) {
|
||||||
|
component.visible = false;
|
||||||
|
|
||||||
|
// abort halfway through the outro transition
|
||||||
|
raf.tick(50);
|
||||||
|
|
||||||
|
await component.$set({
|
||||||
|
visible: true,
|
||||||
|
array: ['a', 'b', 'c']
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>a</div>
|
||||||
|
<div>b</div>
|
||||||
|
<div>c</div>
|
||||||
|
|
||||||
|
<div>a</div>
|
||||||
|
<div>b</div>
|
||||||
|
<div>c</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,21 @@
|
|||||||
|
<script>
|
||||||
|
export let array = ['a'];
|
||||||
|
export let visible = true;
|
||||||
|
|
||||||
|
function slide(_, params) {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if visible}
|
||||||
|
{#each array as item}
|
||||||
|
<div transition:slide={{duration:100}}>{item}</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if !visible}
|
||||||
|
{:else}
|
||||||
|
{#each array as item}
|
||||||
|
<div transition:slide={{duration:100}}>{item}</div>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
Loading…
Reference in new issue