diff --git a/core.js b/core.js index 26ce494..1e2708e 100644 --- a/core.js +++ b/core.js @@ -1,186 +1,326 @@ -function render(...entries) -{ - let content = {}; - let domContainer = document.createElement('div'); - renderTreeQueQue( - domContainer, - entries, - content - ); - return domContainer; -}; - -function renderTreeQueQue(domContainer, entries, content) -{ - if(!content._renderPlanned) +((window)=>{ + function render(...entries) { - requestAnimationFrame(()=>{ - createTree( - domContainer, - entries, - content - ) - }); - content._renderPlanned = true; - } -}; - -function createTree(domContainer, entries, content) -{ - let vdom = renderTree(entries, content); - for (const vnode of vdom) { - domContainer.append(vnode) - } -} - -function * renderTree(entries,content) -{ - let fragment = document.createDocumentFragment(); - for (const entry of entries) { - fragment.appendChild(é(entry).render(content)) + let content = {}; + let domContainer = document.createElement('div'); + renderTreeQueQue( + domContainer, + entries, + content + ); + return domContainer; }; - return fragment; -} - -function élement(...args) -{ - this._args = args; - let _stateIndex = []; - let _requireedRender = true; - let _previousCopy = []; - let _shadow = null; - this.hooks = []; - let _currentCopy = []; - this.getState = function(n){ - return _stateIndex[n]; - }; - this.setCurrentCopy = function(shadow){ - _previousCopy = _currentCopy; - _currentCopy = shadow; - }; - this.setState = function(n,o){ - if( - Object.is(_stateIndex[n], o) - ) + function renderTreeQueQue(domContainer, entries, content) + { + if(!content._renderPlanned) { - _requireedRender = true; - _stateIndex[n]=o; + requestAnimationFrame(()=>{ + createTree( + domContainer, + entries, + content + ) + }); + content._renderPlanned = true; } }; - this.render = function(ctx) { - if(_requireedRender) + + function createTree(domContainer, entries, content) + { + let root = é(entries[0]); + RenderElement(domContainer, root); + } + /** + * @param {vnode} data + */ + function RenderElement(parent, data) + { + let elem; + if( + (typeof data == "boolean" && !data) || + data == null || + data === undefined + ) { - if(this._args[0] instanceof Function) - { - _shadow = document.createDocumentFragment(); - RenderCompanent( - this, - ctx, - this._args[1] - ); - for (const entry of _currentCopy) { - _shadow.appendChild(é(entry).render(ctx)) - }; - }else{ - _shadow = RenderElement(this._args[0], ctx); - } + return document.createDocumentFragment() }; - return _shadow || []; - }; -}; - -function RenderElement(data) -{ - let elem = document.createElement(data.$ || "div"); - for (const [name,value] of Object.entries(data)) { - switch(name) + if(data.type == é.type) { - case "$": - break; - case "in": - break; - default:{ - if(name.startsWith('on')) + if(typeof data.companent == "string") + { + elem = document.createElement(data.companent); + for (const [name,value] of Object.entries(data.props)) { - elem.addEventListener(name.slice(2),value) - }else{ - elem.setAttribute(name, value) + if(["key","children"].includes(name)) + { + continue; + } + if(name.startsWith('on')) + { + elem.addEventListener(name.slice(2),value) + } + else + { + elem.setAttribute(name, value) + } + }; + } + else if(typeof data.companent == "function") + { + let companent = RenderCompanent(data); + elem = RenderElement(null, companent) + } + else if(typeof data.companent == "string") + { + elem = document.createTextNode(companent); + } + else if(!data.companent) + { + elem = document.createDocumentFragment() + }; + if(data.props && data.props.children instanceof Array) + { + for (const companent of (data.props.children||[])) + { + if( typeof companent == "string" ) + { + elem.append(document.createTextNode(companent)); + } + else + { + RenderElement(elem, companent); + } + } + } + }else if(data.$){ + elem = document.createElement(data.$ || "div"); + for (const [name,value] of Object.entries(data)) { + switch(name) + { + case "$": + break; + case "in": + break; + default: + { + if(name.startsWith('on')) + { + elem.addEventListener(name.slice(2),value) + } + else + { + elem.setAttribute(name, value) + } + }; } }; - } - }; - if(data.in instanceof Array) - { - for (const companent of (data.in||[])) { - if( - typeof companent != élement && - typeof companent == "string" - ) + if(data.in) { - elem.append(document.createTextNode(companent)); - }else{ - elem.append( - é(companent).render() - ); + if(data.in instanceof Array) + { + for (const companent of (data.in||[])) { + if( + typeof companent == "string" + ) + { + elem.append(document.createTextNode(companent)); + } + else + { + RenderElement(elem, companent) + } + } + }else{ + if( + typeof data.in == "string" + ) + { + elem.append(document.createTextNode(data.in)); + } + else + { + RenderElement(elem, companent) + } + } + } + data.parent = parent; + data.dom = elem; + } + else if(data instanceof Array) + { + if(parent) + { + for (const vdata of data.flat(Infinity)) { + RenderElement(parent, vdata) + }; + } + else + { + let d = document.createDocumentFragment(); + for (const vdata of data.flat(Infinity)) { + RenderElement(d, vdata) + }; + elem = d; } } - }else{ - if( - typeof data.in != élement && - typeof data.in == "string" - ) + else if(typeof data == "string") { - elem.append(document.createTextNode(data.in)); - }else{ - elem.append( - é(data.in).render() - ); + elem = document.createTextNode(data); + }; + data._render = false; + if(parent) + { + parent.append(elem); + } + else + { + return elem; } } - return elem; -} - -let currentCompanent; -let currentStateIndex = 0; -function RenderCompanent(élement, context, attr) -{ - currentCompanent = élement; - currentStateIndex = 0; - let vshadow = élement._args[0].apply(context,[attr]); - élement.setCurrentCopy(vshadow instanceof Array ? vshadow : [vshadow]); -}; -function Update() -{ - // -} -function Var(value) -{ - let index = currentStateIndex++; - let state = currentCompanent.getState(); - if(state.length) + + function RenderCompanent(data) { - state[index] = value; - }; - return [ - state[index], - (newValue) => { - if(newValue instanceof Function) - { - newValue = newValue(state[index]); - }; - if(Object.is( - state[index], - newValue - )) - { - currentCompanent._requireedRender = true; + useCompanent(data); + let result = data.companent(data.props); + useCompanent(undefined); + return result; + } + function é(a,b) + { + if(a instanceof Array) + { + let t = b instanceof Array ? b : []; + for (const _a of a) { + if(_a instanceof Array) + { + é(_a, t); + }else{ + t.push(é(_a)); + } }; + t = t.flat(Infinity); + return é({ + $: é.fragment, + in: t + }) } - ] - return [value, () => {}]; -}; + if(a.type == é.type) + { + return a; + } + let t = vnode(), companent, key, props = {}; + if(typeof a == "function") + { + t.companent = a; + t.key = b && ('key' in b) ? b.key : undefined; + t.props = b; + }else if(typeof a == "string"){ + t.companent = null; + t.props = { + children: [a] + }; + }else if('$' in a){ + props = {}; + for (const index of Object.keys(a)) { + switch(index) + { + case "$": companent = a[index]; break; + case "in":{ + if(a[index] instanceof Array) + { + props.children = a[index].map(é); + }else{ + props.children = [ + é(a[index]) + ] + } + break + }; + case "key": key = a[index]; break; + default:{ + props[index] = a[index]; + } + } + }; + t.companent = companent; + t.key = key; + t.props = props; + }else{ + throw new Error("Unknown companent type") + } + return t; + }; + é.type = Symbol("élement"); + é.fragment = Symbol("framént"); -function é(a,b) -{ - return a instanceof élement ? a : new élement(a,b); -} \ No newline at end of file + let currentCompanent; + let currentCompanentStateIndex = 0; + + function useCompanent(vnode) + { + currentCompanent = vnode; + currentCompanentStateIndex = 0; + }; + + function useState(initial) + { + let companent = currentCompanent; + let id = currentCompanentStateIndex++; + let value; + if(!companent) + { + throw new Error("Cannot be used outside of components") + }; + if(companent._state.length <= id) + { + if(typeof initial == "function") + { + value = initial(); + } + else + { + value = initial; + } + companent._state[id] = value; + }else + { + value = companent._state[id]; + }; + return [ + value, + newValue => { + if(typeof newValue == "function") + { + value = newValue(); + } + if(!Object.is(newValue, value)) + { + companent._state[id] = value; + return companent._render = true; + } + } + ] + }; + é.useState = useState; + + function vnode() + { + return { + type: é.type, + // Raw render requirements + parent: undefined, + key: undefined, + companent: undefined, + props:{}, + // Companent requirements + ref: undefined, + dom: undefined, + _state: [], + _hooks: [], + _render: true, + context: undefined + } + }; + window.é = é; + window.render = render; +})(window) \ No newline at end of file diff --git a/core.min.js b/core.min.js new file mode 100644 index 0000000..18cf35c --- /dev/null +++ b/core.min.js @@ -0,0 +1 @@ +(e=>{function t(e,o){let r;if("boolean"==typeof o&&!o||null==o||void 0===o)return document.createDocumentFragment();if(o.type==n.type){if("string"==typeof o.companent){r=document.createElement(o.companent);for(const[e,t]of Object.entries(o.props))["key","children"].includes(e)||(e.startsWith("on")?r.addEventListener(e.slice(2),t):r.setAttribute(e,t))}else if("function"==typeof o.companent){let e=function(e){i(e);let t=e.companent(e.props);return i(void 0),t}(o);r=t(null,e)}else"string"==typeof o.companent?r=document.createTextNode(companent):o.companent||(r=document.createDocumentFragment());if(o.props&&o.props.children instanceof Array)for(const e of o.props.children||[])"string"==typeof e?r.append(document.createTextNode(e)):t(r,e)}else if(o.$){r=document.createElement(o.$||"div");for(const[e,t]of Object.entries(o))switch(e){case"$":case"in":break;default:e.startsWith("on")?r.addEventListener(e.slice(2),t):r.setAttribute(e,t)}if(o.in)if(o.in instanceof Array)for(const e of o.in||[])"string"==typeof e?r.append(document.createTextNode(e)):t(r,e);else"string"==typeof o.in?r.append(document.createTextNode(o.in)):t(r,companent);o.parent=e,o.dom=r}else if(o instanceof Array)if(e)for(const n of o.flat(1/0))t(e,n);else{let e=document.createDocumentFragment();for(const n of o.flat(1/0))t(e,n);r=e}else"string"==typeof o&&(r=document.createTextNode(o));if(o._render=!1,!e)return r;e.append(r)}function n(e,t){if(e instanceof Array){let o=t instanceof Array?t:[];for(const t of e)t instanceof Array?n(t,o):o.push(n(t));return o=o.flat(1/0),n({$:n.fragment,in:o})}if(e.type==n.type)return e;let o,r,i={type:n.type,parent:void 0,key:void 0,companent:void 0,props:{},ref:void 0,dom:void 0,_state:[],_hooks:[],_render:!0,context:void 0},c={};if("function"==typeof e)i.companent=e,i.key=t&&"key"in t?t.key:void 0,i.props=t;else if("string"==typeof e)i.companent=null,i.props={children:[e]};else{if(!("$"in e))throw new Error("Unknown companent type");c={};for(const t of Object.keys(e))switch(t){case"$":o=e[t];break;case"in":e[t]instanceof Array?c.children=e[t].map(n):c.children=[n(e[t])];break;case"key":r=e[t];break;default:c[t]=e[t]}i.companent=o,i.key=r,i.props=c}return i}let o;n.type=Symbol("élement"),n.fragment=Symbol("framént");let r=0;function i(e){o=e,r=0}n.useState=function(e){let t,n=o,i=r++;if(!n)throw new Error("Cannot be used outside of components");return n._state.length<=i?(t="function"==typeof e?e():e,n._state[i]=t):t=n._state[i],[t,e=>{if("function"==typeof e&&(t=e()),!Object.is(e,t))return n._state[i]=t,n._render=!0}]},e.é=n,e.render=function(...e){let o=document.createElement("div");return function(e,o,r){r._renderPlanned||(requestAnimationFrame((()=>{!function(e,o,r){let i=n(o[0]);t(e,i)}(e,o)})),r._renderPlanned=!0)}(o,e,{}),o}})(window); \ No newline at end of file diff --git a/index.js b/index.js index 645a50f..8eec613 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,14 @@ -function BoldText({text}) +function Bootstrap() { + let [get, set] = é.useState(1); + setTimeout(()=>{ + set(2); + }, 5000); return { - $:"b", - in: text + $:"link", + rel: "stylesheet", + href: "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/css/bootstrap.min.css", + v: get } } let e = é({ @@ -11,13 +17,8 @@ let e = é({ onclick:()=>{ alert("Clicked ") }, - in:[ - "Hi !", - é(BoldText,{ - text: "Bold Hi!" - }) - ] + in: é(Bootstrap) }); -e = e.render(); -document.body.appendChild(e); \ No newline at end of file +let t = render(e); +document.body.appendChild(t); \ No newline at end of file