The vanilla alternative for writing JSX-based React applications
git clone git://soophie.de/figure
1
# segment1
# figure2
Reactive template literals for React4
### Example6
```javascript7
import {segment, html, css} from './segment.js';7
import {figure, html, css} from '...';9
segment({createElement});9
figure({createElement});11
const Counter = () => {12
const [count, setCount] = useState(0);
5
import {useState, createElement} from 'https://cdn.skypack.dev/react';6
import {render} from 'https://cdn.skypack.dev/react-dom';7
import {segment, html, css} from '../segment.js';7
import {figure, html, css} from '../lib.js';9
const Counter = () => {10
const [count, setCount] = useState(0);
43
}45
const app = document.querySelector('#app');46
segment({createElement});46
figure({createElement});47
render(createElement(Counter), app);49
</script>
5
import {useState, createElement} from 'https://cdn.skypack.dev/react';6
import {render} from 'https://cdn.skypack.dev/react-dom';7
import {segment, html, css} from '../segment.js';7
import {figure, html, css} from '../lib.js';9
const Range = ({index, value, setValue}) => {10
const style = css`
85
}87
const app = document.querySelector('#app');88
segment({createElement});88
figure({createElement});89
render(createElement(Picker), app);91
</script>
1
const parser = new DOMParser();2
let count = 1000;3
let create = null;5
const figure = ({createElement}) => {6
create = createElement;7
}9
const html = (strings, ...props) => {10
const [html, refs] = compose(strings, props);11
let dom;12
try {13
dom = parser.parseFromString(html, 'text/html');14
}15
catch(error) {16
console.error(error);17
throw 'Invalid DOM structure!';18
}19
const node = dom.body.childNodes[0] ?? dom.head.childNodes[0];20
const elements = render(node, refs);21
if(elements.length === 0) {22
throw 'No DOM element was returned!';23
}24
if(elements.length > 1) {25
console.warn('Only one DOM element can be returned!');26
}27
return elements[0];28
}30
/**31
* Joins the template literal strings together and replaces the properties with references.32
* The properties are being mapped to there corresponding references and with the populated33
* HTML string returned.34
*35
* @param {string[]} strings - The template literal strings36
* @param {any[]} props - The template literal properties37
* @return {any[]} The joined HTML string and the properties mapped to there references.38
*/39
const compose = (strings, props) => {40
const refs = {};41
let string = '';42
for(let i = 0; i < strings.length; i++) {43
string += strings[i];44
if(props[i] !== undefined) {45
const uid = `$tlx-${count++}`;46
refs[uid] = props[i];47
string += uid ?? '';48
}49
}50
return [string.trim(), refs];51
}53
/**54
* Injects the properties into the corresponding reference locations of the string.55
*56
* @param {string} string - The string containing references57
* @param {any[]} refs - The properties mapped to there references58
* @return {any[]} The string populate with the passed properties59
*/60
const feed = (string, refs) => {61
const expr = /\$tlx-\d+/g;62
let values = [];63
let match = null;64
let last = 0;65
while((match = expr.exec(string)) !== null) {66
const index = match.index;67
const uid = match[0];68
values.push(string.substring(last, index));69
let value = refs[uid];70
if(value instanceof Function) {71
value = value();72
}73
values.push(value);74
last = index + uid.length;75
}76
values.push(string.substring(last));77
return values;78
}80
const render = (node, refs) => {81
if(node.nodeType === Node.TEXT_NODE) {82
return feed(node.textContent, refs);83
}84
if(node.nodeType === Node.COMMENT_NODE) {85
return [];86
}87
const tag = node.tagName;88
const attributes = {};89
for(const attribute of node.attributes) {90
const key = attribute.name;91
const value = attribute.textContent;92
let isDynamic = false;93
for(const ref in refs) {94
if(value === ref) {95
let match = null;96
if((match = /^@(\w+)$/.exec(key)) !== null) {97
const event = match[1];98
attributes[`on${event.substring(0, 1).toUpperCase()}${event.substring(1)}`] = refs[ref];99
}100
else {101
attributes[key] = refs[ref];102
}103
isDynamic = true;104
break;105
}106
}107
if(!isDynamic) {108
if(key === 'style') {109
const styles = {};110
for(const item of value.split(';')) {111
if(item.trim().length === 0) {112
break;113
}114
let [key, value] = item.split(':');115
key = key.trim();116
let match = null;117
if((match = /-(\w)/.exec(key)) !== null) {118
const char = match[1];119
key = key.replace(`-${char}`, char.toUpperCase());120
}121
value = value.trim();122
styles[key] = feed(value, refs).join('');123
}124
attributes[key] = styles;125
}126
else {127
attributes[key] = feed(value, refs).join('');128
}129
}130
}131
const children = [];132
(node.childNodes ?? []).forEach((child) => children.push(...render(child, refs)));133
return [create(tag, attributes, ...children)];134
}136
import {defCss, defStyle} from './mods.js';138
const css = defCss({html, compose, feed});139
const style = defStyle({html, compose, feed});141
export { figure, html, css, style };
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 [html, refs] = compose(strings, props);11
let dom;12
try {13
dom = parser.parseFromString(html, 'text/html');14
}15
catch(error) {16
console.error(error);17
throw 'Invalid DOM structure!';18
}19
const node = dom.body.childNodes[0] ?? dom.head.childNodes[0];20
const elements = render(node, refs);21
if(elements.length === 0) {22
throw 'No DOM element was returned!';23
}24
if(elements.length > 1) {25
console.warn('Only one DOM element can be returned!');26
}27
return elements[0];28
}30
/**31
* Joins the template literal strings together and replaces the properties with references.32
* The properties are being mapped to there corresponding references and with the populated33
* HTML string returned.34
*35
* @param {string[]} strings - The template literal strings36
* @param {any[]} props - The template literal properties37
* @return {any[]} The joined HTML string and the properties mapped to there references.38
*/39
const compose = (strings, props) => {40
const refs = {};41
let string = '';42
for(let i = 0; i < strings.length; i++) {43
string += strings[i];44
if(props[i] !== undefined) {45
const uid = `$tlx-${count++}`;46
refs[uid] = props[i];47
string += uid ?? '';48
}49
}50
return [string.trim(), refs];51
}53
/**54
* Injects the properties into the corresponding reference locations of the string.55
*56
* @param {string} string - The string containing references57
* @param {any[]} refs - The properties mapped to there references58
* @return {any[]} The string populate with the passed properties59
*/60
const feed = (string, refs) => {61
const expr = /\$tlx-\d+/g;62
let values = [];63
let match = null;64
let last = 0;65
while((match = expr.exec(string)) !== null) {66
const index = match.index;67
const uid = match[0];68
values.push(string.substring(last, index));69
let value = refs[uid];70
if(value instanceof Function) {71
value = value();72
}73
values.push(value);74
last = index + uid.length;75
}76
values.push(string.substring(last));77
return values;78
}80
const render = (node, refs) => {81
if(node.nodeType === Node.TEXT_NODE) {82
return feed(node.textContent, refs);83
}84
if(node.nodeType === Node.COMMENT_NODE) {85
return [];86
}87
const tag = node.tagName;88
const attributes = {};89
for(const attribute of node.attributes) {90
const key = attribute.name;91
const value = attribute.textContent;92
let isDynamic = false;93
for(const ref in refs) {94
if(value === ref) {95
let match = null;96
if((match = /^@(\w+)$/.exec(key)) !== null) {97
const event = match[1];98
attributes[`on${event.substring(0, 1).toUpperCase()}${event.substring(1)}`] = refs[ref];99
}100
else {101
attributes[key] = refs[ref];102
}103
isDynamic = true;104
break;105
}106
}107
if(!isDynamic) {108
if(key === 'style') {109
const styles = {};110
for(const item of value.split(';')) {111
if(item.trim().length === 0) {112
break;113
}114
let [key, value] = item.split(':');115
key = key.trim();116
let match = null;117
if((match = /-(\w)/.exec(key)) !== null) {118
const char = match[1];119
key = key.replace(`-${char}`, char.toUpperCase());120
}121
value = value.trim();122
styles[key] = feed(value, refs).join('');123
}124
attributes[key] = styles;125
}126
else {127
attributes[key] = feed(value, refs).join('');128
}129
}130
}131
const children = [];132
(node.childNodes ?? []).forEach((child) => children.push(...render(child, refs)));133
return [create(tag, attributes, ...children)];134
}136
import {defCss, defStyle} from './mods.js';138
const css = defCss({html, compose, feed});139
const style = defStyle({html, compose, feed});141
export { segment, html, css, style };