esaQute/core.js

326 lines
9.0 KiB
JavaScript

((window)=>{
function render(...entries)
{
let content = {};
let domContainer = document.createElement('div');
renderTreeQueQue(
domContainer,
entries,
content
);
return domContainer;
};
function renderTreeQueQue(domContainer, entries, content)
{
if(!content._renderPlanned)
{
requestAnimationFrame(()=>{
createTree(
domContainer,
entries,
content
)
});
content._renderPlanned = true;
}
};
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
)
{
return document.createDocumentFragment()
};
if(data.type == é.type)
{
if(typeof data.companent == "string")
{
elem = document.createElement(data.companent);
for (const [name,value] of Object.entries(data.props))
{
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)
{
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 == "string")
{
elem = document.createTextNode(data);
};
data._render = false;
if(parent)
{
parent.append(elem);
}
else
{
return elem;
}
}
function RenderCompanent(data)
{
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
})
}
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");
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)