The vanilla alternative for writing JSX-based React applications
git clone git://soophie.de/figure
blob: 4783f1ad4fe1cad8f80dc5bdb559f3938a0862cc (4331 bytes)[doc][blame][raw]
1
const parser = new DOMParser();2
let count = 1000;3
let create = null;5
const segment = ({createElement}) => {6
create = createElement;7
}9
const html = (strings, ...props) => {10
const elements = parse(strings, ...props);11
if(elements.length === 0) {12
throw 'No DOM element was returned!';13
}14
if(elements.length > 1) {15
console.warn('Only one DOM element can be returned!');16
}17
return elements[0];18
}20
const parse = (strings, ...props) => {21
const [html, refs] = compose(strings, props);22
let dom;23
try {24
dom = parser.parseFromString(html, 'text/html');25
}26
catch(error) {27
console.error(error);28
throw 'Invalid DOM structure!';29
}30
const nodes = [...dom.head.childNodes, ...dom.body.childNodes];31
return nodes.map((node) => render(node, refs));32
}34
/**35
* Joins the template literal strings together and replaces the properties with references.36
* The properties are being mapped to there corresponding references and with the populated37
* HTML string returned.38
*39
* @param {string[]} strings - The template literal strings40
* @param {any[]} props - The template literal properties41
* @return {any[]} The joined HTML string and the properties mapped to there references.42
*/43
const compose = (strings, props) => {44
if(strings === undefined) {45
// handles dyn function without body46
return ['', {}];47
}48
const refs = {};49
let string = '';50
for(let i = 0; i < strings.length; i++) {51
string += strings[i];52
if(props[i] !== undefined) {53
const uid = `$seg-${count++}`;54
refs[uid] = props[i];55
string += uid ?? '';56
}57
}58
return [string.trim(), refs];59
}61
/**62
* Injects the properties into the corresponding reference locations of the string.63
*64
* @param {string} string - The string containing references65
* @param {any[]} refs - The properties mapped to there references66
* @return {any[]} The string populate with the passed properties67
*/68
const feed = (string, refs) => {69
const expr = /\$seg-\d+/g;70
let values = [];71
let match = null;72
let last = 0;73
while((match = expr.exec(string)) !== null) {74
const index = match.index;75
const uid = match[0];76
values.push(string.substring(last, index));77
let value = refs[uid];78
if(value instanceof Function) {79
value = value();80
}81
values.push(value);82
last = index + uid.length;83
}84
values.push(string.substring(last));85
return values;86
}88
const dyn = (element, props) => {89
return (strings, ...childProps) => {90
return create(element, props, ...parse(strings, ...childProps));91
};92
}94
const render = (node, refs) => {95
if(node.nodeType === Node.TEXT_NODE) {96
return feed(node.textContent, refs);97
}98
if(node.nodeType === Node.COMMENT_NODE) {99
return [];100
}101
const tag = node.tagName;102
const attributes = {};103
for(const attribute of node.attributes) {104
const key = attribute.name;105
const value = attribute.textContent;106
let isDynamic = false;107
for(const ref in refs) {108
if(value === ref) {109
let match = null;110
if((match = /^@(\w+)$/.exec(key)) !== null) {111
const event = match[1];112
attributes[`on${event.substring(0, 1).toUpperCase()}${event.substring(1)}`] = refs[ref];113
}114
else {115
attributes[key] = refs[ref];116
}117
isDynamic = true;118
break;119
}120
}121
if(!isDynamic) {122
if(key === 'style') {123
const styles = {};124
for(const item of value.split(';')) {125
if(item.trim().length === 0) {126
break;127
}128
let [key, value] = item.split(':');129
key = key.trim();130
let match = null;131
if((match = /-(\w)/.exec(key)) !== null) {132
const char = match[1];133
key = key.replace(`-${char}`, char.toUpperCase());134
}135
value = value.trim();136
styles[key] = feed(value, refs).join('');137
}138
attributes[key] = styles;139
}140
else {141
attributes[key] = feed(value, refs).join('');142
}143
}144
}145
const children = [];146
(node.childNodes ?? []).forEach((child) => children.push(...render(child, refs)));147
return [create(tag, attributes, ...children)];148
}150
import {defCss, defStyle} from './mods.js';152
const css = defCss({html, compose, feed});153
const style = defStyle({html, compose, feed});155
export { segment, html, dyn, css, style };