Published
Edited
Aug 7, 2019
2 forks
Importers
19 stars
Insert cell
Insert cell
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
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
_svelte_both`<style>
p {
color: purple;
font-family: 'Comic Sans MS';
font-size: 2em;
}
</style>
<script>
export let l = 1
$: m = l * 2
</script>

<p>Styled {l} {m}!</p>`.ssr.default.render({l: 10})
Insert cell
Insert cell
_compiler({generate: 'ssr'})`<!-- 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/>`.js.code

Insert cell
function _compiler(options) {
return function (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] || ''}`, '')

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

const compiled = compiler.compile(s, {format: "cjs", name, ...options})
// HACK(adamb) interpolation checking
const unknownSymTypes = []
compiler.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
load = {
const requires = ({
"svelte/internal": internal,
"svelte": core,
"svelte/store": store,
"svelte/transition": transition,
})
return function(compiled) {
const css = compiled.css
const bundledRequires = compiled.requires || {}
const fn = new Function('require', 'exports', compiled.js.code)
const exports = {}
fn.call(
window,
name => requires[name] || bundledRequires[name],
exports,
)
exports[CSSTag] = css
return exports
}
}
Insert cell
Insert cell
Insert cell
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(_compiler({css: true})(strings, ...values))
}
Insert cell
// Experimental
function _svelte_ssr(strings, ...values) {
return load(_compiler({css: true, generate: "ssr"})(strings, ...values))
}
Insert cell
// Experimental
function _svelte_both(strings, ...values) {
return {
dom: svelte(strings, ...values),
ssr: _svelte_ssr(strings, ...values),
}
}
Insert cell
readable = store.readable
Insert cell
writable = store.writable
Insert cell
derived = store.derived
Insert cell
get = store.get
Insert cell
function generatedPromises(gen, initialValue, ...args) {
return store.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(upstream, gen, initialValue) {
return store.derived(upstream, (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", upstream, 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
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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