const $id = document.getElementById.bind(document); const $query = document.querySelector.bind(document); const $queryAll = document.querySelectorAll.bind(document); const $text = document.createTextNode.bind(document); const $insertBefore = function(target, element) { target.parentNode.insertBefore(element, target); }; const $appendChild = function(element, child) { switch(typeof child) { case 'undefined': break; case 'string': element.appendChild($text(child)); break; case 'function': $appendChild(element, child()); break; case 'object': if(child === null) break; if(child instanceof Node) element.appendChild(child); else if(child?.element instanceof Node) element.appendChild(child.element); else if(typeof child?.toString === 'function') element.appendChild($text(child.toString())); break; default: element.appendChild($text(child.toString())); break; } }; const $appendChildren = function(element, ...children) { for(const child of children) $appendChild(element, child); }; const $removeChildren = function(element) { while(element.lastChild) element.removeChild(element.lastChild); }; const $fragment = function(props, ...children) { const fragment = document.createDocumentFragment(); $appendChildren(fragment, ...children); return fragment; }; const $element = function(type, props, ...children) { if(typeof type === 'function') return new type(props ?? {}, ...children); const element = document.createElement(type ?? 'div'); if(props) for(let key in props) { const prop = props[key]; if(prop === undefined || prop === null) continue; switch(typeof prop) { case 'function': if(key.substring(0, 2) === 'on') key = key.substring(2).toLowerCase(); element.addEventListener(key, prop); break; case 'object': if(prop instanceof Array) { if(key === 'class') key = 'classList'; const attr = element[key]; let addFunc = null; if(attr instanceof Array) addFunc = attr.push.bind(attr); else if(attr instanceof DOMTokenList) addFunc = attr.add.bind(attr); if(addFunc !== null) { for(let j = 0; j < prop.length; ++j) addFunc(prop[j]); } else { if(key === 'classList') key = 'class'; element.setAttribute(key, prop.toString()); } } else { if(key === 'class' || key === 'className') key = 'classList'; let setFunc = null; if(element[key] instanceof DOMTokenList) setFunc = (ak, av) => { if(av) element[key].add(ak); }; else if(element[key] instanceof CSSStyleDeclaration) setFunc = (ak, av) => { element[key].setProperty(ak, av); } else setFunc = (ak, av) => { element[key][ak] = av; }; for(const attrKey in prop) { const attrValue = prop[attrKey]; if(attrValue) setFunc(attrKey, attrValue); } } break; case 'boolean': if(prop) element.setAttribute(key, ''); break; default: if(key === 'className') key = 'class'; element.setAttribute(key, prop.toString()); break; } } $appendChildren(element, ...children); return element; };