Published
Edited
Jul 23, 2019
Fork of Svelte
Importers
6 stars
Insert cell
md`# Svelte`
Insert cell
md`# Examples`
Insert cell
render(svelte`<h3>Hello world!</h3>`)
Insert cell
render(svelte`<script>
let name = 'world';
</script>

<h3>Hello {name}!</h3>`)
Insert cell
render(svelte`<style>
p {
color: purple;
font-family: 'Comic Sans MS';
font-size: 2em;
}
</style>

<p>Styled!</p>`)
Insert cell
m = render(svelte`<!-- a -->
<script>
import {onMount} from 'svelte';
import {readable} from 'svelte/store';

let svg;

let svgRect = {width: undefined, height: undefined}
$: width = svgRect.width;
$: height = svgRect.height;

function maybeUpdateSvgRect() {
const rects = svg.getClientRects()
console.log(svg, rects, svg.getBoundingClientRect());
if (rects.length < 1) {
return false
}
svgRect = rects[0]
return true
}

export const refresh = maybeUpdateSvgRect

onMount(() => maybeUpdateSvgRect || setTimeout(maybeUpdateSvgRect, 0))

$: console.log({width, height})
</script>
<style>
svg {
display: block;
background: green;
}
</style>

<svelte:window on:resize='{maybeUpdateSvgRect}'/>

<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" bind:this={svg} preserveAspectRatio="none">
<circle r=10 cx={width / 2} cy={height / 2} fill="black"/>
</svg>
`)

Insert cell
getComponent(m).refresh()
Insert cell
nested = svelte`<p>...don't affect this element</p>`
Insert cell
render(svelte`<script>
import Nested from ${nested};
</script>

<style>
.foo {
color: purple;
font-family: 'Comic Sans MS';
font-size: 2em;
}
</style>

<p class="foo ">These styles...</p>
<Nested/>`)
Insert cell
render(svelte`
<script>
import { fade } from 'svelte/transition';
let visible = true;
</script>

<label>
<input type="checkbox" bind:checked={visible}>
visible
</label>

{#if visible}
<p transition:fade>
Fades in and out
</p>
{/if}
`)
Insert cell
md `### More advanced`
Insert cell
function* exampleTicker() {
yield Promise.resolve(new Date())
while (true) {
yield Promises.delay(1000, new Date());
}
}
Insert cell
exampleInput = html`<input type=range>`
Insert cell
render(svelte`<script>
export let now;
export let value;
$: console.log("NOW", $now, $value)
</script>
The time is now {$now}<br>
The value is {$value}`, {
now: generatedPromises(exampleTicker),
value: readableInput(exampleInput),
})
Insert cell
md `## Under the hood`
Insert cell
compile`<!-- x --><script>
import Nested from ${nested};
</script>

<style>
.foo {
color: purple;
font-family: 'Comic Sans MS';
font-size: 2em;
}
</style>

<p class="foo">These styles...</p>
<Nested/>`

Insert cell
function compile(strings, ...values) {
// Replace values with random strings... and then preprocess to either replace them with properties OR values in require

// TODO(adamb) Choose a gensymPrefix that doesn't exist ANYWHERE in strings
const genSymPrefix = "gensym_923wedsojasjq_"
const rawSyms = []
const symVals = {}
let ix = 0
for (const value of values) {
const sym = genSymPrefix + ix++
rawSyms.push(`"${sym}"`)
symVals[sym] = value
}
const s = strings.reduce((prev, next, i) => `${prev}${next}${rawSyms[i] || ''}`, '')

let name
const nameMatch = s.match(/^\s*<!--\s*([a-zA-Z0-9_]+)/)
if (nameMatch) {
name = nameMatch[1]
}

const compiled = svelteCompiler.compile(s, {format: "cjs", css: true, name})
// HACK(adamb) Once this svelte bug is addressed, put back interpolation checking
// https://github.com/sveltejs/eslint-plugin-svelte3/issues/13
// const unknownSymTypes = []
// svelteCompiler.walk(compiled.ast.instance, {
// enter(node, parent, prop, index) {
// console.log("node", node)
// if (node.type !== "Literal" || !(node.value in symVals)) {
// return
// }
// if (parent.type !== "ImportDeclaration") {
// unknownSymTypes.push(node)
// }
// },
// })
// if (unknownSymTypes.length > 0) {
// throw Error("Interpolation is only allowed in import statements (for now)")
// }

return Object.assign({requires: symVals}, compiled)
}
Insert cell
// HACK(adamb) Apply the workaround described in https://github.com/sveltejs/svelte/issues/2086#issuecomment-490989491
hackedOverrides = ({
detach(node) {
if(node.parentNode) {
node.parentNode.removeChild(node);
}
},
})
Insert cell
svelteInternal = Object.assign(
Object.create(await import("svelte@3.6.7/internal/index.mjs")),
hackedOverrides,
)
Insert cell
load = {
const requires = ({
"svelte/internal": svelteInternal,
"svelte": svelteInternal,
"svelte/store": svelteStore,
"svelte/transition": svelteTransition,
})
return function(compiled) {
const css = compiled.css
const bundledRequires = compiled.requires || {}
const fn = eval(`(function(require, exports){${compiled.js.code}})`)
const exports = {}
fn(
name => requires[name] || bundledRequires[name],
exports,
)
// HACK(adamb) Apply workaround described in https://github.com/sveltejs/svelte/issues/2086#issuecomment-490989491
Object.assign(exports, hackedOverrides)
exports[CSSTag] = css
return exports
}
}
Insert cell
CSSTag = Symbol("css")
Insert cell
svelteCompiler = require("svelte@3.6.7/compiler");
Insert cell
// There seems to be a bug in 3.4.4+ that prevents us from loading store.mjs directly
svelteStore = require('https://bundle.run/svelte@3.6.7/store/index.js').catch(() => ({
get: svelteInternal.get_store_value,
readable: window['readable'],
writable: window['writable'],
derived: window['derived'],
}))
Insert cell
// There seems to be a bug in 3.4.4+ that prevents us from loading index.mjs directly
svelteTransition = require('https://bundle.run/svelte@3.6.7/transition/index.js').catch(() => ({
crossfade: window['crossfade'],
draw: window['draw'],
fade: window['fade'],
fly: window['fly'],
scale: window['scale'],
slide: window['slide'],
}))
Insert cell
componentTag = Symbol("svelte-component")
Insert cell
md`## API`
Insert cell
function render(component, props, target) {
let t = target || DOM.element('div')
const css = component[CSSTag]
let style
if (css !== undefined) {
const head = document.getElementsByTagName('head')[0]
style = DOM.element('style')
head.appendChild(style)
style.innerHTML = css.code
}
let c = new component.default({target: t, props})
t[componentTag] = c
return Generators.disposable(t, () => {
c.$destroy()
if (t[componentTag] === c) {
delete t[componentTag]
}
t = undefined
c = undefined
if (style !== undefined && style.parentNode) {
style.parentNode.removeChild(style)
}
})
}
Insert cell
function getComponent(element) {
return element[componentTag]
}
Insert cell
function svelte(strings, ...values) {
return load(compile(strings, ...values))
}
Insert cell
readable = svelteStore.readable
Insert cell
writable = svelteStore.writable
Insert cell
derived = svelteStore.derived
Insert cell
get = svelteStore.get
Insert cell
function generatedPromises(gen, initialValue, ...args) {
return svelteStore.readable(initialValue, set => {
const g = gen(...args)
let cancelled = false
function afn({value, done}) {
if (done) {
return
}
value.then(v => {
if (!cancelled) {
set(v)
afn(g.next())
}
})
}
afn(g.next())

return () => {
console.log("cleaning up generatedPromises", gen, g)
cancelled = true
g.return()
}
})
}
Insert cell
function derivedPromises(store, gen, initialValue) {
return svelteStore.derived(store, (current, set) => {
const g = gen(current)
let cancelled = false
function afn({value, done}) {
if (done) {
return
}
value.then(v => {
if (!cancelled) {
set(v)
afn(g.next())
}
})
}
afn(g.next())

return () => {
console.log("cleaning up derivedPromises", store, gen, g)
cancelled = true
g.return()
}
}, initialValue)
}
Insert cell
function readableInput(input) {
return generatedPromises(() => Generators.input(input), input.value)
}
Insert cell
function observe(observable) {
return readable(observable.value, set => {
const inputted = () => set(observable.value)
observable.addEventListener('input', inputted)
return () => observable.removeEventListener('input', inputted)
})
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more