The vanilla alternative for writing JSX-based React applications
git clone git://soophie.de/figure
blob: 23e244bd01a68939a9e711854e9372f3e9a2825b (2645 bytes)[doc][blame][raw]
1
const parser = new DOMParser();2
let counter = 1000;4
function tlx(parts, ...props) {5
const [html, refs] = ltr(parts, props);6
const dom = parser.parseFromString(html, 'text/html');7
if(dom.body.childNodes.length !== 1) {8
throw 'invalid DOM structure!';9
}10
const node = dom.body.childNodes[0];11
const elements = render(node, refs);12
if(elements.length !== 1) {13
throw 'invalid VDOM structure!';14
}15
return elements[0];16
}18
function render(node, refs) {19
if(node.nodeType === Node.TEXT_NODE) {20
return apply(node.textContent, refs);21
}22
const tag = node.tagName.toLowerCase();23
const attributes = {};24
for(const attribute of node.attributes) {25
const key = attribute.name;26
const value = attribute.textContent;27
let isDynamic = false;28
for(const ref in refs) {29
if(value === ref) {30
if((match = /^@(\w+)$/.exec(key)) !== null) {31
const event = match[1];32
attributes[`on${event.substr(0, 1).toUpperCase()}${event.substr(1)}`] = refs[ref];33
}34
else {35
attributes[key] = refs[ref];36
}37
isDynamic = true;38
break;39
}40
}41
if(!isDynamic) {42
if(key === 'style') {43
const styles = {};44
for(const item of value.split(';')) {45
if(item.trim().length === 0) {46
break;47
}48
let [key, value] = item.split(':');49
key = key.trim();50
if((match = /-(\w)/.exec(key)) !== null) {51
const char = match[1];52
key = key.replace(`-${char}`, char.toUpperCase());53
}54
value = value.trim();55
styles[key] = apply(value, refs).join('');56
}57
attributes[key] = styles;58
}59
else {60
attributes[key] = apply(value, refs).join('');61
}62
}63
}64
const children = [];65
(node.childNodes ?? []).forEach((child) => children.push(...render(child, refs)));66
return [React.createElement(tag, attributes, ...children)];67
}69
function apply(value, refs) {70
let values = [];71
const expr = /\$tlx-\d+/g;72
let match = null;73
let last = 0;74
while((match = expr.exec(value)) !== null) {75
const index = match.index;76
values.push(value.substring(last, index));77
values.push(refs[match[0]]);78
last = index + match[0].length;79
}80
values.push(value.substring(last));81
return values;82
}84
function ltr(parts, props) {85
let string = '';86
const refs = {};87
for(let i = 0; i < parts.length; i++) {88
string += parts[i];89
if(props[i] !== undefined) {90
const id = `$tlx-${counter}`;91
refs[id] = props[i];92
string += id ?? '';93
counter++;94
}95
}96
return [string.trim(), refs];97
}