diff --git a/dist/lego.js b/dist/lego.js index 492ac6e..b864a1b 100644 --- a/dist/lego.js +++ b/dist/lego.js @@ -1,716 +1,2 @@ -const EMPTY_OBJECT = {}; - -const VTYPE_ELEMENT = 1; -const VTYPE_FUNCTION = 2; -const VTYPE_COMPONENT = 4; - -const isEmpty = (c) => - c === null || (Array.isArray(c) && c.length === 0); -const isNonEmptyArray = (c) => Array.isArray(c) && c.length > 0; -const isLeaf = (c) => typeof c === "string" || typeof c === "number"; -const isElement = (c) => c?.vtype === VTYPE_ELEMENT; -const isRenderFunction = (c) => c?.vtype === VTYPE_FUNCTION; -const isComponent = (c) => c?.vtype === VTYPE_COMPONENT; - -const isValidComponentType = (c) => typeof c?.mount === "function"; - -function h(type, props, ...children) { - props = props ?? EMPTY_OBJECT; - - props = - children.length > 1 - ? Object.assign({}, props, { children }) - : children.length === 1 - ? Object.assign({}, props, { children: children[0] }) - : props; - - return jsx(type, props, props.key); -} - -function jsx(type, props, key) { - if (key !== key) throw new Error("Invalid NaN key"); - const vtype = - typeof type === "string" - ? VTYPE_ELEMENT - : isValidComponentType(type) - ? VTYPE_COMPONENT - : typeof type === "function" - ? VTYPE_FUNCTION - : undefined; - if (vtype === undefined) throw new Error("Invalid VNode type"); - return { - vtype, - type, - key, - props, - }; -} - -const REF_SINGLE = 1; // ref with a single dom node -const REF_ARRAY = 4; // ref with an array od nodes -const REF_PARENT = 8; // ref with a child ref - -const SVG_NS = "http://www.w3.org/2000/svg"; - -function propDirective(prop) { - return { - mount(element, value) { - element[prop] = value; - }, - patch(element, newValue, oldValue) { - if (newValue !== oldValue) { - element[prop] = newValue; - } - }, - unmount(element, _) { - element[prop] = null; - }, - }; -} - -const DOM_PROPS_DIRECTIVES = { - selected: propDirective("selected"), - checked: propDirective("checked"), - value: propDirective("value"), - innerHTML: propDirective("innerHTML"), -}; -/** - TODO: activate full namespaced attributes (not supported in JSX) - const XML_NS = "http://www.w3.org/XML/1998/namespace" -**/ -const XLINK_NS = "http://www.w3.org/1999/xlink"; -const NS_ATTRS = { - show: XLINK_NS, - actuate: XLINK_NS, - href: XLINK_NS, -}; - -function getDomNode(ref) { - if (ref.type === REF_SINGLE) { - return ref.node; - } else if (ref.type === REF_ARRAY) { - return getDomNode(ref.children[0]); - } else if (ref.type === REF_PARENT) { - return getDomNode(ref.childRef); - } - throw new Error("Unkown ref type " + JSON.stringify(ref)); -} - -function getParentNode(ref) { - if (ref.type === REF_SINGLE) { - return ref.node.parentNode; - } else if (ref.type === REF_ARRAY) { - return getParentNode(ref.children[0]); - } else if (ref.type === REF_PARENT) { - return getParentNode(ref.childRef); - } - throw new Error("Unkown ref type " + ref); -} - -function getNextSibling(ref) { - if (ref.type === REF_SINGLE) { - return ref.node.nextSibling; - } else if (ref.type === REF_ARRAY) { - return getNextSibling(ref.children[ref.children.length - 1]); - } else if (ref.type === REF_PARENT) { - return getNextSibling(ref.childRef); - } - throw new Error("Unkown ref type " + JSON.stringify(ref)); -} - -function insertDom(parent, ref, nextSibling) { - if (ref.type === REF_SINGLE) { - parent.insertBefore(ref.node, nextSibling); - } else if (ref.type === REF_ARRAY) { - ref.children.forEach((ch) => { - insertDom(parent, ch, nextSibling); - }); - } else if (ref.type === REF_PARENT) { - insertDom(parent, ref.childRef, nextSibling); - } else { - throw new Error("Unkown ref type " + JSON.stringify(ref)); - } -} - -function removeDom(parent, ref) { - if (ref.type === REF_SINGLE) { - parent.removeChild(ref.node); - } else if (ref.type === REF_ARRAY) { - ref.children.forEach((ch) => { - removeDom(parent, ch); - }); - } else if (ref.type === REF_PARENT) { - removeDom(parent, ref.childRef); - } else { - throw new Error("Unkown ref type " + ref); - } -} - -function replaceDom(parent, newRef, oldRef) { - insertDom(parent, newRef, getDomNode(oldRef)); - removeDom(parent, oldRef); -} - -function mountDirectives(domElement, props, env) { - for (let key in props) { - if (key in env.directives) { - env.directives[key].mount(domElement, props[key]); - } - } -} - -function patchDirectives(domElement, newProps, oldProps, env) { - for (let key in newProps) { - if (key in env.directives) { - env.directives[key].patch(domElement, newProps[key], oldProps[key]); - } - } - for (let key in oldProps) { - if (key in env.directives && !(key in newProps)) { - env.directives[key].unmount(domElement, oldProps[key]); - } - } -} - -function unmountDirectives(domElement, props, env) { - for (let key in props) { - if (key in env.directives) { - env.directives[key].unmount(domElement, props[key]); - } - } -} - -function mountAttributes(domElement, props, env) { - for (var key in props) { - if (key === "key" || key === "children" || key in env.directives) continue; - if (key.startsWith("on")) { - domElement[key.toLowerCase()] = props[key]; - } else { - setDOMAttribute(domElement, key, props[key], env.isSVG); - } - } -} - -function patchAttributes(domElement, newProps, oldProps, env) { - for (var key in newProps) { - if (key === "key" || key === "children" || key in env.directives) continue; - var oldValue = oldProps[key]; - var newValue = newProps[key]; - if (oldValue !== newValue) { - if (key.startsWith("on")) { - domElement[key.toLowerCase()] = newValue; - } else { - setDOMAttribute(domElement, key, newValue, env.isSVG); - } - } - } - for (key in oldProps) { - if ( - key === "key" || - key === "children" || - key in env.directives || - key in newProps - ) - continue; - if (key.startsWith("on")) { - domElement[key.toLowerCase()] = null; - } else { - domElement.removeAttribute(key); - } - } -} - -function setDOMAttribute(el, attr, value, isSVG) { - if (value === true) { - el.setAttribute(attr, ""); - } else if (value === false) { - el.removeAttribute(attr); - } else { - var namespace = isSVG ? NS_ATTRS[attr] : undefined; - if (namespace !== undefined) { - el.setAttributeNS(namespace, attr, value); - } else { - el.setAttribute(attr, value); - } - } -} - -const DEFAULT_ENV = { - isSvg: false, - directives: DOM_PROPS_DIRECTIVES, -}; - -class Renderer { - constructor(props, env) { - this.props = props; - this._STATE_ = { - env, - vnode: null, - parentDomNode: null, - ref: mount(null), - }; - this.render = this.render.bind(this); - } - - setProps(props) { - this.oldProps = this.props; - this.props = props; - } - - render(vnode) { - const state = this._STATE_; - const oldVNode = state.vnode; - state.vnode = vnode; - if (state.parentDomNode == null) { - let parentNode = getParentNode(state.ref); - if (parentNode == null) { - state.ref = mount(vnode, state.env); - return; - } else { - state.parentDomNode = parentNode; - } - } - // here we're sure state.parentDOMNode is defined - state.ref = patchInPlace( - state.parentDomNode, - vnode, - oldVNode, - state.ref, - state.env - ); - } -} - -function mount(vnode, env = DEFAULT_ENV) { - if (isEmpty(vnode)) { - return { - type: REF_SINGLE, - node: document.createComment("NULL"), - }; - } else if (isLeaf(vnode)) { - return { - type: REF_SINGLE, - node: document.createTextNode(vnode), - }; - } else if (isElement(vnode)) { - let node; - let { type, props } = vnode; - if (type === "svg" && !env.isSvg) { - env = Object.assign({}, env, { isSVG: true }); - } - // TODO : {is} for custom elements - if (!env.isSVG) { - node = document.createElement(type); - } else { - node = document.createElementNS(SVG_NS, type); - } - mountAttributes(node, props, env); - let childrenRef = - props.children == null ? props.children : mount(props.children, env); - /** - * We need to insert content before setting interactive props - * that rely on children been present (e.g select) - */ - if (childrenRef != null) insertDom(node, childrenRef); - mountDirectives(node, props, env); - return { - type: REF_SINGLE, - node, - children: childrenRef, - }; - } else if (isNonEmptyArray(vnode)) { - return { - type: REF_ARRAY, - children: vnode.map((child) => mount(child, env)), - }; - } else if (isRenderFunction(vnode)) { - let childVNode = vnode.type(vnode.props); - let childRef = mount(childVNode, env); - return { - type: REF_PARENT, - childRef, - childState: childVNode, - }; - } else if (isComponent(vnode)) { - let renderer = new Renderer(vnode.props, env); - vnode.type.mount(renderer); - return { - type: REF_PARENT, - childRef: renderer._STATE_.ref, - childState: renderer, - }; - } else if (vnode instanceof Node) { - return { - type: REF_SINGLE, - node: vnode, - }; - } - if (vnode === undefined) { - throw new Error("mount: vnode is undefined!"); - } - - throw new Error("mount: Invalid Vnode!"); -} - -function patch( - parentDomNode, - newVNode, - oldVNode, - ref, - env = DEFAULT_ENV -) { - if (oldVNode === newVNode) { - return ref; - } else if (isEmpty(newVNode) && isEmpty(oldVNode)) { - return ref; - } else if (isLeaf(newVNode) && isLeaf(oldVNode)) { - ref.node.nodeValue = newVNode; - return ref; - } else if ( - isElement(newVNode) && - isElement(oldVNode) && - newVNode.type === oldVNode.type - ) { - if (newVNode.type === "svg" && !env.isSvg) { - env = Object.assign({}, env, { isSVG: true }); - } - patchAttributes(ref.node, newVNode.props, oldVNode.props, env); - let oldChildren = oldVNode.props.children; - let newChildren = newVNode.props.children; - if (oldChildren == null) { - if (newChildren != null) { - ref.children = mount(newChildren, env); - insertDom(ref.node, ref.children); - } - } else { - if (newChildren == null) { - ref.node.textContent = ""; - unmount(oldChildren, ref.children, env); - ref.children = null; - } else { - ref.children = patchInPlace( - ref.node, - newChildren, - oldChildren, - ref.children, - env - ); - } - } - patchDirectives(ref.node, newVNode.props, oldVNode.props, env); - return ref; - } else if (isNonEmptyArray(newVNode) && isNonEmptyArray(oldVNode)) { - patchChildren(parentDomNode, newVNode, oldVNode, ref, env); - return ref; - } else if ( - isRenderFunction(newVNode) && - isRenderFunction(oldVNode) && - newVNode.type === oldVNode.type - ) { - let renderFn = newVNode.type; - let shouldUpdate = - renderFn.shouldUpdate != null - ? renderFn.shouldUpdate(oldVNode.props, newVNode.props) - : defaultShouldUpdate(oldVNode.props, newVNode.props); - if (shouldUpdate) { - let childVNode = renderFn(newVNode.props); - let childRef = patch( - parentDomNode, - childVNode, - ref.childState, - ref.childRef, - env - ); - // We need to return a new ref in order for parent patches to - // properly replace changing DOM nodes - if (childRef !== ref.childRef) { - return { - type: REF_PARENT, - childRef, - childState: childVNode, - }; - } else { - ref.childState = childVNode; - return ref; - } - } else { - return ref; - } - } else if ( - isComponent(newVNode) && - isComponent(oldVNode) && - newVNode.type === oldVNode.type - ) { - const renderer = ref.childState; - const state = renderer._STATE_; - state.env = env; - state.parentNode = parentDomNode; - renderer.setProps(newVNode.props); - newVNode.type.patch(renderer); - if (ref.childRef !== state.ref) { - return { - type: REF_PARENT, - childRef: state.ref, - childState: renderer, - }; - } else { - return ref; - } - } else if (newVNode instanceof Node && oldVNode instanceof Node) { - ref.node = newVNode; - return ref; - } else { - return mount(newVNode, env); - } -} - -/** - * Execute any compoenent specific unmount code - */ -function unmount(vnode, ref, env) { - // if (vnode instanceof Node || isEmpty(vnode) || isLeaf(vnode)) return; - if (isElement(vnode)) { - unmountDirectives(ref.node, vnode.props, env); - if (vnode.props.children != null) - unmount(vnode.props.children, ref.children, env); - } else if (isNonEmptyArray(vnode)) { - vnode.forEach((childVNode, index) => - unmount(childVNode, ref.children[index], env) - ); - } else if (isRenderFunction(vnode)) { - unmount(ref.childState, ref.childRef, env); - } else if (isComponent(vnode)) { - vnode.type.unmount(ref.childState); - } -} - -function patchInPlace(parentDomNode, newVNode, oldVNode, ref, env) { - const newRef = patch(parentDomNode, newVNode, oldVNode, ref, env); - if (newRef !== ref) { - replaceDom(parentDomNode, newRef, ref); - unmount(oldVNode, ref, env); - } - return newRef; -} - -function patchChildren(parentDomNode, newChildren, oldchildren, ref, env) { - // We need to retreive the next sibling before the old children - // get eventually removed from the current DOM document - const nextNode = getNextSibling(ref); - const children = Array(newChildren.length); - let refChildren = ref.children; - let newStart = 0, - oldStart = 0, - newEnd = newChildren.length - 1, - oldEnd = oldchildren.length - 1; - let oldVNode, newVNode, oldRef, newRef, refMap; - - while (newStart <= newEnd && oldStart <= oldEnd) { - if (refChildren[oldStart] === null) { - oldStart++; - continue; - } - if (refChildren[oldEnd] === null) { - oldEnd--; - continue; - } - - oldVNode = oldchildren[oldStart]; - newVNode = newChildren[newStart]; - if (newVNode?.key === oldVNode?.key) { - oldRef = refChildren[oldStart]; - newRef = children[newStart] = patchInPlace( - parentDomNode, - newVNode, - oldVNode, - oldRef, - env - ); - newStart++; - oldStart++; - continue; - } - - oldVNode = oldchildren[oldEnd]; - newVNode = newChildren[newEnd]; - if (newVNode?.key === oldVNode?.key) { - oldRef = refChildren[oldEnd]; - newRef = children[newEnd] = patchInPlace( - parentDomNode, - newVNode, - oldVNode, - oldRef, - env - ); - newEnd--; - oldEnd--; - continue; - } - - if (refMap == null) { - refMap = {}; - for (let i = oldStart; i <= oldEnd; i++) { - oldVNode = oldchildren[i]; - if (oldVNode?.key != null) { - refMap[oldVNode.key] = i; - } - } - } - - newVNode = newChildren[newStart]; - const idx = newVNode?.key != null ? refMap[newVNode.key] : null; - if (idx != null) { - oldVNode = oldchildren[idx]; - oldRef = refChildren[idx]; - newRef = children[newStart] = patch( - parentDomNode, - newVNode, - oldVNode, - oldRef, - env - ); - insertDom(parentDomNode, newRef, getDomNode(refChildren[oldStart])); - if (newRef !== oldRef) { - removeDom(parentDomNode, oldRef); - unmount(oldVNode, oldRef, env); - } - refChildren[idx] = null; - } else { - newRef = children[newStart] = mount(newVNode, env); - insertDom(parentDomNode, newRef, getDomNode(refChildren[oldStart])); - } - newStart++; - } - - const beforeNode = - newEnd < newChildren.length - 1 - ? getDomNode(children[newEnd + 1]) - : nextNode; - while (newStart <= newEnd) { - const newRef = mount(newChildren[newStart], env); - children[newStart] = newRef; - insertDom(parentDomNode, newRef, beforeNode); - newStart++; - } - while (oldStart <= oldEnd) { - oldRef = refChildren[oldStart]; - if (oldRef != null) { - removeDom(parentDomNode, oldRef); - unmount(oldchildren[oldStart], oldRef, env); - } - oldStart++; - } - ref.children = children; -} - -function defaultShouldUpdate(p1, p2) { - if (p1 === p2) return false; - for (let key in p2) { - if (p1[key] !== p2[key]) return true; - } - return false; -} - -function render(vnode, parentDomNode, options = {}) { - let rootRef = parentDomNode.$$PETIT_DOM_REF; - let env = Object.assign({}, DEFAULT_ENV); - Object.assign(env.directives, options.directives); - if (rootRef == null) { - const ref = mount(vnode, env); - parentDomNode.$$PETIT_DOM_REF = { ref, vnode }; - parentDomNode.textContent = ""; - insertDom(parentDomNode, ref, null); - } else { - rootRef.ref = patchInPlace( - parentDomNode, - vnode, - rootRef.vnode, - rootRef.ref, - env - ); - rootRef.vnode = vnode; - } -} - -function toCamelCase(name) { - if(name.includes('-')) { - const parts = name.split('-'); - name = parts[0] + parts.splice(1).map(s => s[0].toUpperCase() + s.substr(1)).join(''); - } - return name -} - - -class Component extends HTMLElement { - constructor() { - super(); - this.useShadowDOM = true; - this.__isConnected = false; - this.__state = {}; - if(this.init) this.init(); - this.watchProps = Object.keys(this.__state); - this.__attributesToState(); - this.document = this.useShadowDOM ? this.attachShadow({mode: 'open'}) : this; - } - - __attributesToState() { - Object.assign(this.state, Array.from(this.attributes).reduce((obj, attr) => { - return Object.assign(obj, { [toCamelCase(attr.name)]: attr.value }) - }, {})); - } - - get vdom() { return ({ state }) => '' } - - get vstyle() { return ({ state }) => '' } - - setAttribute(name, value) { - super.setAttribute(name, value); - const prop = toCamelCase(name); - if(this.watchProps.includes(prop)) this.render({ [prop]: value }); - } - - removeAttribute(name) { - super.removeAttribute(name); - const prop = toCamelCase(name); - if(this.watchProps.includes(prop) && prop in this.state) { - this.render({ [prop]: null }); - delete this.state[prop]; - } - } - - connectedCallback() { - this.__isConnected = true; - if(this.connected) this.connected(); - this.render(); - } - - disconnectedCallback() { - this.__isConnected = false; - this.setState({}); - if(this.disconnected) this.disconnected(); - } - - async setState(props = {}) { - Object.assign(this.__state, props); - if(this.changed && this.__isConnected) await this.changed(props); - } - - set state(value) { - this.setState(value); - } - - get state() { - return this.__state - } - - async render(state) { - await this.setState(state); - if(!this.__isConnected) return - return render([ - this.vdom({ state: this.__state }), - this.vstyle({ state: this.__state }), - ], this.document) - } -} - -export { Component, h, render }; +export { h, render } from '../../../../../../node_modules/petit-dom/src/index.js'; +export { default as Component } from '../../../../../../src/lib/Component.js'; diff --git a/dist/lego.min.js b/dist/lego.min.js index c4e8ec0..14e421b 100644 --- a/dist/lego.min.js +++ b/dist/lego.min.js @@ -1 +1 @@ -const e={},t=e=>null===e||Array.isArray(e)&&0===e.length,n=e=>Array.isArray(e)&&e.length>0,i=e=>"string"==typeof e||"number"==typeof e,r=e=>1===e?.vtype,o=e=>2===e?.vtype,s=e=>4===e?.vtype;function c(t,n,...i){return n=n??e,function(e,t,n){if(n!=n)throw new Error("Invalid NaN key");const i="string"==typeof e?1:(r=e,"function"==typeof r?.mount?4:"function"==typeof e?2:void 0);var r;if(void 0===i)throw new Error("Invalid VNode type");return{vtype:i,type:e,key:n,props:t}}(t,n=i.length>1?Object.assign({},n,{children:i}):1===i.length?Object.assign({},n,{children:i[0]}):n,n.key)}function l(e){return{mount(t,n){t[e]=n},patch(t,n,i){n!==i&&(t[e]=n)},unmount(t,n){t[e]=null}}}const d={selected:l("selected"),checked:l("checked"),value:l("value"),innerHTML:l("innerHTML")},u="http://www.w3.org/1999/xlink",h={show:u,actuate:u,href:u};function f(e){if(1===e.type)return e.node;if(4===e.type)return f(e.children[0]);if(8===e.type)return f(e.childRef);throw new Error("Unkown ref type "+JSON.stringify(e))}function p(e){if(1===e.type)return e.node.parentNode;if(4===e.type)return p(e.children[0]);if(8===e.type)return p(e.childRef);throw new Error("Unkown ref type "+e)}function a(e){if(1===e.type)return e.node.nextSibling;if(4===e.type)return a(e.children[e.children.length-1]);if(8===e.type)return a(e.childRef);throw new Error("Unkown ref type "+JSON.stringify(e))}function y(e,t,n){if(1===t.type)e.insertBefore(t.node,n);else if(4===t.type)t.children.forEach((t=>{y(e,t,n)}));else{if(8!==t.type)throw new Error("Unkown ref type "+JSON.stringify(t));y(e,t.childRef,n)}}function v(e,t){if(1===t.type)e.removeChild(t.node);else if(4===t.type)t.children.forEach((t=>{v(e,t)}));else{if(8!==t.type)throw new Error("Unkown ref type "+t);v(e,t.childRef)}}function w(e,t,n,i){if(!0===n)e.setAttribute(t,"");else if(!1===n)e.removeAttribute(t);else{var r=i?h[t]:void 0;void 0!==r?e.setAttributeNS(r,t,n):e.setAttribute(t,n)}}const m={isSvg:!1,directives:d};class _{constructor(e,t){this.props=e,this._STATE_={env:t,vnode:null,parentDomNode:null,ref:g(null)},this.render=this.render.bind(this)}setProps(e){this.oldProps=this.props,this.props=e}render(e){const t=this._STATE_,n=t.vnode;if(t.vnode=e,null==t.parentDomNode){let n=p(t.ref);if(null==n)return void(t.ref=g(e,t.env));t.parentDomNode=n}t.ref=k(t.parentDomNode,e,n,t.ref,t.env)}}function g(e,c=m){if(t(e))return{type:1,node:document.createComment("NULL")};if(i(e))return{type:1,node:document.createTextNode(e)};if(r(e)){let t,{type:n,props:i}=e;"svg"!==n||c.isSvg||(c=Object.assign({},c,{isSVG:!0})),t=c.isSVG?document.createElementNS("http://www.w3.org/2000/svg",n):document.createElement(n),function(e,t,n){for(var i in t)"key"===i||"children"===i||i in n.directives||(i.startsWith("on")?e[i.toLowerCase()]=t[i]:w(e,i,t[i],n.isSVG))}(t,i,c);let r=null==i.children?i.children:g(i.children,c);return null!=r&&y(t,r),function(e,t,n){for(let i in t)i in n.directives&&n.directives[i].mount(e,t[i])}(t,i,c),{type:1,node:t,children:r}}if(n(e))return{type:4,children:e.map((e=>g(e,c)))};if(o(e)){let t=e.type(e.props);return{type:8,childRef:g(t,c),childState:t}}if(s(e)){let t=new _(e.props,c);return e.type.mount(t),{type:8,childRef:t._STATE_.ref,childState:t}}if(e instanceof Node)return{type:1,node:e};if(void 0===e)throw new Error("mount: vnode is undefined!");throw new Error("mount: Invalid Vnode!")}function S(e,c,l,d,u=m){if(l===c)return d;if(t(c)&&t(l))return d;if(i(c)&&i(l))return d.node.nodeValue=c,d;if(r(c)&&r(l)&&c.type===l.type){"svg"!==c.type||u.isSvg||(u=Object.assign({},u,{isSVG:!0})),function(e,t,n,i){for(var r in t)if("key"!==r&&"children"!==r&&!(r in i.directives)){var o=n[r],s=t[r];o!==s&&(r.startsWith("on")?e[r.toLowerCase()]=s:w(e,r,s,i.isSVG))}for(r in n)"key"===r||"children"===r||r in i.directives||r in t||(r.startsWith("on")?e[r.toLowerCase()]=null:e.removeAttribute(r))}(d.node,c.props,l.props,u);let e=l.props.children,t=c.props.children;return null==e?null!=t&&(d.children=g(t,u),y(d.node,d.children)):null==t?(d.node.textContent="",b(e,d.children,u),d.children=null):d.children=k(d.node,t,e,d.children,u),function(e,t,n,i){for(let r in t)r in i.directives&&i.directives[r].patch(e,t[r],n[r]);for(let r in n)r in i.directives&&!(r in t)&&i.directives[r].unmount(e,n[r])}(d.node,c.props,l.props,u),d}if(n(c)&&n(l))return function(e,t,n,i,r){const o=a(i),s=Array(t.length);let c,l,d,u,h,p=i.children,w=0,m=0,_=t.length-1,E=n.length-1;for(;w<=_&&m<=E;){if(null===p[m]){m++;continue}if(null===p[E]){E--;continue}if(c=n[m],l=t[w],l?.key===c?.key){d=p[m],u=s[w]=k(e,l,c,d,r),w++,m++;continue}if(c=n[E],l=t[_],l?.key===c?.key){d=p[E],u=s[_]=k(e,l,c,d,r),_--,E--;continue}if(null==h){h={};for(let e=m;e<=E;e++)c=n[e],null!=c?.key&&(h[c.key]=e)}l=t[w];const i=null!=l?.key?h[l.key]:null;null!=i?(c=n[i],d=p[i],u=s[w]=S(e,l,c,d,r),y(e,u,f(p[m])),u!==d&&(v(e,d),b(c,d,r)),p[i]=null):(u=s[w]=g(l,r),y(e,u,f(p[m]))),w++}const A=_b(e,t.children[n],i))):o(e)?b(t.childState,t.childRef,i):s(e)&&e.type.unmount(t.childState)}function k(e,t,n,i,r){const o=S(e,t,n,i,r);return o!==i&&(!function(e,t,n){y(e,t,f(n)),v(e,n)}(e,o,i),b(n,i,r)),o}function E(e,t,n={}){let i=t.$$PETIT_DOM_REF,r=Object.assign({},m);if(Object.assign(r.directives,n.directives),null==i){const n=g(e,r);t.$$PETIT_DOM_REF={ref:n,vnode:e},t.textContent="",y(t,n,null)}else i.ref=k(t,e,i.vnode,i.ref,r),i.vnode=e}function A(e){if(e.includes("-")){const t=e.split("-");e=t[0]+t.splice(1).map((e=>e[0].toUpperCase()+e.substr(1))).join("")}return e}class N extends HTMLElement{constructor(){super(),this.useShadowDOM=!0,this.__isConnected=!1,this.__state={},this.init&&this.init(),this.watchProps=Object.keys(this.__state),this.__attributesToState(),this.document=this.useShadowDOM?this.attachShadow({mode:"open"}):this}__attributesToState(){Object.assign(this.state,Array.from(this.attributes).reduce(((e,t)=>Object.assign(e,{[A(t.name)]:t.value})),{}))}get vdom(){return({state:e})=>""}get vstyle(){return({state:e})=>""}setAttribute(e,t){super.setAttribute(e,t);const n=A(e);this.watchProps.includes(n)&&this.render({[n]:t})}removeAttribute(e){super.removeAttribute(e);const t=A(e);this.watchProps.includes(t)&&t in this.state&&(this.render({[t]:null}),delete this.state[t])}connectedCallback(){this.__isConnected=!0,this.connected&&this.connected(),this.render()}disconnectedCallback(){this.__isConnected=!1,this.setState({}),this.disconnected&&this.disconnected()}async setState(e={}){Object.assign(this.__state,e),this.changed&&this.__isConnected&&await this.changed(e)}set state(e){this.setState(e)}get state(){return this.__state}async render(e){if(await this.setState(e),this.__isConnected)return E([this.vdom({state:this.__state}),this.vstyle({state:this.__state})],this.document)}}export{N as Component,c as h,E as render}; +export{h,render}from"../../../../../../node_modules/petit-dom/src/index.js";export{default as Component}from"../../../../../../src/lib/Component.js"; diff --git a/dist/lego.min.js.gz b/dist/lego.min.js.gz index 77a4e4a..6048d47 100644 Binary files a/dist/lego.min.js.gz and b/dist/lego.min.js.gz differ diff --git a/docs/10-getting-started.md b/docs/10-getting-started.md index e86fa01..e80b816 100644 --- a/docs/10-getting-started.md +++ b/docs/10-getting-started.md @@ -35,15 +35,13 @@ index.html Create a file called __bricks/hello-world.html__: ```html - - + + ``` Compile with `npx lego` (or `yarn lego`) diff --git a/docs/20.04-custom.md b/docs/20.04-custom.md index ced217b..708eacc 100644 --- a/docs/20.04-custom.md +++ b/docs/20.04-custom.md @@ -12,14 +12,15 @@ parent: Usage A custom directive will interpret in JS whatever you pass as value. ```html - + + ``` outputs @@ -31,5 +32,5 @@ outputs [Boolean attributes](https://www.w3.org/TR/html5/infrastructure.html#sec-boolean-attributes) Example: ``. -With the following state: `this.state = { agreed: false, mustAgree: true }` would render +With the following state: `const state = { agreed: false, mustAgree: true }` would render ``. diff --git a/docs/20.05-event.md b/docs/20.05-event.md index fae718f..27bf416 100644 --- a/docs/20.05-event.md +++ b/docs/20.05-event.md @@ -10,14 +10,13 @@ parent: Usage #### `@` Directive for binding Events ```html -