implement context API

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

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

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

@ -4,20 +4,25 @@ export function set_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) {
current_component.$$.before_render.push(fn);
get_current_component().$$.before_render.push(fn);
}
export function onMount(fn) {
current_component.$$.on_mount.push(fn);
get_current_component().$$.on_mount.push(fn);
}
export function afterUpdate(fn) {
current_component.$$.after_render.push(fn);
get_current_component().$$.after_render.push(fn);
}
export function onDestroy(fn) {
current_component.$$.on_destroy.push(fn);
get_current_component().$$.on_destroy.push(fn);
}
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
// shorthand events, or if we want to implement
// a real bubbling mechanism

@ -1,4 +1,5 @@
import { run_all } from './utils.js';
import { set_current_component } from './lifecycle.js';
export let dirty_components = [];
export const intros = { enabled: false };
@ -34,7 +35,9 @@ export function flush() {
// first, call beforeUpdate functions
// and update components
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()();

@ -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';
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) {
return {
render: (props = {}, options = {}) => {
const parent_component = current_component;
// TODO do we need on_ready, since on_mount,
// before_render and after_render don't run?
const $$ = {
@ -75,6 +77,7 @@ export function create_ssr_component($$render) {
on_destroy: [],
before_render: [],
after_render: [],
context: new Map(parent_component ? parent_component.$$.context : []),
callbacks: blankObject()
};

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

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

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

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

Loading…
Cancel
Save