mirror of https://github.com/sveltejs/svelte
commit
dedd01eb86
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,86 @@
|
||||
---
|
||||
title: What's new in Svelte: January 2021
|
||||
description: A Svelte-packed showcase to kick-off the new year!
|
||||
author: Daniel Sandoval
|
||||
authorURL: https://desandoval.net
|
||||
---
|
||||
|
||||
Happy new year from Svelte! In the last month we made progress on Sapper's upcoming release, fine-tuned our `SvelteComponent` typings, and have seen some amazing apps, sites, and libraries coming out in the showcase.
|
||||
|
||||
## What's changed in Svelte?
|
||||
|
||||
A new minor release replaces the `SvelteComponent` class with a `SvelteComponentTyped` class. This renaming should help with backwards compatibility. We've updated [last month's blog post](https://svelte.dev/blog/whats-new-in-svelte-december-2020) to avoid any confusion with the name change.
|
||||
|
||||
If you're using `SvelteComponent` or the new `SvelteComponentTyped` in your project or library, let us know what you're using it for and we'll add it to the showcase!
|
||||
|
||||
|
||||
## What's going on in Sapper?
|
||||
|
||||
More quality of life features are landing in the upcoming release every day. `0.29.0` will include new TypeScript definitions, fixes to scroll tracking and prefetching behavior, and improvements to the runtime router to support encoded query parameters.
|
||||
|
||||
If you're upgrading from 0.28.x, check out [the migration guide](https://sapper.svelte.dev/migrating/#0_28_to_0_29) for steps on updating to Sapper 0.29.
|
||||
|
||||
|
||||
## Is SvelteKit ready yet?
|
||||
|
||||
To avoid too much churn during development, SvelteKit is still being worked on in a private repo. There will be an announcement on the Discord, blog and Twitter when it's ready for a larger group of users and contributors.
|
||||
|
||||
In the meantime, you can explore the current build by running `npm init svelte@next` from your command line.
|
||||
|
||||
As cautioned in _[What's the deal with SvelteKit?](https://svelte.dev/blog/whats-the-deal-with-sveltekit)_, there are no docs or support available yet... So use at your own risk / for your own enjoyment!
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Community Showcase
|
||||
|
||||
**Apps & Sites**
|
||||
|
||||
- [manitu.me](https://manitu.me/) is a background sound / pomodoro timer for focus and relaxation
|
||||
- [Answer Socrates](https://answersocrates.com/) helps you find trending questions on the internet so that you can write the most relevant blog post, tweet, or billboard
|
||||
- [multris](https://multris.s1h.org/) is a multiplayer Tetris game. You can read about its development [here](https://blog.s1h.org/svelte-multiplayer-game/)
|
||||
- [weather-ab](https://github.com/ganochenkodg/weather-ab) compares the archive of weather in different cities of the world. Indispensable for people thinking about migration
|
||||
- [Game Nibs](https://gamenibs.com/) is a platform for gamers to find and share concise bite-sized bits of gaming advice, tips, tricks, screenshots, builds, and much more
|
||||
- [Ora](https://github.com/cupcakearmy/ora) is an open source website tracking and limiting tool for Chrome and Firefox
|
||||
- [vscode-dms](https://github.com/techsyndicate/vscode-dms) is a group direct messaging chat app for VSCode
|
||||
- [Zero.2](https://zero.oleksandrdemian.tech/) is a math-based challenge game where you try to get to zero as quickly as possible
|
||||
- [Octave Compass](https://octavecompass.com/2741) is a chord table and scale explorer for many popular musical scales
|
||||
- [Infinite Walking Bass Generator 2](https://github.com/elialbert/infinitewalkingbass2) is an online music player that generates a unique walking bass line
|
||||
- [ListenAddict](https://www.listenaddict.com/) is a site that notifies you whenever a person has a new talk/interview on podcast
|
||||
|
||||
**Demos, Libraries & Components**
|
||||
|
||||
- [svelte-tiny-virtual-list](https://github.com/Skayo/svelte-tiny-virtual-list) speeds up long lists by only rendering visible items
|
||||
- [svelte-query](https://github.com/TanStack/svelte-query) is a collection of helpful hooks for managing, caching and syncing asynchronous and remote data
|
||||
- [svelte-previous](https://github.com/bryanmylee/svelte-previous) is a svelte store to remember previous values - helpful for transitions or a quick undo stack
|
||||
- [Let's Build a Confetti Cannon](https://varun.ca/confetti/) explains how to build a particle system and integrate a Canvas based animation into a larger application
|
||||
- [svelte-micro](https://github.com/ayndqy/svelte-micro) is a one-component router
|
||||
- [svelte-standalone-router](https://github.com/hjalmar/svelte-standalone-router) is a standalone router with an API based on [standalone-router](https://github.com/hjalmar/standalone-router)
|
||||
- [svelte-datepicker](https://github.com/beyonk-adventures/svelte-datepicker) is a datepicker component with variations for time selection, date ranges and responsive themes
|
||||
- [svelte-slimscroll](https://github.com/MelihAltintas/svelte-slimscroll) is a action for Svelte.js, which can transforms any div into a scrollable area with a nice scrollbar.
|
||||
- [Svelte Zoomable](https://svelte.dev/repl/58dfe87756ee4db897c281b52fdef7b7?version=3.31.0) is a custom transition with a nice zoom effect
|
||||
|
||||
**Have a component you'd like to share?** Check out the [Components](https://sveltesociety.dev/components) page on the Svelte Society site. You can contribute by making [a PR to this file](https://github.com/svelte-society/sveltesociety.dev/blob/master/src/pages/components/components.json).
|
||||
|
||||
**Learning Resources**
|
||||
|
||||
- [Using Svelte to create a scroll video effect](https://blog.koenvangilst.nl/tutorial-svelte-scroll-video/) showcases how the `bind` command can be used to create a cool scroll video effect with very little code
|
||||
- [How to make a flappybird game in svelte and typescript](https://www.youtube.com/watch?v=nhrYBoVI8pQ) is a video tutorial including docs and code for reference
|
||||
- [Accessible Svelte Transition](https://www.youtube.com/watch?v=QK_QuRL7nSo&feature=youtu.be) walks through `prefers-reduced-motion` to make svelte transitions more accessible
|
||||
- [Svelte's module scripts explained](https://codechips.me/svelte-module-scripts-explained/) is a great introduction to the module context, a common Sapper pattern
|
||||
- [Awesome Svelte](https://github.com/TheComputerM/awesome-svelte#readme) is a curated list of Svelte resources
|
||||
- [.NET Core and Svelte](https://dev.to/cainux/net-core-and-svelte-f8o) explains how to get Svelte up and running with .NET Core
|
||||
- [A la découverte de Svelte JS](https://www.youtube.com/watch?v=SLpx1Y8e1ek&list=PLff5I1miao9ZEUhpqkrOx7k8RGAZt-nm9) is a svelte tutorial series in French!
|
||||
- [Svelte for React Developers](https://soshace.com/svelte-for-react-developers/) explains Svelte's core concepts to folks who are used to React
|
||||
- [Building a Svelte Static Website with Smooth Page Transitions](https://www.youtube.com/watch?v=dvPfmcGtmrI&feature=emb_title) shows how to build a static website with Svelte and add smooth page transitions using Three.js and GSAP.
|
||||
- [Using Apollo Client in Sapper](https://bjornlu.com/blog/using-apollo-client-in-sapper/) explains the "simplest" solutions to integrate the Apollo query client into Sapper
|
||||
- [Reactive web apps with Crystal + Svelte](https://www.youtube.com/watch?v=i1xjLd6z7BU) explores how to build full-stack, server-rendered Svelte apps with a [Crystal](https://crystal-lang.org) backend
|
||||
|
||||
**Related Projects**
|
||||
|
||||
- [Snowpack's v3 release candidate](https://www.snowpack.dev/posts/2020-12-03-snowpack-3-release-candidate) is out now in preparation for a January 6 release date. Check out the [Getting Started with Svelte](https://www.snowpack.dev/tutorials/svelte) for more info on how to use Snowpack.
|
||||
- [Uppy](https://uppy.io/blog/2020/12/1.24/), the open source file uploader, announced Svelte support in its new version 1.24
|
||||
|
||||
## See you next month!
|
||||
|
||||
Want to add your work to the Showcase? Want to contribute to Svelte? 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!
|
||||
@ -1,4 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:3000",
|
||||
"video": false
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,18 @@
|
||||
import Component from '../../Component';
|
||||
import TemplateScope from './TemplateScope';
|
||||
import { is_reserved_keyword } from '../../utils/reserved_keywords';
|
||||
|
||||
export default function is_contextual(component: Component, scope: TemplateScope, name: string) {
|
||||
if (is_reserved_keyword(name)) return true;
|
||||
|
||||
// if it's a name below root scope, it's contextual
|
||||
if (!scope.is_top_level(name)) return true;
|
||||
|
||||
const variable = component.var_lookup.get(name);
|
||||
|
||||
// hoistables, module declarations, and imports are non-contextual
|
||||
if (!variable || variable.hoistable) return false;
|
||||
|
||||
// assume contextual
|
||||
return true;
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
import Renderer, { RenderOptions } from '../Renderer';
|
||||
import RawMustacheTag from '../../nodes/RawMustacheTag';
|
||||
import { Expression } from 'estree';
|
||||
|
||||
export default function(node: RawMustacheTag, renderer: Renderer, _options: RenderOptions) {
|
||||
renderer.add_expression(node.expression.node);
|
||||
renderer.add_expression(node.expression.node as Expression);
|
||||
}
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
export default {
|
||||
html: `
|
||||
<button>action</button>
|
||||
`,
|
||||
async test({ assert, target, window }) {
|
||||
assert.equal(target.querySelector('button').foo, 'bar1337');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
const obj = {
|
||||
deep: {
|
||||
foo : 'bar',
|
||||
action(element, { leet }) {
|
||||
element.foo = this.foo + leet;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<button use:obj.deep.action={{ leet: 1337 }}>action</button>
|
||||
@ -0,0 +1,53 @@
|
||||
export default {
|
||||
html: `
|
||||
<input type="checkbox" value="a" data-index="x-1">
|
||||
<input type="checkbox" value="b" data-index="x-1">
|
||||
<input type="checkbox" value="c" data-index="x-1">
|
||||
<input type="checkbox" value="a" data-index="x-2">
|
||||
<input type="checkbox" value="b" data-index="x-2">
|
||||
<input type="checkbox" value="c" data-index="x-2">
|
||||
<input type="checkbox" value="a" data-index="y-1">
|
||||
<input type="checkbox" value="b" data-index="y-1">
|
||||
<input type="checkbox" value="c" data-index="y-1">
|
||||
<input type="checkbox" value="a" data-index="y-2">
|
||||
<input type="checkbox" value="b" data-index="y-2">
|
||||
<input type="checkbox" value="c" data-index="y-2">
|
||||
<input type="checkbox" value="a" data-index="z-1">
|
||||
<input type="checkbox" value="b" data-index="z-1">
|
||||
<input type="checkbox" value="c" data-index="z-1">
|
||||
<input type="checkbox" value="a" data-index="z-2">
|
||||
<input type="checkbox" value="b" data-index="z-2">
|
||||
<input type="checkbox" value="c" data-index="z-2">
|
||||
`,
|
||||
|
||||
async test({ assert, component, target, window }) {
|
||||
const inputs = target.querySelectorAll('input');
|
||||
const checked = new Set();
|
||||
const checkInbox = async (i) => {
|
||||
checked.add(i);
|
||||
inputs[i].checked = true;
|
||||
await inputs[i].dispatchEvent(event);
|
||||
};
|
||||
|
||||
for (let i = 0; i < 18; i++) {
|
||||
assert.equal(inputs[i].checked, checked.has(i));
|
||||
}
|
||||
|
||||
const event = new window.Event('change');
|
||||
|
||||
await checkInbox(2);
|
||||
for (let i = 0; i < 18; i++) {
|
||||
assert.equal(inputs[i].checked, checked.has(i));
|
||||
}
|
||||
|
||||
await checkInbox(12);
|
||||
for (let i = 0; i < 18; i++) {
|
||||
assert.equal(inputs[i].checked, checked.has(i));
|
||||
}
|
||||
|
||||
await checkInbox(8);
|
||||
for (let i = 0; i < 18; i++) {
|
||||
assert.equal(inputs[i].checked, checked.has(i));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,15 @@
|
||||
<script>
|
||||
const list = [
|
||||
{ id: 'x', data: [{ id: 1, data: [] }, { id: 2, data: [] }] },
|
||||
{ id: 'y', data: [{ id: 1, data: [] }, { id: 2, data: [] }] },
|
||||
{ id: 'z', data: [{ id: 1, data: [] }, { id: 2, data: [] }] }
|
||||
];
|
||||
</script>
|
||||
|
||||
{#each list as { id, data }}
|
||||
{#each data as item}
|
||||
<input type="checkbox" bind:group={item.data} value="a" data-index="{id}-{item.id}" />
|
||||
<input type="checkbox" bind:group={item.data} value="b" data-index="{id}-{item.id}" />
|
||||
<input type="checkbox" bind:group={item.data} value="c" data-index="{id}-{item.id}" />
|
||||
{/each}
|
||||
{/each}
|
||||
@ -0,0 +1,7 @@
|
||||
export default {
|
||||
async test({ assert, target }) {
|
||||
const iframe = target.querySelector('iframe');
|
||||
|
||||
assert.equal(iframe.style.zIndex, '-1');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,8 @@
|
||||
<script>
|
||||
let offsetWidth = 0;
|
||||
let offsetHeight = 0;
|
||||
</script>
|
||||
|
||||
<div style="z-index: 42;" bind:offsetHeight bind:offsetWidth>
|
||||
<h1>Hello</h1>
|
||||
</div>
|
||||
@ -0,0 +1,13 @@
|
||||
let result;
|
||||
|
||||
export default {
|
||||
before_test() {
|
||||
result = [];
|
||||
},
|
||||
props: {
|
||||
collect: (str) => result.push(str)
|
||||
},
|
||||
test({ assert }) {
|
||||
assert.deepEqual(result, ['each_action', 'import_action']);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,17 @@
|
||||
<script>
|
||||
import action from './util.js';
|
||||
export let collect;
|
||||
|
||||
function each_action(_, fn) {
|
||||
fn('each_action');
|
||||
}
|
||||
const array = [each_action];
|
||||
</script>
|
||||
|
||||
<div use:action={collect} />
|
||||
|
||||
<ul>
|
||||
{#each array as action}
|
||||
<div use:action={collect} />
|
||||
{/each}
|
||||
</ul>
|
||||
@ -0,0 +1,3 @@
|
||||
export default function (_, fn) {
|
||||
fn('import_action');
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
export default {
|
||||
html: `
|
||||
<label><input type="checkbox" value="Vanilla"> Vanilla</label>
|
||||
<label><input type="checkbox" value="Strawberry"> Strawberry</label>
|
||||
<label><input type="checkbox" value="Chocolate"> Chocolate</label>
|
||||
<label><input type="checkbox" value="Lemon"> Lemon</label>
|
||||
<label><input type="checkbox" value="Coconut"> Coconut</label>
|
||||
`,
|
||||
|
||||
async test({ assert, target, window }) {
|
||||
const [input1, input2, input3, input4, input5] = target.querySelectorAll('input');
|
||||
const event = new window.Event('change');
|
||||
|
||||
input3.checked = true;
|
||||
await input3.dispatchEvent(event);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<label><input type="checkbox" value="Chocolate"> Chocolate</label>
|
||||
<label><input type="checkbox" value="Vanilla"> Vanilla</label>
|
||||
<label><input type="checkbox" value="Strawberry"> Strawberry</label>
|
||||
<label><input type="checkbox" value="Lemon"> Lemon</label>
|
||||
<label><input type="checkbox" value="Coconut"> Coconut</label>
|
||||
`);
|
||||
|
||||
assert.equal(input1.checked, false);
|
||||
assert.equal(input2.checked, false);
|
||||
assert.equal(input3.checked, true);
|
||||
assert.equal(input4.checked, false);
|
||||
assert.equal(input5.checked, false);
|
||||
|
||||
input4.checked = true;
|
||||
await input4.dispatchEvent(event);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<label><input type="checkbox" value="Chocolate"> Chocolate</label>
|
||||
<label><input type="checkbox" value="Lemon"> Lemon</label>
|
||||
<label><input type="checkbox" value="Vanilla"> Vanilla</label>
|
||||
<label><input type="checkbox" value="Strawberry"> Strawberry</label>
|
||||
<label><input type="checkbox" value="Coconut"> Coconut</label>
|
||||
`);
|
||||
|
||||
assert.equal(input1.checked, false);
|
||||
assert.equal(input2.checked, false);
|
||||
assert.equal(input3.checked, true);
|
||||
assert.equal(input4.checked, true);
|
||||
assert.equal(input5.checked, false);
|
||||
|
||||
input3.checked = false;
|
||||
await input3.dispatchEvent(event);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<label><input type="checkbox" value="Lemon"> Lemon</label>
|
||||
<label><input type="checkbox" value="Chocolate"> Chocolate</label>
|
||||
<label><input type="checkbox" value="Vanilla"> Vanilla</label>
|
||||
<label><input type="checkbox" value="Strawberry"> Strawberry</label>
|
||||
<label><input type="checkbox" value="Coconut"> Coconut</label>
|
||||
`);
|
||||
|
||||
assert.equal(input1.checked, false);
|
||||
assert.equal(input2.checked, false);
|
||||
assert.equal(input3.checked, false);
|
||||
assert.equal(input4.checked, true);
|
||||
assert.equal(input5.checked, false);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,21 @@
|
||||
<script>
|
||||
let flavours = [
|
||||
'Vanilla',
|
||||
'Strawberry',
|
||||
'Chocolate',
|
||||
'Lemon',
|
||||
'Coconut'
|
||||
];
|
||||
|
||||
let choices = [];
|
||||
|
||||
// Put choices first by sorting
|
||||
$: flavours = flavours.sort((a, b) => choices.includes(b) - choices.includes(a));
|
||||
</script>
|
||||
|
||||
{#each flavours as flavour (flavour)}
|
||||
<label>
|
||||
<input type=checkbox bind:group={choices} value={flavour}>
|
||||
{flavour}
|
||||
</label>
|
||||
{/each}
|
||||
@ -0,0 +1,3 @@
|
||||
export default {
|
||||
html: '<p>aca</p>'
|
||||
};
|
||||
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
export let a = 'a';
|
||||
let b;
|
||||
$: c = a;
|
||||
|
||||
function foo() {
|
||||
b = c === 'a' ? 'b' : 'c';
|
||||
}
|
||||
foo();
|
||||
</script>
|
||||
|
||||
<p>{a}{b}{c}</p>
|
||||
@ -0,0 +1,3 @@
|
||||
export default {
|
||||
html: '{"answer":4}'
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
<script>
|
||||
import { writable } from '../../../../store';
|
||||
|
||||
let value = writable({ foo: 1, bar: 2 });
|
||||
$value.foo = $value.foo + $value.bar; // 3
|
||||
$value.bar = $value.foo * $value.bar; // 6
|
||||
|
||||
// should resubscribe immediately
|
||||
value = writable({ foo: $value.foo + 2, bar: $value.bar - 2 }); // { foo: 5, bar: 4 }
|
||||
|
||||
// should mutate the store value
|
||||
$value.baz = $value.foo + $value.bar; // { foo: 5, bar: 4, baz: 9 }
|
||||
|
||||
// should resubscribe immediately
|
||||
value = writable({ qux: $value.baz - $value.foo }); // { qux: 4 }
|
||||
|
||||
// making sure instrumentation returns the expression value
|
||||
$value = {
|
||||
one: writable(
|
||||
$value = {
|
||||
two: ({ $value } = { $value: { fred: $value.qux } }) // { fred: 4 }
|
||||
} // { two: { $value: { fred: 4 } } }
|
||||
) // { one: { two: { $value: { fred: 4 } } } }
|
||||
};
|
||||
|
||||
const one = $value.one;
|
||||
|
||||
value.update(val => ({ answer: $one.two.$value.fred })); // { answer: 4 }
|
||||
</script>
|
||||
|
||||
{JSON.stringify($value)}
|
||||
@ -0,0 +1,174 @@
|
||||
let fulfil;
|
||||
|
||||
export default {
|
||||
props: {
|
||||
promise: new Promise((f) => {
|
||||
fulfil = f;
|
||||
})
|
||||
},
|
||||
intro: true,
|
||||
|
||||
async test({ assert, target, component, raf }) {
|
||||
assert.htmlEqual(target.innerHTML, '<p class="pending" foo="0.0">loading...</p>');
|
||||
|
||||
let time = 0;
|
||||
|
||||
raf.tick(time += 50);
|
||||
assert.htmlEqual(target.innerHTML, '<p class="pending" foo="0.5">loading...</p>');
|
||||
|
||||
await fulfil(42);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.0">42</p>
|
||||
<p class="pending" foo="0.5">loading...</p>
|
||||
`);
|
||||
|
||||
// see the transition 30% complete
|
||||
raf.tick(time += 30);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.3">42</p>
|
||||
<p class="pending" foo="0.2">loading...</p>
|
||||
`);
|
||||
|
||||
// completely transition in the {:then} block
|
||||
raf.tick(time += 70);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="1.0">42</p>
|
||||
`);
|
||||
|
||||
// update promise #1
|
||||
component.promise = new Promise((f) => {
|
||||
fulfil = f;
|
||||
});
|
||||
await Promise.resolve();
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="1.0">42</p>
|
||||
<p class="pending" foo="0.0">loading...</p>
|
||||
`);
|
||||
|
||||
raf.tick(time += 100);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="pending" foo="1.0">loading...</p>
|
||||
`);
|
||||
|
||||
await fulfil(43);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="pending" foo="1.0">loading...</p>
|
||||
<p class="then" foo="0.0">43</p>
|
||||
`);
|
||||
|
||||
raf.tick(time += 100);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="1.0">43</p>
|
||||
`);
|
||||
|
||||
// update promise #2
|
||||
component.promise = new Promise((f) => {
|
||||
fulfil = f;
|
||||
});
|
||||
await Promise.resolve();
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="1.0">43</p>
|
||||
<p class="pending" foo="0.0">loading...</p>
|
||||
`);
|
||||
|
||||
raf.tick(time += 50);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.5">43</p>
|
||||
<p class="pending" foo="0.5">loading...</p>
|
||||
`);
|
||||
|
||||
await fulfil(44);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.5">43</p>
|
||||
<p class="pending" foo="0.5">loading...</p>
|
||||
<p class="then" foo="0.0">44</p>
|
||||
`);
|
||||
|
||||
raf.tick(time += 100);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="1.0">44</p>
|
||||
`);
|
||||
|
||||
// update promise #3 - quick succession
|
||||
component.promise = new Promise((f) => {
|
||||
fulfil = f;
|
||||
});
|
||||
await Promise.resolve();
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="1.0">44</p>
|
||||
<p class="pending" foo="0.0">loading...</p>
|
||||
`);
|
||||
|
||||
raf.tick(time += 40);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.6">44</p>
|
||||
<p class="pending" foo="0.4">loading...</p>
|
||||
`);
|
||||
|
||||
await fulfil(45);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.6">44</p>
|
||||
<p class="pending" foo="0.4">loading...</p>
|
||||
<p class="then" foo="0.0">45</p>
|
||||
`);
|
||||
|
||||
raf.tick(time += 20);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.4">44</p>
|
||||
<p class="pending" foo="0.2">loading...</p>
|
||||
<p class="then" foo="0.2">45</p>
|
||||
`);
|
||||
|
||||
component.promise = new Promise((f) => {
|
||||
fulfil = f;
|
||||
});
|
||||
await Promise.resolve();
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.4">44</p>
|
||||
<p class="pending" foo="0.2">loading...</p>
|
||||
<p class="then" foo="0.2">45</p>
|
||||
<p class="pending" foo="0.0">loading...</p>
|
||||
`);
|
||||
|
||||
raf.tick(time += 10);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.3">44</p>
|
||||
<p class="pending" foo="0.1">loading...</p>
|
||||
<p class="then" foo="0.1">45</p>
|
||||
<p class="pending" foo="0.1">loading...</p>
|
||||
`);
|
||||
|
||||
await fulfil(46);
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.3">44</p>
|
||||
<p class="pending" foo="0.1">loading...</p>
|
||||
<p class="then" foo="0.1">45</p>
|
||||
<p class="pending" foo="0.1">loading...</p>
|
||||
<p class="then" foo="0.0">46</p>
|
||||
`);
|
||||
|
||||
raf.tick(time += 10);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.2">44</p>
|
||||
<p class="then" foo="0.1">46</p>
|
||||
`);
|
||||
|
||||
raf.tick(time += 20);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="0.3">46</p>
|
||||
`);
|
||||
|
||||
raf.tick(time += 70);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="then" foo="1.0">46</p>
|
||||
`);
|
||||
}
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue