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