start using context API for REPL

pull/2179/head
Richard Harris 7 years ago
parent 64295c7d1a
commit 9e5c5a9f89

@ -1,33 +1,31 @@
<script> <script>
import { createEventDispatcher } from 'svelte'; import { getContext, createEventDispatcher } from 'svelte';
import Icon from '../../Icon.svelte'; import Icon from '../../Icon.svelte';
import { enter } from '../../../utils/events.js'; import { enter } from '../../../utils/events.js';
const { components, selected } = getContext('REPL');
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let component_store;
export let selected_store;
let editing = null; let editing = null;
function selectComponent(component) { function selectComponent(component) {
if ($selected_store != component) { if ($selected != component) {
editing = null; editing = null;
} }
selected_store.set(component); selected.set(component);
} }
function editTab(component) { function editTab(component) {
if ($selected_store === component) { if ($selected === component) {
editing = $selected_store; editing = $selected;
} }
} }
function closeEdit() { function closeEdit() {
const match = /(.+)\.(svelte|js)$/.exec($selected_store.name); const match = /(.+)\.(svelte|js)$/.exec($selected.name);
$selected_store.name = match ? match[1] : $selected_store.name; $selected.name = match ? match[1] : $selected.name;
if (match && match[2]) $selected_store.type = match[2]; if (match && match[2]) $selected.type = match[2];
editing = null; editing = null;
components = components; // TODO necessary? components = components; // TODO necessary?
@ -60,8 +58,8 @@
document.getElementById(component.name).scrollIntoView(false); document.getElementById(component.name).scrollIntoView(false);
}); });
component_store.update(components => components.concat(component)); components.update(components => components.concat(component));
selected_store.set(component); selected.set(component);
} }
</script> </script>
@ -171,10 +169,10 @@
<div class="component-selector"> <div class="component-selector">
<div class="file-tabs" on:dblclick="{addNew}"> <div class="file-tabs" on:dblclick="{addNew}">
{#each $component_store as component} {#each $components as component}
<button <button
id={component.name} id={component.name}
class:active="{component === $selected_store}" class:active="{component === $selected}"
data-name={component.name} data-name={component.name}
on:click="{() => selectComponent(component)}" on:click="{() => selectComponent(component)}"
on:dblclick="{e => e.stopPropagation()}" on:dblclick="{e => e.stopPropagation()}"

@ -1,7 +1,9 @@
<script> <script>
import { getContext } from 'svelte';
import CodeMirror from '../CodeMirror.svelte'; import CodeMirror from '../CodeMirror.svelte';
export let component; const { selected } = getContext('REPL');
export let error; export let error;
export let errorLoc; export let errorLoc;
export let warningCount = 0; export let warningCount = 0;
@ -24,10 +26,10 @@
</style> </style>
<div class="editor-wrapper"> <div class="editor-wrapper">
{#if component} {#if $selected}
<CodeMirror <CodeMirror
mode="{component.type === 'js' ? 'javascript' : 'handlebars'}" mode="{$selected.type === 'js' ? 'javascript' : 'handlebars'}"
code={component.source} code={$selected.source}
{error} {error}
{errorLoc} {errorLoc}
{warningCount} {warningCount}

@ -2,8 +2,6 @@
import ComponentSelector from './ComponentSelector.svelte'; import ComponentSelector from './ComponentSelector.svelte';
import ModuleEditor from './ModuleEditor.svelte'; import ModuleEditor from './ModuleEditor.svelte';
export let selected_store;
export let component_store;
export let error; export let error;
export let errorLoc; export let errorLoc;
export let warningCount; export let warningCount;
@ -11,15 +9,12 @@
<!-- TODO would be nice if events bubbled --> <!-- TODO would be nice if events bubbled -->
<ComponentSelector <ComponentSelector
{component_store}
{selected_store}
on:create on:create
on:remove on:remove
on:select on:select
/> />
<ModuleEditor <ModuleEditor
component={$selected_store}
{error} {error}
{errorLoc} {errorLoc}
{warningCount} {warningCount}

@ -1,12 +1,12 @@
<script> <script>
import { onMount, onDestroy, createEventDispatcher } from 'svelte'; import { onMount, onDestroy, createEventDispatcher, getContext } from 'svelte';
import getLocationFromStack from './getLocationFromStack.js'; import getLocationFromStack from './getLocationFromStack.js';
import ReplProxy from './replProxy.js'; import ReplProxy from './replProxy.js';
import { decode } from 'sourcemap-codec'; import { decode } from 'sourcemap-codec';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
const { values } = getContext('REPL');
export let values_store;
export let bundle; export let bundle;
export let dom; export let dom;
export let ssr; export let ssr;
@ -79,7 +79,7 @@
replProxy.onPropUpdate = (prop, value) => { replProxy.onPropUpdate = (prop, value) => {
dispatch('binding', { prop, value }); dispatch('binding', { prop, value });
values_store.update(values => Object.assign({}, values, { values.update(values => Object.assign({}, values, {
[prop]: value [prop]: value
})); }));
}; };
@ -132,7 +132,7 @@
const createHtml = () => { const createHtml = () => {
replProxy.eval(`${ssr.code} replProxy.eval(`${ssr.code}
var rendered = SvelteComponent.render(${JSON.stringify($values_store)}); var rendered = SvelteComponent.render(${JSON.stringify($values)});
if (rendered.css.code) { if (rendered.css.code) {
var style = document.createElement('style'); var style = document.createElement('style');
@ -173,7 +173,7 @@
window.component = new SvelteComponent({ window.component = new SvelteComponent({
target: document.body, target: document.body,
props: ${JSON.stringify($values_store)} props: ${JSON.stringify($values)}
}); });
`) `)
.then(()=> { .then(()=> {

@ -1,11 +1,12 @@
<script> <script>
import { getContext } from 'svelte';
import SplitPane from '../SplitPane.svelte'; import SplitPane from '../SplitPane.svelte';
import Viewer from './Viewer.svelte'; import Viewer from './Viewer.svelte';
import CompilerOptions from './CompilerOptions.svelte'; import CompilerOptions from './CompilerOptions.svelte';
import PropEditor from './PropEditor.svelte'; import PropEditor from './PropEditor.svelte';
import CodeMirror from '../CodeMirror.svelte'; import CodeMirror from '../CodeMirror.svelte';
export let values_store; const { values } = getContext('REPL');
export let bundle; export let bundle;
export let js; export let js;
@ -28,7 +29,7 @@
let view = 'result'; let view = 'result';
function updateValues(prop, value) { function updateValues(prop, value) {
values_store.update(v => Object.assign({}, v, { values.update(v => Object.assign({}, v, {
[prop]: value [prop]: value
})); }));
} }
@ -130,7 +131,6 @@
{bundle} {bundle}
{dom} {dom}
{ssr} {ssr}
{values_store}
{props} {props}
{sourceError} {sourceError}
bind:error={runtimeError} bind:error={runtimeError}
@ -155,7 +155,7 @@
<!-- TODO `bind:this={propEditors[prop]}` — currently fails --> <!-- TODO `bind:this={propEditors[prop]}` — currently fails -->
<PropEditor <PropEditor
value={$values_store[prop]} value={$values[prop]}
on:change="{e => setPropFromEditor(prop, e.detail.value)}" on:change="{e => setPropFromEditor(prop, e.detail.value)}"
/> />
{/each} {/each}

@ -1,5 +1,5 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount, setContext } from 'svelte';
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
import * as fleece from 'golden-fleece'; import * as fleece from 'golden-fleece';
import SplitPane from './SplitPane.svelte'; import SplitPane from './SplitPane.svelte';
@ -16,26 +16,32 @@
export function toJSON() { export function toJSON() {
// TODO there's a bug here — Svelte hoists this function because // TODO there's a bug here — Svelte hoists this function because
// it wrongly things that $component_store is global. Needs to // it wrongly things that $components is global. Needs to
// factor in $ variables when determining hoistability // factor in $ variables when determining hoistability
version; // workaround version; // workaround
return { return {
imports: bundle && bundle.imports || [], imports: bundle && bundle.imports || [],
components: $component_store, components: $components,
values: $values_store values: $values
}; };
} }
let component_store = writable([]); const components = writable([]);
let values_store = writable({}); const values = writable({});
let selected_store = writable(null); const selected = writable(null);
setContext('REPL', {
components,
values,
selected
});
$: { $: {
component_store.set(app.components); components.set(app.components);
values_store.set(app.values); values.set(app.values);
selected_store.set(app.components[0]); selected.set(app.components[0]);
} }
let workers; let workers;
@ -93,23 +99,19 @@
}); });
function removeComponent() { function removeComponent() {
const selected = $selected_store; if ($selected.name === 'App') {
if (selected.name === 'App') {
// App.svelte can't be removed // App.svelte can't be removed
selected.source = ''; $selected.source = '';
// $selected_store.set(selected);
} else { } else {
const components = $component_store; const index = $components.indexOf($selected);
const index = components.indexOf(selected);
if (~index) { if (~index) {
component_store.set(components.slice(0, index).concat(components.slice(index + 1))); components.set($components.slice(0, index).concat($components.slice(index + 1)));
} else { } else {
console.error(`Could not find component! That's... odd`); console.error(`Could not find component! That's... odd`);
} }
selected_store.set(components[index] || components[components.length - 1]); selected.set($components[index] || $components[$components.length - 1]);
} }
} }
@ -122,7 +124,7 @@
name: component.name, name: component.name,
filename: `${component.name}.svelte` filename: `${component.name}.svelte`
}, options), }, options),
entry: component === $component_store[0] entry: component === $components[0]
}); });
} else { } else {
js = css = `/* Select a component to see its compiled code */`; js = css = `/* Select a component to see its compiled code */`;
@ -130,9 +132,9 @@
} }
function handleChange(event) { function handleChange(event) {
selected_store.update(component => { selected.update(component => {
// TODO this is a bit hacky — we're relying on mutability // TODO this is a bit hacky — we're relying on mutability
// so that updating component_store works... might be better // so that updating components works... might be better
// if a) components had unique IDs, b) we tracked selected // if a) components had unique IDs, b) we tracked selected
// *index* rather than component, and c) `selected` was // *index* rather than component, and c) `selected` was
// derived from `components` and `index` // derived from `components` and `index`
@ -140,13 +142,13 @@
return component; return component;
}); });
component_store.update(c => c); components.update(c => c);
// recompile selected component // recompile selected component
compile($selected_store, compileOptions); compile($selected, compileOptions);
// regenerate bundle (TODO do this in a separate worker?) // regenerate bundle (TODO do this in a separate worker?)
workers.bundler.postMessage({ type: 'bundle', components: $component_store }); workers.bundler.postMessage({ type: 'bundle', components: $components });
} }
function navigate(filename) { function navigate(filename) {
@ -158,14 +160,14 @@
// selected = components.find(c => c.name === name); // selected = components.find(c => c.name === name);
} }
$: if (sourceError && $selected_store) { $: if (sourceError && $selected) {
sourceErrorLoc = sourceError.filename === `${$selected_store.name}.${$selected_store.type}` sourceErrorLoc = sourceError.filename === `${$selected.name}.${$selected.type}`
? sourceError.start ? sourceError.start
: null; : null;
} }
$: if (runtimeError && $selected_store) { $: if (runtimeError && $selected) {
runtimeErrorLoc = runtimeError.filename === `${$selected_store.name}.${$selected_store.type}` runtimeErrorLoc = runtimeError.filename === `${$selected.name}.${$selected.type}`
? runtimeError.start ? runtimeError.start
: null; : null;
} }
@ -174,8 +176,8 @@
workers.bundler.postMessage({ type: 'bundle', components: app.components }); workers.bundler.postMessage({ type: 'bundle', components: app.components });
} }
$: if (workers && $selected_store) { $: if (workers && $selected) {
compile($selected_store, compileOptions); compile($selected, compileOptions);
} }
</script> </script>
@ -287,9 +289,6 @@
> >
<section slot=a> <section slot=a>
<Input <Input
{component_store}
{selected_store}
{values_store}
error={sourceError} error={sourceError}
errorLoc="{sourceErrorLoc || runtimeErrorLoc}" errorLoc="{sourceErrorLoc || runtimeErrorLoc}"
{warningCount} {warningCount}
@ -302,14 +301,12 @@
<Output <Output
bind:compileOptions bind:compileOptions
{version} {version}
{selected_store}
{js} {js}
{css} {css}
{bundle} {bundle}
{ssr} {ssr}
{dom} {dom}
{props} {props}
{values_store}
{sourceError} {sourceError}
{runtimeError} {runtimeError}
{embedded} {embedded}

Loading…
Cancel
Save