Comparing version 0.0.4 to 0.0.5
{ | ||
"name": "realdom", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"author": "Fedot Kriutchenko <fodyadev@gmail.com>", | ||
@@ -5,0 +5,0 @@ "description": "", |
149
src/dom.js
import { runWithState, getCurrentHandler } from './state.js'; | ||
import { argsToArray, toString, kebab } from './common.js'; | ||
let tree = null; | ||
const symbol = Symbol(); | ||
export class Tree { | ||
list = [] | ||
i = 0 | ||
tmpl = null | ||
init() { | ||
let ns; | ||
let l = 0, node; | ||
const nodes = []; | ||
for (const item of this.list) switch (item.constructor) { | ||
case NodeOpen: | ||
const elem = ( | ||
item.tag === '' | ||
? document.createTextNode('') | ||
: document.createElement(item.tag) | ||
); | ||
if (node) node.appendChild(elem); else this.tmpl = elem; | ||
node = nodes[l] = elem; | ||
l++; | ||
break; | ||
case NodeOperation: | ||
if (!item.rerender) item.func(node, item.names, item.args); | ||
break; | ||
case NodeText: | ||
if (!item.rerender) node.textContent = item.value; | ||
break; | ||
case NodeClose: | ||
l--; | ||
node = nodes[l - 1]; | ||
break; | ||
} | ||
} | ||
hydrate(root) { | ||
let l = 0, node; | ||
const path = []; | ||
const nodes = []; | ||
for (const item of this.list) switch (item.constructor) { | ||
case NodeOpen: | ||
node = nodes[l] = node ? node.childNodes[path[l - 1]] : root; | ||
path[l] = 0; | ||
l++; | ||
break; | ||
case NodeOperation: | ||
if (item.rerender) item.func(node, item.names, item.args); | ||
break; | ||
case NodeText: | ||
if (item.rerender) node.textContent = item.value; | ||
break; | ||
case NodeClose: | ||
l--; | ||
node = nodes[l - 1]; | ||
path[l - 1]++; | ||
break; | ||
} | ||
return root; | ||
} | ||
update(treeNode) { | ||
const prevTree = tree; | ||
tree = this; | ||
this.i = 0; | ||
treeNode(); | ||
if (!this.tmpl) { this.init(); console.log(this); } | ||
tree = prevTree; | ||
} | ||
} | ||
function builder(effect) { | ||
@@ -80,4 +10,7 @@ let names = []; | ||
const call = (...args) => { | ||
if (args.length === 0) { | ||
for (const t of tasks) effect(t.names, t.args); | ||
if (args[0] === symbol) { | ||
const a = args.slice(1); | ||
let res; | ||
for (const t of tasks) res ??= effect(t.names, t.args, ...a); | ||
return res; | ||
} else { | ||
@@ -90,3 +23,3 @@ tasks.push({ names, args }); | ||
const get = (_, k) => { | ||
if (k === symbol) return true; | ||
if (k === symbol) return effect[k]; | ||
names.push(k); | ||
@@ -98,48 +31,50 @@ return p; | ||
export const Builder = (effect) => new Proxy( | ||
(...a) => builder(effect)(...a), | ||
{ get: (_, k) => builder(effect)[k] } | ||
); | ||
export const Operator = (reactive, func) => { | ||
const effect = (names, args, node, init) => { | ||
const r = typeof reactive == 'function' ? reactive(args) : reactive; | ||
if (init || r) func(node, names, args); | ||
} | ||
effect[symbol] = 2; | ||
return new Proxy( | ||
(...a) => builder(effect)(...a), | ||
{ get: (_, k) => builder(effect)[k] } | ||
); | ||
} | ||
class NodeOpen { | ||
constructor(tag) { this.tag = tag; } | ||
const elementBuilder = effect => { | ||
effect[symbol] = 1; | ||
return builder(effect); | ||
} | ||
class NodeOperation { | ||
constructor(func, names) { this.func = func; this.names = names; } | ||
update(rerender, args) { this.rerender = rerender; this.args = args; } | ||
} | ||
class NodeText { | ||
constructor(value) { this.value = value; } | ||
update(value) { this.rerender = this.value != value; this.value = value; } | ||
} | ||
class NodeClose {} | ||
export const Operator = (reactive, func) => Builder((names, args) => { | ||
(tree.list[tree.i++] ??= new NodeOperation(func, names)).update( | ||
typeof reactive == 'function' ? reactive(args) : reactive, | ||
args | ||
export const Element = tag => elementBuilder((_, content, node, init) => { | ||
init ??= !node; | ||
node ??= ( | ||
tag === '' ? document.createTextNode('') : | ||
document.createElement(tag) | ||
); | ||
}); | ||
export const Element = tag => builder((_, content) => { | ||
tree.list[tree.i++] ??= new NodeOpen( | ||
!tag ? tag : tag[0].toLowerCase() + kebab(tag.slice(1)) | ||
); | ||
let childNode; | ||
for (const item of argsToArray(content)) { | ||
if (typeof item == 'function' && item[symbol]) item(); | ||
else { | ||
tree.list[tree.i++] ??= new NodeOpen(''); | ||
(tree.list[tree.i++] ??= new NodeText(item)).update(item); | ||
tree.list[tree.i++] ??= new NodeClose(); | ||
const type = typeof item == 'function' && item[symbol]; | ||
if (type === 1) { | ||
if (init) { | ||
node.appendChild(item(symbol, null, init)); | ||
} else { | ||
item(symbol, childNode ??= node.firstChild, init); | ||
childNode = childNode.nextSibling; | ||
} | ||
} | ||
else if (type === 2) item(symbol, node, init); | ||
else if (tag === '') node.textContent = toString(item); | ||
else Element('')(item)(symbol, node, init); | ||
} | ||
tree.list[tree.i++] ??= new NodeClose(); | ||
return node; | ||
}); | ||
export const Component = func => { | ||
const compTree = new Tree(); | ||
let i = 0; | ||
let tmpl; | ||
return (...args) => { | ||
compTree.update(func(...args)); | ||
return compTree.hydrate(compTree.tmpl.cloneNode(true)); | ||
const clone = func(...args)(symbol, tmpl?.cloneNode?.(true)); | ||
tmpl ??= clone; | ||
return clone; | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3283
71