implement context API

pull/1998/head
Richard Harris 7 years ago
parent 9cfe0593d4
commit d4036ada85

@ -3,6 +3,8 @@ export {
onDestroy, onDestroy,
beforeUpdate, beforeUpdate,
afterUpdate, afterUpdate,
setContext,
getContext,
nextTick, nextTick,
createEventDispatcher createEventDispatcher
} from './internal'; } from './internal';

@ -54,7 +54,7 @@ function make_dirty(component, key) {
} }
export function init(component, options, instance, create_fragment, not_equal) { export function init(component, options, instance, create_fragment, not_equal) {
const previous_component = current_component; const parent_component = current_component;
set_current_component(component); set_current_component(component);
const props = options.props || {}; const props = options.props || {};
@ -64,7 +64,6 @@ export function init(component, options, instance, create_fragment, not_equal) {
ctx: null, ctx: null,
// state // state
set: noop,
update: noop, update: noop,
not_equal, not_equal,
bound: blankObject(), bound: blankObject(),
@ -74,6 +73,7 @@ export function init(component, options, instance, create_fragment, not_equal) {
on_destroy: [], on_destroy: [],
before_render: [], before_render: [],
after_render: [], after_render: [],
context: new Map(parent_component ? parent_component.$$.context : []),
// everything else // everything else
callbacks: blankObject(), callbacks: blankObject(),
@ -115,7 +115,7 @@ export function init(component, options, instance, create_fragment, not_equal) {
flush(); flush();
} }
set_current_component(previous_component); set_current_component(parent_component);
} }
export let SvelteElement; export let SvelteElement;

@ -4,20 +4,25 @@ export function set_current_component(component) {
current_component = component; current_component = component;
} }
function get_current_component() {
if (!current_component) throw new Error(`Function called outside component initialization`);
return current_component;
}
export function beforeUpdate(fn) { export function beforeUpdate(fn) {
current_component.$$.before_render.push(fn); get_current_component().$$.before_render.push(fn);
} }
export function onMount(fn) { export function onMount(fn) {
current_component.$$.on_mount.push(fn); get_current_component().$$.on_mount.push(fn);
} }
export function afterUpdate(fn) { export function afterUpdate(fn) {
current_component.$$.after_render.push(fn); get_current_component().$$.after_render.push(fn);
} }
export function onDestroy(fn) { export function onDestroy(fn) {
current_component.$$.on_destroy.push(fn); get_current_component().$$.on_destroy.push(fn);
} }
export function createEventDispatcher() { export function createEventDispatcher() {
@ -37,6 +42,14 @@ export function createEventDispatcher() {
}; };
} }
export function setContext(key, context) {
get_current_component().$$.context.set(key, context);
}
export function getContext(key) {
return get_current_component().$$.context.get(key);
}
// TODO figure out if we still want to support // TODO figure out if we still want to support
// shorthand events, or if we want to implement // shorthand events, or if we want to implement
// a real bubbling mechanism // a real bubbling mechanism

@ -1,4 +1,5 @@
import { run_all } from './utils.js'; import { run_all } from './utils.js';
import { set_current_component } from './lifecycle.js';
export let dirty_components = []; export let dirty_components = [];
export const intros = { enabled: false }; export const intros = { enabled: false };
@ -34,7 +35,9 @@ export function flush() {
// first, call beforeUpdate functions // first, call beforeUpdate functions
// and update components // and update components
while (dirty_components.length) { while (dirty_components.length) {
update(dirty_components.shift().$$); const component = dirty_components.shift();
set_current_component(component);
update(component.$$);
} }
while (binding_callbacks.length) binding_callbacks.shift()(); while (binding_callbacks.length) binding_callbacks.shift()();

@ -1,4 +1,4 @@
import { set_current_component } from './lifecycle.js'; import { set_current_component, current_component } from './lifecycle.js';
import { run_all, blankObject } from './utils.js'; import { run_all, blankObject } from './utils.js';
export const invalidAttributeNameCharacter = /[\s'">\/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; export const invalidAttributeNameCharacter = /[\s'">\/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u;
@ -68,6 +68,8 @@ export function debug(file, line, column, values) {
export function create_ssr_component($$render) { export function create_ssr_component($$render) {
return { return {
render: (props = {}, options = {}) => { render: (props = {}, options = {}) => {
const parent_component = current_component;
// TODO do we need on_ready, since on_mount, // TODO do we need on_ready, since on_mount,
// before_render and after_render don't run? // before_render and after_render don't run?
const $$ = { const $$ = {
@ -75,6 +77,7 @@ export function create_ssr_component($$render) {
on_destroy: [], on_destroy: [],
before_render: [], before_render: [],
after_render: [], after_render: [],
context: new Map(parent_component ? parent_component.$$.context : []),
callbacks: blankObject() callbacks: blankObject()
}; };

@ -12,6 +12,6 @@
}); });
</script> </script>
<button class:selected={$selectedTab} on:click="{() => selectTab(tab)}"> <button class:selected="{$selectedTab === tab}" on:click="{() => selectTab(tab)}">
<slot></slot> <slot></slot>
</button> </button>

@ -11,6 +11,6 @@
}); });
</script> </script>
{#if $selected === panel} {#if $selectedPanel === panel}
<slot></slot> <slot></slot>
{/if} {/if}

@ -10,36 +10,40 @@
const tabs = []; const tabs = [];
const panels = []; const panels = [];
const selected = writable(null); const selectedTab = writable(null);
const selectedPanel = writable(null);
setContext(TABS, { setContext(TABS, {
registerTab: tab => { registerTab: tab => {
tabs.push(tab); tabs.push(tab);
selectedTab.update(current => current || tab);
}, },
unregisterTab: tab => { unregisterTab: tab => {
const i = tabs.indexOf(tab); const i = tabs.indexOf(tab);
tabs.splice(i, 1); tabs.splice(i, 1);
selectedTab.update(current => current === tab ? (tabs[i] || tabs[tabs.length - 1]) : current);
}, },
registerPanel: panel => { registerPanel: panel => {
panels.push(panel); panels.push(panel);
selectedPanel.update(current => current || panel);
// if this is the first panel, select it
selected.update(current => current || panel);
}, },
unregisterPanel: panel => { unregisterPanel: panel => {
const i = panels.indexOf(panel); const i = panels.indexOf(panel);
panels.splice(i, 1); panels.splice(i, 1);
selectedPanel.update(current => current === panel ? (panels[i] || panels[panels.length - 1]) : current);
}, },
selectTab: tab => { selectTab: tab => {
const i = tabs.indexOf(tab); const i = tabs.indexOf(tab);
selected.set(panels[i]); selectedTab.set(tab);
selectedPanel.set(panels[i]);
}, },
selected selectedTab,
selectedPanel
}); });
</script> </script>

@ -19,7 +19,7 @@ export default {
assert.htmlEqual(target.innerHTML, ` assert.htmlEqual(target.innerHTML, `
<div class="tabs"> <div class="tabs">
<div class="tab-list"> <div class="tab-list">
<button>small</button> <button class="">small</button>
<button class="selected">large</button> <button class="selected">large</button>
</div> </div>
@ -32,7 +32,7 @@ export default {
assert.htmlEqual(target.innerHTML, ` assert.htmlEqual(target.innerHTML, `
<div class="tabs"> <div class="tabs">
<div class="tab-list"> <div class="tab-list">
<button>small</button> <button class="">small</button>
<button>medium</button> <button>medium</button>
<button class="selected">large</button> <button class="selected">large</button>
</div> </div>
@ -48,9 +48,9 @@ export default {
assert.htmlEqual(target.innerHTML, ` assert.htmlEqual(target.innerHTML, `
<div class="tabs"> <div class="tabs">
<div class="tab-list"> <div class="tab-list">
<button>small</button> <button class="">small</button>
<button class="selected">medium</button> <button class="selected">medium</button>
<button>large</button> <button class="">large</button>
</div> </div>
<h2>Medium panel</h2> <h2>Medium panel</h2>
@ -62,7 +62,7 @@ export default {
assert.htmlEqual(target.innerHTML, ` assert.htmlEqual(target.innerHTML, `
<div class="tabs"> <div class="tabs">
<div class="tab-list"> <div class="tab-list">
<button>small</button> <button class="">small</button>
<button class="selected">large</button> <button class="selected">large</button>
</div> </div>

Loading…
Cancel
Save