360 lines
10 KiB
JavaScript
360 lines
10 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 = RenderCompanentScope(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
|
||
{
|
||
RenderCompanentScope(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
|
||
{
|
||
RenderCompanentScope(elem, companent)
|
||
}
|
||
}
|
||
}else{
|
||
if(
|
||
typeof data.in == "string"
|
||
)
|
||
{
|
||
elem.append(document.createTextNode(data.in));
|
||
}
|
||
else
|
||
{
|
||
RenderCompanentScope(elem, companent)
|
||
}
|
||
}
|
||
}
|
||
data.parent = parent;
|
||
data.dom = elem;
|
||
}
|
||
else if(data instanceof Array)
|
||
{
|
||
if(parent)
|
||
{
|
||
for (const vdata of data.flat(Infinity)) {
|
||
RenderCompanentScope(parent, vdata)
|
||
};
|
||
}
|
||
else
|
||
{
|
||
let d = document.createDocumentFragment();
|
||
for (const vdata of data.flat(Infinity)) {
|
||
RenderCompanentScope(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 RenderCompanentScope(data)
|
||
{
|
||
useCompanent(data);
|
||
let result = data.companent(data.props);
|
||
useCompanent(undefined);
|
||
return result;
|
||
};
|
||
function clone(original)
|
||
{
|
||
if(Array.isArray(original))
|
||
{
|
||
let e = [];
|
||
for (const original of original) {
|
||
// Klonlanabilirlik
|
||
}
|
||
}
|
||
}
|
||
function checkSyncRender(data)
|
||
{
|
||
// İki kompanentin farkına bakılmalı ve yeniden çizilmeleri gerekiyor
|
||
}
|
||
function scheduleRender(data)
|
||
{
|
||
if(scheduleRender.planned)
|
||
{
|
||
scheduleRender.items.push(data);
|
||
return;
|
||
};
|
||
requestAnimationFrame(()=>{
|
||
scheduleRender.planned = false;
|
||
checkSyncRender(data)
|
||
});
|
||
scheduleRender.planned = true;
|
||
};
|
||
scheduleRender.planned = false;
|
||
scheduleRender.items = [];
|
||
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((child) => {
|
||
let item = é(child);
|
||
item.parent = t;
|
||
return item;
|
||
});
|
||
}else{
|
||
let child = é(a[index]);
|
||
child.parent = t;
|
||
props.children = [child]
|
||
}
|
||
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;
|
||
companent._render = true;
|
||
scheduleRenderCompanent(companent);
|
||
}
|
||
}
|
||
]
|
||
};
|
||
é.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) |