@surface/custom-element
Version:
Provides support of directives and data binding on custom elements.
59 lines (58 loc) • 2.7 kB
JavaScript
import bind from "../bind.js";
import Directive from "../directive.js";
import observe from "../observe.js";
export default function elementFactory(tag, attributes, binds, events, customDirectives, childs) {
return () => {
const element = document.createElement(tag);
window.customElements.upgrade(element);
if (attributes) {
for (const [key, value] of attributes) {
element.setAttribute(key, value);
}
}
const activators = [];
if (childs) {
for (const childFactory of childs) {
const [childElement, activator] = childFactory();
// TODO: Allow factory returns multiples nodes.
element.appendChild(childElement);
activators.push(activator);
}
}
const activator = (_parent, host, scope, directives) => {
const disposables = [];
const subscriptions = [];
for (const activator of activators) {
disposables.push(activator(element, host, scope, directives));
}
if (binds) {
for (const [type, key, expression, observables] of binds) {
switch (type) {
case "oneway":
subscriptions.push(observe(scope, observables, () => void (element[key] = expression(scope)), false));
break;
case "twoway":
subscriptions.push(bind(element, [key], scope, observables[0]));
break;
default:
subscriptions.push(observe(scope, observables, () => element.setAttribute(key, `${expression(scope)}`), false));
}
}
}
if (events) {
for (const [key, expression] of events) {
const listener = expression(scope);
element.addEventListener(key, listener);
subscriptions.push({ unsubscribe: () => element.removeEventListener(key, listener) });
}
}
if (customDirectives) {
for (const [key, expression, observables] of customDirectives) {
disposables.push(new Directive({ element, scope, key, expression, observables }));
}
}
return { dispose: () => (subscriptions.splice(0).forEach(x => x.unsubscribe()), disposables.splice(0).forEach(x => x.dispose())) };
};
return [element, activator];
};
}