UNPKG

springtype

Version:

1k TypeScript/TSX nano-framework for the web

142 lines (141 loc) 6.66 kB
"use strict"; exports.__esModule = true; var st_1 = require("../st/st"); var CLASS_ATTRIBUTE_NAME = 'class'; var XLINK_ATTRIBUTE_NAME = 'xlink'; var REF_ATTRIBUTE_NAME = 'ref'; var SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; // istanbul ignore else if (!st_1.st.dom) { // DOM abstraction layer for manipulation st_1.st.dom = { hasElNamespace: function (domElement) { return domElement.namespaceURI === SVG_NAMESPACE; }, hasSvgNamespace: function (parentElement, type) { return st_1.st.dom.hasElNamespace(parentElement) && type !== 'STYLE' && type !== 'SCRIPT'; }, createElementOrElements: function (virtualNode, parentDomElement) { if (Array.isArray(virtualNode)) { return st_1.st.dom.createChildElements(virtualNode, parentDomElement); } if (typeof virtualNode !== 'undefined') { return st_1.st.dom.createElement(virtualNode, parentDomElement); } // undefined virtualNode -> e.g. when a tsx variable is used in markup which is undefined return st_1.st.dom.createTextNode('', parentDomElement); }, createElement: function (virtualNode, parentDomElement) { var newEl; if (virtualNode.type.toUpperCase() === 'SVG' || (parentDomElement && st_1.st.dom.hasSvgNamespace(parentDomElement, virtualNode.type.toUpperCase()))) { newEl = document.createElementNS(SVG_NAMESPACE, virtualNode.type); } else { newEl = document.createElement(virtualNode.type); } // reference SpringType as a reference to every element created // this allows microframework addition libs like st-query to re-use this instance // with the correct domImpl the element belongs to newEl[st_1.ST_KEY] = st_1.st; // istanbul ignore else if (virtualNode.attributes) { st_1.st.dom.setAttributes(virtualNode.attributes, newEl); } // istanbul ignore else if (virtualNode.children) { st_1.st.dom.createChildElements(virtualNode.children, newEl); } // istanbul ignore else if (parentDomElement) { parentDomElement.appendChild(newEl); // check for a lifecycle "onMount" hook and call it if (typeof newEl.$onMount === 'function') { newEl.$onMount(); } } return newEl; }, createTextNode: function (text, domElement) { var node = document.createTextNode(text.toString()); // istanbul ignore else if (domElement) { domElement.appendChild(node); } return node; }, createChildElements: function (virtualChildren, domElement) { var children = []; for (var i = 0; i < virtualChildren.length; i++) { var virtualChild = virtualChildren[i]; if (virtualChild === null || (typeof virtualChild !== 'object' && typeof virtualChild !== 'function')) { children.push(st_1.st.dom.createTextNode((typeof virtualChild === 'undefined' || virtualChild === null ? '' : virtualChild).toString(), domElement)); } else { children.push(st_1.st.dom.createElement(virtualChild, domElement)); } } return children; }, setAttribute: function (name, value, domElement) { // attributes not set (undefined) are ignored; use null value to reset an attributes state if (typeof value === 'undefined') return; // save ref as { current: DOMElement } in ref object // allows for ref={someRef} if (name === REF_ATTRIBUTE_NAME && typeof value !== 'function') { value.current = domElement; } else if (name === REF_ATTRIBUTE_NAME && typeof value === 'function') { // allow for functional ref's like: render(<div ref={(el) => console.log('got el', el)} />) value(domElement); } if (name.startsWith('on') && typeof value === 'function') { var eventName = name.substring(2).toLowerCase(); var capturePos = eventName.indexOf('capture'); var doCapture = capturePos > -1; if (eventName === 'mount') { domElement.$onMount = value; } // onClickCapture={...} support if (doCapture) { eventName = eventName.substring(0, capturePos); } domElement.addEventListener(eventName, value, doCapture); return; } // transforms className="..." -> class="..." // allows for React TSX to work seamlessly if (name === 'className') { name = CLASS_ATTRIBUTE_NAME; } // transforms class={['a', 'b']} into class="a b" if (name === CLASS_ATTRIBUTE_NAME && Array.isArray(value)) { value = value.join(' '); } if (st_1.st.dom.hasElNamespace(domElement) && name.startsWith(XLINK_ATTRIBUTE_NAME)) { // allows for <svg><use xlinkHref ...></svg> domElement.setAttributeNS('http://www.w3.org/1999/xlink', (XLINK_ATTRIBUTE_NAME + ":" + name.replace(XLINK_ATTRIBUTE_NAME, '')).toLowerCase(), value); } else if (name === 'style' && typeof value !== 'string') { var propNames = Object.keys(value); // allows for style={{ margin: 10 }} etc. for (var i = 0; i < propNames.length; i++) { domElement.style[propNames[i]] = value[propNames[i]]; } } else if (typeof value === 'boolean') { // for cases like <button checked={false} /> domElement[name] = value; } else { // for any other case domElement.setAttribute(name, value); } }, setAttributes: function (attributes, domElement, forceNative) { var attrNames = Object.keys(attributes); for (var i = 0; i < attrNames.length; i++) { st_1.st.dom.setAttribute(attrNames[i], attributes[attrNames[i]], domElement, forceNative); } } }; }