so://phie

figure

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

blob: ae0918053155a821025d95ab6c480518610f35eb (3979 bytes)[doc][blame][raw]

1const parser = new DOMParser();

2let count = 1000;

3let create = null;

4

5const figure = ({createElement}) => {

6 create = createElement;

7}

8

9const 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}

29

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 populated

33 * HTML string returned.

34 *

35 * @param {string[]} strings - The template literal strings

36 * @param {any[]} props - The template literal properties

37 * @return {any[]} The joined HTML string and the properties mapped to there references.

38 */

39const 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}

52

53/**

54 * Injects the properties into the corresponding reference locations of the string.

55 *

56 * @param {string} string - The string containing references

57 * @param {any[]} refs - The properties mapped to there references

58 * @return {any[]} The string populate with the passed properties

59 */

60const 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}

79

80const 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}

135

136import {defCss, defStyle} from './mods.js';

137

138const css = defCss({html, compose, feed});

139const style = defStyle({html, compose, feed});

140

141export { figure, html, css, style };