94 lines
4.3 KiB
JavaScript
94 lines
4.3 KiB
JavaScript
|
/* Riot WIP, @license MIT */
|
||
|
import { autobindMethods, defineProperties, isObject, defineProperty, IS_PURE_SYMBOL, PARENT_KEY_SYMBOL, ATTRIBUTES_KEY_SYMBOL, PROPS_KEY, evaluateAttributeExpressions, STATE_KEY, TEMPLATE_KEY_SYMBOL, ROOT_KEY, SLOTS_KEY, ON_BEFORE_MOUNT_KEY, ON_MOUNTED_KEY, SHOULD_UPDATE_KEY, ON_BEFORE_UPDATE_KEY, IS_COMPONENT_UPDATING, ON_UPDATED_KEY, ON_BEFORE_UNMOUNT_KEY, ON_UNMOUNTED_KEY, isFunction } from '@riotjs/util';
|
||
|
import { addCssHook } from './add-css-hook.js';
|
||
|
import { bindDOMNodeToComponentInstance } from './bind-dom-node-to-component-instance.js';
|
||
|
import { computeComponentState } from './compute-component-state.js';
|
||
|
import { computeInitialProps } from './compute-initial-props.js';
|
||
|
import { createAttributeBindings } from './create-attribute-bindings.js';
|
||
|
import { runPlugins } from './run-plugins.js';
|
||
|
|
||
|
/**
|
||
|
* Component creation factory function that will enhance the user provided API
|
||
|
* @param {Object} component - a component implementation previously defined
|
||
|
* @param {Array} options.slots - component slots generated via riot compiler
|
||
|
* @param {Array} options.attributes - attribute expressions generated via riot compiler
|
||
|
* @returns {Riot.Component} a riot component instance
|
||
|
*/
|
||
|
|
||
|
function manageComponentLifecycle(component, _ref) {
|
||
|
let {
|
||
|
slots,
|
||
|
attributes,
|
||
|
props
|
||
|
} = _ref;
|
||
|
return autobindMethods(runPlugins(defineProperties(isObject(component) ? Object.create(component) : component, {
|
||
|
mount(element, state, parentScope) {
|
||
|
if (state === void 0) {
|
||
|
state = {};
|
||
|
}
|
||
|
|
||
|
// any element mounted passing through this function can't be a pure component
|
||
|
defineProperty(element, IS_PURE_SYMBOL, false);
|
||
|
this[PARENT_KEY_SYMBOL] = parentScope;
|
||
|
this[ATTRIBUTES_KEY_SYMBOL] = createAttributeBindings(element, attributes).mount(parentScope);
|
||
|
defineProperty(this, PROPS_KEY, Object.freeze(Object.assign({}, computeInitialProps(element, props), evaluateAttributeExpressions(this[ATTRIBUTES_KEY_SYMBOL].expressions))));
|
||
|
this[STATE_KEY] = computeComponentState(this[STATE_KEY], state);
|
||
|
this[TEMPLATE_KEY_SYMBOL] = this.template.createDOM(element).clone(); // link this object to the DOM node
|
||
|
|
||
|
bindDOMNodeToComponentInstance(element, this); // add eventually the 'is' attribute
|
||
|
|
||
|
component.name && addCssHook(element, component.name); // define the root element
|
||
|
|
||
|
defineProperty(this, ROOT_KEY, element); // define the slots array
|
||
|
|
||
|
defineProperty(this, SLOTS_KEY, slots); // before mount lifecycle event
|
||
|
|
||
|
this[ON_BEFORE_MOUNT_KEY](this[PROPS_KEY], this[STATE_KEY]); // mount the template
|
||
|
|
||
|
this[TEMPLATE_KEY_SYMBOL].mount(element, this, parentScope);
|
||
|
this[ON_MOUNTED_KEY](this[PROPS_KEY], this[STATE_KEY]);
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
update(state, parentScope) {
|
||
|
if (state === void 0) {
|
||
|
state = {};
|
||
|
}
|
||
|
|
||
|
if (parentScope) {
|
||
|
this[PARENT_KEY_SYMBOL] = parentScope;
|
||
|
this[ATTRIBUTES_KEY_SYMBOL].update(parentScope);
|
||
|
}
|
||
|
|
||
|
const newProps = evaluateAttributeExpressions(this[ATTRIBUTES_KEY_SYMBOL].expressions);
|
||
|
if (this[SHOULD_UPDATE_KEY](newProps, this[PROPS_KEY]) === false) return;
|
||
|
defineProperty(this, PROPS_KEY, Object.freeze(Object.assign({}, this[PROPS_KEY], newProps)));
|
||
|
this[STATE_KEY] = computeComponentState(this[STATE_KEY], state);
|
||
|
this[ON_BEFORE_UPDATE_KEY](this[PROPS_KEY], this[STATE_KEY]); // avoiding recursive updates
|
||
|
// see also https://github.com/riot/riot/issues/2895
|
||
|
|
||
|
if (!this[IS_COMPONENT_UPDATING]) {
|
||
|
this[IS_COMPONENT_UPDATING] = true;
|
||
|
this[TEMPLATE_KEY_SYMBOL].update(this, this[PARENT_KEY_SYMBOL]);
|
||
|
}
|
||
|
|
||
|
this[ON_UPDATED_KEY](this[PROPS_KEY], this[STATE_KEY]);
|
||
|
this[IS_COMPONENT_UPDATING] = false;
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
unmount(preserveRoot) {
|
||
|
this[ON_BEFORE_UNMOUNT_KEY](this[PROPS_KEY], this[STATE_KEY]);
|
||
|
this[ATTRIBUTES_KEY_SYMBOL].unmount(); // if the preserveRoot is null the template html will be left untouched
|
||
|
// in that case the DOM cleanup will happen differently from a parent node
|
||
|
|
||
|
this[TEMPLATE_KEY_SYMBOL].unmount(this, this[PARENT_KEY_SYMBOL], preserveRoot === null ? null : !preserveRoot);
|
||
|
this[ON_UNMOUNTED_KEY](this[PROPS_KEY], this[STATE_KEY]);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
})), Object.keys(component).filter(prop => isFunction(component[prop])));
|
||
|
}
|
||
|
|
||
|
export { manageComponentLifecycle };
|