Merge branch 'master' into site-headings-level-4

pull/2373/head
Rich Harris 7 years ago committed by GitHub
commit 9a0b847455
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -267,21 +267,21 @@ const time = readable(new Date(), set => {
#### `derive` #### `derive`
* `store = derive(a, callback: (a: any) => any)` * `store = derived(a, callback: (a: any) => any)`
* `store = derive(a, callback: (a: any, set: (value: any) => void) => void)` * `store = derived(a, callback: (a: any, set: (value: any) => void) => void)`
* `store = derive([a, ...b], callback: ([a: any, ...b: any[]]) => any)` * `store = derived([a, ...b], callback: ([a: any, ...b: any[]]) => any)`
* `store = derive([a, ...b], callback: ([a: any, ...b: any[]], set: (value: any) => void) => void)` * `store = derived([a, ...b], callback: ([a: any, ...b: any[]], set: (value: any) => void) => void)`
--- ---
Derives a store from one or more other stores. Whenever those dependencies change, the callback runs. Derives a store from one or more other stores. Whenever those dependencies change, the callback runs.
In the simplest version, `derive` takes a single store, and the callback returns a derived value. In the simplest version, `derived` takes a single store, and the callback returns a derived value.
```js ```js
import { derive } from 'svelte/store'; import { derived } from 'svelte/store';
const doubled = derive(a, $a => $a * 2); const doubled = derived(a, $a => $a * 2);
``` ```
--- ---
@ -289,9 +289,9 @@ const doubled = derive(a, $a => $a * 2);
The callback can set a value asynchronously by accepting a second argument, `set`, and calling it when appropriate. The callback can set a value asynchronously by accepting a second argument, `set`, and calling it when appropriate.
```js ```js
import { derive } from 'svelte/store'; import { derived } from 'svelte/store';
const delayed = derive(a, ($a, set) => { const delayed = derived(a, ($a, set) => {
setTimeout(() => set($a), 1000); setTimeout(() => set($a), 1000);
}); });
``` ```
@ -301,11 +301,11 @@ const delayed = derive(a, ($a, set) => {
In both cases, an array of arguments can be passed as the first argument instead of a single store. In both cases, an array of arguments can be passed as the first argument instead of a single store.
```js ```js
import { derive } from 'svelte/store'; import { derived } from 'svelte/store';
const summed = derive([a, b], ([$a, $b]) => $a + $b); const summed = derived([a, b], ([$a, $b]) => $a + $b);
const delayed = derive([a, b], ([$a, $b], set) => { const delayed = derived([a, b], ([$a, $b], set) => {
setTimeout(() => set($a + $b), 1000); setTimeout(() => set($a + $b), 1000);
}); });
``` ```
@ -434,7 +434,7 @@ As with [`tweened`](#tweened) stores, `set` and `update` return a Promise that r
TODO TODO
* fade, fly, slide, draw * fade, fly, slide, scale, draw
* crossfade... * crossfade...
### `svelte/animation` ### `svelte/animation`

@ -1,4 +1,4 @@
import { readable, derive } from 'svelte/store'; import { readable, derived } from 'svelte/store';
export const time = readable(new Date(), function start(set) { export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => { const interval = setInterval(() => {
@ -12,7 +12,7 @@ export const time = readable(new Date(), function start(set) {
const start = new Date(); const start = new Date();
export const elapsed = derive( export const elapsed = derived(
time, time,
$time => Math.round(($time - start) / 1000) $time => Math.round(($time - start) / 1000)
); );

@ -1,4 +1,4 @@
import { readable, derive } from 'svelte/store'; import { readable, derived } from 'svelte/store';
export const time = readable(new Date(), function start(set) { export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => { const interval = setInterval(() => {
@ -12,7 +12,7 @@ export const time = readable(new Date(), function start(set) {
const start = new Date(); const start = new Date();
export const elapsed = derive( export const elapsed = derived(
time, time,
$time => {} $time => {}
); );

@ -1,4 +1,4 @@
import { readable, derive } from 'svelte/store'; import { readable, derived } from 'svelte/store';
export const time = readable(new Date(), function start(set) { export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => { const interval = setInterval(() => {
@ -12,7 +12,7 @@ export const time = readable(new Date(), function start(set) {
const start = new Date(); const start = new Date();
export const elapsed = derive( export const elapsed = derived(
time, time,
$time => Math.round(($time - start) / 1000) $time => Math.round(($time - start) / 1000)
); );

@ -2,10 +2,10 @@
title: Derived stores title: Derived stores
--- ---
You can create a store whose value is based on the value of one or more *other* stores with `derive`. Building on our previous example, we can create a store that derives the time the page has been open: You can create a store whose value is based on the value of one or more *other* stores with `derived`. Building on our previous example, we can create a store that derives the time the page has been open:
```js ```js
export const elapsed = derive( export const elapsed = derived(
time, time,
$time => Math.round(($time - start) / 1000) $time => Math.round(($time - start) / 1000)
); );

@ -0,0 +1,166 @@
<style>
.container {
position: relative;
display: grid;
margin: 10rem auto;
padding: 0 var(--side-nav);
max-width: 120rem;
grid-row-gap: 1em;
grid-template-areas:
"one"
"two"
"three"
"what"
"start";
}
.box {
padding: 1em;
display: flex;
flex-direction: column;
}
h2 {
padding: 0;
margin: 0 0 0.5em 0;
font-size: var(--h2);
color: white;
text-align: left;
}
p {
font-size: var(--h5);
}
.box a {
position: relative;
text-align: right;
margin-top: auto;
padding: 0 1.2em 0 0;
font-family: Roboto, sans-serif;
font-size: 1.6rem;
}
.box a:hover {
color: white;
text-decoration: underline;
}
.box a::after, .cta a::after {
content: '';
position: absolute;
display: block;
right: 0;
top: 0.35em;
width: 1em;
height: 1em;
background: url(/icons/arrow-right.svg);
}
.cta a {
display: inline-block;
text-align: right;
background-color: var(--prime);
padding: 0.5em 1.8em 0.5em 1em;
border-radius: var(--border-r);
color: white;
position: relative;
}
.cta a::after {
right: 0.5em;
top: 0.75em;
}
.description {
margin: 2em 0 0 0;
}
.cta {
margin: 0;
}
@media (min-width: 900px) {
.container {
grid-column-gap: 1em;
grid-row-gap: 1em;
grid-template-columns: repeat(2, 1fr);
grid-template-areas:
"one two"
"three start"
"what what";
}
.box {
padding: 2em;
}
.cta {
text-align: right;
}
}
@media (min-width: 1200px) {
.container {
grid-column-gap: 1em;
grid-row-gap: 5em;
grid-template-columns: repeat(6, 1fr);
grid-template-areas:
"one one two two three three"
"what what what start start start";
}
.description {
margin: 0;
}
.cta {
text-align: left;
}
}
</style>
<section class='container'>
<div class='box bg-prime white' style="grid-area: one">
<h2 style='padding:2.4rem 0 0 0'>Write less code</h2>
<p>Build boilerplate-free components using languages you already know — HTML, CSS and JavaScript</p>
<a href="TODO-blog-post-on-loc">learn more</a>
</div>
<div class='box bg-flash white' style="grid-area: two">
<h2 style='padding:2.4rem 0 0 0'>No virtual DOM</h2>
<p>Svelte compiles your code to tiny, framework-less vanilla JS — your app starts fast and stays fast</p>
<a href="TODO-blog-post-on-vdom-overhead">learn more</a>
</div>
<div class='box bg-second white' style="grid-area: three">
<h2 style='padding:2.4rem 0 0 0'>Truly reactive</h2>
<p>No more complex state management libraries — Svelte brings reactivity to JavaScript itself</p>
<a href="TODO-blog-post-on-reactivity">learn more</a>
</div>
<div class="linkify description" style="grid-area: what;">
<p>Svelte is a radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the <em>browser</em>, Svelte shifts that work into a <em>compile step</em> that happens when you build your app.</p>
<p>Instead of using techniques like virtual DOM diffing, Svelte writes code that surgically updates the DOM when the state of your app changes.</p>
<p><a href="TODO-svelte-3-blog-post">Read the introductory blog post</a> to learn more.</p>
</div>
<div style="grid-area: start; display: flex; flex-direction: column">
<pre class="language-bash" style="margin: 0 0 1em 0">
npx degit sveltejs/template my-svelte-project
cd my-svelte-project
npm install
npm run dev & open http://localhost:5000
</pre>
<p class="linkify" style="flex: 1">See the <a href="blog/the-easiest-way-to-get-started">quickstart guide</a> for more information.</p>
<p class="cta"><a rel="prefetch" href="tutorial">Learn Svelte</a></p>
</div>
</section>

@ -1,7 +1,8 @@
<script> <script>
import Icon from '../components/Icon.svelte'; import Icon from '../components/Icon.svelte';
import Logo from '../components/Logo.svelte'; import Logo from '../components/Logo.svelte';
import WhosUsingSvelte from '../components/WhosUsingSvelte/index.svelte'; import Blurb from './_components/Blurb.svelte';
import WhosUsingSvelte from './_components/WhosUsingSvelte.svelte';
import IntersectionObserver from '../components/IntersectionObserver.svelte'; import IntersectionObserver from '../components/IntersectionObserver.svelte';
// import Lazy from '../components/Lazy.svelte'; // import Lazy from '../components/Lazy.svelte';
import ReplWidget from '../components/Repl/ReplWidget.svelte'; import ReplWidget from '../components/Repl/ReplWidget.svelte';
@ -70,54 +71,6 @@
opacity: 0.7; opacity: 0.7;
} }
.box {
padding: 2em;
display: flex;
flex-direction: column;
}
.box > h2 {
padding: 0;
margin: 0 0 0.5em 0;
font-size: var(--h2);
color: white;
text-align: left;
}
.box > p {
font-size: var(--h5);
}
.box a {
position: relative;
text-align: right;
margin-top: auto;
padding: 0 1.2em 0 0;
font-family: Roboto, sans-serif;
font-size: 1.6rem;
}
.box a:hover {
color: white;
text-decoration: underline;
}
.box a::after, .cta::after {
content: '';
position: absolute;
display: block;
right: 0;
top: 0.25em;
width: 1em;
height: 1em;
background: url(/icons/arrow-right.svg);
}
.cta::after {
right: 0.5em;
top: 0.6em;
}
.examples { .examples {
background: var(--second); background: var(--second);
color: white; color: white;
@ -145,14 +98,6 @@
/* padding: 0.8rem; */ /* padding: 0.8rem; */
} }
a.cta {
background-color: var(--prime);
padding: 0.5em 1.8em 0.5em 1em;
border-radius: var(--border-r);
color: white;
position: relative;
}
.contributor { .contributor {
width: 2.4em; width: 2.4em;
height: 2.4em; height: 2.4em;
@ -197,54 +142,7 @@
<h1>Svelte</h1> <h1>Svelte</h1>
</section> </section>
<section class='container'> <Blurb/>
<ul class='grid stretch'>
<li class='box bg-prime white'>
<h2 style='padding:2.4rem 0 0 0'>Write less code</h2>
<p>Build boilerplate-free components using languages you already know — HTML, CSS and JavaScript</p>
<a href="TODO-blog-post-on-loc">learn more</a>
</li>
<li class='box bg-flash white'>
<h2 style='padding:2.4rem 0 0 0'>No virtual DOM</h2>
<p>Svelte compiles your code to tiny, framework-less vanilla JS — your app starts fast and stays fast</p>
<a href="TODO-blog-post-on-vdom-overhead">learn more</a>
</li>
<li class='box bg-second white'>
<h2 style='padding:2.4rem 0 0 0'>Truly reactive</h2>
<p>No more complex state management libraries — Svelte brings reactivity to JavaScript itself</p>
<a href="TODO-blog-post-on-reactivity">learn more</a>
</li>
</ul>
</section>
<section class="container grid half">
<div class="linkify">
<p>Svelte is a radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the <em>browser</em>, Svelte shifts that work into a <em>compile step</em> that happens when you build your app.</p>
<p>Instead of using techniques like virtual DOM diffing, Svelte writes code that surgically updates the DOM when the state of your app changes.</p>
<p><a href="TODO-svelte-3-blog-post">Read the introductory blog post</a> to learn more.</p>
</div>
<div>
<pre class="language-bash">
npx degit sveltejs/template my-svelte-project
cd my-svelte-project
npm install
npm run dev & open http://localhost:5000
</pre>
<p class="linkify">See the <a href="blog/the-easiest-way-to-get-started">quickstart guide</a> for more information.</p>
<p><a rel="prefetch" class="cta" href="tutorial">Learn Svelte</a></p>
</div>
</section>
<div class="examples"> <div class="examples">
<section class="container example linkify"> <section class="container example linkify">

@ -28,7 +28,7 @@
a { a {
display: block; display: block;
padding: 0.7em 0; padding: 0.75em 0;
text-align: center; text-align: center;
opacity: 0.7; opacity: 0.7;
} }
@ -54,6 +54,7 @@
height: 100%; height: 100%;
opacity: 0.0001; opacity: 0.0001;
cursor: pointer; cursor: pointer;
-webkit-appearance: none;
} }
</style> </style>
@ -63,7 +64,13 @@
</a> </a>
<div> <div>
<span><strong>{selected.section.title} /</strong> {selected.chapter.title}</span> <span>
<strong>
<span style="position: relative; top: -0.1em; margin: 0 0.5em 0 0"><Icon name="menu"/></span>
{selected.section.title} /
</strong>
{selected.chapter.title}
</span>
<select value={slug} on:change={navigate}> <select value={slug} on:change={navigate}>
{#each sections as section, i} {#each sections as section, i}

@ -16,7 +16,7 @@ import list from '../../utils/list';
import Let from './Let'; import Let from './Let';
import TemplateScope from './shared/TemplateScope'; import TemplateScope from './shared/TemplateScope';
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/; const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/;
const aria_attributes = 'activedescendant atomic autocomplete busy checked colindex controls current describedby details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowindex selected setsize sort valuemax valuemin valuenow valuetext'.split(' '); const aria_attributes = 'activedescendant atomic autocomplete busy checked colindex controls current describedby details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowindex selected setsize sort valuemax valuemin valuenow valuetext'.split(' ');
const aria_attribute_set = new Set(aria_attributes); const aria_attribute_set = new Set(aria_attributes);
@ -73,6 +73,21 @@ const passive_events = new Set([
'touchcancel' 'touchcancel'
]); ]);
function get_namespace(parent: Element, element: Element, explicit_namespace: string) {
const parent_element = parent.find_nearest(/^Element/);
if (!parent_element) {
return explicit_namespace || (svg.test(element.name)
? namespaces.svg
: null);
}
if (element.name.toLowerCase() === 'svg') return namespaces.svg;
if (parent_element.name.toLowerCase() === 'foreignobject') return null;
return parent_element.namespace;
}
export default class Element extends Node { export default class Element extends Node {
type: 'Element'; type: 'Element';
name: string; name: string;
@ -93,12 +108,7 @@ export default class Element extends Node {
super(component, parent, scope, info); super(component, parent, scope, info);
this.name = info.name; this.name = info.name;
const parent_element = parent.find_nearest(/^Element/); this.namespace = get_namespace(parent, this, component.namespace);
this.namespace = this.name === 'svg' || (!parent_element && svg.test(this.name))
? namespaces.svg
: this.name === 'foreignObject'
? namespaces.html
: parent_element ? parent_element.namespace : this.component.namespace;
if (this.name === 'textarea') { if (this.name === 'textarea') {
if (info.children.length > 0) { if (info.children.length > 0) {

@ -39,7 +39,7 @@ export function writable(value, start = noop) {
return { set, update, subscribe }; return { set, update, subscribe };
} }
export function derive(stores, fn) { export function derived(stores, fn) {
const single = !Array.isArray(stores); const single = !Array.isArray(stores);
if (single) stores = [stores]; if (single) stores = [stores];

@ -1,9 +1,9 @@
<script> <script>
import { derive } from 'svelte/store'; import { derived } from 'svelte/store';
export let count; export let count;
const doubled = derive(count, $count => $count * 2); const doubled = derived(count, $count => $count * 2);
</script> </script>
<button on:click="{() => $count += 1}">count {$count}</button> <button on:click="{() => $count += 1}">count {$count}</button>

@ -8,6 +8,9 @@ export default {
`, `,
test({ assert, target }) { test({ assert, target }) {
const foreignObject = target.querySelector('foreignObject');
assert.equal(foreignObject.namespaceURI, 'http://www.w3.org/2000/svg');
const p = target.querySelector('p'); const p = target.querySelector('p');
assert.equal(p.namespaceURI, 'http://www.w3.org/1999/xhtml'); assert.equal(p.namespaceURI, 'http://www.w3.org/1999/xhtml');
} }

@ -1,5 +1,5 @@
import * as assert from 'assert'; import * as assert from 'assert';
import { readable, writable, derive, get } from '../../store.js'; import { readable, writable, derived, get } from '../../store.js';
describe('store', () => { describe('store', () => {
describe('writable', () => { describe('writable', () => {
@ -100,10 +100,10 @@ describe('store', () => {
}); });
}); });
describe('derive', () => { describe('derived', () => {
it('maps a single store', () => { it('maps a single store', () => {
const a = writable(1); const a = writable(1);
const b = derive(a, n => n * 2); const b = derived(a, n => n * 2);
const values = []; const values = [];
@ -123,7 +123,7 @@ describe('store', () => {
it('maps multiple stores', () => { it('maps multiple stores', () => {
const a = writable(2); const a = writable(2);
const b = writable(3); const b = writable(3);
const c = derive(([a, b]), ([a, b]) => a * b); const c = derived(([a, b]), ([a, b]) => a * b);
const values = []; const values = [];
@ -143,7 +143,7 @@ describe('store', () => {
it('passes optional set function', () => { it('passes optional set function', () => {
const number = writable(0); const number = writable(0);
const evens = derive(number, (n, set) => { const evens = derived(number, (n, set) => {
if (n % 2 === 0) set(n); if (n % 2 === 0) set(n);
}); });
@ -169,9 +169,9 @@ describe('store', () => {
it('prevents glitches', () => { it('prevents glitches', () => {
const lastname = writable('Jekyll'); const lastname = writable('Jekyll');
const firstname = derive(lastname, n => n === 'Jekyll' ? 'Henry' : 'Edward'); const firstname = derived(lastname, n => n === 'Jekyll' ? 'Henry' : 'Edward');
const fullname = derive([firstname, lastname], names => names.join(' ')); const fullname = derived([firstname, lastname], names => names.join(' '));
const values = []; const values = [];

@ -66,6 +66,32 @@ export function slide(node, {
}; };
} }
export function scale(node, {
delay = 0,
duration = 400,
easing = cubicOut,
start = 0,
opacity = 0
}) {
const sd = 1 - start;
const od = 1 - opacity;
const transform = (
node.style.transform ||
getComputedStyle(node).transform
).replace('none', '');
return {
delay,
duration,
easing,
css: (t, u) => `
transform: ${transform} scale(${1 - (sd * u)});
opacity: ${1 - (od * u)}
`
};
}
export function draw(node, { export function draw(node, {
delay = 0, delay = 0,
duration = 800, duration = 800,

Loading…
Cancel
Save