You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte/src/internal/Component.js

196 lines
4.4 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

import { add_render_callback, flush, intros, schedule_update } from './scheduler.js';
import { current_component, set_current_component } from './lifecycle.js'
import { is_function, run, run_all, noop } from './utils.js';
import { blankObject } from './utils.js';
import { children } from './dom.js';
export function bind(component, name, callback) {
component.$$.bound[name] = callback;
callback(component.$$.ctx[name]);
}
export function mount_component(component, target, anchor) {
const { fragment, on_mount, on_destroy, after_render } = component.$$;
fragment[fragment.i ? 'i' : 'm'](target, anchor);
// onMount happens after the initial afterUpdate. Because
// afterUpdate callbacks happen in reverse order (inner first)
// we schedule onMount callbacks before afterUpdate callbacks
add_render_callback(() => {
const new_on_destroy = on_mount.map(run).filter(is_function);
if (on_destroy) {
on_destroy.push(...new_on_destroy);
} else {
// Edge case — component was destroyed immediately,
// most likely as a result of a binding initialising
run_all(new_on_destroy);
}
component.$$.on_mount = [];
});
after_render.forEach(add_render_callback);
}
function destroy(component, detach) {
if (component.$$) {
run_all(component.$$.on_destroy);
component.$$.fragment.d(detach);
// TODO null out other refs, including component.$$ (but need to
// preserve final state?)
component.$$.on_destroy = component.$$.fragment = null;
component.$$.ctx = {};
}
}
function make_dirty(component, key) {
if (!component.$$.dirty) {
schedule_update(component);
component.$$.dirty = {};
}
component.$$.dirty[key] = true;
}
export function init(component, options, instance, create_fragment, not_equal) {
const previous_component = current_component;
set_current_component(component);
const $$ = component.$$ = {
fragment: null,
ctx: null,
// state
set: noop,
update: noop,
not_equal,
bound: blankObject(),
// lifecycle
on_mount: [],
on_destroy: [],
before_render: [],
after_render: [],
// everything else
callbacks: blankObject(),
slotted: options.slots || {},
dirty: null,
binding_groups: []
};
let ready = false;
$$.ctx = instance(component, options.props || {}, (key, value) => {
if ($$.bound[key]) $$.bound[key](value);
if ($$.ctx) {
const changed = not_equal(value, $$.ctx[key]);
if (ready && changed) {
make_dirty(component, key);
}
$$.ctx[key] = value;
return changed;
}
});
$$.update();
ready = true;
run_all($$.before_render);
$$.fragment = create_fragment($$, $$.ctx);
if (options.target) {
intros.enabled = !!options.intro;
if (options.hydrate) {
$$.fragment.l(children(options.target));
} else {
$$.fragment.c();
}
mount_component(component, options.target, options.anchor);
flush();
intros.enabled = true;
}
set_current_component(previous_component);
}
export let SvelteElement;
if (typeof HTMLElement !== 'undefined') {
SvelteElement = class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
for (let key in this.$$.slotted) {
this.appendChild(this.$$.slotted[key]);
}
}
attributeChangedCallback(attr, oldValue, newValue) {
this[attr] = newValue;
}
$destroy() {
destroy(this, true);
this.$destroy = noop;
}
$on(type, callback) {
// TODO should this delegate to addEventListener?
const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
callbacks.push(callback);
return () => {
const index = callbacks.indexOf(callback);
if (index !== -1) callbacks.splice(index, 1);
};
}
$set() {
// overridden by instance, if it has props
}
}
}
export class SvelteComponent {
$destroy() {
destroy(this, true);
this.$destroy = noop;
}
$on(type, callback) {
const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
callbacks.push(callback);
return () => {
const index = callbacks.indexOf(callback);
if (index !== -1) callbacks.splice(index, 1);
};
}
$set() {
// overridden by instance, if it has props
}
}
export class SvelteComponentDev extends SvelteComponent {
constructor(options) {
if (!options || (!options.target && !options.$$inline)) {
throw new Error(`'target' is a required option`);
}
super();
}
$destroy() {
super.$destroy();
this.$destroy = () => {
console.warn(`Component was already destroyed`);
};
}
}