Merge branch 'master' into site/database

pull/2572/head
Luke Edwards 7 years ago committed by GitHub
commit b724a3d354
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

1
.gitattributes vendored

@ -0,0 +1 @@
*.svelte linguist-language=HTML

@ -1,5 +1,9 @@
# Svelte changelog # Svelte changelog
## 3.1.0
* Allow store subscribe functions to return an object with an `unsubscribe` method, providing native RxJS support ([#2549](https://github.com/sveltejs/svelte/issues/2549))
## 3.0.1 ## 3.0.1
* Prevent text input cursor jumping in Safari ([#2506](https://github.com/sveltejs/svelte/issues/2506)) * Prevent text input cursor jumping in Safari ([#2506](https://github.com/sveltejs/svelte/issues/2506))

@ -1,4 +1,4 @@
Copyright (c) 2016 [these people](https://github.com/sveltejs/svelte/graphs/contributors) Copyright (c) 2016-19 [these people](https://github.com/sveltejs/svelte/graphs/contributors)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

@ -58,7 +58,7 @@ The source code for https://svelte.dev, including all the documentation, lives i
```bash ```bash
cd site cd site
npm install npm install && npm run update
npm run dev npm run dev
``` ```

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.0.1", "version": "3.1.0",
"description": "Cybernetically enhanced web apps", "description": "Cybernetically enhanced web apps",
"module": "index.mjs", "module": "index.mjs",
"main": "index", "main": "index",

@ -17,16 +17,20 @@ By default, the REPL will fetch the most recent version of Svelte from https://u
## REPL GitHub integration ## REPL GitHub integration
In order for the REPL's GitHub integration to work properly when running locally, you will need to create a GitHub OAuth app. Set its authorization callback URL to `http://localhost:3000/auth/callback`, and in this project, create `site/.env` containing: In order for the REPL's GitHub integration to work properly when running locally, you will need to:
- [create a GitHub OAuth app](https://github.com/settings/developers):
``` - set `Authorization callback URL` to `http://localhost:3000/auth/callback`;
GITHUB_CLIENT_ID=[your app's client id] - set `Application name` as you like, and `Homepage URL` as `http://localhost:3000/`;
GITHUB_CLIENT_SECRET=[your app's client secret] - create the app and take note of `Client ID` and `Client Secret`
BASEURL=http://localhost:3000 - in this repo, create `site/.env` containing:
``` ```
GITHUB_CLIENT_ID=[your app's Client ID]
GITHUB_CLIENT_SECRET=[your app's Client Secret]
BASEURL=http://localhost:3000
```
## Translating the API docs ## Translating the API docs
Anchors are automatically generated using headings in the documentation and by default (for the english language) they are latinised to make sure the URL is always conforming to RFC3986. Anchors are automatically generated using headings in the documentation and by default (for the english language) they are latinised to make sure the URL is always conforming to RFC3986.
If we need to translate the API documentation to a language using unicode chars, we can setup this app to export the correct anchors by setting up `SLUG_PRESERVE_UNICODE` to `true` and `SLUG_LANG` to the ISO 639-1 two-letter language code of your choice in `config.js`. If we need to translate the API documentation to a language using unicode chars, we can setup this app to export the correct anchors by setting up `SLUG_PRESERVE_UNICODE` to `true` in `config.js`.

@ -1,3 +1,2 @@
export const SLUG_PRESERVE_UNICODE = false; export const SLUG_PRESERVE_UNICODE = false;
export const SLUG_SEPARATOR = '_'; export const SLUG_SEPARATOR = '_';
export const SLUG_LANG = 'en';

@ -366,7 +366,13 @@ Components can emit events using [createEventDispatcher](docs#createEventDispatc
<SomeComponent on:whatever={handler}/> <SomeComponent on:whatever={handler}/>
``` ```
---
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.
```html
<SomeComponent on:whatever/>
```
### Element bindings ### Element bindings
@ -983,7 +989,7 @@ Named slots can also expose values. The `let:` directive goes on the element wit
{/each} {/each}
</ul> </ul>
</slot name="footer"></slot> <slot name="footer"></slot>
``` ```

@ -176,8 +176,39 @@ Retrieves the context that belongs to the closest parent component with the spec
#### `createEventDispatcher` #### `createEventDispatcher`
TODO ```js
dispatch: ((name: string, detail?: any) => void) = createEventDispatcher();
```
---
Creates an event dispatcher that can be used to dispatch [component events](docs#Component_events). Event dispatchers are functions that can take two arguments: `name` and `detail`.
Component events created with `createEventDispatcher` create a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture) and are not cancellable with `event.preventDefault()`. The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property and can contain any type of data.
```html
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
</script>
<button on:click="{() => dispatch('notify', 'detail value')}">Fire Event</button>
```
---
Events dispatched from child components can be listened to in their parent. Any data provided when the event was dispatched is available on the `detail` property of the event object.
```html
<script>
function callbackFunction(event) {
console.log(`Notify fired! Detail: ${event.detail}`)
}
</script>
<Child on:notify="{callbackFunction}"/>
```
### `svelte/store` ### `svelte/store`
@ -475,13 +506,51 @@ TODO
* fade, fly, slide, scale, draw * fade, fly, slide, scale, draw
* crossfade... * crossfade...
### `svelte/animation` ### `svelte/animate`
TODO The `svelte/animate` module exports one function for use with svelte [animations](docs#Animations).
#### `flip`
```sv
animate:flip={params}
```
The `flip` function calculates the start and end position of an element and animates between them, translating the `x` and `y` values. `flip` stands for [First, Last, Invert, Play](https://aerotwist.com/blog/flip-your-animations/).
`flip` accepts the following parameters:
* `delay` (`number`, default 0) — milliseconds before starting
* `duration` (`number` | `function`, default `d => Math.sqrt(d) * 120`) — see below
* `easing` (`function`, default [`cubicOut`](docs#cubicOut)) — an [easing function](docs#svelte_easing)
`duration` can be be provided as either:
- a `number`, in milliseconds.
- a function, `distance: number => duration: number`, receiving the distance the element will travel in pixels and returning the duration in milliseconds. This allows you to assign a duration that is relative to the distance travelled by each element.
---
You can see a full example on the [animations tutorial](tutorial/animate)
```html
<script>
import { flip } from 'svelte/animate';
import { quintOut } from 'svelte/easing';
let list = [1, 2, 3];
</script>
{#each list as n (n)}
<div animate:flip="{{delay: 250, duration: 250, easing: quintOut}}">
{n}
</div>
{/each}
```
* TODO this doesn't even exist yet
TODO
### `svelte/easing` ### `svelte/easing`
@ -573,10 +642,14 @@ component.$on(event, callback)
Causes the `callback` function to be called whenever the component dispatches an `event`. Causes the `callback` function to be called whenever the component dispatches an `event`.
A function is returned that will remove the event listener when called.
```js ```js
app.$on('selected', event => { const off = app.$on('selected', event => {
console.log(event.detail.selection); console.log(event.detail.selection);
}); });
off();
``` ```
#### `$destroy` #### `$destroy`

@ -18,10 +18,10 @@ DOM event handlers can have *modifiers* that alter their behaviour. For example,
The full list of modifiers: The full list of modifiers:
* `preventDefault` — calls `event.preventDefault()` before running the handler. Useful for e.g. client-side form handling * `preventDefault` — calls `event.preventDefault()` before running the handler. Useful for client-side form handling, for example.
* `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element * `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element
* `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 ([MDN docs](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture)) * `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase ([MDN docs](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture))
* `once` — remove the handler after the first time it runs * `once` — remove the handler after the first time it runs
You can chain modifiers together, e.g. `on:click|once|capture={...}`. You can chain modifiers together, e.g. `on:click|once|capture={...}`.

@ -8,8 +8,8 @@ On line 116, add `currentTime={time}`, `duration` and `paused` bindings:
```html ```html
<video <video
poster="http://svelte-assets.surge.sh/caminandes-llamigos.jpg" poster="https://svelte-assets.surge.sh/caminandes-llamigos.jpg"
src="http://svelte-assets.surge.sh/caminandes-llamigos.mp4" src="https://svelte-assets.surge.sh/caminandes-llamigos.mp4"
on:mousemove={handleMousemove} on:mousemove={handleMousemove}
on:mousedown={handleMousedown} on:mousedown={handleMousedown}
bind:currentTime={time} bind:currentTime={time}
@ -36,4 +36,4 @@ The complete set of bindings for `<audio>` and `<video>` is as follows — four
* `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

@ -2,7 +2,7 @@
title: This title: This
--- ---
The readonly `this` binding applies to every element (and component) and allows to you obtain a reference to rendered elements. For example, we can get a reference to a `<canvas>` element: The readonly `this` binding applies to every element (and component) and allows you to obtain a reference to rendered elements. For example, we can get a reference to a `<canvas>` element:
```html ```html
<canvas <canvas
@ -12,4 +12,4 @@ The readonly `this` binding applies to every element (and component) and allows
></canvas> ></canvas>
``` ```
Note that the value of `canvas` will be `undefined` until the component has mounted, so we put the logic inside the `onMount` [lifecycle function](tutorial/onmount). Note that the value of `canvas` will be `undefined` until the component has mounted, so we put the logic inside the `onMount` [lifecycle function](tutorial/onmount).

@ -4,7 +4,7 @@ title: Local transitions
Ordinarily, transitions will play on elements when any container block is added or destroyed. In the example here, toggling the visibility of the entire list also applies transitions to individual list elements. Ordinarily, transitions will play on elements when any container block is added or destroyed. In the example here, toggling the visibility of the entire list also applies transitions to individual list elements.
Instead, we'd like transitions to play only when individual items are added and removed — on other words, when the user drags the slider. Instead, we'd like transitions to play only when individual items are added and removed — in other words, when the user drags the slider.
We can achieve this with a *local* transition, which only plays when the immediate parent block is added or removed: We can achieve this with a *local* transition, which only plays when the immediate parent block is added or removed:
@ -12,4 +12,4 @@ We can achieve this with a *local* transition, which only plays when the immedia
<div transition:slide|local> <div transition:slide|local>
{item} {item}
</div> </div>
``` ```

@ -42,6 +42,6 @@ You can rename the variable, if you want — let's call it `active` in the paren
</Hoverable> </Hoverable>
``` ```
You can have as many of these components you like, and the slotted props will remain local to the component where they're declared. You can have as many of these components as you like, and the slotted props will remain local to the component where they're declared.
> Named slots can also have props; use the `let` directive on an element with a `slot="..."` attribute, instead of on the component itself. > Named slots can also have props; use the `let` directive on an element with a `slot="..."` attribute, instead of on the component itself.

@ -1336,6 +1336,16 @@
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.1.tgz", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.1.tgz",
"integrity": "sha512-6d8YbKW4hjJMnU6ZJSDLtALWiB4J//OIPaP885ruf5U8MLZHigocDxhjgvLwbV6bGkikhllgTjD9eWioKWAQdA==" "integrity": "sha512-6d8YbKW4hjJMnU6ZJSDLtALWiB4J//OIPaP885ruf5U8MLZHigocDxhjgvLwbV6bGkikhllgTjD9eWioKWAQdA=="
}, },
"@sindresorhus/slugify": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-0.9.1.tgz",
"integrity": "sha512-b6heYM9dzZD13t2GOiEQTDE0qX+I1GyOotMwKh9VQqzuNiVdPVT8dM43fe9HNb/3ul+Qwd5oKSEDrDIfhq3bnQ==",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.5",
"lodash.deburr": "^4.1.0"
}
},
"@sveltejs/svelte-repl": { "@sveltejs/svelte-repl": {
"version": "0.0.10", "version": "0.0.10",
"resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.0.10.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.0.10.tgz",
@ -1682,11 +1692,6 @@
"integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
"dev": true "dev": true
}, },
"bulk-replace": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/bulk-replace/-/bulk-replace-0.0.1.tgz",
"integrity": "sha1-8JVoKolqvUs9ngjeQJzCIuIT+d0="
},
"cache-base": { "cache-base": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@ -2936,6 +2941,7 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -3151,14 +3157,6 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true "dev": true
}, },
"hepburn": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/hepburn/-/hepburn-1.1.1.tgz",
"integrity": "sha512-Ok3ZmMJN3ek4WFAL4f5t8k+BmrDRlS5qGjI4um+3cHH0SrYVzJgUTYwIfGvU8s/eWqOEY+gsINwjJSoaBG3A9g==",
"requires": {
"bulk-replace": "0.0.1"
}
},
"home-or-tmp": { "home-or-tmp": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-3.0.0.tgz", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-3.0.0.tgz",
@ -3609,16 +3607,6 @@
"invert-kv": "^2.0.0" "invert-kv": "^2.0.0"
} }
}, },
"limax": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/limax/-/limax-1.7.0.tgz",
"integrity": "sha512-ibcGylOXT5vry2JKfKwLWx2tZudRYWm4SzG9AE/cc5zqwW+3nQy/uPLUvfAUChRdmqxVrK6SNepmO7ZY8RoKfA==",
"requires": {
"hepburn": "^1.1.0",
"pinyin": "^2.8.3",
"speakingurl": "^14.0.1"
}
},
"load-bmfont": { "load-bmfont": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.0.tgz", "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.0.tgz",
@ -4054,15 +4042,6 @@
"semver": "^5.3.0" "semver": "^5.3.0"
} }
}, },
"nodejieba": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/nodejieba/-/nodejieba-2.3.0.tgz",
"integrity": "sha512-ZzLsVuNDlrmcBQa/b8G/yegdXje2iFmktYmPksk6qLha1brKEANYqg4XPiBspF1D0y7Npho91KTmvKFcDr0UdA==",
"optional": true,
"requires": {
"nan": "~2.10.0"
}
},
"normalize-package-data": { "normalize-package-data": {
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@ -4444,16 +4423,6 @@
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true "dev": true
}, },
"pinyin": {
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/pinyin/-/pinyin-2.8.3.tgz",
"integrity": "sha1-MBzLQ1jM/oAlI8S9ZAphK+5NfEs=",
"requires": {
"commander": "~1.1.1",
"nodejieba": "^2.2.1",
"object-assign": "^4.0.1"
}
},
"pixelmatch": { "pixelmatch": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz",
@ -5213,19 +5182,6 @@
"integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==",
"dev": true "dev": true
}, },
"speakingurl": {
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
"integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="
},
"split": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
"integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
"requires": {
"through": "2"
}
},
"split-string": { "split-string": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",

@ -21,7 +21,6 @@
"golden-fleece": "^1.0.9", "golden-fleece": "^1.0.9",
"httpie": "^1.1.1", "httpie": "^1.1.1",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"limax": "^1.7.0",
"marked": "^0.6.1", "marked": "^0.6.1",
"pg": "^7.10.0", "pg": "^7.10.0",
"polka": "^1.0.0-next.2", "polka": "^1.0.0-next.2",
@ -34,6 +33,7 @@
"@babel/plugin-transform-runtime": "^7.2.0", "@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.3.1", "@babel/preset-env": "^7.3.1",
"@babel/runtime": "^7.3.1", "@babel/runtime": "^7.3.1",
"@sindresorhus/slugify": "^0.9.1",
"@sveltejs/svelte-repl": "0.0.10", "@sveltejs/svelte-repl": "0.0.10",
"chokidar": "^2.1.2", "chokidar": "^2.1.2",
"degit": "^2.1.3", "degit": "^2.1.3",

@ -5,7 +5,7 @@
- advantage of css-styling - advantage of css-styling
- https://github.com/jacobmischka/svelte-feather-icon - https://github.com/jacobmischka/svelte-feather-icon
- https://feathericons.com/ - https://feathericons.com/
- if requred we can split out app-controls to REPL only - if required we can split out app-controls to REPL only
----------------------------------------------- -----------------------------------------------
--> -->
@ -112,4 +112,4 @@
<symbol id="chevron" class="icon" viewBox="0 0 24 24"> <symbol id="chevron" class="icon" viewBox="0 0 24 24">
<path d="M2,7 L12,17 L20,7"/> <path d="M2,7 L12,17 L20,7"/>
</symbol> </symbol>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

@ -97,11 +97,9 @@
</svelte:head> </svelte:head>
<div class='examples-container' bind:clientWidth={width}> <div class='examples-container' bind:clientWidth={width}>
<div <div class="viewport offset-{offset}">
class="viewport offset-{offset}"
>
<TableOfContents {sections} active_section={active_slug} {isLoading} /> <TableOfContents {sections} active_section={active_slug} {isLoading} />
<div class="toc" class:loading={isLoading}> <div class="repl-container" class:loading={isLoading}>
<Repl <Repl
bind:this={repl} bind:this={repl}
{svelteUrl} {svelteUrl}
@ -136,10 +134,24 @@
grid-auto-rows: 100%; grid-auto-rows: 100%;
} }
.toc.loading { .repl-container.loading {
opacity: 0.6; opacity: 0.6;
} }
/* temp fix for #2499 and #2550 while waiting for a fix for https://github.com/sveltejs/svelte-repl/issues/8 */
.repl-container :global(.tab-content),
.repl-container :global(.tab-content.visible) {
pointer-events: all;
opacity: 1;
}
.repl-container :global(.tab-content) {
visibility: hidden;
}
.repl-container :global(.tab-content.visible) {
visibility: visible;
}
.offset-1 { transform: translate(-33.333%, 0); } .offset-1 { transform: translate(-33.333%, 0); }
.offset-2 { transform: translate(-66.666%, 0); } .offset-2 { transform: translate(-66.666%, 0); }

@ -6,6 +6,7 @@
import downloadBlob from '../../_utils/downloadBlob.js'; import downloadBlob from '../../_utils/downloadBlob.js';
import { user } from '../../../../user.js'; import { user } from '../../../../user.js';
import { enter } from '../../../../utils/events.js'; import { enter } from '../../../../utils/events.js';
import { isMac } from '../../../../utils/compat.js';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
@ -20,8 +21,6 @@
let justSaved = false; let justSaved = false;
let justForked = false; let justForked = false;
const isMac = typeof navigator !== 'undefined' && navigator.platform === 'MacIntel';
function wait(ms) { function wait(ms) {
return new Promise(f => setTimeout(f, ms)); return new Promise(f => setTimeout(f, ms));
} }

@ -27,7 +27,7 @@
let repl; let repl;
let gist; let gist;
let name = 'loading...'; let name = 'Loading...';
let zen_mode = false; let zen_mode = false;
let relaxed = false; let relaxed = false;
let width = process.browser ? window.innerWidth : 1000; let width = process.browser ? window.innerWidth : 1000;
@ -155,6 +155,20 @@
transform: translate(-50%, 0); transform: translate(-50%, 0);
} }
/* temp fix for #2499 and #2550 while waiting for a fix for https://github.com/sveltejs/svelte-repl/issues/8 */
.viewport :global(.tab-content),
.viewport :global(.tab-content.visible) {
pointer-events: all;
opacity: 1;
}
.viewport :global(.tab-content) {
visibility: hidden;
}
.viewport :global(.tab-content.visible) {
visibility: visible;
}
.zen-mode { .zen-mode {
position: fixed; position: fixed;
width: 100%; width: 100%;
@ -187,7 +201,7 @@
</style> </style>
<svelte:head> <svelte:head>
<title>REPL • Svelte</title> <title>{name} • REPL • Svelte</title>
<meta name="twitter:title" content="Svelte REPL"> <meta name="twitter:title" content="Svelte REPL">
<meta name="twitter:description" content="Cybernetically enhanced web apps"> <meta name="twitter:description" content="Cybernetically enhanced web apps">
@ -198,9 +212,9 @@
<div class="repl-outer {zen_mode ? 'zen-mode' : ''}" class:mobile> <div class="repl-outer {zen_mode ? 'zen-mode' : ''}" class:mobile>
<AppControls <AppControls
{name}
{gist} {gist}
{repl} {repl}
bind:name
bind:zen_mode bind:zen_mode
on:forked={handle_fork} on:forked={handle_fork}
/> />

@ -17,4 +17,4 @@ API()
// //
}) })
) )
.listen(PORT); .listen(PORT);

@ -2,7 +2,7 @@
<html lang='en' class="theme-default typo-default"> <html lang='en' class="theme-default typo-default">
<head> <head>
<meta charset='utf-8'> <meta charset='utf-8'>
<meta name='viewport' content='width=device-width'> <meta name='viewport' content='width=device-width,initial-scale=1'>
<meta name='theme-color' content='#ff3e00'> <meta name='theme-color' content='#ff3e00'>
%sapper.base% %sapper.base%

@ -0,0 +1 @@
export const isMac = typeof navigator !== 'undefined' && navigator.platform === 'MacIntel';

@ -1,14 +1,20 @@
import limax from 'limax'; import slugify from '@sindresorhus/slugify';
import {SLUG_LANG, SLUG_SEPARATOR} from '../../config'; import {SLUG_SEPARATOR} from '../../config';
/* latinizer processor */ /* url-safe processor */
export const limaxProcessor = (string, lang = SLUG_LANG) => limax(string, { export const urlsafeSlugProcessor = string =>
custom: ['$'], slugify(string, {
separator: SLUG_SEPARATOR, customReplacements: [ // runs before any other transformations
maintainCase: true, ['$', 'DOLLAR'], // `$destroy` & co
lang ['-', 'DASH'], // conflicts with `separator`
}); ],
separator: SLUG_SEPARATOR,
decamelize: false,
lowercase: false
})
.replace(/DOLLAR/g, '$')
.replace(/DASH/g, '-');
/* unicode-preserver processor */ /* unicode-preserver processor */
@ -40,7 +46,7 @@ export const unicodeSafeProcessor = string =>
.chunks .chunks
.reduce((accum, chunk) => { .reduce((accum, chunk) => {
const processed = chunk.type === 'process' const processed = chunk.type === 'process'
? limaxProcessor(chunk.string) ? urlsafeSlugProcessor(chunk.string)
: chunk.string; : chunk.string;
processed.length > 0 && accum.push(processed); processed.length > 0 && accum.push(processed);
@ -52,7 +58,7 @@ export const unicodeSafeProcessor = string =>
/* session processor */ /* session processor */
export const makeSessionSlugProcessor = (preserveUnicode = false) => { export const makeSessionSlugProcessor = (preserveUnicode = false) => {
const processor = preserveUnicode ? unicodeSafeProcessor : limaxProcessor; const processor = preserveUnicode ? unicodeSafeProcessor : urlsafeSlugProcessor;
const seen = new Set(); const seen = new Set();
return string => { return string => {

@ -469,7 +469,6 @@ input[type="checkbox"]::before {
top: 0; top: 0;
left: 0; left: 0;
background: var(--second); background: var(--second);
-webkit-transition: .25s ease-out;
/* box-sizing: border-box; */ /* box-sizing: border-box; */
box-sizing: content-box; box-sizing: content-box;
} }
@ -489,7 +488,7 @@ input[type="checkbox"]::after {
border-radius: 1em; border-radius: 1em;
background: white; background: white;
box-shadow: 0 0px 1px rgba(0,0,0,.4), 0 4px 2px rgba(0,0,0,.1); box-shadow: 0 0px 1px rgba(0,0,0,.4), 0 4px 2px rgba(0,0,0,.1);
-webkit-transition: .2s ease-out; -webkit-transition: background .2s ease-out, left .2s ease-out;
} }
input[type="checkbox"]:checked::after { input[type="checkbox"]:checked::after {

@ -1,61 +1,61 @@
import {strict as assert} from 'assert'; import {strict as assert} from 'assert';
import {limaxProcessor, unicodeSafeProcessor} from '../../src/utils/slug'; import {urlsafeSlugProcessor, unicodeSafeProcessor} from '../../src/utils/slug';
import {SLUG_SEPARATOR as _, SLUG_LANG} from '../../config'; import {SLUG_SEPARATOR as _} from '../../config';
describe('slug', () => { describe('slug', () => {
describe('limaxProcessor (latinize unicode)', () => { describe('urlsafeSlugProcessor', () => {
describe('ascii', () => { describe('ascii', () => {
it('space separated words', () => { it('space separated words', () => {
assert.equal( assert.equal(
limaxProcessor('Text expressions'), urlsafeSlugProcessor('Text expressions'),
`text${_}expressions` `Text${_}expressions`
); );
}); });
it('numbered text', () => { it('numbered text', () => {
assert.equal( assert.equal(
limaxProcessor('1. export creates'), urlsafeSlugProcessor('1. export creates'),
`1${_}export${_}creates` `1${_}export${_}creates`
); );
}); });
it('punctuated text', () => { it('punctuated text', () => {
assert.equal( assert.equal(
limaxProcessor('svelte.VERSION'), urlsafeSlugProcessor('svelte.VERSION'),
`svelte${_}version` `svelte${_}VERSION`
); );
}); });
it('text starting with the dollar sign', () => { it('text starting with the dollar sign', () => {
assert.equal( assert.equal(
limaxProcessor('$destroy method'), urlsafeSlugProcessor('$destroy method'),
`$destroy${_}method` `$destroy${_}method`
); );
}); });
it('numbered text containing the dollar sign', () => { it('numbered text containing the dollar sign', () => {
assert.equal( assert.equal(
limaxProcessor('1. export $destroy'), urlsafeSlugProcessor('1. export $destroy'),
`1${_}export${_}$destroy` `1${_}export${_}$destroy`
); );
}); });
it('text containing the equal char', () => { it('text containing the equal char', () => {
assert.equal( assert.equal(
limaxProcessor('script context=module'), urlsafeSlugProcessor('script context=module'),
`script${_}context${_}module` `script${_}context${_}module`
); );
}); });
it('text containing the colon char', () => { it('text containing the colon char', () => {
assert.equal( assert.equal(
limaxProcessor('svelte:body'), urlsafeSlugProcessor('svelte:body'),
`svelte${_}body` `svelte${_}body`
); );
}); });
it('text containing the slash char', () => { it('text containing the slash char', () => {
assert.equal( assert.equal(
limaxProcessor('svelte/motion'), urlsafeSlugProcessor('svelte/motion'),
`svelte${_}motion` `svelte${_}motion`
); );
}); });
it('text containing the comma char', () => { it('text containing the comma char', () => {
assert.equal( assert.equal(
limaxProcessor('svelte, motion'), urlsafeSlugProcessor('svelte, motion'),
`svelte${_}motion` `svelte${_}motion`
); );
}); });
@ -63,156 +63,150 @@ describe('slug', () => {
describe('unicode', () => { describe('unicode', () => {
it('should translate symbols to English', () => { it('should translate symbols to English', () => {
assert.equal( assert.equal(
limaxProcessor('Ich ♥ Deutsch'), urlsafeSlugProcessor('Ich ♥ Deutsch'),
`ich${_}love${_}deutsch` `Ich${_}love${_}Deutsch`
); );
}); });
it('should remove emoji', () => { it('should remove emoji', () => {
assert.equal( assert.equal(
limaxProcessor('Ich 😍 Deutsch'), urlsafeSlugProcessor('Ich 😍 Deutsch'),
`ich${_}deutsch` `Ich${_}Deutsch`
);
});
it('should translate symbols to the given language (German)', () => {
assert.equal(
limaxProcessor('Ich ♥ Deutsch', 'de'),
`ich${_}liebe${_}deutsch`
); );
}); });
}); });
describe('cyricllic', () => { describe('cyricllic', () => {
it('space separated words', () => { it('space separated words', () => {
assert.equal( assert.equal(
limaxProcessor('Всплытие и перехват событий'), urlsafeSlugProcessor('Всплытие и перехват событий'),
`vsplytie${_}i${_}perekhvat${_}sobytii` `Vsplytie${_}i${_}perehvat${_}sobytij`
); );
}); });
it('numbered text', () => { it('numbered text', () => {
assert.equal( assert.equal(
limaxProcessor('1 Всплытие и перехват событий'), urlsafeSlugProcessor('1 Всплытие и перехват событий'),
`1${_}vsplytie${_}i${_}perekhvat${_}sobytii` `1${_}Vsplytie${_}i${_}perehvat${_}sobytij`
); );
}); });
it('punctuated text', () => { it('punctuated text', () => {
assert.equal( assert.equal(
limaxProcessor('.Всплытие.и.перехват событий'), urlsafeSlugProcessor('.Всплытие.и.перехват событий'),
`vsplytie${_}i${_}perekhvat${_}sobytii` `Vsplytie${_}i${_}perehvat${_}sobytij`
); );
}); });
it('text starting with the dollar sign', () => { it('text starting with the dollar sign', () => {
assert.equal( assert.equal(
limaxProcessor('$Всплытие $ перехват событий'), urlsafeSlugProcessor('$Всплытие $ перехват событий'),
`$vsplytie${_}$${_}perekhvat${_}sobytii` `$Vsplytie${_}$${_}perehvat${_}sobytij`
); );
}); });
it('text containing the dollar sign', () => { it('text containing the dollar sign', () => {
assert.equal( assert.equal(
limaxProcessor('Всплытие$перехват'), urlsafeSlugProcessor('Всплытие$перехват'),
`vsplytie$perekhvat` `Vsplytie$perehvat`
); );
}); });
it('text containing the equal char', () => { it('text containing the equal char', () => {
assert.equal( assert.equal(
limaxProcessor('Всплытие = перехват=событий'), urlsafeSlugProcessor('Всплытие = перехват=событий'),
`vsplytie${_}perekhvat${_}sobytii` `Vsplytie${_}perehvat${_}sobytij`
); );
}); });
it('text containing the colon char', () => { it('text containing the colon char', () => {
assert.equal( assert.equal(
limaxProcessor('Всплытие : перехват:событий'), urlsafeSlugProcessor('Всплытие : перехват:событий'),
`vsplytie${_}perekhvat${_}sobytii` `Vsplytie${_}perehvat${_}sobytij`
); );
}); });
it('text containing the slash char', () => { it('text containing the slash char', () => {
assert.equal( assert.equal(
limaxProcessor('Всплытие / перехват/событий'), urlsafeSlugProcessor('Всплытие / перехват/событий'),
`vsplytie${_}perekhvat${_}sobytii` `Vsplytie${_}perehvat${_}sobytij`
); );
}); });
it('text containing the comma char', () => { it('text containing the comma char', () => {
assert.equal( assert.equal(
limaxProcessor('Всплытие, перехват'), urlsafeSlugProcessor('Всплытие, перехват'),
`vsplytie${_}perekhvat` `Vsplytie${_}perehvat`
); );
}); });
}); });
describe('ascii + cyricllic', () => { describe('ascii + cyricllic', () => {
it('space separated words', () => { it('space separated words', () => {
assert.equal( assert.equal(
limaxProcessor('Всплытие и export перехват событий'), urlsafeSlugProcessor('Всплытие и export перехват событий'),
`vsplytie${_}i${_}export${_}perekhvat${_}sobytii` `Vsplytie${_}i${_}export${_}perehvat${_}sobytij`
); );
}); });
it('ascii word concatenated to a cyricllic word', () => { it('ascii word concatenated to a cyricllic word', () => {
assert.equal( assert.equal(
limaxProcessor('exportВсплытие'), urlsafeSlugProcessor('exportВсплытие'),
'exportvsplytie' 'exportVsplytie'
); );
}); });
it('cyricllic word concatenated to an ascii word', () => { it('cyricllic word concatenated to an ascii word', () => {
assert.equal( assert.equal(
limaxProcessor('Всплытиеexport'), urlsafeSlugProcessor('Всплытиеexport'),
`vsplytieexport` `Vsplytieexport`
); );
}); });
it('numbered text', () => { it('numbered text', () => {
assert.equal( assert.equal(
limaxProcessor('1 export Всплытие и перехват событий'), urlsafeSlugProcessor('1 export Всплытие и перехват событий'),
`1${_}export${_}vsplytie${_}i${_}perekhvat${_}sobytii` `1${_}export${_}Vsplytie${_}i${_}perehvat${_}sobytij`
); );
}); });
it('punctuated text', () => { it('punctuated text', () => {
assert.equal( assert.equal(
limaxProcessor('.Всплытие.export.и.перехват событий'), urlsafeSlugProcessor('.Всплытие.export.и.перехват событий'),
`vsplytie${_}export${_}i${_}perekhvat${_}sobytii` `Vsplytie${_}export${_}i${_}perehvat${_}sobytij`
); );
}); });
it('text starting with the dollar sign, followed by ascii char', () => { it('text starting with the dollar sign, followed by ascii char', () => {
assert.equal( assert.equal(
limaxProcessor('$exportВсплытие перехват событий'), urlsafeSlugProcessor('$exportВсплытие перехват событий'),
`$exportvsplytie${_}perekhvat${_}sobytii` `$exportVsplytie${_}perehvat${_}sobytij`
); );
}); });
it('text starting with the dollar sign, followed by unicode char', () => { it('text starting with the dollar sign, followed by unicode char', () => {
assert.equal( assert.equal(
limaxProcessor('$Всплытие export перехват событий'), urlsafeSlugProcessor('$Всплытие export перехват событий'),
`$vsplytie${_}export${_}perekhvat${_}sobytii` `$Vsplytie${_}export${_}perehvat${_}sobytij`
); );
}); });
it('text containing the dollar sign, followed by ascii char', () => { it('text containing the dollar sign, followed by ascii char', () => {
assert.equal( assert.equal(
limaxProcessor('export $destroy a component prop Всплытие и перехват событий'), urlsafeSlugProcessor('export $destroy a component prop Всплытие и перехват событий'),
`export${_}$destroy${_}a${_}component${_}prop${_}vsplytie${_}i${_}perekhvat${_}sobytii` `export${_}$destroy${_}a${_}component${_}prop${_}Vsplytie${_}i${_}perehvat${_}sobytij`
); );
}); });
it('text containing the dollar sign, followed by unicode char', () => { it('text containing the dollar sign, followed by unicode char', () => {
assert.equal( assert.equal(
limaxProcessor('Всплытие export $Всплытие a component prop Всплытие и перехват событий'), urlsafeSlugProcessor('Всплытие export $Всплытие a component prop Всплытие и перехват событий'),
`vsplytie${_}export${_}$vsplytie${_}a${_}component${_}prop${_}vsplytie${_}i${_}perekhvat${_}sobytii` `Vsplytie${_}export${_}$Vsplytie${_}a${_}component${_}prop${_}Vsplytie${_}i${_}perehvat${_}sobytij`
); );
}); });
it('text containing the equal char', () => { it('text containing the equal char', () => {
assert.equal( assert.equal(
limaxProcessor('script context=module Всплытие=и перехват событий'), urlsafeSlugProcessor('script context=module Всплытие=и перехват событий'),
`script${_}context${_}module${_}vsplytie${_}i${_}perekhvat${_}sobytii` `script${_}context${_}module${_}Vsplytie${_}i${_}perehvat${_}sobytij`
); );
}); });
it('text containing the colon char', () => { it('text containing the colon char', () => {
assert.equal( assert.equal(
limaxProcessor('svelte:body Всплытие и:перехват событий'), urlsafeSlugProcessor('svelte:body Всплытие и:перехват событий'),
`svelte${_}body${_}vsplytie${_}i${_}perekhvat${_}sobytii` `svelte${_}body${_}Vsplytie${_}i${_}perehvat${_}sobytij`
); );
}); });
it('text containing the slash char', () => { it('text containing the slash char', () => {
assert.equal( assert.equal(
limaxProcessor('svelte/motion Всплытие и / перехват/событий'), urlsafeSlugProcessor('svelte/motion Всплытие и / перехват/событий'),
`svelte${_}motion${_}vsplytie${_}i${_}perekhvat${_}sobytii` `svelte${_}motion${_}Vsplytie${_}i${_}perehvat${_}sobytij`
); );
}); });
it('text containing the comma char', () => { it('text containing the comma char', () => {
assert.equal( assert.equal(
limaxProcessor('Всплытие, export'), urlsafeSlugProcessor('Всплытие, export'),
`vsplytie${_}export` `Vsplytie${_}export`
); );
}); });
}); });
@ -223,7 +217,7 @@ describe('slug', () => {
it('space separated words', () => { it('space separated words', () => {
assert.equal( assert.equal(
unicodeSafeProcessor('Text expressions'), unicodeSafeProcessor('Text expressions'),
`text${_}expressions` `Text${_}expressions`
); );
}); });
it('numbered text', () => { it('numbered text', () => {
@ -235,7 +229,7 @@ describe('slug', () => {
it('punctuated text', () => { it('punctuated text', () => {
assert.equal( assert.equal(
unicodeSafeProcessor('svelte.VERSION'), unicodeSafeProcessor('svelte.VERSION'),
`svelte${_}version` `svelte${_}VERSION`
); );
}); });
it('text starting with the dollar sign', () => { it('text starting with the dollar sign', () => {
@ -279,13 +273,13 @@ describe('slug', () => {
it('should preserve symbols', () => { it('should preserve symbols', () => {
assert.equal( assert.equal(
unicodeSafeProcessor('Ich ♥ Deutsch'), unicodeSafeProcessor('Ich ♥ Deutsch'),
`ich${_}love${_}deutsch` `Ich${_}love${_}Deutsch`
); );
}); });
it('should remove emoji', () => { it('should remove emoji', () => {
assert.equal( assert.equal(
unicodeSafeProcessor('Ich 😍 Deutsch'), unicodeSafeProcessor('Ich 😍 Deutsch'),
`ich${_}deutsch` `Ich${_}Deutsch`
); );
}); });
}); });

@ -11,7 +11,7 @@ import Slot from './handlers/Slot';
import Tag from './handlers/Tag'; import Tag from './handlers/Tag';
import Text from './handlers/Text'; import Text from './handlers/Text';
import Title from './handlers/Title'; import Title from './handlers/Title';
import { CompileOptions } from '../../interfaces'; import { AppendTarget, CompileOptions } from '../../interfaces';
type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void; type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void;
@ -36,8 +36,6 @@ const handlers: Record<string, Handler> = {
Window: noop Window: noop
}; };
type AppendTarget = any; // TODO
export default class Renderer { export default class Renderer {
has_bindings = false; has_bindings = false;
code = ''; code = '';

@ -4,8 +4,7 @@ import { snip } from '../../utils/snip';
import Renderer from '../Renderer'; import Renderer from '../Renderer';
import { stringify_props } from '../../utils/stringify_props'; import { stringify_props } from '../../utils/stringify_props';
import { get_slot_scope } from './shared/get_slot_scope'; import { get_slot_scope } from './shared/get_slot_scope';
import { AppendTarget } from '../../../interfaces';
type AppendTarget = any; // TODO
function stringify_attribute(chunk: Node) { function stringify_attribute(chunk: Node) {
if (chunk.type === 'Text') { if (chunk.type === 'Text') {
@ -111,4 +110,4 @@ export default function(node, renderer: Renderer, options) {
const slots = stringify_props(slot_fns); const slots = stringify_props(slot_fns);
renderer.append(`\${@validate_component(${expression}, '${node.name}').$$render($$result, ${props}, ${bindings}, ${slots})}`); renderer.append(`\${@validate_component(${expression}, '${node.name}').$$render($$result, ${props}, ${bindings}, ${slots})}`);
} }

@ -48,7 +48,11 @@ export function validate_store(store, name) {
} }
export function subscribe(component, store, callback) { export function subscribe(component, store, callback) {
component.$$.on_destroy.push(store.subscribe(callback)); const unsub = store.subscribe(callback);
component.$$.on_destroy.push(unsub.unsubscribe
? () => unsub.unsubscribe()
: unsub);
} }
export function create_slot(definition, ctx, fn) { export function create_slot(definition, ctx, fn) {
@ -74,4 +78,4 @@ export function exclude_internal_props(props) {
const result = {}; const result = {};
for (const k in props) if (k[0] !== '$') result[k] = props[k]; for (const k in props) if (k[0] !== '$') result[k] = props[k];
return result; return result;
} }

@ -0,0 +1,5 @@
<script>
export let observable;
</script>
<p>value: {$observable}</p>

@ -0,0 +1,49 @@
const subscribers = [];
let value = 'initial';
const observable = {
subscribe: fn => {
subscribers.push(fn);
fn(value);
return {
unsubscribe: () => {
const i = subscribers.indexOf(fn);
subscribers.splice(i, 1);
}
};
}
};
export default {
props: {
observable,
visible: false
},
html: ``,
async test({ assert, component, target }) {
assert.equal(subscribers.length, 0);
component.visible = true;
assert.equal(subscribers.length, 1);
assert.htmlEqual(target.innerHTML, `
<p>value: initial</p>
`);
value = 42;
await subscribers.forEach(fn => fn(value));
assert.htmlEqual(target.innerHTML, `
<p>value: 42</p>
`);
component.visible = false;
assert.equal(subscribers.length, 0);
}
};

@ -0,0 +1,10 @@
<script>
import Nested from './Nested.svelte';
export let observable;
export let visible;
</script>
{#if visible}
<Nested {observable}/>
{/if}
Loading…
Cancel
Save