Merge branch 'master' into api-reference

pull/2206/head
Richard Harris 7 years ago
commit d0739c4971

52
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.0.0-beta.20",
"version": "3.0.0-beta.22",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -30,6 +30,16 @@
"integrity": "sha512-UdVB1rSL7H8TS8674fH02p5lRbhfIqQ18YKLxLKEnHFztHUH6bhMqjebMxgSTmWVrs5raS5JSLJIKKHFT4WfPg==",
"dev": true
},
"@sveltejs/svelte-repl": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.0.5.tgz",
"integrity": "sha512-SKSX4xkqwH0XcUHQozwTNm3OCqatk66CXYZnqOW9Jf4E1B6opyQUb9f96KwAxh7ghZMbeePRv51oOWsw6n0Yww==",
"dev": true,
"requires": {
"codemirror": "^5.45.0",
"yootils": "0.0.15"
}
},
"@types/estree": {
"version": "0.0.39",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
@ -139,7 +149,7 @@
},
"ansi-escapes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
"resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
"integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==",
"dev": true
},
@ -199,7 +209,7 @@
},
"array-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
"resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
"dev": true
},
@ -591,6 +601,12 @@
"urlgrey": "^0.4.4"
}
},
"codemirror": {
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.45.0.tgz",
"integrity": "sha512-c19j644usCE8gQaXa0jqn2B/HN9MnB2u6qPIrrhrMkB+QAP42y8G4QnTwuwbVSoUS1jEl7JU9HZMGhCDL0nsAw==",
"dev": true
},
"collection-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@ -627,7 +643,7 @@
},
"commander": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
"dev": true
},
@ -878,7 +894,7 @@
"dependencies": {
"domelementtype": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
"integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=",
"dev": true
}
@ -1131,7 +1147,7 @@
},
"doctrine": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
"resolved": "http://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
"integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
"dev": true,
"requires": {
@ -1826,7 +1842,7 @@
},
"is-builtin-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"dev": true,
"requires": {
@ -2112,7 +2128,7 @@
},
"load-json-file": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"dev": true,
"requires": {
@ -2271,7 +2287,7 @@
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
@ -2298,7 +2314,7 @@
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
@ -2608,7 +2624,7 @@
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
},
@ -2692,7 +2708,7 @@
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
@ -2737,7 +2753,7 @@
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
},
@ -3440,7 +3456,7 @@
},
"safe-regex": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
"resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
"dev": true,
"requires": {
@ -4024,7 +4040,7 @@
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
"dev": true
},
@ -4607,6 +4623,12 @@
"resolved": "https://registry.npmjs.org/yn/-/yn-3.0.0.tgz",
"integrity": "sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==",
"dev": true
},
"yootils": {
"version": "0.0.15",
"resolved": "https://registry.npmjs.org/yootils/-/yootils-0.0.15.tgz",
"integrity": "sha512-GvGLuJ7XHJPGEUQ52vh8fh+vPjfikuGcu7yBswfrsNsHqnAoytOVuSb69eM0j8wQIjMz0U3kY3YsfwMhJgfG9w==",
"dev": true
}
}
}

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.0.0-beta.20",
"version": "3.0.0-beta.22",
"description": "The magical disappearing UI framework",
"module": "index.mjs",
"main": "index",
@ -49,6 +49,7 @@
},
"homepage": "https://github.com/sveltejs/svelte#README",
"devDependencies": {
"@sveltejs/svelte-repl": "0.0.5",
"@types/mocha": "^5.2.0",
"@types/node": "^10.5.5",
"acorn": "^6.1.1",

@ -121,7 +121,7 @@ function MoreRealisticComponent(props) {
<p>Selected {selected ? selected.name : 'nothing'}</p>
<ul>
${props.items.map(item =>
{props.items.map(item =>
<li>
<button onClick={() => setSelected(item)}>
{item.name}

@ -109,8 +109,8 @@
<div>
<video
poster="http://svelte-assets.surge.sh/caminandes-llamigos.jpg"
src="http://svelte-assets.surge.sh/caminandes-llamigos.mp4"
poster="https://svelte-assets.surge.sh/caminandes-llamigos.jpg"
src="https://svelte-assets.surge.sh/caminandes-llamigos.mp4"
on:mousemove={handleMousemove}
on:mousedown={handleMousedown}
></video>

@ -109,8 +109,8 @@
<div>
<video
poster="http://svelte-assets.surge.sh/caminandes-llamigos.jpg"
src="http://svelte-assets.surge.sh/caminandes-llamigos.mp4"
poster="https://svelte-assets.surge.sh/caminandes-llamigos.jpg"
src="https://svelte-assets.surge.sh/caminandes-llamigos.mp4"
on:mousemove={handleMousemove}
on:mousedown={handleMousedown}
bind:currentTime={time}

@ -34,5 +34,6 @@ The complete set of bindings for `<audio>` and `<video>` is as follows — four
...and three *two-way* bindings:
* `currentTime` — the current point in the video, in seconds
* `playbackRate` — how fast to play the video, where `1` is 'normal'
* `paused` — this one should be self-explanatory
* `volume` — a value between 0 and 1

@ -1,9 +1,7 @@
import { readable } from 'svelte/store';
export const time = readable(function start(set) {
export const time = readable(null, function start(set) {
// implementation goes here
return function stop() {
};
return function stop() {};
});

@ -1,6 +1,6 @@
import { readable } from 'svelte/store';
export const time = readable(function start(set) {
export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => {
set(new Date());
}, 1000);
@ -8,4 +8,4 @@ export const time = readable(function start(set) {
return function stop() {
clearInterval(interval);
};
}, new Date());
});

@ -4,10 +4,10 @@ title: Readable stores
Not all stores should be writable by whoever has a reference to them. For example, you might have a store representing the mouse position or the user's geolocation, and it doesn't make sense to be able to set those values from 'outside'. For those cases, we have *readable* stores.
Click over to the `stores.js` tab. The first argument to `readable` is a `start` function that takes a `set` callback and returns a `stop` function. The `start` function is called when the store gets its first subscriber; `stop` is called when the last subscriber unsubscribes. The second (optional) argument is the initial value.
Click over to the `stores.js` tab. The first argument to `readable` is an initial value, which can be `null` or `undefined` if you don't have one yet. The second argument is a `start` function that takes a `set` callback and returns a `stop` function. The `start` function is called when the store gets its first subscriber; `stop` is called when the last subscriber unsubscribes.
```js
export const time = readable(function start(set) {
export const time = readable(new Date(), function start(set) {
const interval = setInterval(() => {
set(new Date());
}, 1000);
@ -15,5 +15,5 @@ export const time = readable(function start(set) {
return function stop() {
clearInterval(interval);
};
}, new Date());
});
```

@ -1139,6 +1139,30 @@
"resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz",
"integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw=="
},
"@sveltejs/svelte-repl": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.0.6.tgz",
"integrity": "sha512-TF4n1rDPANntU5TFYU5b0WhuUtXDKs/e2JRyGPlfzTOHa9oWWkZpqqkyAy/wCWenXT+0A6tSgbVbThDCzWFSzw==",
"dev": true,
"requires": {
"codemirror": "^5.45.0",
"yootils": "0.0.15"
},
"dependencies": {
"codemirror": {
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.45.0.tgz",
"integrity": "sha512-c19j644usCE8gQaXa0jqn2B/HN9MnB2u6qPIrrhrMkB+QAP42y8G4QnTwuwbVSoUS1jEl7JU9HZMGhCDL0nsAw==",
"dev": true
},
"yootils": {
"version": "0.0.15",
"resolved": "https://registry.npmjs.org/yootils/-/yootils-0.0.15.tgz",
"integrity": "sha512-GvGLuJ7XHJPGEUQ52vh8fh+vPjfikuGcu7yBswfrsNsHqnAoytOVuSb69eM0j8wQIjMz0U3kY3YsfwMhJgfG9w==",
"dev": true
}
}
},
"@types/estree": {
"version": "0.0.39",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
@ -1941,8 +1965,9 @@
"dev": true
},
"eslint-plugin-svelte3": {
"version": "git+https://github.com/sveltejs/eslint-plugin-svelte3.git#651d7e3695b1731251ab3a501d1067b561ede09f",
"from": "git+https://github.com/sveltejs/eslint-plugin-svelte3.git#semver:*",
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-svelte3/-/eslint-plugin-svelte3-0.4.4.tgz",
"integrity": "sha512-RHCRZCZicBZz/6ENUQhja6ISz4BiIft93MaZzhyaII36z3eBehzWLP9Ovt3EIHGVwGt8PcOpkfpdaATiz4ikew==",
"dev": true
},
"estree-walker": {
@ -2346,24 +2371,28 @@
"dependencies": {
"abbrev": {
"version": "1.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
},
"aproba": {
"version": "1.2.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"dev": true,
"optional": true,
"requires": {
@ -2373,12 +2402,14 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
@ -2387,34 +2418,40 @@
},
"chownr": {
"version": "1.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
"dev": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true
},
"core-util-is": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true,
"optional": true
},
"debug": {
"version": "2.6.9",
"bundled": true,
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"optional": true,
"requires": {
@ -2423,25 +2460,29 @@
},
"deep-extend": {
"version": "0.6.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"dev": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"dev": true,
"optional": true,
"requires": {
@ -2450,13 +2491,15 @@
},
"fs.realpath": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
"bundled": true,
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"optional": true,
"requires": {
@ -2472,7 +2515,8 @@
},
"glob": {
"version": "7.1.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"dev": true,
"optional": true,
"requires": {
@ -2486,13 +2530,15 @@
},
"has-unicode": {
"version": "2.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.24",
"bundled": true,
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"optional": true,
"requires": {
@ -2501,7 +2547,8 @@
},
"ignore-walk": {
"version": "3.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"dev": true,
"optional": true,
"requires": {
@ -2510,7 +2557,8 @@
},
"inflight": {
"version": "1.0.6",
"bundled": true,
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"optional": true,
"requires": {
@ -2520,18 +2568,21 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true
},
"ini": {
"version": "1.3.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"requires": {
"number-is-nan": "^1.0.0"
@ -2539,13 +2590,15 @@
},
"isarray": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
"bundled": true,
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
@ -2553,12 +2606,14 @@
},
"minimist": {
"version": "0.0.8",
"bundled": true,
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"dev": true,
"requires": {
"safe-buffer": "^5.1.2",
@ -2567,7 +2622,8 @@
},
"minizlib": {
"version": "1.2.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"dev": true,
"optional": true,
"requires": {
@ -2576,7 +2632,8 @@
},
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
"minimist": "0.0.8"
@ -2584,13 +2641,15 @@
},
"ms": {
"version": "2.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true,
"optional": true
},
"needle": {
"version": "2.2.4",
"bundled": true,
"resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz",
"integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==",
"dev": true,
"optional": true,
"requires": {
@ -2601,7 +2660,8 @@
},
"node-pre-gyp": {
"version": "0.10.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz",
"integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==",
"dev": true,
"optional": true,
"requires": {
@ -2619,7 +2679,8 @@
},
"nopt": {
"version": "4.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"dev": true,
"optional": true,
"requires": {
@ -2629,13 +2690,15 @@
},
"npm-bundled": {
"version": "1.0.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz",
"integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==",
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.2.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.2.0.tgz",
"integrity": "sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ==",
"dev": true,
"optional": true,
"requires": {
@ -2645,7 +2708,8 @@
},
"npmlog": {
"version": "4.1.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"optional": true,
"requires": {
@ -2657,18 +2721,21 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true
},
"object-assign": {
"version": "4.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true,
"optional": true
},
"once": {
"version": "1.4.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
@ -2676,19 +2743,22 @@
},
"os-homedir": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"dev": true,
"optional": true,
"requires": {
@ -2698,19 +2768,22 @@
},
"path-is-absolute": {
"version": "1.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"dev": true,
"optional": true
},
"rc": {
"version": "1.2.8",
"bundled": true,
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"dev": true,
"optional": true,
"requires": {
@ -2722,7 +2795,8 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
}
@ -2730,7 +2804,8 @@
},
"readable-stream": {
"version": "2.3.6",
"bundled": true,
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"optional": true,
"requires": {
@ -2745,7 +2820,8 @@
},
"rimraf": {
"version": "2.6.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"dev": true,
"optional": true,
"requires": {
@ -2754,42 +2830,49 @@
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"optional": true
},
"sax": {
"version": "1.2.4",
"bundled": true,
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true,
"optional": true
},
"semver": {
"version": "5.6.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
"dev": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"requires": {
"code-point-at": "^1.0.0",
@ -2799,7 +2882,8 @@
},
"string_decoder": {
"version": "1.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"optional": true,
"requires": {
@ -2808,7 +2892,8 @@
},
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
@ -2816,13 +2901,15 @@
},
"strip-json-comments": {
"version": "2.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true,
"optional": true
},
"tar": {
"version": "4.4.8",
"bundled": true,
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
"dev": true,
"optional": true,
"requires": {
@ -2837,13 +2924,15 @@
},
"util-deprecate": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true,
"optional": true
},
"wide-align": {
"version": "1.1.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"dev": true,
"optional": true,
"requires": {
@ -2852,12 +2941,14 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"dev": true
}
}
@ -5296,9 +5387,9 @@
}
},
"svelte": {
"version": "3.0.0-beta.20",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.0.0-beta.20.tgz",
"integrity": "sha512-IEZrUseN2Hzpo1KFdyZf3Neqw7abbXLU7oRRkyBVm0iT1PQKHj8G75hR0wISvz7pOegYisiVFdi3C5Asz4ps9Q==",
"version": "3.0.0-beta.21",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.0.0-beta.21.tgz",
"integrity": "sha512-TlYvRrwnA9SeoNwxD1nv6kzQO/KxPGISyaJrzizt1kEBSKEdY4rB9U1URDfpMtdAKdYJkeXXca4Tt6FWAyS5Ng==",
"dev": true
},
"tar": {

@ -39,9 +39,10 @@
"@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.3.1",
"@babel/runtime": "^7.3.1",
"@sveltejs/svelte-repl": "0.0.6",
"chokidar": "^2.1.2",
"degit": "^2.1.3",
"eslint-plugin-svelte3": "git+https://github.com/sveltejs/eslint-plugin-svelte3.git#semver:*",
"eslint-plugin-svelte3": "^0.4.4",
"jimp": "^0.6.0",
"now": "^14.0.0",
"npm-run-all": "^4.1.5",
@ -54,6 +55,6 @@
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-terser": "^4.0.4",
"sapper": "^0.26.0-alpha.12",
"svelte": "^3.0.0-beta.20"
"svelte": "^3.0.0-beta.21"
}
}

@ -1,44 +0,0 @@
const workers = new Map();
let uid = 1;
export default class Bundler {
constructor(version) {
if (!workers.has(version)) {
const worker = new Worker('/workers/bundler.js');
worker.postMessage({ type: 'init', version });
workers.set(version, worker);
}
this.worker = workers.get(version);
this.handlers = new Map();
this.worker.addEventListener('message', event => {
const handler = this.handlers.get(event.data.id);
if (handler) { // if no handler, was meant for a different REPL
handler(event.data);
this.handlers.delete(event.data.id);
}
});
}
bundle(components) {
return new Promise(fulfil => {
const id = uid++;
this.handlers.set(id, fulfil);
this.worker.postMessage({
id,
type: 'bundle',
components
});
});
}
destroy() {
this.worker.terminate();
}
}

@ -1,273 +0,0 @@
<script context="module">
let codemirror_promise;
let _CodeMirror;
if (process.browser) {
codemirror_promise = import(/* webpackChunkName: "codemirror" */ './_codemirror.js');
codemirror_promise.then(mod => {
_CodeMirror = mod.default;
});
}
</script>
<script>
import { onMount, beforeUpdate, createEventDispatcher, getContext } from 'svelte';
import Message from './Message.svelte';
const dispatch = createEventDispatcher();
const { navigate } = getContext('REPL');
export let readonly = false;
export let errorLoc = null;
export let flex = false;
export let lineNumbers = true;
export let tab = true;
let w;
let h;
let code = '';
let mode;
// We have to expose set and update methods, rather
// than making this state-driven through props,
// because it's difficult to update an editor
// without resetting scroll otherwise
export async function set(new_code, new_mode) {
if (new_mode !== mode) {
await createEditor(mode = new_mode);
}
code = new_code;
updating_externally = true;
if (editor) editor.setValue(code);
updating_externally = false;
}
export function update(new_code) {
code = new_code;
if (editor) {
const { left, top } = editor.getScrollInfo();
editor.setValue(code = new_code);
editor.scrollTo(left, top);
}
}
export function resize() {
editor.refresh();
}
export function focus() {
editor.focus();
}
const modes = {
js: {
name: 'javascript',
json: false
},
json: {
name: 'javascript',
json: true
},
svelte: {
name: 'handlebars',
base: 'text/html'
}
};
const refs = {};
let editor;
let updating_externally = false;
let marker;
let error_line;
let destroyed = false;
let CodeMirror;
$: if (editor && w && h) {
editor.refresh();
}
$: {
if (marker) marker.clear();
if (errorLoc) {
const line = errorLoc.line - 1;
const ch = errorLoc.column;
marker = editor.markText({ line, ch }, { line, ch: ch + 1 }, {
className: 'error-loc'
});
error_line = line;
} else {
error_line = null;
}
}
let previous_error_line;
$: if (editor) {
if (previous_error_line != null) {
editor.removeLineClass(previous_error_line, 'wrap', 'error-line')
}
if (error_line && (error_line !== previous_error_line)) {
editor.addLineClass(error_line, 'wrap', 'error-line');
previous_error_line = error_line;
}
}
onMount(() => {
if (_CodeMirror) {
CodeMirror = _CodeMirror;
createEditor(mode || 'svelte').then(() => {
editor.setValue(code || '');
});
} else {
codemirror_promise.then(async mod => {
CodeMirror = mod.default;
await createEditor(mode || 'svelte');
editor.setValue(code || '');
});
}
return () => {
destroyed = true;
if (editor) editor.toTextArea();
}
});
async function createEditor(mode) {
if (destroyed || !CodeMirror) return;
if (editor) editor.toTextArea();
const opts = {
lineNumbers,
lineWrapping: true,
indentWithTabs: true,
indentUnit: 2,
tabSize: 2,
value: '',
mode: modes[mode] || {
name: mode
},
readOnly: readonly
};
if (!tab) opts.extraKeys = {
Tab: tab,
'Shift-Tab': tab
};
// Creating a text editor is a lot of work, so we yield
// the main thread for a moment. This helps reduce jank
await sleep(50);
if (destroyed) return;
editor = CodeMirror.fromTextArea(refs.editor, opts);
editor.on('change', instance => {
if (!updating_externally) {
const value = instance.getValue();
dispatch('change', { value });
}
});
await sleep(50);
editor.refresh();
}
function sleep(ms) {
return new Promise(fulfil => setTimeout(fulfil, ms));
}
</script>
<style>
.codemirror-container {
position: relative;
width: 100%;
height: 100%;
border: none;
line-height: 1.5;
overflow: hidden;
}
.codemirror-container :global(.CodeMirror) {
height: 100%;
/* background: var(--background); */
background: transparent;
font: 400 var(--code-fs)/1.7 var(--font-mono);
color: var(--base);
}
.codemirror-container.flex :global(.CodeMirror) {
height: auto;
}
.codemirror-container.flex :global(.CodeMirror-lines) {
padding: 0;
}
.codemirror-container :global(.CodeMirror-gutters) {
padding: 0 1.6rem 0 .8rem;
border: none;
}
.codemirror-container :global(.error-loc) {
position: relative;
border-bottom: 2px solid #da106e;
}
.codemirror-container :global(.error-line) {
background-color: rgba(200, 0, 0, .05);
}
textarea {
visibility: hidden;
}
pre {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
border: none;
padding: 4px 4px 4px 60px;
resize: none;
font-family: var(--font-mono);
font-size: 1.3rem;
line-height: 1.7;
user-select: none;
pointer-events: none;
color: #ccc;
tab-size: 2;
-moz-tab-size: 2;
}
.flex pre {
padding: 0 0 0 4px;
height: auto;
}
</style>
<div class='codemirror-container' class:flex bind:offsetWidth={w} bind:offsetHeight={h}>
<textarea
tabindex='2'
bind:this={refs.editor}
readonly
value={code}
></textarea>
{#if !CodeMirror}
<pre style="position: absolute; left: 0; top: 0"
>{code}</pre>
<div style="position: absolute; width: 100%; bottom: 0">
<Message kind='info'>loading editor...</Message>
</div>
{/if}
</div>

@ -1,233 +0,0 @@
<script>
import { getContext, createEventDispatcher } from 'svelte';
import Icon from '../../Icon.svelte';
import { enter } from '../../../utils/events.js';
export let handle_select;
const { components, selected, request_focus, rebundle } = getContext('REPL');
let editing = null;
function selectComponent(component) {
if ($selected !== component) {
editing = null;
handle_select(component);
}
}
function editTab(component) {
if ($selected === component) {
editing = $selected;
}
}
function closeEdit() {
const match = /(.+)\.(svelte|js)$/.exec($selected.name);
$selected.name = match ? match[1] : $selected.name;
if (match && match[2]) $selected.type = match[2];
editing = null;
// re-select, in case the type changed
handle_select($selected);
components = components; // TODO necessary?
// focus the editor, but wait a beat (so key events aren't misdirected)
setTimeout(request_focus);
rebundle();
}
function remove(component) {
let result = confirm(`Are you sure you want to delete ${component.name}.${component.type}?`);
if (result) {
const index = $components.indexOf(component);
if (~index) {
components.set($components.slice(0, index).concat($components.slice(index + 1)));
} else {
console.error(`Could not find component! That's... odd`);
}
handle_select($components[index] || $components[$components.length - 1]);
}
}
function selectInput(event) {
setTimeout(() => {
event.target.select();
});
}
let uid = 1;
function addNew() {
const component = {
name: uid++ ? `Component${uid}` : 'Component1',
type: 'svelte',
source: ''
};
editing = component;
setTimeout(() => {
// TODO we can do this without IDs
document.getElementById(component.name).scrollIntoView(false);
});
components.update(components => components.concat(component));
handle_select(component);
}
</script>
<style>
.component-selector {
position: relative;
border-bottom: 1px solid #eee;
overflow: hidden;
}
.file-tabs {
border: none;
margin: 0;
white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
height: 10em;
}
.file-tabs .button, .file-tabs button {
position: relative;
display: inline-block;
font: 400 1.2rem/1.5 var(--font);
border-bottom: var(--border-w) solid transparent;
padding: 1.2rem 1.4rem 0.8rem 0.8rem;
margin: 0;
color: #999;
}
.file-tabs .button:first-child {
padding-left: 1.2rem;
}
.file-tabs .button.active {
/* color: var(--second); */
color: #333;
border-bottom: var(--border-w) solid var(--prime);
}
.editable, .uneditable, .input-sizer, input {
display: inline-block;
position: relative;
line-height: 1;
}
.input-sizer {
color: #ccc;
}
input {
position: absolute;
width: 100%;
left: 0.8rem;
top: 1.2rem;
font: 400 1.2rem/1.5 var(--font);
border: none;
color: var(--flash);
outline: none;
background-color: transparent;
}
.remove {
position: absolute;
display: none;
right: .1rem;
top: .4rem;
width: 1.6rem;
text-align: right;
padding: 1.2em 0 1.2em .5em;
font-size: 0.8rem;
cursor: pointer;
}
.remove:hover {
color: var(--flash);
}
.file-tabs .button.active .editable {
cursor: text;
}
.file-tabs .button.active .remove {
display: block;
}
.add-new {
position: absolute;
left: 0;
top: 0;
padding: 1.2rem 1rem 0.8rem 0 !important;
height: 4.2rem;
text-align: center;
background-color: white;
}
.add-new:hover {
color: var(--flash) !important;
}
</style>
<div class="component-selector">
{#if $components.length}
<div class="file-tabs" on:dblclick="{addNew}">
{#each $components as component}
<div
id={component.name}
class="button"
role="button"
class:active="{component === $selected}"
on:click="{() => selectComponent(component)}"
on:dblclick="{e => e.stopPropagation()}"
>
{#if component.name == 'App'}
<div class="uneditable">
App.svelte
</div>
{:else}
{#if component === editing}
<span class="input-sizer">{editing.name + (/\./.test(editing.name) ? '' : `.${editing.type}`)}</span>
<input
autofocus
spellcheck={false}
bind:value={editing.name}
on:focus={selectInput}
on:blur={closeEdit}
use:enter="{e => e.target.blur()}"
>
{:else}
<div
class="editable"
title="edit component name"
on:click="{() => editTab(component)}"
>
{component.name}.{component.type}
</div>
<span class="remove" on:click="{() => remove(component)}">
<Icon name="close" size={12}/>
<!-- &times; -->
</span>
{/if}
{/if}
</div>
{/each}
<button class="add-new" on:click={addNew} title="add new component">
<Icon name="plus" />
</button>
</div>
{/if}
</div>

@ -1,63 +0,0 @@
<script>
import { getContext, onMount } from 'svelte';
import CodeMirror from '../CodeMirror.svelte';
import Message from '../Message.svelte';
const { bundle, selected, handle_change, navigate, register_module_editor } = getContext('REPL');
export let errorLoc;
let editor;
onMount(() => {
register_module_editor(editor);
});
export function focus() {
editor.focus();
}
</script>
<style>
.editor-wrapper {
z-index: 5;
background: var(--back-light);
display: flex;
flex-direction: column;
}
.editor {
height: 0;
flex: 1 1 auto;
}
@media (min-width: 600px) {
:global(.columns) .editor-wrapper {
/* make it easier to interact with scrollbar */
padding-right: 8px;
height: auto;
/* height: 100%; */
}
}
</style>
<div class="editor-wrapper">
<div class="editor">
<CodeMirror
bind:this={editor}
{errorLoc}
on:change={handle_change}
/>
</div>
<div class="info">
{#if $bundle}
{#if $bundle.error}
<Message kind="error" details={$bundle.error} filename="{$selected.name}.{$selected.type}"/>
{:else if $bundle.warnings.length > 0}
{#each $bundle.warnings as warning}
<Message kind="warning" details={warning} filename="{$selected.name}.{$selected.type}"/>
{/each}
{/if}
{/if}
</div>
</div>

@ -1,35 +0,0 @@
<script>
export let checked;
</script>
<style>
.input-output-toggle {
display: grid;
position: absolute;
user-select: none;
grid-template-columns: 1fr 40px 1fr;
grid-gap: 0.5em;
align-items: center;
width: 100%;
height: 4.2rem;
border-top: 1px solid var(--second);
}
input {
display: block;
}
span {
color: #ccc;
}
.active {
color: #555;
}
</style>
<label class="input-output-toggle">
<span class:active={!checked} style="text-align: right">input</span>
<input type="checkbox" bind:checked>
<span class:active={checked}>output</span>
</label>

@ -1,80 +0,0 @@
<script>
import { getContext } from 'svelte';
const { navigate } = getContext('REPL');
export let kind;
export let details = null;
export let filename = null;
function message(details) {
let str = details.message || '[missing message]';
let loc = [];
if (details.filename && details.filename !== filename) {
loc.push(details.filename);
}
if (details.start) loc.push(details.start.line, details.start.column);
return str + (loc.length ? ` (${loc.join(':')})` : ``);
};
</script>
<style>
.message {
position: relative;
color: white;
padding: 1.2rem 1.6rem 1.2rem 4.4rem;
font: 400 1.2rem/1.7 var(--font);
margin: 0;
border-top: 1px solid white;
}
.navigable {
cursor: pointer;
}
.message::before {
content: '!';
position: absolute;
left: 1.2rem;
top: 1.1rem;
width: 1rem;
height: 1rem;
text-align: center;
line-height: 1;
padding: .4rem;
border-radius: 50%;
color: white;
border: .2rem solid white;
}
p {
margin: 0;
}
.info {
background-color: var(--second);
}
.error {
background-color: #da106e;
}
.warning {
background-color: #e47e0a;
}
</style>
<div class="message {kind}">
{#if details}
<p
class:navigable={details.filename}
on:click="{() => navigate(details)}"
>{message(details)}</p>
{:else}
<slot></slot>
{/if}
</div>

@ -1,49 +0,0 @@
const workers = new Map();
let uid = 1;
export default class Compiler {
constructor(version) {
if (!workers.has(version)) {
const worker = new Worker('/workers/compiler.js');
worker.postMessage({ type: 'init', version });
workers.set(version, worker);
}
this.worker = workers.get(version);
this.handlers = new Map();
this.worker.addEventListener('message', event => {
const handler = this.handlers.get(event.data.id);
if (handler) { // if no handler, was meant for a different REPL
handler(event.data.result);
this.handlers.delete(event.data.id);
}
});
}
compile(component, options) {
return new Promise(fulfil => {
const id = uid++;
this.handlers.set(id, fulfil);
this.worker.postMessage({
id,
type: 'compile',
source: component.source,
options: Object.assign({
name: component.name,
filename: `${component.name}.svelte`
}, options),
entry: component.name === 'App'
});
});
}
destroy() {
this.worker.terminate();
}
}

@ -1,146 +0,0 @@
<script>
import { getContext } from 'svelte';
const { compile_options } = getContext('REPL');
</script>
<style>
.options {
padding: 0 1rem;
font-family: var(--font-ui);
font-size: 1.3rem;
color: #999;
}
.option {
display: block;
padding: 0 0 0 1.25em;
white-space: nowrap;
color: var(--text);
user-select: none;
}
.key {
display: inline-block;
width: 9em;
}
.string {
color: hsl(41, 37%, 45%);
}
.boolean {
color: hsl(45, 7%, 45%);
}
label {
display: inline-block;
}
label[for] {
color: var(--string);
}
input[type=checkbox] {
top: -1px;
}
input[type=radio] {
position: absolute;
top: auto;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
width: 1px;
height: 1px;
white-space: nowrap;
}
input[type=radio] + label {
padding: 0 0 0 1.6em;
margin: 0 0.6em 0 0;
opacity: 0.7;
}
input[type=radio]:checked + label {
opacity: 1;
}
/* input[type=radio]:focus + label {
color: #00f;
outline: 1px dotted #00f;
} */
input[type=radio] + label:before {
content: '';
background: #eee;
display: block;
box-sizing: border-box;
float: left;
width: 1.5rem;
height: 1.5rem;
margin-left: -2.1rem;
margin-top: 0.4rem;
vertical-align: top;
cursor: pointer;
text-align: center;
transition: box-shadow 0.1s ease-out;
}
input[type=radio] + label:before {
background-color: var(--second);
border-radius: 100%;
box-shadow: inset 0 0 0 0.5em rgba(255, 255, 255, .95);
border: 1px solid var(--second);
}
input[type=radio]:checked + label:before {
background-color: var(--prime);
box-shadow: inset 0 0 0 .15em rgba(255, 255, 255, .95);
border: 1px solid var(--second);
transition: box-shadow 0.2s ease-out;
}
</style>
<div class="options">
result = svelte.compile(source, &#123;
<div class="option">
<span class="key">generate:</span>
<input id="dom-input" type="radio" bind:group={$compile_options.generate} value="dom">
<label for="dom-input"><span class="string">"dom"</span></label>
<input id="ssr-input" type="radio" bind:group={$compile_options.generate} value="ssr">
<label for="ssr-input"><span class="string">"ssr"</span>,</label>
</div>
<label class="option">
<span class="key">dev:</span>
<input type="checkbox" bind:checked={$compile_options.dev}> <span class="boolean">{$compile_options.dev}</span>,
</label>
<label class="option">
<span class="key">css:</span>
<input type="checkbox" bind:checked={$compile_options.css}> <span class="boolean">{$compile_options.css}</span>,
</label>
<label class="option">
<span class="key">hydratable:</span>
<input type="checkbox" bind:checked={$compile_options.hydratable}> <span class="boolean">{$compile_options.hydratable}</span>,
</label>
<label class="option">
<span class="key">customElement:</span>
<input type="checkbox" bind:checked={$compile_options.customElement}> <span class="boolean">{$compile_options.customElement}</span>,
</label>
<label class="option">
<span class="key">immutable:</span>
<input type="checkbox" bind:checked={$compile_options.immutable}> <span class="boolean">{$compile_options.immutable}</span>,
</label>
<label class="option">
<span class="key">legacy:</span>
<input type="checkbox" bind:checked={$compile_options.legacy}> <span class="boolean">{$compile_options.legacy}</span>
</label>
});
</div>

@ -1,75 +0,0 @@
let uid = 1;
export default class ReplProxy {
constructor(iframe, handlers) {
this.iframe = iframe;
this.handlers = handlers;
this.pending_cmds = new Map();
this.handle_event = e => this.handle_repl_message(e);
window.addEventListener('message', this.handle_event, false);
}
destroy() {
window.removeEventListener('message', this.handle_event);
}
iframe_command(action, args) {
return new Promise((resolve, reject) => {
const cmd_id = uid++;
this.pending_cmds.set(cmd_id, { resolve, reject });
this.iframe.contentWindow.postMessage({ action, cmd_id, args }, '*');
});
}
handle_command_message(cmd_data) {
let action = cmd_data.action;
let id = cmd_data.cmd_id;
let handler = this.pending_cmds.get(id);
if (handler) {
this.pending_cmds.delete(id);
if (action === 'cmd_error') {
let { message, stack } = cmd_data;
let e = new Error(message);
e.stack = stack;
handler.reject(e)
}
if (action === 'cmd_ok') {
handler.resolve(cmd_data.args)
}
} else {
console.error('command not found', id, cmd_data, [...this.pending_cmds.keys()]);
}
}
handle_repl_message(event) {
if (event.source !== this.iframe.contentWindow) return;
const { action, args } = event.data;
if (action === 'cmd_error' || action === 'cmd_ok') {
this.handle_command_message(event.data);
}
if (action === 'fetch_progress') {
this.handlers.on_fetch_progress(args.remaining)
}
}
eval(script) {
return this.iframe_command('eval', { script });
}
handle_links() {
return this.iframe_command('catch_clicks', {});
}
fetch_imports(imports, import_map) {
return this.iframe_command('fetch_imports', { imports, import_map })
}
}

@ -1,156 +0,0 @@
<script>
import { onMount, createEventDispatcher, getContext } from 'svelte';
import getLocationFromStack from './getLocationFromStack.js';
import ReplProxy from './ReplProxy.js';
import Message from '../Message.svelte';
import { decode } from 'sourcemap-codec';
const dispatch = createEventDispatcher();
const { bundle, navigate } = getContext('REPL');
export let error; // TODO should this be exposed as a prop?
export function setProp(prop, value) {
if (!proxy) return;
proxy.setProp(prop, value);
}
export let relaxed = false;
let iframe;
let pending_imports = 0;
let pending = false;
let proxy = null;
let ready = false;
let inited = false;
onMount(() => {
proxy = new ReplProxy(iframe, {
on_fetch_progress: progress => {
pending_imports = progress;
}
});
iframe.addEventListener('load', () => {
proxy.handle_links();
ready = true;
});
return () => {
proxy.destroy();
}
});
let current_token;
async function apply_bundle($bundle) {
if (!$bundle || $bundle.error) return;
const token = current_token = {};
try {
await proxy.fetch_imports($bundle.imports, $bundle.import_map);
if (token !== current_token) return;
await proxy.eval(`
// needed for context API tutorial
window.MAPBOX_ACCESS_TOKEN = process.env.MAPBOX_ACCESS_TOKEN;
const styles = document.querySelectorAll('style[id^=svelte-]');
${$bundle.dom.code}
let i = styles.length;
while (i--) styles[i].parentNode.removeChild(styles[i]);
if (window.component) {
try {
window.component.$destroy();
} catch (err) {
console.error(err);
}
}
document.body.innerHTML = '';
window.location.hash = '';
window._svelteTransitionManager = null;
window.component = new SvelteComponent.default({
target: document.body
});
`);
error = null;
} catch (e) {
const loc = getLocationFromStack(e.stack, $bundle.dom.map);
if (loc) {
e.filename = loc.source;
e.loc = { line: loc.line, column: loc.column };
}
error = e;
}
inited = true;
}
$: if (ready) apply_bundle($bundle);
</script>
<style>
.iframe-container {
position: absolute;
background-color: white;
border: none;
width: 100%;
height: 100%;
}
iframe {
width: 100%;
height: 100%;
/* height: calc(100vh - var(--nav-h)); */
border: none;
display: block;
}
.greyed-out {
filter: grayscale(50%) blur(1px);
opacity: .25;
}
.overlay {
position: absolute;
bottom: 0;
width: 100%;
}
</style>
<div class="iframe-container">
<iframe title="Result" class:inited bind:this={iframe} sandbox="allow-popups-to-escape-sandbox allow-scripts allow-popups allow-forms allow-pointer-lock allow-top-navigation allow-modals {relaxed ? 'allow-scripts allow-same-origin' : ''}" class="{error || pending || pending_imports ? 'greyed-out' : ''}" srcdoc='
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="/repl-viewer.css">
</head>
<body>
<script src="/curl.js"></script>
<script>curl.config(&#123; dontAddFileExt: /./ });</script>
<script src="/repl-runner.js"></script>
</body>
</html>
'></iframe>
<div class="overlay">
{#if error}
<Message kind="error" details={error}/>
{:else if !$bundle}
<Message kind="info">loading Svelte compiler...</Message>
{:else if pending_imports}
<Message kind="info">loading {pending_imports} {pending_imports === 1 ? 'dependency' : 'dependencies'} from
https://bundle.run</Message>
{/if}
</div>
</div>

@ -1,31 +0,0 @@
import { decode } from 'sourcemap-codec';
export default function getLocationFromStack(stack, map) {
if (!stack) return;
const last = stack.split('\n')[1];
const match = /<anonymous>:(\d+):(\d+)\)$/.exec(last);
if (!match) return null;
const line = +match[1];
const column = +match[2];
return trace({ line, column }, map);
}
function trace(loc, map) {
const mappings = decode(map.mappings);
const segments = mappings[loc.line - 1];
for (let i = 0; i < segments.length; i += 1) {
const segment = segments[i];
if (segment[0] === loc.column) {
const [, sourceIndex, line, column] = segment;
const source = map.sources[sourceIndex].slice(2);
return { source, line: line + 1, column };
}
}
return null;
}

@ -1,166 +0,0 @@
<script>
import { getContext, onMount } from 'svelte';
import SplitPane from '../SplitPane.svelte';
import Viewer from './Viewer.svelte';
import CompilerOptions from './CompilerOptions.svelte';
import Compiler from './Compiler.js';
import CodeMirror from '../CodeMirror.svelte';
const { register_output } = getContext('REPL');
export let version;
export let sourceErrorLoc = null;
export let runtimeError = null;
export let embedded = false;
export let relaxed = false;
let foo; // TODO workaround for https://github.com/sveltejs/svelte/issues/2122
register_output({
set: async (selected, options) => {
if (selected.type === 'js') {
js_editor.set(`/* Select a component to see its compiled code */`);
css_editor.set(`/* Select a component to see its compiled code */`);
return;
}
const compiled = await compiler.compile(selected, options);
js_editor.set(compiled.js, 'js');
css_editor.set(compiled.css, 'css');
},
update: async (selected, options) => {
if (selected.type === 'js') return;
const compiled = await compiler.compile(selected, options);
js_editor.update(compiled.js);
css_editor.update(compiled.css);
}
});
const compiler = process.browser && new Compiler(version);
// refs
let viewer;
let js_editor;
let css_editor;
const setters = {};
let view = 'result';
</script>
<style>
.view-toggle {
height: var(--pane-controls-h);
border-bottom: 1px solid #eee;
white-space: nowrap;
}
button {
/* width: 50%;
height: 100%; */
text-align: left;
position: relative;
font: 400 1.2rem/1.5 var(--font);
border-bottom: var(--border-w) solid transparent;
padding: 1.2rem 1.2rem 0.8rem 1.2rem;
color: #999;
}
button.active {
border-bottom: var(--border-w) solid var(--prime);
color: #333;
}
div[slot] {
height: 100%;
}
h3 {
font: 700 1.2rem/1.5 var(--font);
padding: 1.2rem 0 0.8rem 1rem;
color: var(--text);
}
.tab-content {
position: absolute;
width: 100%;
height: calc(100% - 4.2rem);
opacity: 0;
pointer-events: none;
}
.tab-content.visible {
/* can't use visibility due to a weird painting bug in Chrome */
opacity: 1;
pointer-events: all;
}
</style>
<div class="view-toggle">
<button
class:active="{view === 'result'}"
on:click="{() => view = 'result'}"
>Result</button>
<button
class:active="{view === 'js'}"
on:click="{() => view = 'js'}"
>JS output</button>
<button
class:active="{view === 'css'}"
on:click="{() => view = 'css'}"
>CSS output</button>
</div>
<!-- component viewer -->
<div class="tab-content" class:visible="{view === 'result'}">
<Viewer
bind:this={viewer}
bind:error={runtimeError}
{relaxed}
on:binding="{e => setPropFromViewer(e.detail.prop, e.detail.value)}"
/>
</div>
<!-- js output -->
<div class="tab-content" class:visible="{view === 'js'}">
{#if embedded}
<CodeMirror
bind:this={js_editor}
mode="js"
errorLoc={sourceErrorLoc}
readonly
/>
{:else}
<SplitPane type="vertical" pos={67}>
<div slot="a">
<CodeMirror
bind:this={js_editor}
mode="js"
errorLoc={sourceErrorLoc}
readonly
/>
</div>
<section slot="b">
<h3>Compiler options</h3>
<CompilerOptions bind:foo={foo}/>
</section>
</SplitPane>
{/if}
</div>
<!-- css output -->
<div class="tab-content" class:visible="{view === 'css'}">
<CodeMirror
bind:this={css_editor}
mode="css"
errorLoc={sourceErrorLoc}
readonly
/>
</div>

@ -1,7 +1,7 @@
<script>
import { onMount } from 'svelte';
import { process_example } from './process_example.js';
import Repl from '../../components/Repl/index.svelte';
import Repl from '@sveltejs/svelte-repl';
export let version = 'beta';
export let gist = null;
@ -65,6 +65,12 @@
});
$: if (embedded) document.title = `${name} • Svelte REPL`;
$: svelteUrl = version === 'local' ?
'/repl/local' :
`https://unpkg.com/svelte@${version}`;
const rollupUrl = `https://unpkg.com/rollup@1/dist/rollup.browser.js`;
</script>
<style>
@ -83,6 +89,6 @@
<div class="repl-outer">
{#if process.browser}
<Repl bind:this={repl} {version} embedded={true} relaxed/>
<Repl bind:this={repl} {svelteUrl} {rollupUrl} embedded={true} relaxed/>
{/if}
</div>

@ -1,164 +0,0 @@
<script>
import * as yootils from 'yootils';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
export let type;
export let pos = 50;
export let fixed = false;
export let fixed_pos = pos;
export let min = 50;
// export let min1 = min;
// export let min2 = min;
const refs = {};
const side = type === 'horizontal' ? 'left' : 'top';
const dimension = type === 'horizontal' ? 'width' : 'height';
let dragging = false;
function setPos(event) {
const { top, bottom, left, right } = refs.container.getBoundingClientRect();
const extents = type === 'vertical' ? [top, bottom] : [left, right];
const px = yootils.clamp(
type === 'vertical' ? event.clientY : event.clientX,
extents[0] + min,
extents[1] - min
);
pos = 100 * (px - extents[0]) / (extents[1] - extents[0]);
dispatch('change');
}
function drag(node, callback) {
const mousedown = event => {
if (event.which !== 1) return;
event.preventDefault();
dragging = true;
const onmouseup = () => {
dragging = false;
window.removeEventListener('mousemove', callback, false);
window.removeEventListener('mouseup', onmouseup, false);
};
window.addEventListener('mousemove', callback, false);
window.addEventListener('mouseup', onmouseup, false);
}
node.addEventListener('mousedown', mousedown, false);
return {
destroy() {
node.removeEventListener('mousedown', onmousedown, false);
}
};
}
</script>
<style>
.container {
position: relative;
width: 100%;
height: 100%;
}
.pane {
position: relative;
float: left;
width: 100%;
height: 100%;
}
.mousecatcher {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255,255,255,.01);
}
.divider {
position: absolute;
z-index: 10;
display: none;
}
.divider::after {
content: '';
position: absolute;
/* background-color: #eee; */
background-color: var(--second);
}
.horizontal {
padding: 0 8px;
width: 0;
height: 100%;
cursor: ew-resize;
}
.horizontal::after {
left: 8px;
top: 0;
width: 1px;
height: 100%;
}
.vertical {
padding: 8px 0;
width: 100%;
height: 0;
cursor: ns-resize;
}
.vertical::after {
top: 8px;
left: 0;
width: 100%;
height: 1px;
}
.left, .right, .divider {
display: block;
}
.left, .right {
height: 100%;
float: left;
}
.top, .bottom {
position: absolute;
width: 100%;
}
.top { top: 0; }
.bottom { bottom: 0; }
</style>
<div class="container" bind:this={refs.container}>
<div class="pane" style="{dimension}: {fixed ? fixed_pos : pos}%;">
<slot name="a"></slot>
</div>
<div class="pane" style="{dimension}: {100 - (fixed ? fixed_pos : pos)}%;">
<slot name="b"></slot>
</div>
{#if !fixed}
<div class="{type} divider" style="{side}: calc({pos}% - 8px)" use:drag={setPos}></div>
{/if}
</div>
{#if dragging}
<div class="mousecatcher"></div>
{/if}

@ -1,10 +0,0 @@
const CodeMirror = require('codemirror');
require('./codemirror.css');
require('codemirror/mode/javascript/javascript.js');
require('codemirror/mode/shell/shell.js');
require('codemirror/mode/handlebars/handlebars.js');
require('codemirror/mode/htmlmixed/htmlmixed.js');
require('codemirror/mode/xml/xml.js');
require('codemirror/mode/css/css.js');
module.exports = CodeMirror;

@ -1,350 +0,0 @@
/* BASICS */
.CodeMirror {
/* copied colors over from prism */
--background: var(--back-light);
--base: hsl(45, 7%, 45%);
--comment: hsl(210, 25%, 60%);
--keyword: hsl(204, 58%, 45%);
--function: hsl(19, 67%, 45%);
--string: hsl(41, 37%, 45%);
--number: hsl(102, 27%, 50%);
--tags: var(--function);
--important: var(--string);
/* Set height, width, borders, and global font properties here */
/* see prism.css */
height: 300px;
direction: ltr;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: var(--back-light);
white-space: nowrap;
}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: var(--comment);
white-space: nowrap;
opacity: .6;
}
.CodeMirror-guttermarker { color: black; }
.CodeMirror-guttermarker-subtle { color: #999; }
/* CURSOR */
.CodeMirror-cursor {
border-left: 1px solid black;
border-right: none;
width: 0;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
width: auto;
border: 0 !important;
background: #7e7;
}
.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
}
.cm-fat-cursor-mark {
background-color: rgba(20, 255, 20, .5);
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
}
.cm-animate-fat-cursor {
width: auto;
border: 0;
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
background-color: #7e7;
}
@-moz-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@-webkit-keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
@keyframes blink {
0% {}
50% { background-color: transparent; }
100% {}
}
.cm-tab { display: inline-block; text-decoration: inherit; }
.CodeMirror-rulers {
position: absolute;
left: 0; right: 0; top: -50px; bottom: -20px;
overflow: hidden;
}
.CodeMirror-ruler {
border-left: 1px solid #ccc;
top: 0; bottom: 0;
position: absolute;
}
/* DEFAULT THEME */
.cm-s-default .cm-header {color: blue}
.cm-s-default .cm-quote {color: #090}
.cm-negative {color: #d44}
.cm-positive {color: #292}
.cm-header, .cm-strong {font-weight: bold}
.cm-em {font-style: italic}
.cm-link {text-decoration: underline}
.cm-strikethrough {text-decoration: line-through}
.cm-s-default .cm-atom,
.cm-s-default .cm-def,
.cm-s-default .cm-property,
.cm-s-default .cm-variable-2,
.cm-s-default .cm-variable-3,
.cm-s-default .cm-punctuation {color: var(--base)}
.cm-s-default .cm-hr,
.cm-s-default .cm-comment {color: var(--comment)}
.cm-s-default .cm-attribute,
.cm-s-default .cm-keyword {color: var(--keyword)}
.cm-s-default .cm-variable,
.cm-s-default .cm-bracket,
.cm-s-default .cm-tag {color: var(--tags)}
.cm-s-default .cm-number {color: var(--number)}
.cm-s-default .cm-string {color: var(--string)}
.cm-s-default .cm-string-2 {color: #f50}
.cm-s-default .cm-type {color: #085}
.cm-s-default .cm-meta {color: #555}
.cm-s-default .cm-qualifier {color: #555}
.cm-s-default .cm-builtin {color: #30a}
.cm-s-default .cm-link {color: var(--flash)}
.cm-s-default .cm-error {color: #ff008c}
.cm-invalidchar {color: #ff008c}
.CodeMirror-composing { border-bottom: 2px solid; }
/* Default styles for common addons */
div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
.CodeMirror-activeline-background {background: #e8f2ff;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
position: relative;
overflow: hidden;
background: white;
}
.CodeMirror-scroll {
overflow: scroll !important; /* Things will break if this is overridden */
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
}
.CodeMirror-sizer {
position: relative;
border-right: 30px solid transparent;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actual scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
left: 0; bottom: 0;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
min-height: 100%;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
display: inline-block;
vertical-align: top;
margin-bottom: -30px;
}
.CodeMirror-gutter-wrapper {
position: absolute;
z-index: 4;
background: none !important;
border: none !important;
}
.CodeMirror-gutter-background {
position: absolute;
top: 0; bottom: 0;
z-index: 4;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
.CodeMirror-lines {
cursor: text;
min-height: 1px; /* prevents collapsing before first draw */
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
-webkit-tap-highlight-color: transparent;
-webkit-font-variant-ligatures: contextual;
font-variant-ligatures: contextual;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
padding: .1px; /* Force widget margins to stay inside of the container */
}
.CodeMirror-rtl pre { direction: rtl; }
.CodeMirror-code {
outline: none;
}
/* Force content-box sizing for the elements where we expect it */
.CodeMirror-scroll,
.CodeMirror-sizer,
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-cursor {
position: absolute;
pointer-events: none;
}
.CodeMirror-measure pre { position: static; }
div.CodeMirror-cursors {
visibility: hidden;
position: relative;
z-index: 3;
}
div.CodeMirror-dragcursors {
visibility: visible;
}
.CodeMirror-focused div.CodeMirror-cursors {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-crosshair { cursor: crosshair; }
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
.cm-searching {
background-color: #ffa;
background-color: rgba(255, 255, 0, .4);
}
/* Used to force a border model for a node */
.cm-force-border { padding-right: .1px; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursors {
visibility: hidden;
}
}
/* See issue #2901 */
.cm-tab-wrap-hack:after { content: ''; }
/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }

@ -1,232 +0,0 @@
<script>
import { onMount, setContext, createEventDispatcher } from 'svelte';
import { writable } from 'svelte/store';
import SplitPane from './SplitPane.svelte';
import CodeMirror from './CodeMirror.svelte';
import ComponentSelector from './Input/ComponentSelector.svelte';
import ModuleEditor from './Input/ModuleEditor.svelte';
import Output from './Output/index.svelte';
import InputOutputToggle from './InputOutputToggle.svelte';
import Bundler from './Bundler.js';
export let version = 'beta'; // TODO change this to latest when the time comes
export let embedded = false;
export let orientation = 'columns';
export let relaxed = false;
export function toJSON() {
// TODO there's a bug here — Svelte hoists this function because
// it wrongly things that $components is global. Needs to
// factor in $ variables when determining hoistability
version; // workaround
return {
imports: $bundle.imports,
components: $components
};
}
export function set(data) {
components.set(data.components);
selected.set(data.components[0]);
module_editor.set($selected.source, $selected.type);
output.set($selected, $compile_options);
rebundle();
}
export function update(data) {
const { name, type } = $selected || {};
components.set(data.components);
const matched_component = data.components.find(file => file.name === name && file.type === type);
selected.set(matched_component || data.components[0]);
if (matched_component) {
module_editor.update(matched_component.source);
output.update(matched_component, $compile_options);
} else {
module_editor.set(matched_component.source, matched_component.type);
output.set(matched_component, $compile_options);
}
}
const dispatch = createEventDispatcher();
const components = writable([]);
const selected = writable(null);
const bundle = writable(null);
const compile_options = writable({
generate: 'dom',
dev: false,
css: false,
hydratable: false,
customElement: false,
immutable: false,
legacy: false
});
let module_editor;
let output;
let current_token;
async function rebundle() {
const token = current_token = {};
const result = await bundler.bundle($components);
if (result && token === current_token) bundle.set(result);
}
setContext('REPL', {
components,
selected,
bundle,
compile_options,
rebundle,
navigate: item => {
const match = /^(.+)\.(\w+)$/.exec(item.filename);
if (!match) return; // ???
const [, name, type] = match;
const component = $components.find(c => c.name === name && c.type === type);
handle_select(component);
// TODO select the line/column in question
},
handle_change: event => {
selected.update(component => {
// TODO this is a bit hacky — we're relying on mutability
// so that updating components works... might be better
// if a) components had unique IDs, b) we tracked selected
// *index* rather than component, and c) `selected` was
// derived from `components` and `index`
component.source = event.detail.value;
return component;
});
components.update(c => c);
// recompile selected component
output.update($selected, $compile_options);
rebundle();
dispatch('change', {
components: $components
});
},
register_module_editor(editor) {
module_editor = editor;
},
register_output(handlers) {
output = handlers;
},
request_focus() {
module_editor.focus();
}
});
function handle_select(component) {
selected.set(component);
module_editor.set(component.source, component.type);
output.set($selected, $compile_options);
}
let workers;
let input;
let sourceErrorLoc;
let runtimeErrorLoc; // TODO refactor this stuff — runtimeErrorLoc is unused
let width = typeof window !== 'undefined' ? window.innerWidth : 300;
let show_output = false;
const bundler = process.browser && new Bundler(version);
$: if (output && $selected) {
output.update($selected, $compile_options);
}
</script>
<style>
.container {
position: relative;
width: 100%;
height: calc(100% - 4.2rem);
}
.repl-inner {
width: 200%;
height: 100%;
transition: transform 0.3s;
}
.repl-inner :global(section) {
position: relative;
padding: 4.2rem 0 0 0;
height: 100%;
}
.repl-inner :global(section) > :global(*):first-child {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4.2rem;
}
.repl-inner :global(section) > :global(*):last-child {
width: 100%;
height: 100%;
}
.offset {
transform: translate(-50%,0);
}
@media (min-width: 600px) {
.container {
height: 100%;
}
.repl-inner {
width: 100%;
}
.offset {
transition: none;
transform: none;
}
}
</style>
<div class="container" class:orientation bind:clientWidth={width}>
<div class="repl-inner" class:offset="{show_output}">
<SplitPane
type="{orientation === 'rows' ? 'vertical' : 'horizontal'}"
fixed="{600 > width}"
pos="{orientation === 'rows' ? 50 : 60}"
fixed_pos={50}
>
<section slot=a>
<ComponentSelector {handle_select}/>
<ModuleEditor bind:this={input} errorLoc="{sourceErrorLoc || runtimeErrorLoc}"/>
</section>
<section slot=b style='height: 100%;'>
<Output {version} {embedded} {relaxed}/>
</section>
</SplitPane>
</div>
</div>
<InputOutputToggle bind:checked={show_output}/>

@ -74,25 +74,6 @@
border-radius: 2px;
box-shadow: 1px 1px 3px rgba(0,0,0,0.1);
}
/* .thumbnail::before {
content: "";
width: 1px;
margin-left: -1px;
float: left;
height: 0;
padding-top: 100%;
}
.thumbnail::after {
content: "";
display: table;
clear: both;
} */
img {
background-color: #eee;
}
</style>
<div class="content">

@ -144,14 +144,6 @@
/* padding: 0.8rem; */
}
iframe {
display: block;
width: 100%;
height: 420px;
border: none;
border-radius: var(--border-r);
}
a.cta {
background-color: var(--prime);
padding: 0.5em 1.8em 0.5em 1em;

@ -263,15 +263,6 @@ export default app;` });
color: white;
}
.hidden-select {
position: absolute;
width: 100%;
height: 100%;
opacity: 0.0001;
top: 0;
left: 0;
}
.icon {
position: relative;
top: -0.1rem;
@ -300,6 +291,7 @@ export default app;` });
font-size: 1.6rem;
opacity: 0.7;
outline: none;
flex: 1;
}
input:focus {

@ -10,14 +10,13 @@
<script>
import { onMount } from 'svelte';
import { locate } from 'locate-character';
import { process_example } from '../../components/Repl/process_example.js';
import AppControls from './_components/AppControls/index.svelte';
import Repl from '../../components/Repl/index.svelte';
import Repl from '@sveltejs/svelte-repl';
export let version, example, gist_id;
console.log({ example });
export let version;
export let example;
export let gist_id;
let repl;
let gist;
@ -52,7 +51,7 @@
relaxed = false;
fetch(`gist/${gist_id}`).then(r => r.json()).then(data => {
gist = data;
const { id, description, files } = data;
const { description, files } = data;
name = description;
@ -84,14 +83,9 @@
repl.set({ components });
});
}
});
function load_example(slug) {
console.log(`loading ${slug}`);
} else {
relaxed = true;
fetch(`examples/${slug}.json`).then(async response => {
fetch(`examples/${example}.json`).then(async response => {
if (response.ok) {
const data = await response.json();
@ -104,6 +98,7 @@
}
});
}
});
function handle_fork(event) {
example = null;
@ -111,9 +106,14 @@
gist_id = gist.id;
}
$: if (process.browser && example) {
load_example(example);
}
$: svelteUrl = version === 'local' ?
'/repl/local' :
`https://unpkg.com/svelte@${version}`;
const rollupUrl = `https://unpkg.com/rollup@1/dist/rollup.browser.js`;
// needed for context API example
const mapbox_setup = `window.MAPBOX_ACCESS_TOKEN = process.env.MAPBOX_ACCESS_TOKEN;`;
</script>
<style>
@ -134,7 +134,7 @@
width: 100%;
height: 100%;
top: 0;
z-index: 11;
z-index: 111;
}
.pane { width: 100%; height: 100% }
@ -174,6 +174,12 @@
/>
{#if process.browser}
<Repl bind:this={repl} {version} {relaxed}/>
<Repl
bind:this={repl}
{svelteUrl}
{rollupUrl}
{relaxed}
setup={mapbox_setup}
/>
{/if}
</div>

@ -1,12 +1,12 @@
import { createReadStream } from 'fs';
export function get(req, res) {
if (process.env.NODE_ENV !== 'development' || !/^[a-z.]+$/.test(req.query.file)) {
if (process.env.NODE_ENV !== 'development' || !/^[a-z.]+$/.test(req.params.file)) {
res.writeHead(403);
res.end();
return;
}
createReadStream('../' + req.query.file)
createReadStream('../' + req.params.file)
.on('error', () => {
res.writeHead(403);
res.end();

@ -16,7 +16,7 @@
<script>
import TableOfContents from './_components/TableOfContents.svelte';
import Icon from '../../../components/Icon.svelte';
import Repl from '../../../components/Repl/index.svelte';
import Repl from '@sveltejs/svelte-repl';
import { getContext } from 'svelte';
export let slug;
@ -94,6 +94,12 @@
);
});
}
const svelteUrl = `https://unpkg.com/svelte@beta`;
const rollupUrl = `https://unpkg.com/rollup@1/dist/rollup.browser.js`;
// needed for context API tutorial
const mapbox_setup = `window.MAPBOX_ACCESS_TOKEN = process.env.MAPBOX_ACCESS_TOKEN;`;
</script>
<style>
@ -239,6 +245,14 @@
</div>
<div class="tutorial-repl">
<Repl bind:this={repl} orientation="rows" on:change={handle_change} relaxed/>
<Repl
bind:this={repl}
{svelteUrl}
{rollupUrl}
orientation="rows"
on:change={handle_change}
setup={mapbox_setup}
relaxed
/>
</div>
</div>

@ -1,221 +0,0 @@
self.window = self; // egregious hack to get magic-string to work in a worker
let version;
let fulfil;
let ready = new Promise(f => fulfil = f);
self.addEventListener('message', async event => {
switch (event.data.type) {
case 'init':
version = event.data.version;
importScripts(
version === 'local' ?
'/repl/local?file=compiler.js' :
`https://unpkg.com/svelte@${version}/compiler.js`,
`https://unpkg.com/rollup@1/dist/rollup.browser.js`
);
fulfil();
break;
case 'bundle':
if (event.data.components.length === 0) return;
await ready;
const result = await bundle(event.data);
if (result) {
postMessage(result);
}
break;
}
});
const common_options = {
dev: true,
};
let cached = {
dom: {},
ssr: {}
};
const is_svelte_module = id => id === 'svelte' || id.startsWith('svelte/');
const cache = new Map();
function fetch_if_uncached(url) {
if (!cache.has(url)) {
cache.set(url, fetch(url.startsWith('https://unpkg.com/svelte@local/') ? '/repl/local?file=' + url.slice(31) : url)
.then(r => r.text())
.catch(err => {
console.error(err);
cache.delete(url);
}));
}
return cache.get(url);
}
async function get_bundle(mode, cache, lookup) {
let bundle;
const all_warnings = [];
const new_cache = {};
try {
bundle = await rollup.rollup({
input: './App.svelte',
external: id => {
if (id[0] === '.') return false;
if (is_svelte_module(id)) return false;
if (id.startsWith('https://')) return false;
return true;
},
plugins: [{
resolveId(importee, importer) {
// v3 hack
if (importee === `svelte`) return `https://unpkg.com/svelte@${version}/index.mjs`;
if (importee.startsWith(`svelte/`)) return `https://unpkg.com/svelte@${version}/${importee.slice(7)}.mjs`;
if (importer && importer.startsWith(`https://`)) {
return new URL(`${importee}.mjs`, importer).href;
}
if (importee.endsWith('.html')) importee = importee.replace(/\.html$/, '.svelte');
if (importee in lookup) return importee;
throw new Error(`Could not resolve "${importee}" from "${importer}"`);
},
load(id) {
if (id.startsWith(`https://`)) return fetch_if_uncached(id);
if (id in lookup) return lookup[id].source;
},
transform(code, id) {
if (!/\.svelte$/.test(id)) return null;
const name = id.replace(/^\.\//, '').replace(/\.svelte$/, '');
const result = cache[id] && cache[id].code === code
? cache[id].result
: svelte.compile(code, Object.assign({
generate: mode,
format: 'esm',
name,
filename: name + '.svelte'
}, common_options));
new_cache[id] = { code, result };
(result.warnings || result.stats.warnings).forEach(warning => { // TODO remove stats post-launch
all_warnings.push({
message: warning.message,
filename: warning.filename,
start: warning.start,
end: warning.end
});
});
return result.js;
}
}],
inlineDynamicImports: true,
onwarn(warning) {
all_warnings.push({
message: warning.message
});
}
});
} catch (error) {
return { error, bundle: null, cache: new_cache, warnings: all_warnings };
}
return { bundle, cache: new_cache, error: null, warnings: all_warnings };
}
async function bundle({ id, components }) {
// console.clear();
console.log(`running Svelte compiler version %c${svelte.VERSION}`, 'font-weight: bold');
const lookup = {};
components.forEach(component => {
const path = `./${component.name}.${component.type}`;
lookup[path] = component;
});
const import_map = new Map();
let dom;
let error;
try {
dom = await get_bundle('dom', cached.dom, lookup);
if (dom.error) {
throw dom.error;
}
cached.dom = dom.cache;
let uid = 1;
const dom_result = (await dom.bundle.generate({
format: 'iife',
name: 'SvelteComponent',
globals: id => {
const name = `import_${uid++}`;
import_map.set(id, name);
return name;
},
exports: 'named',
sourcemap: true
})).output[0];
const ssr = false // TODO how can we do SSR?
? await get_bundle('ssr', cached.ssr, lookup)
: null;
if (ssr) {
cached.ssr = ssr.cache;
if (ssr.error) {
throw ssr.error;
}
}
const ssr_result = ssr
? (await ssr.bundle.generate({
format: 'iife',
name: 'SvelteComponent',
globals: id => import_map.get(id),
exports: 'named',
sourcemap: true
})).output[0]
: null;
return {
id,
imports: dom_result.imports,
import_map,
dom: dom_result,
ssr: ssr_result,
warnings: dom.warnings,
error: null
};
} catch (err) {
const e = error || err;
delete e.toString;
return {
id,
imports: [],
import_map,
dom: null,
ssr: null,
warnings: dom.warnings,
error: Object.assign({}, e, {
message: e.message,
stack: e.stack
})
};
}
}

@ -1,58 +0,0 @@
self.window = self; // egregious hack to get magic-string to work in a worker
let fulfil_ready;
const ready = new Promise(f => {
fulfil_ready = f;
});
self.addEventListener('message', async event => {
switch (event.data.type) {
case 'init':
importScripts(
event.data.version === 'local' ?
'/repl/local?file=compiler.js' :
`https://unpkg.com/svelte@${event.data.version}/compiler.js`
);
fulfil_ready();
break;
case 'compile':
await ready;
postMessage(compile(event.data));
break;
}
});
const common_options = {
dev: false,
css: false
};
function compile({ id, source, options }) {
try {
const { js, css } = svelte.compile(
source,
Object.assign({}, common_options, options)
);
return {
id,
result: {
js: js.code,
css: css.code || `/* Add a <sty` + `le> tag to see compiled CSS */`
}
};
} catch (err) {
let message = `/* Error compiling component\n\n${err.message}`;
if (err.frame) message += `\n${err.frame}`;
message += `\n\n*/`;
return {
id,
result: {
js: message,
css: message
}
};
}
}

@ -648,7 +648,7 @@ export default class Component {
this.add_reference(name.slice(1));
const variable = this.var_lookup.get(name.slice(1));
variable.subscribable = true;
if (variable) variable.subscribable = true;
} else {
this.add_var({
name,
@ -1164,9 +1164,11 @@ export default class Component {
const variable = this.var_lookup.get(name);
if (!variable) return name;
if (variable && variable.hoistable) return name;
this.add_reference(name); // TODO we can probably remove most other occurrences of this
if (variable.hoistable) return name;
return `ctx.${name}`;
}
@ -1180,7 +1182,7 @@ export default class Component {
if (name[0] === '$') return; // $$props
}
if (this.var_lookup.has(name)) return;
if (this.var_lookup.has(name) && !this.var_lookup.get(name).global) return;
if (template_scope && template_scope.names.has(name)) return;
if (globals.has(name)) return;

@ -39,7 +39,7 @@ export default class Binding extends Node {
} else {
const variable = component.var_lookup.get(name);
if (!variable) component.error(this.expression.node, {
if (!variable || variable.global) component.error(this.expression.node, {
code: 'binding-undeclared',
message: `${name} is not declared`
});

@ -94,16 +94,11 @@ export default class Element extends Node {
this.name = info.name;
const parent_element = parent.find_nearest(/^Element/);
this.namespace = this.name === 'svg' ?
namespaces.svg :
parent_element ? parent_element.namespace : this.component.namespace;
if (!this.namespace && svg.test(this.name)) {
this.component.warn(this, {
code: `missing-namespace`,
message: `<${this.name}> is an SVG element did you forget to add <svelte:options namespace="svg"/> ?`
});
}
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 (info.children.length > 0) {
@ -493,11 +488,12 @@ export default class Element extends Node {
});
}
if (check_type_attribute() !== 'checkbox') {
component.error(binding, {
code: `invalid-binding`,
message: `'${name}' binding can only be used with <input type="checkbox">`
});
const type = check_type_attribute();
if (type !== 'checkbox') {
let message = `'${name}' binding can only be used with <input type="checkbox">`;
if (type === 'radio') message += ` — for <input type="radio">, use 'group' binding`;
component.error(binding, { code: `invalid-binding`, message });
}
} else if (name === 'group') {
if (this.name !== 'input') {
@ -512,14 +508,14 @@ export default class Element extends Node {
if (type !== 'checkbox' && type !== 'radio') {
component.error(binding, {
code: `invalid-binding`,
message: `'checked' binding can only be used with <input type="checkbox"> or <input type="radio">`
message: `'group' binding can only be used with <input type="checkbox"> or <input type="radio">`
});
}
} else if (name == 'files') {
if (this.name !== 'input') {
component.error(binding, {
code: `invalid-binding`,
message: `'files' binding acn only be used with <input type="file">`
message: `'files' is not a valid binding on <${this.name}> elements`
});
}
@ -538,7 +534,8 @@ export default class Element extends Node {
name === 'buffered' ||
name === 'seekable' ||
name === 'played' ||
name === 'volume'
name === 'volume' ||
name === 'playbackRate'
) {
if (this.name !== 'audio' && this.name !== 'video') {
component.error(binding, {
@ -635,23 +632,6 @@ export default class Element extends Node {
});
}
get_static_attribute_value(name: string) {
const attribute = this.attributes.find(
(attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name
);
if (!attribute) return null;
if (attribute.is_true) return true;
if (attribute.chunks.length === 0) return '';
if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') {
return attribute.chunks[0].data;
}
return null;
}
is_media_node() {
return this.name === 'audio' || this.name === 'video';
}

@ -5,6 +5,7 @@ import Attribute from './Attribute';
export default class Slot extends Element {
type: 'Element';
name: string;
slot_name: string;
attributes: Attribute[];
children: Node[];
@ -27,8 +28,8 @@ export default class Slot extends Element {
});
}
const slot_name = attr.value[0].data;
if (slot_name === 'default') {
this.slot_name = attr.value[0].data;
if (this.slot_name === 'default') {
component.error(attr, {
code: `invalid-slot-name`,
message: `default is a reserved word — it cannot be used as a slot name`
@ -46,6 +47,8 @@ export default class Slot extends Element {
// validator.slots.add(slot_name);
});
if (!this.slot_name) this.slot_name = 'default';
// if (node.attributes.length === 0) && validator.slots.has('default')) {
// validator.error(node, {
// code: `duplicate-slot`,
@ -53,21 +56,4 @@ export default class Slot extends Element {
// });
// }
}
get_static_attribute_value(name: string) {
const attribute = this.attributes.find(
attr => attr.name.toLowerCase() === name
);
if (!attribute) return null;
if (attribute.is_true) return true;
if (attribute.chunks.length === 0) return '';
if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') {
return attribute.chunks[0].data;
}
return null;
}
}

@ -364,7 +364,18 @@ export default class Expression {
let body = code.slice(node.body.start, node.body.end).trim();
if (node.body.type !== 'BlockStatement') {
if (pending_assignments.size > 0) {
const insert = Array.from(pending_assignments).map(name => component.invalidate(name)).join('; ');
const dependencies = new Set();
pending_assignments.forEach(name => {
if (template_scope.names.has(name)) {
template_scope.dependencies_for_name.get(name).forEach(dependency => {
dependencies.add(dependency);
});
} else {
dependencies.add(name);
}
});
const insert = Array.from(dependencies).map(name => component.invalidate(name)).join('; ');
pending_assignments = new Set();
component.has_reactive_assignments = true;

@ -37,17 +37,34 @@ export default class Node {
}
}
find_nearest(selector: RegExp) {
if (selector.test(this.type)) return this;
if (this.parent) return this.parent.find_nearest(selector);
}
get_static_attribute_value(name: string) {
const attribute = this.attributes.find(
(attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name
);
if (!attribute) return null;
if (attribute.is_true) return true;
if (attribute.chunks.length === 0) return '';
if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') {
return attribute.chunks[0].data;
}
return null;
}
has_ancestor(type: string) {
return this.parent ?
this.parent.type === type || this.parent.has_ancestor(type) :
false;
}
find_nearest(selector: RegExp) {
if (selector.test(this.type)) return this;
if (this.parent) return this.parent.find_nearest(selector);
}
warn_if_empty_block() {
if (!/Block$/.test(this.type) || !this.children) return;
if (this.children.length > 1) return;

@ -10,7 +10,6 @@ import add_to_set from '../utils/add_to_set';
import get_object from '../utils/get_object';
import { extract_names } from '../utils/scope';
import { nodes_match } from '../../utils/nodes_match';
import { sanitize } from '../../utils/names';
export default function dom(
component: Component,
@ -305,8 +304,7 @@ export default function dom(
const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$');
if (renderer.slots.size > 0) {
const arr = Array.from(renderer.slots);
filtered_declarations.push(...arr.map(name => `$$slot_${sanitize(name)}`), '$$scope');
filtered_declarations.push('$$slots', '$$scope');
}
if (renderer.binding_groups.length > 0) {
@ -399,7 +397,7 @@ export default function dom(
${component.javascript}
${renderer.slots.size && `let { ${[...renderer.slots].map(name => `$$slot_${sanitize(name)}`).join(', ')}, $$scope } = $$props;`}
${renderer.slots.size && `let { $$slots = {}, $$scope } = $$props;`}
${renderer.binding_groups.length > 0 && `const $$binding_groups = [${renderer.binding_groups.map(_ => `[]`).join(', ')}];`}

@ -92,7 +92,9 @@ export default class EachBlockWrapper extends Wrapper {
this.index_name = this.node.index || renderer.component.get_unique_name(`${this.node.context}_index`);
const fixed_length = node.expression.node.type === 'ArrayExpression'
const fixed_length =
node.expression.node.type === 'ArrayExpression' &&
node.expression.node.elements.every(element => element.type !== 'SpreadElement')
? node.expression.node.elements.length
: null;
@ -207,8 +209,8 @@ export default class EachBlockWrapper extends Wrapper {
if (needs_anchor) {
block.add_element(
this.vars.anchor,
`@comment()`,
parent_nodes && `@comment()`,
`@empty()`,
parent_nodes && `@empty()`,
parent_node
);
}
@ -300,8 +302,8 @@ export default class EachBlockWrapper extends Wrapper {
this.block.first = this.block.get_unique_name('first');
this.block.add_element(
this.block.first,
`@comment()`,
parent_nodes && `@comment()`,
`@empty()`,
parent_nodes && `@empty()`,
null
);
}

@ -117,7 +117,7 @@ export default class AttributeWrapper {
updater = `@set_input_type(${element.var}, ${should_cache ? last : value});`;
} else if (is_select_value_attribute) {
// annoying special case
const is_multiple_select = element.get_static_attribute_value('multiple');
const is_multiple_select = element.node.get_static_attribute_value('multiple');
const i = block.get_unique_name('i');
const option = block.get_unique_name('option');
@ -445,6 +445,7 @@ const attribute_lookup = {
],
},
volume: { applies_to: ['audio', 'video'] },
playbackRate: { applies_to: ['audio', 'video'] },
width: {
applies_to: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
},

@ -139,6 +139,7 @@ export default class BindingWrapper {
break;
case 'currentTime':
case 'playbackRate':
case 'volume':
update_conditions.push(`!isNaN(${this.snippet})`);
break;
@ -153,7 +154,7 @@ export default class BindingWrapper {
break;
case 'value':
if (parent.get_static_attribute_value('type') === 'file') {
if (parent.node.get_static_attribute_value('type') === 'file') {
update_dom = null;
}
}

@ -20,6 +20,7 @@ import add_event_handlers from '../shared/add_event_handlers';
import add_actions from '../shared/add_actions';
import create_debugging_comment from '../shared/create_debugging_comment';
import { get_context_merger } from '../shared/get_context_merger';
import Slot from '../../../nodes/Slot';
const events = [
{
@ -82,7 +83,14 @@ const events = [
filter: (node: Element, name: string) =>
node.is_media_node() &&
name === 'volume'
}
},
{
event_names: ['ratechange'],
filter: (node: Element, name: string) =>
node.is_media_node() &&
name === 'playbackRate'
},
];
export default class ElementWrapper extends Wrapper {
@ -213,8 +221,7 @@ export default class ElementWrapper extends Wrapper {
const { renderer } = this;
if (this.node.name === 'slot') {
const slotName = this.get_static_attribute_value('name') || 'default';
renderer.slots.add(slotName);
renderer.slots.add((this.node as Slot).slot_name);
}
if (this.node.name === 'noscript') return;
@ -804,23 +811,6 @@ export default class ElementWrapper extends Wrapper {
});
}
get_static_attribute_value(name: string) {
const attribute = this.node.attributes.find(
(attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name
);
if (!attribute) return null;
if (attribute.is_true) return true;
if (attribute.chunks.length === 0) return '';
if (attribute.chunks.length === 1 && attribute.chunks[0].type === 'Text') {
return attribute.chunks[0].data;
}
return null;
}
add_css_class(class_name = this.component.stylesheet.id) {
const class_attribute = this.attributes.find(a => a.name === 'class');
if (class_attribute && !class_attribute.is_true) {

@ -185,8 +185,8 @@ export default class IfBlockWrapper extends Wrapper {
if (needs_anchor) {
block.add_element(
anchor,
`@comment()`,
parent_nodes && `@comment()`,
`@empty()`,
parent_nodes && `@empty()`,
parent_node
);
}

@ -119,16 +119,19 @@ export default class InlineComponentWrapper extends Wrapper {
const uses_spread = !!this.node.attributes.find(a => a.is_spread);
const slot_props = Array.from(this.slots).map(([name, slot]) => `$$slot_${sanitize(name)}: [${slot.block.name}${slot.fn ? `, ${slot.fn}` : ''}]`);
if (slot_props.length > 0) slot_props.push(`$$scope: { ctx }`);
const slot_props = Array.from(this.slots).map(([name, slot]) => `${quote_name_if_necessary(name)}: [${slot.block.name}${slot.fn ? `, ${slot.fn}` : ''}]`);
const initial_props = slot_props.length > 0
? [`$$slots: ${stringify_props(slot_props)}`, `$$scope: { ctx }`]
: [];
const attribute_object = uses_spread
? stringify_props(slot_props)
? stringify_props(initial_props)
: stringify_props(
this.node.attributes.map(attr => `${quote_name_if_necessary(attr.name)}: ${attr.get_value(block)}`).concat(slot_props)
this.node.attributes.map(attr => `${quote_name_if_necessary(attr.name)}: ${attr.get_value(block)}`).concat(initial_props)
);
if (this.node.attributes.length || this.node.bindings.length || slot_props.length) {
if (this.node.attributes.length || this.node.bindings.length || initial_props.length) {
if (!uses_spread && this.node.bindings.length === 0) {
component_opts.push(`props: ${attribute_object}`);
} else {

@ -4,7 +4,7 @@ import Block from '../Block';
import Slot from '../../nodes/Slot';
import FragmentWrapper from './Fragment';
import deindent from '../../utils/deindent';
import { sanitize } from '../../../utils/names';
import { sanitize, quote_prop_if_necessary } from '../../../utils/names';
import add_to_set from '../../utils/add_to_set';
import get_slot_data from '../../utils/get_slot_data';
import { stringify_props } from '../../utils/stringify_props';
@ -42,6 +42,10 @@ export default class SlotWrapper extends Wrapper {
});
block.add_dependencies(this.dependencies);
// we have to do this, just in case
block.add_intro();
block.add_outro();
}
render(
@ -51,7 +55,7 @@ export default class SlotWrapper extends Wrapper {
) {
const { renderer } = this;
const slot_name = this.node.get_static_attribute_value('name') || 'default';
const { slot_name } = this.node;
renderer.slots.add(slot_name);
let get_slot_changes;
@ -95,7 +99,7 @@ export default class SlotWrapper extends Wrapper {
const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot`);
block.builders.init.add_block(deindent`
const ${slot_definition} = ctx.$$slot_${sanitize(slot_name)};
const ${slot_definition} = ctx.$$slots${quote_prop_if_necessary(slot_name)};
const ${slot} = @create_slot(${slot_definition}, ctx, ${get_slot_context});
`);
@ -137,6 +141,14 @@ export default class SlotWrapper extends Wrapper {
}
`);
block.builders.intro.add_line(
`if (${slot} && ${slot}.i) ${slot}.i(#local);`
);
block.builders.outro.add_line(
`if (${slot} && ${slot}.o) ${slot}.o(#local);`
);
let update_conditions = [...this.dependencies].map(name => `changed.${name}`).join(' || ');
if (this.dependencies.size > 1) update_conditions = `(${update_conditions})`;

@ -53,8 +53,8 @@ export default class Wrapper {
if (needs_anchor) {
block.add_element(
anchor,
`@comment()`,
parent_nodes && `@comment()`,
`@empty()`,
parent_nodes && `@empty()`,
parent_node
);
}

@ -2,10 +2,7 @@ import { quote_prop_if_necessary } from '../../../utils/names';
import get_slot_data from '../../utils/get_slot_data';
export default function(node, renderer, options) {
const name = node.attributes.find(attribute => attribute.name === 'name');
const slot_name = name && name.chunks[0].data || 'default';
const prop = quote_prop_if_necessary(slot_name);
const prop = quote_prop_if_necessary(node.slot_name);
const slot_data = get_slot_data(node.attributes, true);

@ -50,8 +50,8 @@ export function space() {
return text(' ');
}
export function comment() {
return document.createComment('');
export function empty() {
return text('');
}
export function listen(node, event, handler, options) {

@ -191,8 +191,7 @@ export default function tag(parser: Parser) {
}
if (name === 'svelte:component') {
// TODO post v2, treat this just as any other attribute
const index = element.attributes.findIndex(attr => attr.name === 'this');
const index = element.attributes.findIndex(attr => attr.type === 'Attribute' && attr.name === 'this');
if (!~index) {
parser.error({
code: `missing-component-definition`,

@ -95,8 +95,8 @@ export default async function preprocess(
for (const fn of script) {
source = await replace_async(
source,
/<script([^]*?)>([^]*?)<\/script>/gi,
async (match, attributes, content) => {
/<script(\s[^]*?)?>([^]*?)<\/script>/gi,
async (match, attributes = '', content) => {
const processed: Processed = await fn({
content,
attributes: parse_attributes(attributes),
@ -111,8 +111,8 @@ export default async function preprocess(
for (const fn of style) {
source = await replace_async(
source,
/<style([^]*?)>([^]*?)<\/style>/gi,
async (match, attributes, content) => {
/<style(\s[^]*?)?>([^]*?)<\/style>/gi,
async (match, attributes = '', content) => {
const processed: Processed = await fn({
content,
attributes: parse_attributes(attributes),

@ -111,5 +111,9 @@ export function quote_prop_if_necessary(name: string) {
}
export function sanitize(name: string) {
return name.replace(/[^a-zA-Z]+/g, '_').replace(/^_/, '').replace(/_$/, '');
return name
.replace(/[^a-zA-Z0-9_]+/g, '_')
.replace(/^_/, '')
.replace(/_$/, '')
.replace(/^[0-9]/, '_$&');
}

@ -1,8 +1,9 @@
import { run_all, noop, get_store_value, safe_not_equal } from './internal';
export function readable(start, value) {
const { set, subscribe } = writable(value, () => start(set));
return { subscribe };
export function readable(value, start) {
return {
subscribe: writable(value, start).subscribe
};
}
export function writable(value, start = noop) {
@ -25,7 +26,7 @@ export function writable(value, start = noop) {
function subscribe(run, invalidate = noop) {
const subscriber = [run, invalidate];
subscribers.push(subscriber);
if (subscribers.length === 1) stop = start() || noop;
if (subscribers.length === 1) stop = start(set) || noop;
run(value);
return () => {
@ -45,7 +46,7 @@ export function derive(stores, fn) {
const auto = fn.length < 2;
let value = {};
return readable(set => {
return readable(undefined, set => {
let inited = false;
const values = [];

@ -1,2 +0,0 @@
#!/usr/bin/env node
require('./cli/index.js');

@ -2,10 +2,10 @@
import {
SvelteComponent as SvelteComponent_1,
append,
comment,
destroy_each,
detach,
element,
empty,
init,
insert,
noop,
@ -66,7 +66,7 @@ function create_fragment(ctx) {
each_blocks[i].c();
}
each_1_anchor = comment();
each_1_anchor = empty();
},
m(target, anchor) {

@ -2,10 +2,10 @@
import {
SvelteComponent as SvelteComponent_1,
append,
comment,
destroy_each,
detach,
element,
empty,
init,
insert,
noop,
@ -66,7 +66,7 @@ function create_fragment(ctx) {
each_blocks[i].c();
}
each_1_anchor = comment();
each_1_anchor = empty();
},
m(target, anchor) {

@ -3,10 +3,10 @@ import {
SvelteComponent as SvelteComponent_1,
append,
blank_object,
comment,
create_animation,
detach,
element,
empty,
fix_and_outro_and_destroy_block,
fix_position,
init,
@ -89,7 +89,7 @@ function create_fragment(ctx) {
c() {
for (i = 0; i < each_blocks.length; i += 1) each_blocks[i].c();
each_1_anchor = comment();
each_1_anchor = empty();
},
m(target, anchor) {

@ -3,10 +3,10 @@ import {
SvelteComponent as SvelteComponent_1,
append,
blank_object,
comment,
destroy_block,
detach,
element,
empty,
init,
insert,
noop,
@ -73,7 +73,7 @@ function create_fragment(ctx) {
c() {
for (i = 0; i < each_blocks.length; i += 1) each_blocks[i].c();
each_1_anchor = comment();
each_1_anchor = empty();
},
m(target, anchor) {

@ -1,9 +1,9 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent as SvelteComponent_1,
comment,
detach,
element,
empty,
init,
insert,
noop,
@ -68,7 +68,7 @@ function create_fragment(ctx) {
return {
c() {
if_block.c();
if_block_anchor = comment();
if_block_anchor = empty();
},
m(target, anchor) {

@ -1,9 +1,9 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent as SvelteComponent_1,
comment,
detach,
element,
empty,
init,
insert,
noop,
@ -40,7 +40,7 @@ function create_fragment(ctx) {
return {
c() {
if (if_block) if_block.c();
if_block_anchor = comment();
if_block_anchor = empty();
},
m(target, anchor) {

@ -38,7 +38,8 @@ function create_fragment(ctx) {
listen(audio, "pause", ctx.audio_play_pause_handler),
listen(audio, "progress", ctx.audio_progress_handler),
listen(audio, "loadedmetadata", ctx.audio_loadedmetadata_handler),
listen(audio, "volumechange", ctx.audio_volumechange_handler)
listen(audio, "volumechange", ctx.audio_volumechange_handler),
listen(audio, "ratechange", ctx.audio_ratechange_handler)
];
},
@ -46,12 +47,15 @@ function create_fragment(ctx) {
insert(target, audio, anchor);
audio.volume = ctx.volume;
audio.playbackRate = ctx.playbackRate;
},
p(changed, ctx) {
if (!audio_updating && changed.currentTime && !isNaN(ctx.currentTime)) audio.currentTime = ctx.currentTime;
if (changed.paused && audio_is_paused !== (audio_is_paused = ctx.paused)) audio[audio_is_paused ? "pause" : "play"]();
if (changed.volume && !isNaN(ctx.volume)) audio.volume = ctx.volume;
if (changed.playbackRate && !isNaN(ctx.playbackRate)) audio.playbackRate = ctx.playbackRate;
audio_updating = false;
},
@ -69,7 +73,7 @@ function create_fragment(ctx) {
}
function instance($$self, $$props, $$invalidate) {
let { buffered, seekable, played, currentTime, duration, paused, volume } = $$props;
let { buffered, seekable, played, currentTime, duration, paused, volume, playbackRate } = $$props;
function audio_timeupdate_handler() {
played = time_ranges_to_array(this.played);
@ -105,6 +109,11 @@ function instance($$self, $$props, $$invalidate) {
$$invalidate('volume', volume);
}
function audio_ratechange_handler() {
playbackRate = this.playbackRate;
$$invalidate('playbackRate', playbackRate);
}
$$self.$set = $$props => {
if ('buffered' in $$props) $$invalidate('buffered', buffered = $$props.buffered);
if ('seekable' in $$props) $$invalidate('seekable', seekable = $$props.seekable);
@ -113,6 +122,7 @@ function instance($$self, $$props, $$invalidate) {
if ('duration' in $$props) $$invalidate('duration', duration = $$props.duration);
if ('paused' in $$props) $$invalidate('paused', paused = $$props.paused);
if ('volume' in $$props) $$invalidate('volume', volume = $$props.volume);
if ('playbackRate' in $$props) $$invalidate('playbackRate', playbackRate = $$props.playbackRate);
};
return {
@ -123,19 +133,21 @@ function instance($$self, $$props, $$invalidate) {
duration,
paused,
volume,
playbackRate,
audio_timeupdate_handler,
audio_durationchange_handler,
audio_play_pause_handler,
audio_progress_handler,
audio_loadedmetadata_handler,
audio_volumechange_handler
audio_volumechange_handler,
audio_ratechange_handler
};
}
class SvelteComponent extends SvelteComponent_1 {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, ["buffered", "seekable", "played", "currentTime", "duration", "paused", "volume"]);
init(this, options, instance, create_fragment, safe_not_equal, ["buffered", "seekable", "played", "currentTime", "duration", "paused", "volume", "playbackRate"]);
}
}

@ -6,6 +6,7 @@
export let duration;
export let paused;
export let volume;
export let playbackRate;
</script>
<audio bind:buffered bind:seekable bind:played bind:currentTime bind:duration bind:paused bind:volume/>
<audio bind:buffered bind:seekable bind:played bind:currentTime bind:duration bind:paused bind:volume bind:playbackRate/>

@ -2,10 +2,10 @@
import {
SvelteComponent as SvelteComponent_1,
add_render_callback,
comment,
create_in_transition,
detach,
element,
empty,
init,
insert,
noop,
@ -21,7 +21,7 @@ function create_if_block(ctx) {
return {
c() {
if (if_block) if_block.c();
if_block_anchor = comment();
if_block_anchor = empty();
},
m(target, anchor) {
@ -98,7 +98,7 @@ function create_fragment(ctx) {
return {
c() {
if (if_block) if_block.c();
if_block_anchor = comment();
if_block_anchor = empty();
},
m(target, anchor) {

@ -2,9 +2,9 @@
import {
SvelteComponent as SvelteComponent_1,
append,
comment,
detach,
element,
empty,
init,
insert,
noop,
@ -153,7 +153,7 @@ function create_fragment(ctx) {
if (if_block3) if_block3.c();
t7 = space();
if (if_block4) if_block4.c();
if_block4_anchor = comment();
if_block4_anchor = empty();
},
m(target, anchor) {

@ -0,0 +1,6 @@
export default {
preprocess: {
script: () => ({ code: '' }),
style: () => ({ code: '' })
}
};

@ -0,0 +1,12 @@
<script-foo>
foo
</script-foo>
<script>
// bar
</script>
<style-foo>
foo
</style-foo>
<style>
bar {}
</style>

@ -0,0 +1,8 @@
<script-foo>
foo
</script-foo>
<script></script>
<style-foo>
foo
</style-foo>
<style></style>

@ -0,0 +1,3 @@
export default {
html: `<div>a</div> <div>b</div> <div>c</div>`
};

@ -0,0 +1,7 @@
<script>
const foo = ['a', 'b', 'c'];
</script>
{#each [...foo] as item}
<div>{item}</div>
{/each}

@ -8,24 +8,29 @@ export default {
assert.equal(component.t, 0);
assert.equal(component.d, 0);
assert.equal(component.v, 0.5);
assert.equal(component.r, 1);
assert.equal(component.paused, true);
const audio = target.querySelector('audio');
const timeupdate = new window.Event('timeupdate');
const durationchange = new window.Event('durationchange');
const volumechange = new window.Event('volumechange');
const ratechange = new window.Event('ratechange');
audio.currentTime = 10;
audio.duration = 20;
audio.volume = 0.75;
audio.playbackRate = 2;
audio.dispatchEvent(timeupdate);
audio.dispatchEvent(durationchange);
audio.dispatchEvent(volumechange);
audio.dispatchEvent(ratechange);
audio.play();
assert.equal(component.t, 10);
assert.equal(component.d, 0); // not 20, because read-only. Not sure how to test this!
assert.equal(component.v, 0.75);
assert.equal(component.r, 2);
assert.equal(component.paused, true); // ditto...
}
};

@ -3,7 +3,8 @@
export let d;
export let paused;
export let v;
export let r;
</script>
<audio bind:currentTime={t} bind:duration={d} bind:paused bind:volume={v}
<audio bind:currentTime={t} bind:duration={d} bind:paused bind:volume={v} bind:playbackRate={r}
src='music.mp3'></audio>

@ -0,0 +1,8 @@
<div>
<slot name="header1" />
<slot name="-header2_" />
<slot name="3header" />
<slot name="_header4" />
<slot name="header-5" />
<slot name="header&5" />
</div>

@ -0,0 +1,12 @@
export default {
html: `
<div>
<h1 slot="header1">Header 1</h1>
<h2 slot="-header2_">Header 2</h2>
<h3 slot="3header">Header 3</h3>
<h4 slot="_header4">Header 4</h4>
<h5 slot="header-5">Header 5</h5>
<h5 slot="header&5">Header 5b</h5>
</div>
`
};

@ -0,0 +1,12 @@
<script>
import Nested from './Nested.svelte';
</script>
<Nested>
<h1 slot="header1">Header 1</h1>
<h2 slot="-header2_">Header 2</h2>
<h3 slot="3header">Header 3</h3>
<h4 slot="_header4">Header 4</h4>
<h5 slot="header-5">Header 5</h5>
<h5 slot="header&5">Header 5b</h5>
</Nested>

@ -4,4 +4,4 @@
export let test;
</script>
<svelte:component this={Foo} bind:this={test}/>
<svelte:component bind:this={test} this={Foo}/>

@ -0,0 +1,35 @@
export default {
html: `
<button>off</button>
<button>on</button>
<button>off</button>
<p>on: 1</p>
`,
async test({ assert, component, target, window }) {
const buttons = target.querySelectorAll('button');
const event = new window.MouseEvent('click');
await buttons[0].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<button>on</button>
<button>on</button>
<button>off</button>
<p>on: 2</p>
`);
await buttons[2].dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<button>on</button>
<button>on</button>
<button>on</button>
<p>on: 3</p>
`);
assert.deepEqual(component.switches, [
{ on: true },
{ on: true },
{ on: true }
]);
}
};

@ -0,0 +1,15 @@
<script>
export let switches = [
{ on: false },
{ on: true },
{ on: false }
];
</script>
{#each switches as s}
<button on:click="{() => s.on = !s.on}">
{s.on ? 'on' : 'off'}
</button>
{/each}
<p>on: {switches.filter(s => !!s.on).length}</p>

@ -0,0 +1,3 @@
export default {
error: 'missingGlobal is not defined'
};

@ -0,0 +1,14 @@
export default {
html: `
<svg>
<foreignObject x="0" y="0" width="100" height="100">
<p>some text</p>
</foreignObject>
</svg>
`,
test({ assert, target }) {
const p = target.querySelector('p');
assert.equal(p.namespaceURI, 'http://www.w3.org/1999/xhtml');
}
};

@ -0,0 +1,5 @@
<svg>
<foreignObject x="0" y="0" width="100" height="100">
<p>some text</p>
</foreignObject>
</svg>

After

Width:  |  Height:  |  Size: 104 B

@ -0,0 +1,9 @@
<script>
export let visible;
</script>
<div>
{#if visible}
<slot/>
{/if}
</div>

@ -0,0 +1,26 @@
export default {
props: {
visible: false
},
html: `
<div></div>
`,
test({ assert, component, target, window, raf }) {
component.visible = true;
const p = target.querySelector('p');
assert.equal(p.foo, 0);
raf.tick(50);
assert.equal(p.foo, 0.5);
component.visible = false;
raf.tick(75);
assert.equal(p.foo, 0.25);
raf.tick(100);
assert.equal(p.foo, 0);
}
};

@ -0,0 +1,18 @@
<script>
import Nested from './Nested.svelte';
export let visible;
function foo(node, params) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
<Nested {visible}>
<p transition:foo>slotted</p>
</Nested>

@ -66,7 +66,7 @@ describe('store', () => {
let running;
let tick;
const store = readable(set => {
const store = readable(undefined, set => {
tick = set;
running = true;
@ -192,7 +192,7 @@ describe('store', () => {
describe('get', () => {
it('gets the current value of a store', () => {
const store = readable(() => {}, 42);
const store = readable(42, () => {});
assert.equal(get(store), 42);
});
});

@ -0,0 +1,15 @@
[{
"code": "binding-undeclared",
"message": "foo is not declared",
"pos": 58,
"start": {
"line": 4,
"column": 19,
"character": 58
},
"end": {
"line": 4,
"column": 22,
"character": 61
}
}]

@ -0,0 +1,4 @@
<script>
console.log(foo);
</script>
<input bind:value={foo}>

@ -1,8 +0,0 @@
<script>
export let x;
export let y;
export let width;
export let height;
</script>
<rect x={x} y={y} width={width} height={height}/>

@ -1,15 +0,0 @@
[{
"code": "missing-namespace",
"message": "<rect> is an SVG element did you forget to add <svelte:options namespace=\"svg\"/> ?",
"start": {
"line": 8,
"column": 0,
"character": 89
},
"end": {
"line": 8,
"column": 49,
"character": 138
},
"pos": 89
}]

@ -0,0 +1,5 @@
<script>
console.log(potato);
</script>
<p>{potato}</p>

@ -0,0 +1,15 @@
[{
"code": "missing-declaration",
"message": "'potato' is not defined",
"pos": 46,
"start": {
"line": 5,
"column": 4,
"character": 46
},
"end": {
"line": 5,
"column": 10,
"character": 52
}
}]

@ -1,6 +1,16 @@
export default {
test(assert, vars) {
assert.deepEqual(vars, [
{
export_name: null,
injected: false,
module: false,
mutated: false,
name: 'hoistable_foo',
reassigned: false,
referenced: true,
writable: false
},
{
export_name: null,
injected: false,

@ -1,5 +1,7 @@
<script>
import hoistable_foo from '';
let foo;
</script>
<div use:hoistable_foo/>
<div use:foo/>

@ -1,6 +1,16 @@
export default {
test(assert, vars) {
assert.deepEqual(vars, [
{
export_name: null,
injected: false,
module: false,
mutated: false,
name: 'hoistable_foo',
reassigned: false,
referenced: true,
writable: false
},
{
export_name: null,
injected: false,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save