so://phie

figure

The vanilla alternative for writing JSX-based React applications
git clone git://soophie.de/figure

blob: 23e244bd01a68939a9e711854e9372f3e9a2825b (2645 bytes)[doc][blame][raw]

1const parser = new DOMParser();

2let counter = 1000;

3

4function 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}

17

18function 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}

68

69function 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}

83

84function 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}