UNPKG

sinuous

Version:

🧬 Small, fast, reactive render engine

141 lines (129 loc) • 3.68 kB
/* Adapted from Hyper DOM Expressions - The MIT License - Ryan Carniato */ import { api } from './api.js'; import { EMPTY_ARR } from './constants.js'; import { insert } from './insert.js'; /** * Create a sinuous `h` tag aka hyperscript. * @param {object} options * @param {boolean} isSvg * @return {Function} `h` tag. */ export function context(options, isSvg) { for (let i in options) api[i] = options[i]; function h() { const args = EMPTY_ARR.slice.call(arguments); let el; function item(arg) { const type = typeof arg; if (arg == null); else if (type === 'string') { if (el) { el.appendChild(document.createTextNode(arg)); } else { if (isSvg) { el = document.createElementNS('http://www.w3.org/2000/svg', arg); } else { el = document.createElement(arg); } } } else if (Array.isArray(arg)) { // Support Fragments if (!el) el = document.createDocumentFragment(); arg.forEach(item); } else if (arg instanceof Node) { if (el) { el.appendChild(arg); } else { // Support updates el = arg; } } else if (type === 'object') { for (let name in arg) { // Create scope for every entry. property(name, arg[name], el, isSvg); } } else if (type === 'function') { if (el) { const marker = el.appendChild(document.createTextNode('')); if (arg.$t) { // Record insert action in template, marker is used as pre-fill. arg.$t(1, insert, el, ''); } else { insert(el, arg, marker); } } else { // Support Components el = arg.apply(null, args.splice(0)); } } else { el.appendChild(document.createTextNode('' + arg)); } } while (args.length) { item(args.shift()); } return el; } api.h = h; return h; } export function property(name, value, el, isSvg, isCss) { if (name[0] === 'o' && name[1] === 'n' && !value.$o) { // Functions added as event handlers are not executed // on render unless they have an observable indicator. handleEvent(el, name, value); } else if (typeof value === 'function') { if (value.$t) { // Record property action in template. value.$t(2, property, el, name); } else { api.subscribe(() => { property(name, value(), el, isSvg, isCss); }); } } else if (isCss) { el.style.setProperty(name, value); } else if ( isSvg || name.slice(0, 5) === 'data-' || name.slice(0, 5) === 'aria-' ) { el.setAttribute(name, value); } else if (name === 'style') { if (typeof value === 'string') { el.style.cssText = value; } else { for (name in value) { property(name, value[name], el, isSvg, true); } } } else if (name === 'attrs') { for (name in value) { property(name, value[name], el, true); } } else { if (name === 'class') name += 'Name'; el[name] = value; } } function handleEvent(el, name, value) { name = name.slice(2); const removeListener = api.cleanup(() => el.removeEventListener(name, eventProxy) ); if (value) { el.addEventListener(name, eventProxy); } else { removeListener(); } (el._listeners || (el._listeners = {}))[name] = value; } /** * Proxy an event to hooked event handlers. * @param {Event} e - The event object from the browser. * @return {Function} */ function eventProxy(e) { // eslint-disable-next-line return this._listeners[e.type](e); }