neaten things up a bit (gets us closer to supporting custom elements again)

pull/1864/head
Rich Harris 7 years ago
parent 97b0fb6e61
commit 0019873dfb

@ -658,10 +658,10 @@ export default class Element extends Node {
const slot = this.attributes.find(attribute => attribute.name === 'slot'); const slot = this.attributes.find(attribute => attribute.name === 'slot');
if (slot) { if (slot) {
const prop = quotePropIfNecessary(slot.chunks[0].data); const prop = quotePropIfNecessary(slot.chunks[0].data);
return `@append(${name}.$$slotted${prop}, ${this.var});`; return `@append(${name}.$$.slotted${prop}, ${this.var});`;
} }
return `@append(${name}.$$slotted.default, ${this.var});`; return `@append(${name}.$$.slotted.default, ${this.var});`;
} }
addCssClass(className = this.component.stylesheet.id) { addCssClass(className = this.component.stylesheet.id) {

@ -1,8 +1,5 @@
import Node from './shared/Node'; import Node from './shared/Node';
import Expression from './shared/Expression'; import Expression from './shared/Expression';
import flattenReference from '../../utils/flattenReference';
import { createScopes } from '../../utils/annotateWithScopes';
import { walk } from 'estree-walker';
import Component from '../Component'; import Component from '../Component';
import deindent from '../../utils/deindent'; import deindent from '../../utils/deindent';

@ -51,7 +51,7 @@ export default class Node {
} }
remount(name: string) { remount(name: string) {
return `${this.var}.m(${name}.$$slotted.default, null);`; return `${this.var}.m(${name}.$$.slotted.default, null);`;
} }
warnIfEmptyBlock() { warnIfEmptyBlock() {

@ -72,35 +72,19 @@ export default function dom(
return ${JSON.stringify(props)}; return ${JSON.stringify(props)};
} }
${props.map(prop => deindent`
get ${prop}() {
return this.get().${prop};
}
set ${prop}(value) {
this.set({ ${prop}: value });
}
`).join('\n\n')}
${renderer.slots.size && deindent` ${renderer.slots.size && deindent`
connectedCallback() { connectedCallback() {
Object.keys(this.$$slotted).forEach(key => { Object.keys(this.$$.slotted).forEach(key => {
this.appendChild(this.$$slotted[key]); this.appendChild(this.$$.slotted[key]);
}); });
}`} }`}
attributeChangedCallback(attr, oldValue, newValue) { attributeChangedCallback(attr, oldValue, newValue) {
this.set({ [attr]: newValue }); this[attr] = newValue;
} }
${(component.hasComponents || renderer.hasComplexBindings || templateProperties.oncreate || renderer.hasIntroTransitions) && deindent`
connectedCallback() {
@flush(this);
}
`}
} }
customElements.define("${component.tag}", ${name}); customElements.define("${component.customElement.tag}", ${name});
`); `);
} else { } else {
const refs = Array.from(component.refs); const refs = Array.from(component.refs);
@ -123,7 +107,7 @@ export default function dom(
const props = component.exports.filter(x => component.writable_declarations.has(x.name)); const props = component.exports.filter(x => component.writable_declarations.has(x.name));
const inject_props = component.meta.props || props.length > 0 const set = component.meta.props || props.length > 0
? deindent` ? deindent`
$$props => { $$props => {
${component.meta.props && deindent` ${component.meta.props && deindent`
@ -135,7 +119,7 @@ export default function dom(
`if ('${prop.as}' in $$props) ${prop.name} = $$props.${prop.as};`)} `if ('${prop.as}' in $$props) ${prop.name} = $$props.${prop.as};`)}
} }
` `
: `@noop`; : null;
const inject_refs = refs.length > 0 const inject_refs = refs.length > 0
? deindent` ? deindent`
@ -143,7 +127,7 @@ export default function dom(
${refs.map(name => `${name} = $$refs.${name};`)} ${refs.map(name => `${name} = $$refs.${name};`)}
} }
` `
: `@noop`; : null;
const body = []; const body = [];
@ -160,7 +144,7 @@ export default function dom(
if (expected.length) { if (expected.length) {
body.push(deindent` body.push(deindent`
$$checkProps() { $$checkProps() {
const state = this.$$.get_state(); const state = this.$$.get();
${expected.map(name => deindent` ${expected.map(name => deindent`
if (state.${name} === undefined) { if (state.${name} === undefined) {
@ -175,7 +159,7 @@ export default function dom(
component.exports.forEach(x => { component.exports.forEach(x => {
body.push(deindent` body.push(deindent`
get ${x.as}() { get ${x.as}() {
return this.$$.get_state().${x.name}; return this.$$.get().${x.name};
} }
`); `);
@ -212,12 +196,12 @@ export default function dom(
${component.partly_hoisted.length > 0 && component.partly_hoisted.join('\n\n')} ${component.partly_hoisted.length > 0 && component.partly_hoisted.join('\n\n')}
return [ // TODO only what's needed by the template
// TODO only what's needed by the template $$self.$$.get = () => ({ ${component.declarations.join(', ')} });
() => ({ ${component.declarations.join(', ')} }),
${inject_props}, ${set && `$$self.$$.set = ${set};`}
${inject_refs}
]; ${inject_refs && `$$self.$$.inject_refs = ${inject_refs};`}
} }
class ${name} extends ${superclass} { class ${name} extends ${superclass} {

@ -515,6 +515,6 @@ export default class EachBlockWrapper extends Wrapper {
remount(name: string) { remount(name: string) {
// TODO consider keyed blocks // TODO consider keyed blocks
return `for (var #i = 0; #i < ${this.vars.iterations}.length; #i += 1) ${this.vars.iterations}[#i].m(${name}.$$slotted.default, null);`; return `for (var #i = 0; #i < ${this.vars.iterations}.length; #i += 1) ${this.vars.iterations}[#i].m(${name}.$$.slotted.default, null);`;
} }
} }

@ -110,11 +110,11 @@ export default class BindingWrapper {
const bindingGroup = getBindingGroup(renderer, this.node.expression.node); const bindingGroup = getBindingGroup(renderer, this.node.expression.node);
block.builders.hydrate.addLine( block.builders.hydrate.addLine(
`(#component.$$bindingGroups[${bindingGroup}] || (#component.$$bindingGroups[${bindingGroup}] = [])).push(${parent.var});` `(#component.$$.binding_groups[${bindingGroup}] || (#component.$$.binding_groups[${bindingGroup}] = [])).push(${parent.var});`
); );
block.builders.destroy.addLine( block.builders.destroy.addLine(
`#component.$$bindingGroups[${bindingGroup}].splice(#component.$$bindingGroups[${bindingGroup}].indexOf(${parent.var}), 1);` `#component.$$.binding_groups[${bindingGroup}].splice(#component.$$.binding_groups[${bindingGroup}].indexOf(${parent.var}), 1);`
); );
} }
@ -273,7 +273,7 @@ function getValueFromDom(
const bindingGroup = getBindingGroup(renderer, binding.node.expression.node); const bindingGroup = getBindingGroup(renderer, binding.node.expression.node);
if (type === 'checkbox') { if (type === 'checkbox') {
renderer.component.init_uses_self = true; renderer.component.init_uses_self = true;
return `@getBindingGroupValue($$self.$$bindingGroups[${bindingGroup}])`; return `@getBindingGroupValue($$self.$$.binding_groups[${bindingGroup}])`;
} }
return `this.__value`; return `this.__value`;

@ -216,7 +216,7 @@ export default class ElementWrapper extends Wrapper {
let initialMountNode; let initialMountNode;
if (this.slotOwner) { if (this.slotOwner) {
initialMountNode = `${this.slotOwner.var}.$$slotted${prop}`; initialMountNode = `${this.slotOwner.var}.$$.slotted${prop}`;
} else { } else {
initialMountNode = parentNode; initialMountNode = parentNode;
} }
@ -635,7 +635,7 @@ export default class ElementWrapper extends Wrapper {
} }
addRef(block: Block) { addRef(block: Block) {
const ref = `#component.$$refs.${this.node.ref.name}`; const ref = `#component.$$.refs.${this.node.ref.name}`;
block.builders.mount.addLine( block.builders.mount.addLine(
`${ref} = ${this.var};` `${ref} = ${this.var};`
@ -644,7 +644,7 @@ export default class ElementWrapper extends Wrapper {
block.builders.destroy.addLine( block.builders.destroy.addLine(
`if (${ref} === ${this.var}) { `if (${ref} === ${this.var}) {
${ref} = null; ${ref} = null;
#component.$$.inject_refs(#component.$$refs); #component.$$.inject_refs(#component.$$.refs);
}` }`
); );
} }
@ -817,10 +817,10 @@ export default class ElementWrapper extends Wrapper {
const slot = this.attributes.find(attribute => attribute.node.name === 'slot'); const slot = this.attributes.find(attribute => attribute.node.name === 'slot');
if (slot) { if (slot) {
const prop = quotePropIfNecessary(slot.node.chunks[0].data); const prop = quotePropIfNecessary(slot.node.chunks[0].data);
return `@append(${name}.$$slotted${prop}, ${this.var});`; return `@append(${name}.$$.slotted${prop}, ${this.var});`;
} }
return `@append(${name}.$$slotted.default, ${this.var});`; return `@append(${name}.$$.slotted.default, ${this.var});`;
} }
addCssClass(className = this.component.stylesheet.id) { addCssClass(className = this.component.stylesheet.id) {

@ -88,7 +88,7 @@ export default class InlineComponentWrapper extends Wrapper {
componentInitProperties.push(`slots: { ${slots.join(', ')} }`); componentInitProperties.push(`slots: { ${slots.join(', ')} }`);
this.fragment.nodes.forEach((child: Wrapper) => { this.fragment.nodes.forEach((child: Wrapper) => {
child.render(block, `${this.var}.$$slotted.default`, 'nodes'); child.render(block, `${this.var}.$$.slotted.default`, 'nodes');
}); });
} }
@ -257,7 +257,7 @@ export default class InlineComponentWrapper extends Wrapper {
component.partly_hoisted.push(body); component.partly_hoisted.push(body);
return `@add_binding_callback(() => ${this.var}.$$bind('${binding.name}', ${name}));`; return `@add_binding_callback(() => @bind(${this.var}, '${binding.name}', ${name}));`;
}); });
const munged_handlers = this.node.handlers.map(handler => { const munged_handlers = this.node.handlers.map(handler => {
@ -297,19 +297,19 @@ export default class InlineComponentWrapper extends Wrapper {
`); `);
block.builders.create.addLine( block.builders.create.addLine(
`if (${name}) ${name}.$$fragment.c();` `if (${name}) ${name}.$$.fragment.c();`
); );
if (parentNodes && this.renderer.options.hydratable) { if (parentNodes && this.renderer.options.hydratable) {
block.builders.claim.addLine( block.builders.claim.addLine(
`if (${name}) ${name}.$$fragment.l(${parentNodes});` `if (${name}) ${name}.$$.fragment.l(${parentNodes});`
); );
} }
block.builders.mount.addBlock(deindent` block.builders.mount.addBlock(deindent`
if (${name}) { if (${name}) {
${name}.$$mount(${parentNode || '#target'}, ${parentNode ? 'null' : 'anchor'}); @mount_component(${name}, ${parentNode || '#target'}, ${parentNode ? 'null' : 'anchor'});
${this.node.ref && `#component.$$refs.${this.node.ref.name} = ${name};`} ${this.node.ref && `#component.$$.refs.${this.node.ref.name} = ${name};`}
} }
`); `);
@ -327,7 +327,7 @@ export default class InlineComponentWrapper extends Wrapper {
if (${name}) { if (${name}) {
@groupOutros(); @groupOutros();
const old_component = ${name}; const old_component = ${name};
old_component.$$fragment.o(() => { old_component.$$.fragment.o(() => {
old_component.$destroy(); old_component.$destroy();
}); });
} }
@ -339,19 +339,19 @@ export default class InlineComponentWrapper extends Wrapper {
${munged_handlers} ${munged_handlers}
${this.fragment && this.fragment.nodes.map(child => child.remount(name))} ${this.fragment && this.fragment.nodes.map(child => child.remount(name))}
${name}.$$mount(${updateMountNode}, ${anchor}); @mount_component(${name}, ${updateMountNode}, ${anchor});
${this.node.handlers.map(handler => deindent` ${this.node.handlers.map(handler => deindent`
${name}.$on("${handler.name}", ${handler.var}); ${name}.$on("${handler.name}", ${handler.var});
`)} `)}
${this.node.ref && `#component.$$refs.${this.node.ref.name} = ${name};`} ${this.node.ref && `#component.$$.refs.${this.node.ref.name} = ${name};`}
} else { } else {
${name} = null; ${name} = null;
${this.node.ref && deindent` ${this.node.ref && deindent`
if (#component.$$refs.${this.node.ref.name} === ${name}) { if (#component.$$.refs.${this.node.ref.name} === ${name}) {
#component.$$refs.${this.node.ref.name} = null; #component.$$.refs.${this.node.ref.name} = null;
#component.$$.inject_refs(#component.$$refs); #component.$$.inject_refs(#component.$$.refs);
}`} }`}
} }
} }
@ -384,19 +384,19 @@ export default class InlineComponentWrapper extends Wrapper {
${munged_bindings} ${munged_bindings}
${munged_handlers} ${munged_handlers}
${this.node.ref && `#component.$$refs.${this.node.ref.name} = ${name};`} ${this.node.ref && `#component.$$.refs.${this.node.ref.name} = ${name};`}
`); `);
block.builders.create.addLine(`${name}.$$fragment.c();`); block.builders.create.addLine(`${name}.$$.fragment.c();`);
if (parentNodes && this.renderer.options.hydratable) { if (parentNodes && this.renderer.options.hydratable) {
block.builders.claim.addLine( block.builders.claim.addLine(
`${name}.$$fragment.l(${parentNodes});` `${name}.$$.fragment.l(${parentNodes});`
); );
} }
block.builders.mount.addLine( block.builders.mount.addLine(
`${name}.$$mount(${parentNode || '#target'}, ${parentNode ? 'null' : 'anchor'});` `@mount_component(${name}, ${parentNode || '#target'}, ${parentNode ? 'null' : 'anchor'});`
); );
if (updates.length) { if (updates.length) {
@ -410,21 +410,21 @@ export default class InlineComponentWrapper extends Wrapper {
block.builders.destroy.addBlock(deindent` block.builders.destroy.addBlock(deindent`
${name}.$destroy(${parentNode ? '' : 'detach'}); ${name}.$destroy(${parentNode ? '' : 'detach'});
${this.node.ref && deindent` ${this.node.ref && deindent`
if (#component.$$refs.${this.node.ref.name} === ${name}) { if (#component.$$.refs.${this.node.ref.name} === ${name}) {
#component.$$refs.${this.node.ref.name} = null; #component.$$.refs.${this.node.ref.name} = null;
#component.$$.inject_refs(#component.$$refs); #component.$$.inject_refs(#component.$$.refs);
} }
`} `}
`); `);
} }
block.builders.outro.addLine( block.builders.outro.addLine(
`if (${name}) ${name}.$$fragment.o(#outrocallback);` `if (${name}) ${name}.$$.fragment.o(#outrocallback);`
); );
} }
remount(name: string) { remount(name: string) {
return `${this.var}.$$fragment.m(${name}.$$slotted.default, null);`; return `${this.var}.$$.fragment.m(${name}.$$.slotted.default, null);`;
} }
} }

@ -46,7 +46,7 @@ export default class SlotWrapper extends Wrapper {
const content_name = block.getUniqueName(`slot_content_${sanitize(slotName)}`); const content_name = block.getUniqueName(`slot_content_${sanitize(slotName)}`);
const prop = quotePropIfNecessary(slotName); const prop = quotePropIfNecessary(slotName);
block.addVariable(content_name, `#component.$$slotted${prop}`); block.addVariable(content_name, `#component.$$.slotted${prop}`);
// TODO can we use isDomNode instead of type === 'Element'? // TODO can we use isDomNode instead of type === 'Element'?
const needsAnchorBefore = this.prev ? this.prev.node.type !== 'Element' : !parentNode; const needsAnchorBefore = this.prev ? this.prev.node.type !== 'Element' : !parentNode;
@ -104,7 +104,7 @@ export default class SlotWrapper extends Wrapper {
// if the slot is unmounted, move nodes back into the document fragment, // if the slot is unmounted, move nodes back into the document fragment,
// so that it can be reinserted later // so that it can be reinserted later
// TODO so that this can work with public API, component.$$slotted should // TODO so that this can work with public API, component.$$.slotted should
// be all fragments, derived from options.slots. Not === options.slots // be all fragments, derived from options.slots. Not === options.slots
const unmountLeadin = block.builders.destroy.toString() !== destroyBefore const unmountLeadin = block.builders.destroy.toString() !== destroyBefore
? `else` ? `else`

@ -62,6 +62,6 @@ export default class TextWrapper extends Wrapper {
} }
remount(name: string) { remount(name: string) {
return `@append(${name}.$$slotted.default, ${this.var});`; return `@append(${name}.$$.slotted.default, ${this.var});`;
} }
} }

@ -52,6 +52,6 @@ export default class Tag extends Wrapper {
} }
remount(name: string) { remount(name: string) {
return `@append(${name}.$$slotted.default, ${this.var});`; return `@append(${name}.$$.slotted.default, ${this.var});`;
} }
} }

@ -87,6 +87,6 @@ export default class Wrapper {
} }
remount(name: string) { remount(name: string) {
return `${this.var}.m(${name}.$$slotted.default, null);`; return `${this.var}.m(${name}.$$.slotted.default, null);`;
} }
} }

@ -1,59 +1,121 @@
import { add_render_callback, flush, intro, schedule_update } from './scheduler.js'; import { add_render_callback, flush, intro, schedule_update } from './scheduler.js';
import { set_current_component } from './lifecycle.js' import { current_component, set_current_component } from './lifecycle.js'
import { is_function, run, run_all, noop } from './utils.js'; import { is_function, run, run_all, noop } from './utils.js';
import { blankObject } from './utils.js'; import { blankObject } from './utils.js';
import { children } from './dom.js'; import { children } from './dom.js';
export class $$Component { export function bind(component, name, callback) {
constructor(options, init, create_fragment, not_equal) { component.$$.bound[name] = callback;
this.$$beforeRender = []; callback(component.$$.get()[name]);
this.$$onMount = []; }
this.$$afterRender = [];
this.$$onDestroy = [];
this.$$bindings = blankObject(); export function mount_component({ $$: { fragment }}, target, anchor, hydrate) {
this.$$callbacks = blankObject(); if (hydrate) {
this.$$slotted = options.slots || {}; fragment.l(children(target));
fragment.m(target, anchor); // TODO can we avoid moving DOM?
} else {
fragment.c();
fragment[fragment.i ? 'i' : 'm'](target, anchor);
}
set_current_component(this); component.$$.inject_refs(component.$$.refs);
const [get_state, inject_props, inject_refs] = init(
this,
key => {
this.$$make_dirty(key);
if (this.$$bindings[key]) this.$$bindings[key](get_state()[key]);
}
);
this.$$ = { get_state, inject_props, inject_refs, not_equal }; // onMount happens after the initial afterRender. Because
// afterRender callbacks happen in reverse order (inner first)
// we schedule onMount callbacks before afterRender callbacks
add_render_callback(() => {
const onDestroy = component.$$.on_mount.map(run).filter(is_function);
if (component.$$.on_destroy) {
component.$$.on_destroy.push(...onDestroy);
} else {
// Edge case — component was destroyed immediately,
// most likely as a result of a binding initialising
run_all(onDestroy);
}
component.$$.on_mount = [];
});
component.$$.after_render.forEach(add_render_callback);
}
this.$$refs = {}; function destroy(component, detach) {
if (component.$$) {
run_all(component.$$.on_destroy);
component.$$.fragment.d(detach);
this.$$dirty = null; // TODO null out other refs, including component.$$ (but need to
this.$$bindingGroups = []; // TODO find a way to not have this here? // preserve final state?)
component.$$.on_destroy = component.$$.fragment = null;
component.$$.get = () => ({});
}
}
function make_dirty(component, key) {
if (!component.$$.dirty) {
schedule_update(component);
component.$$.dirty = {};
}
component.$$.dirty[key] = true;
}
export class $$Component {
constructor(options, init, create_fragment, not_equal) {
const previous_component = current_component;
set_current_component(this);
this.$$ = {
fragment: null,
// state
get: null,
set: noop,
inject_refs: noop,
not_equal,
bound: blankObject(),
// lifecycle
on_mount: [],
on_destroy: [],
before_render: [],
after_render: [],
// everything else
callbacks: blankObject(),
slotted: options.slots || {},
refs: {},
dirty: null,
binding_groups: []
};
init(this, key => {
make_dirty(this, key);
if (this.$$.bound[key]) this.$$.bound[key](this.$$.get()[key]);
});
if (options.props) { if (options.props) {
this.$$.inject_props(options.props); this.$$.set(options.props);
} }
run_all(this.$$beforeRender); run_all(this.$$.before_render);
this.$$fragment = create_fragment(this, this.$$.get_state()); this.$$.fragment = create_fragment(this, this.$$.get());
if (options.target) { if (options.target) {
intro.enabled = !!options.intro; intro.enabled = !!options.intro;
this.$$mount(options.target, options.anchor, options.hydrate); mount_component(this, options.target, options.anchor, options.hydrate);
flush(); flush();
intro.enabled = true; intro.enabled = true;
} }
set_current_component(previous_component);
} }
$destroy() { $destroy() {
this.$$destroy(true); destroy(this, true);
this.$$update = this.$$destroy = noop; this.$destroy = noop;
} }
$on(type, callback) { $on(type, callback) {
const callbacks = (this.$$callbacks[type] || (this.$$callbacks[type] = [])); const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
callbacks.push(callback); callbacks.push(callback);
return () => { return () => {
@ -64,76 +126,13 @@ export class $$Component {
$set(values) { $set(values) {
if (this.$$) { if (this.$$) {
const state = this.$$.get_state(); const state = this.$$.get();
this.$$.inject_props(values); this.$$.set(values);
for (const key in values) { for (const key in values) {
if (this.$$.not_equal(state[key], values[key])) this.$$make_dirty(key); if (this.$$.not_equal(state[key], values[key])) make_dirty(this, key);
} }
} }
} }
$$bind(name, callback) {
this.$$bindings[name] = callback;
callback(this.$$.get_state()[name]);
}
$$destroy(detach) {
if (this.$$) {
run_all(this.$$onDestroy);
this.$$fragment.d(detach);
// TODO null out other refs, including this.$$ (but need to
// preserve final state?)
this.$$onDestroy = this.$$fragment = null;
this.$$.get_state = () => ({});
}
}
$$make_dirty(key) {
if (!this.$$dirty) {
schedule_update(this);
this.$$dirty = {};
}
this.$$dirty[key] = true;
}
$$mount(target, anchor, hydrate) {
if (hydrate) {
this.$$fragment.l(children(target));
this.$$fragment.m(target, anchor); // TODO can we avoid moving DOM?
} else {
this.$$fragment.c();
this.$$fragment[this.$$fragment.i ? 'i' : 'm'](target, anchor);
}
this.$$.inject_refs(this.$$refs);
// onMount happens after the initial afterRender. Because
// afterRender callbacks happen in reverse order (inner first)
// we schedule onMount callbacks before afterRender callbacks
add_render_callback(() => {
const onDestroy = this.$$onMount.map(run).filter(is_function);
if (this.$$onDestroy) {
this.$$onDestroy.push(...onDestroy);
} else {
// Edge case — component was destroyed immediately,
// most likely as a result of a binding initialising
run_all(onDestroy);
}
this.$$onMount = [];
});
this.$$afterRender.forEach(add_render_callback);
}
$$update() {
run_all(this.$$beforeRender);
this.$$fragment.p(this.$$dirty, this.$$.get_state());
this.$$.inject_refs(this.$$refs);
this.$$dirty = null;
this.$$afterRender.forEach(add_render_callback);
}
} }
export class $$ComponentDev extends $$Component { export class $$ComponentDev extends $$Component {
@ -148,7 +147,7 @@ export class $$ComponentDev extends $$Component {
$destroy() { $destroy() {
super.$destroy(); super.$destroy();
this.$$destroy = () => { this.$destroy = () => {
console.warn(`Component was already destroyed`); console.warn(`Component was already destroyed`);
}; };
} }

@ -32,8 +32,8 @@ export function handlePromise(promise, info) {
block[block.i ? 'i' : 'm'](info.mount(), info.anchor); block[block.i ? 'i' : 'm'](info.mount(), info.anchor);
// TODO is some of this redundant? // TODO is some of this redundant?
info.component.$$.inject_refs(info.component.$$refs); info.component.$$.inject_refs(info.component.$$.refs);
run_all(info.component.$$afterRender); run_all(info.component.$$.after_render);
flush(); flush();
} }

@ -1,30 +1,30 @@
let current_component; export let current_component;
export function set_current_component(component) { export function set_current_component(component) {
current_component = component; current_component = component;
} }
export function beforeRender(fn) { export function beforeRender(fn) {
current_component.$$beforeRender.push(fn); current_component.$$.before_render.push(fn);
} }
export function onMount(fn) { export function onMount(fn) {
current_component.$$onMount.push(fn); current_component.$$.on_mount.push(fn);
} }
export function afterRender(fn) { export function afterRender(fn) {
current_component.$$afterRender.push(fn); current_component.$$.after_render.push(fn);
} }
export function onDestroy(fn) { export function onDestroy(fn) {
current_component.$$onDestroy.push(fn); current_component.$$.on_destroy.push(fn);
} }
export function createEventDispatcher() { export function createEventDispatcher() {
const component = current_component; const component = current_component;
return (type, detail) => { return (type, detail) => {
const callbacks = component.$$callbacks[type]; const callbacks = component.$$.callbacks[type];
if (callbacks) { if (callbacks) {
// TODO are there situations where events could be dispatched // TODO are there situations where events could be dispatched
@ -41,7 +41,7 @@ export function createEventDispatcher() {
// shorthand events, or if we want to implement // shorthand events, or if we want to implement
// a real bubbling mechanism // a real bubbling mechanism
export function bubble(component, event) { export function bubble(component, event) {
const callbacks = component.$$callbacks[event.type]; const callbacks = component.$$.callbacks[event.type];
if (callbacks) { if (callbacks) {
callbacks.slice().forEach(fn => fn(event)); callbacks.slice().forEach(fn => fn(event));

@ -1,3 +1,5 @@
import { run_all } from './utils.js';
let update_scheduled = false; let update_scheduled = false;
let dirty_components = []; let dirty_components = [];
@ -29,7 +31,7 @@ export function flush() {
// first, call beforeRender functions // first, call beforeRender functions
// and update components // and update components
while (dirty_components.length) { while (dirty_components.length) {
dirty_components.shift().$$update(); update(dirty_components.shift().$$);
} }
while (binding_callbacks.length) binding_callbacks.pop()(); while (binding_callbacks.length) binding_callbacks.pop()();
@ -51,6 +53,17 @@ export function flush() {
update_scheduled = false; update_scheduled = false;
} }
function update($$) {
if ($$.fragment) {
run_all($$.before_render);
$$.fragment.p($$.dirty, $$.get());
$$.inject_refs($$.refs);
$$.dirty = null;
$$.after_render.forEach(add_render_callback);
}
}
function queue_microtask(callback) { function queue_microtask(callback) {
Promise.resolve().then(() => { Promise.resolve().then(() => {
if (update_scheduled) callback(); if (update_scheduled) callback();

Loading…
Cancel
Save