@esportsplus/template 0.28.3 → 0.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/build/attributes.d.ts +7 -1
  2. package/build/attributes.js +86 -33
  3. package/build/constants.d.ts +3 -11
  4. package/build/constants.js +4 -32
  5. package/build/event/constants.d.ts +3 -0
  6. package/build/event/constants.js +13 -0
  7. package/build/event/index.d.ts +9 -1
  8. package/build/event/index.js +29 -35
  9. package/build/event/ontick.js +6 -9
  10. package/build/html.d.ts +9 -0
  11. package/build/html.js +7 -0
  12. package/build/index.d.ts +8 -2
  13. package/build/index.js +8 -1
  14. package/build/render.d.ts +2 -2
  15. package/build/render.js +2 -3
  16. package/build/runtime.d.ts +1 -0
  17. package/build/runtime.js +5 -0
  18. package/build/slot/array.d.ts +3 -3
  19. package/build/slot/array.js +11 -14
  20. package/build/slot/cleanup.d.ts +1 -1
  21. package/build/slot/cleanup.js +1 -2
  22. package/build/slot/effect.js +5 -7
  23. package/build/slot/index.js +1 -7
  24. package/build/slot/render.js +6 -8
  25. package/build/svg.d.ts +1 -1
  26. package/build/svg.js +1 -1
  27. package/build/transformer/codegen.d.ts +18 -0
  28. package/build/transformer/codegen.js +316 -0
  29. package/build/transformer/index.d.ts +12 -0
  30. package/build/transformer/index.js +62 -0
  31. package/build/transformer/parser.d.ts +18 -0
  32. package/build/transformer/parser.js +166 -0
  33. package/build/transformer/plugins/esbuild.d.ts +5 -0
  34. package/build/transformer/plugins/esbuild.js +35 -0
  35. package/build/transformer/plugins/tsc.d.ts +3 -0
  36. package/build/transformer/plugins/tsc.js +4 -0
  37. package/build/transformer/plugins/vite.d.ts +5 -0
  38. package/build/transformer/plugins/vite.js +37 -0
  39. package/build/transformer/ts-parser.d.ts +21 -0
  40. package/build/transformer/ts-parser.js +72 -0
  41. package/build/transformer/type-analyzer.d.ts +7 -0
  42. package/build/transformer/type-analyzer.js +230 -0
  43. package/build/types.d.ts +2 -3
  44. package/build/utilities.d.ts +7 -0
  45. package/build/utilities.js +31 -0
  46. package/package.json +11 -4
  47. package/src/attributes.ts +115 -51
  48. package/src/constants.ts +6 -53
  49. package/src/event/constants.ts +16 -0
  50. package/src/event/index.ts +36 -42
  51. package/src/event/onconnect.ts +1 -1
  52. package/src/event/onresize.ts +1 -1
  53. package/src/event/ontick.ts +7 -11
  54. package/src/html.ts +18 -0
  55. package/src/index.ts +8 -2
  56. package/src/render.ts +6 -7
  57. package/src/runtime.ts +8 -0
  58. package/src/slot/array.ts +18 -24
  59. package/src/slot/cleanup.ts +3 -4
  60. package/src/slot/effect.ts +6 -8
  61. package/src/slot/index.ts +2 -8
  62. package/src/slot/render.ts +7 -9
  63. package/src/svg.ts +1 -1
  64. package/src/transformer/codegen.ts +518 -0
  65. package/src/transformer/index.ts +98 -0
  66. package/src/transformer/parser.ts +239 -0
  67. package/src/transformer/plugins/esbuild.ts +46 -0
  68. package/src/transformer/plugins/tsc.ts +7 -0
  69. package/src/transformer/plugins/vite.ts +49 -0
  70. package/src/transformer/ts-parser.ts +123 -0
  71. package/src/transformer/type-analyzer.ts +334 -0
  72. package/src/types.ts +3 -4
  73. package/src/utilities.ts +52 -0
  74. package/storage/rewrite-analysis-2026-01-04.md +439 -0
  75. package/test/constants.ts +69 -0
  76. package/test/effects.ts +237 -0
  77. package/test/events.ts +318 -0
  78. package/test/imported-values.ts +253 -0
  79. package/test/nested.ts +298 -0
  80. package/test/slots.ts +259 -0
  81. package/test/spread.ts +290 -0
  82. package/test/static.ts +118 -0
  83. package/test/templates.ts +473 -0
  84. package/test/tsconfig.json +17 -0
  85. package/test/vite.config.ts +50 -0
  86. package/build/html/index.d.ts +0 -9
  87. package/build/html/index.js +0 -29
  88. package/build/html/parser.d.ts +0 -5
  89. package/build/html/parser.js +0 -165
  90. package/build/utilities/element.d.ts +0 -11
  91. package/build/utilities/element.js +0 -9
  92. package/build/utilities/fragment.d.ts +0 -3
  93. package/build/utilities/fragment.js +0 -10
  94. package/build/utilities/marker.d.ts +0 -2
  95. package/build/utilities/marker.js +0 -4
  96. package/build/utilities/node.d.ts +0 -9
  97. package/build/utilities/node.js +0 -10
  98. package/build/utilities/raf.d.ts +0 -2
  99. package/build/utilities/raf.js +0 -1
  100. package/build/utilities/text.d.ts +0 -2
  101. package/build/utilities/text.js +0 -9
  102. package/src/html/index.ts +0 -48
  103. package/src/html/parser.ts +0 -235
  104. package/src/utilities/element.ts +0 -28
  105. package/src/utilities/fragment.ts +0 -19
  106. package/src/utilities/marker.ts +0 -6
  107. package/src/utilities/node.ts +0 -29
  108. package/src/utilities/raf.ts +0 -1
  109. package/src/utilities/text.ts +0 -15
@@ -1,9 +1,15 @@
1
1
  import { Attributes, Element } from './types.js';
2
2
  declare const set: (element: Element, name: string, value: unknown) => void;
3
+ declare const setClass: (element: Element, classlist: false | string | undefined, value: unknown) => void;
4
+ declare const setProperty: (element: Element, name: string, value: unknown) => void;
5
+ declare const setStyle: (element: Element, styles: false | string | undefined, value: unknown) => void;
3
6
  declare const spread: (element: Element, value: Attributes | Attributes[]) => void;
4
7
  declare const _default: {
5
8
  set: (element: Element, name: string, value: unknown) => void;
9
+ setClass: (element: Element, classlist: false | string | undefined, value: unknown) => void;
10
+ setProperty: (element: Element, name: string, value: unknown) => void;
11
+ setStyle: (element: Element, styles: false | string | undefined, value: unknown) => void;
6
12
  spread: (element: Element, value: Attributes | Attributes[]) => void;
7
13
  };
8
14
  export default _default;
9
- export { set, spread };
15
+ export { set, setClass, setProperty, setStyle, spread };
@@ -1,9 +1,8 @@
1
1
  import { effect } from '@esportsplus/reactivity';
2
2
  import { isArray, isObject } from '@esportsplus/utilities';
3
- import { STATE_HYDRATING, STATE_NONE, STATE_WAITING } from './constants.js';
4
- import { className, removeAttribute, setAttribute } from './utilities/element.js';
3
+ import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, STATE_HYDRATING, STATE_NONE, STATE_WAITING } from './constants.js';
4
+ import { raf } from './utilities.js';
5
5
  import q from '@esportsplus/queue';
6
- import raf from './utilities/raf.js';
7
6
  import event from './event/index.js';
8
7
  const STORE = Symbol();
9
8
  let delimiters = {
@@ -12,13 +11,13 @@ let delimiters = {
12
11
  }, queue = q(64), scheduled = false;
13
12
  function apply(element, name, value) {
14
13
  if (value == null || value === false || value === '') {
15
- removeAttribute.call(element, name);
14
+ element.removeAttribute(name);
16
15
  }
17
16
  else if (name === 'class') {
18
- className.call(element, value);
17
+ element.className = value;
19
18
  }
20
19
  else if (name === 'style' || (name[0] === 'd' && name.startsWith('data-')) || element['ownerSVGElement']) {
21
- setAttribute.call(element, name, value);
20
+ element.setAttribute(name, value);
22
21
  }
23
22
  else {
24
23
  element[name] = value;
@@ -31,7 +30,7 @@ function list(ctx, element, id, name, state, value) {
31
30
  if (value == null || value === false || value === '') {
32
31
  value = '';
33
32
  }
34
- let base = name + '.static', delimiter = delimiters[name], store = (ctx ??= context(element)).store ??= {}, dynamic = store[name];
33
+ let base = name + '.static', changed = false, delimiter = delimiters[name], store = (ctx ??= context(element)).store ??= {}, dynamic = store[name];
35
34
  if (dynamic === undefined) {
36
35
  let value = (element.getAttribute(name) || '').trim();
37
36
  store[base] = value;
@@ -39,10 +38,15 @@ function list(ctx, element, id, name, state, value) {
39
38
  }
40
39
  if (id === null) {
41
40
  if (value && typeof value === 'string') {
41
+ changed = true;
42
42
  store[base] += (store[base] ? delimiter : '') + value;
43
43
  }
44
44
  }
45
45
  else {
46
+ if (store[id + '.raw'] === value) {
47
+ return;
48
+ }
49
+ store[id + '.raw'] = value;
46
50
  let hot = {};
47
51
  if (value && typeof value === 'string') {
48
52
  let part, parts = value.split(delimiter);
@@ -51,7 +55,10 @@ function list(ctx, element, id, name, state, value) {
51
55
  if (part === '') {
52
56
  continue;
53
57
  }
54
- dynamic.add(part);
58
+ if (!dynamic.has(part)) {
59
+ changed = true;
60
+ dynamic.add(part);
61
+ }
55
62
  hot[part] = true;
56
63
  }
57
64
  }
@@ -61,11 +68,15 @@ function list(ctx, element, id, name, state, value) {
61
68
  if (hot[part] === true) {
62
69
  continue;
63
70
  }
71
+ changed = true;
64
72
  dynamic.delete(part);
65
73
  }
66
74
  }
67
75
  store[id] = hot;
68
76
  }
77
+ if (!changed) {
78
+ return;
79
+ }
69
80
  value = store[base];
70
81
  for (let key of dynamic) {
71
82
  value += (value ? delimiter : '') + key;
@@ -95,6 +106,26 @@ function property(ctx, element, id, name, state, value) {
95
106
  schedule(ctx, element, name, state, value);
96
107
  }
97
108
  }
109
+ function reactive(element, name, state, value) {
110
+ let ctx = context(element), fn = name === 'class' || name === 'style' ? list : property;
111
+ ctx.effect ??= 0;
112
+ let id = ctx.effect++;
113
+ effect(() => {
114
+ let v = value(element);
115
+ if (v == null || typeof v !== 'object') {
116
+ fn(ctx, element, id, name, state, v);
117
+ }
118
+ else if (isArray(v)) {
119
+ let last = v.length - 1;
120
+ for (let i = 0, n = v.length; i < n; i++) {
121
+ fn(ctx, element, id, name, state === STATE_HYDRATING
122
+ ? state
123
+ : i !== last ? STATE_WAITING : state, v[i]);
124
+ }
125
+ }
126
+ });
127
+ state = STATE_NONE;
128
+ }
98
129
  function schedule(ctx, element, name, state, value) {
99
130
  ctx ??= context(element);
100
131
  (ctx.updates ??= {})[name] = value;
@@ -126,32 +157,25 @@ function task() {
126
157
  }
127
158
  }
128
159
  const set = (element, name, value) => {
129
- let fn = name === 'class' || name === 'style' ? list : property, state = STATE_HYDRATING;
130
160
  if (typeof value === 'function') {
131
161
  if (name[0] === 'o' && name[1] === 'n') {
132
- return event(element, name, value);
133
- }
134
- let ctx = context(element);
135
- ctx.effect ??= 0;
136
- let id = ctx.effect++;
137
- effect(() => {
138
- let v = value(element);
139
- if (v == null || typeof v !== 'object') {
140
- fn(ctx, element, id, name, state, v);
162
+ let e = name.slice(2).toLowerCase(), key = name.toLowerCase();
163
+ if (LIFECYCLE_EVENTS.has(key)) {
164
+ event[key](element, value);
141
165
  }
142
- else if (isArray(v)) {
143
- let last = v.length - 1;
144
- for (let i = 0, n = v.length; i < n; i++) {
145
- fn(ctx, element, id, name, state === STATE_HYDRATING
146
- ? state
147
- : i !== last ? STATE_WAITING : state, v[i]);
148
- }
166
+ else if (DIRECT_ATTACH_EVENTS.has(key)) {
167
+ event.direct(element, e, value);
168
+ }
169
+ else {
170
+ event.delegate(element, e, value);
149
171
  }
150
- });
151
- state = STATE_NONE;
172
+ }
173
+ else {
174
+ reactive(element, name, STATE_HYDRATING, value);
175
+ }
152
176
  return;
153
177
  }
154
- if (typeof value !== 'object') {
178
+ else if (typeof value !== 'object') {
155
179
  }
156
180
  else if (isArray(value)) {
157
181
  for (let i = 0, n = value.length; i < n; i++) {
@@ -163,12 +187,41 @@ const set = (element, name, value) => {
163
187
  }
164
188
  return;
165
189
  }
166
- fn(null, element, null, name, state, value);
190
+ (name === 'class' || name === 'style' ? list : property)(null, element, null, name, STATE_HYDRATING, value);
191
+ };
192
+ const setClass = (element, classlist, value) => {
193
+ let ctx = context(element), store = ctx.store ??= {};
194
+ store['class.static'] = classlist || '';
195
+ store['class'] ??= new Set();
196
+ if (typeof value === 'function') {
197
+ reactive(element, 'class', STATE_HYDRATING, value);
198
+ }
199
+ else {
200
+ list(ctx, element, null, 'class', STATE_HYDRATING, value);
201
+ }
202
+ };
203
+ const setProperty = (element, name, value) => {
204
+ if (typeof value === 'function') {
205
+ reactive(element, name, STATE_HYDRATING, value);
206
+ }
207
+ else {
208
+ property(null, element, null, name, STATE_HYDRATING, value);
209
+ }
210
+ };
211
+ const setStyle = (element, styles, value) => {
212
+ let ctx = context(element), store = ctx.store ??= {};
213
+ store['style.static'] = styles || '';
214
+ store['style'] ??= new Set();
215
+ if (typeof value === 'function') {
216
+ reactive(element, 'style', STATE_HYDRATING, value);
217
+ }
218
+ else {
219
+ list(ctx, element, null, 'style', STATE_HYDRATING, value);
220
+ }
167
221
  };
168
222
  const spread = function (element, value) {
169
223
  if (isObject(value)) {
170
- let names = Object.keys(value), name;
171
- while (name = names.pop()) {
224
+ for (let name in value) {
172
225
  let v = value[name];
173
226
  if (v == null || v === false || v === '') {
174
227
  continue;
@@ -182,5 +235,5 @@ const spread = function (element, value) {
182
235
  }
183
236
  }
184
237
  };
185
- export default { set, spread };
186
- export { set, spread };
238
+ export default { set, setClass, setProperty, setStyle, spread };
239
+ export { set, setClass, setProperty, setStyle, spread };
@@ -1,18 +1,10 @@
1
1
  declare const ARRAY_SLOT: unique symbol;
2
2
  declare const CLEANUP: unique symbol;
3
3
  declare const EMPTY_FRAGMENT: DocumentFragment;
4
- declare const NODE_CLOSING = 1;
5
- declare const NODE_ELEMENT = 3;
6
- declare const NODE_SLOT = 4;
7
- declare const NODE_VOID = 5;
8
- declare const NODE_WHITELIST: Record<string, number>;
9
- declare const REGEX_EMPTY_TEXT_NODES: RegExp;
10
- declare const REGEX_EVENTS: RegExp;
11
- declare const REGEX_SLOT_ATTRIBUTES: RegExp;
12
- declare const REGEX_SLOT_NODES: RegExp;
13
4
  declare const SLOT_HTML = "<!--$-->";
14
- declare const SLOT_MARKER = "{{$}}";
15
5
  declare const STATE_HYDRATING = 0;
16
6
  declare const STATE_NONE = 1;
17
7
  declare const STATE_WAITING = 2;
18
- export { ARRAY_SLOT, CLEANUP, EMPTY_FRAGMENT, NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_EVENTS, REGEX_SLOT_ATTRIBUTES, REGEX_SLOT_NODES, SLOT_HTML, STATE_HYDRATING, SLOT_MARKER, STATE_NONE, STATE_WAITING };
8
+ declare const STORE: unique symbol;
9
+ export { ARRAY_SLOT, CLEANUP, EMPTY_FRAGMENT, SLOT_HTML, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE };
10
+ export * from './event/constants.js';
@@ -1,39 +1,11 @@
1
- import { fragment } from './utilities/fragment.js';
1
+ import { fragment } from './utilities.js';
2
2
  const ARRAY_SLOT = Symbol('template.array.slot');
3
3
  const CLEANUP = Symbol('template.cleanup');
4
4
  const EMPTY_FRAGMENT = fragment('');
5
- const NODE_CLOSING = 1;
6
- const NODE_COMMENT = 2;
7
- const NODE_ELEMENT = 3;
8
- const NODE_SLOT = 4;
9
- const NODE_VOID = 5;
10
- const NODE_WHITELIST = {
11
- '/': NODE_CLOSING,
12
- '!': NODE_COMMENT,
13
- 'area': NODE_VOID,
14
- 'base': NODE_VOID,
15
- 'br': NODE_VOID,
16
- 'col': NODE_VOID,
17
- 'embed': NODE_VOID,
18
- 'hr': NODE_VOID,
19
- 'img': NODE_VOID,
20
- 'input': NODE_VOID,
21
- 'keygen': NODE_VOID,
22
- 'link': NODE_VOID,
23
- 'menuitem': NODE_VOID,
24
- 'meta': NODE_VOID,
25
- 'param': NODE_VOID,
26
- 'source': NODE_VOID,
27
- 'track': NODE_VOID,
28
- 'wbr': NODE_VOID
29
- };
30
- const REGEX_EMPTY_TEXT_NODES = /(>|}|\s)\s+(<|{|\s)/g;
31
- const REGEX_EVENTS = /(?:\s*on[\w-:]+\s*=(?:\s*["'][^"']*["'])*)/g;
32
- const REGEX_SLOT_ATTRIBUTES = /<[\w-]+([^><]*{{\$}}[^><]*)>/g;
33
- const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{{\$}}/g;
34
5
  const SLOT_HTML = '<!--$-->';
35
- const SLOT_MARKER = '{{$}}';
36
6
  const STATE_HYDRATING = 0;
37
7
  const STATE_NONE = 1;
38
8
  const STATE_WAITING = 2;
39
- export { ARRAY_SLOT, CLEANUP, EMPTY_FRAGMENT, NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_EVENTS, REGEX_SLOT_ATTRIBUTES, REGEX_SLOT_NODES, SLOT_HTML, STATE_HYDRATING, SLOT_MARKER, STATE_NONE, STATE_WAITING };
9
+ const STORE = Symbol('template.store');
10
+ export { ARRAY_SLOT, CLEANUP, EMPTY_FRAGMENT, SLOT_HTML, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE };
11
+ export * from './event/constants.js';
@@ -0,0 +1,3 @@
1
+ declare const DIRECT_ATTACH_EVENTS: Set<string>;
2
+ declare const LIFECYCLE_EVENTS: Set<string>;
3
+ export { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS };
@@ -0,0 +1,13 @@
1
+ const DIRECT_ATTACH_EVENTS = new Set([
2
+ 'onblur',
3
+ 'onerror',
4
+ 'onfocus', 'onfocusin', 'onfocusout',
5
+ 'onload',
6
+ 'onplay', 'onpause', 'onended', 'ontimeupdate',
7
+ 'onreset',
8
+ 'onscroll', 'onsubmit'
9
+ ]);
10
+ const LIFECYCLE_EVENTS = new Set([
11
+ 'onconnect', 'ondisconnect', 'onrender', 'onresize', 'ontick'
12
+ ]);
13
+ export { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS };
@@ -1,3 +1,11 @@
1
1
  import { Element } from '../types.js';
2
- declare const _default: (element: Element, event: `on${string}`, listener: Function) => void;
2
+ declare const _default: {
3
+ delegate: (element: Element, event: string, listener: Function) => void;
4
+ direct: (element: Element, event: string, listener: Function) => void;
5
+ onconnect: (element: globalThis.Element, listener: Function) => void;
6
+ ondisconnect: (element: Element, listener: Function) => void;
7
+ onrender: (element: Element, listener: Function) => void;
8
+ onresize: (element: Element, listener: Function) => void;
9
+ ontick: (element: globalThis.Element, listener: Function) => void;
10
+ };
3
11
  export default _default;
@@ -1,20 +1,18 @@
1
1
  import { root } from '@esportsplus/reactivity';
2
2
  import { defineProperty } from '@esportsplus/utilities';
3
- import { addEventListener } from '../utilities/element.js';
4
- import { parentElement } from '../utilities/node.js';
5
- import { ondisconnect } from '../slot/cleanup.js';
3
+ import { ondisconnect as disconnect } from '../slot/cleanup.js';
6
4
  import onconnect from './onconnect.js';
7
5
  import onresize from './onresize.js';
8
6
  import ontick from './ontick.js';
9
- let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(), keys = {}, passive = new Set([
10
- 'onanimationend', 'onanimationiteration', 'onanimationstart',
11
- 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel',
12
- 'onpointerenter', 'onpointerleave', 'onpointermove', 'onpointerout', 'onpointerover',
13
- 'onscroll',
14
- 'ontouchcancel', 'ontouchend', 'ontouchleave', 'ontouchmove', 'ontouchstart', 'ontransitionend',
15
- 'onwheel'
7
+ let controllers = new Map(), host = window.document, keys = {}, passive = new Set([
8
+ 'animationend', 'animationiteration', 'animationstart',
9
+ 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'mousewheel',
10
+ 'pointerenter', 'pointerleave', 'pointermove', 'pointerout', 'pointerover',
11
+ 'scroll',
12
+ 'touchcancel', 'touchend', 'touchleave', 'touchmove', 'touchstart', 'transitionend',
13
+ 'wheel'
16
14
  ]);
17
- ['onmousemove', 'onmousewheel', 'onscroll', 'ontouchend', 'ontouchmove', 'ontouchstart', 'onwheel'].map(event => {
15
+ ['mousemove', 'mousewheel', 'scroll', 'touchend', 'touchmove', 'touchstart', 'wheel'].map(event => {
18
16
  controllers.set(event, null);
19
17
  });
20
18
  function register(element, event) {
@@ -39,7 +37,7 @@ function register(element, event) {
39
37
  signal = controller.signal;
40
38
  }
41
39
  let key = keys[event] = Symbol();
42
- addEventListener.call(window.document, event.slice(2), (e) => {
40
+ host.addEventListener(event.slice(2), (e) => {
43
41
  let fn, node = e.target;
44
42
  while (node) {
45
43
  fn = node[key];
@@ -52,34 +50,30 @@ function register(element, event) {
52
50
  });
53
51
  return fn.call(node, e);
54
52
  }
55
- node = parentElement.call(node);
53
+ node = node.parentElement;
56
54
  }
57
55
  }, {
58
- capture: capture.has(event),
59
56
  passive: passive.has(event),
60
57
  signal
61
58
  });
62
59
  return key;
63
60
  }
64
- export default (element, event, listener) => {
65
- switch (event) {
66
- case 'onconnect':
67
- onconnect(element, listener);
68
- return;
69
- case 'ondisconnect':
70
- ondisconnect(element, () => listener(element));
71
- return;
72
- case 'onrender':
73
- root(() => listener(element));
74
- return;
75
- case 'onresize':
76
- onresize(element, listener);
77
- return;
78
- case 'ontick':
79
- ontick(element, listener);
80
- return;
81
- default:
82
- element[keys[event] || register(element, event)] = listener;
83
- return;
84
- }
61
+ const delegate = (element, event, listener) => {
62
+ element[keys[event] || register(element, event)] = listener;
63
+ };
64
+ const direct = (element, event, listener) => {
65
+ let handler = (e) => listener.call(element, e);
66
+ element.addEventListener(event, handler, {
67
+ passive: passive.has(event)
68
+ });
69
+ ondisconnect(element, () => {
70
+ element.removeEventListener(event, handler);
71
+ });
72
+ };
73
+ const ondisconnect = (element, listener) => {
74
+ disconnect(element, () => listener(element));
75
+ };
76
+ const onrender = (element, listener) => {
77
+ root(() => listener(element));
85
78
  };
79
+ export default { delegate, direct, onconnect, ondisconnect, onrender, onresize, ontick };
@@ -1,5 +1,4 @@
1
- import { STATE_HYDRATING, STATE_NONE } from '../constants.js';
2
- import raf from '../utilities/raf.js';
1
+ import { raf } from '../utilities.js';
3
2
  let tasks = Object.assign(new Set(), { running: false });
4
3
  function tick() {
5
4
  if (tasks.size === 0) {
@@ -22,12 +21,10 @@ const remove = (task) => {
22
21
  tasks.delete(task);
23
22
  };
24
23
  export default (element, listener) => {
25
- let dispose = () => {
26
- remove(fn);
27
- }, fn = () => {
28
- if (state === STATE_HYDRATING) {
24
+ let connected = false, fn = () => {
25
+ if (connected === false) {
29
26
  if (element.isConnected) {
30
- state = STATE_NONE;
27
+ connected = true;
31
28
  }
32
29
  else if (retry--) {
33
30
  return;
@@ -37,8 +34,8 @@ export default (element, listener) => {
37
34
  remove(fn);
38
35
  return;
39
36
  }
40
- listener(dispose, element);
41
- }, retry = 60, state = STATE_HYDRATING;
37
+ listener(() => remove(fn), element);
38
+ }, retry = 60;
42
39
  add(fn);
43
40
  };
44
41
  export { add, remove };
@@ -0,0 +1,9 @@
1
+ import { ReactiveArray } from '@esportsplus/reactivity';
2
+ import { Attribute, Attributes, Renderable } from './types.js';
3
+ import { ArraySlot } from './slot/array.js';
4
+ type Values<T> = Attribute | Attributes<any> | ArraySlot<T> | Renderable<T>;
5
+ declare const html: {
6
+ <T>(_literals: TemplateStringsArray, ..._values: (Values<T> | Values<T>[])[]): DocumentFragment;
7
+ reactive<T>(_arr: ReactiveArray<T>, _template: (value: T) => DocumentFragment): ArraySlot<T>;
8
+ };
9
+ export default html;
package/build/html.js ADDED
@@ -0,0 +1,7 @@
1
+ const html = (_literals, ..._values) => {
2
+ throw new Error('html`` templates must be compiled. Ensure vite-plugin is configured.');
3
+ };
4
+ html.reactive = (_arr, _template) => {
5
+ throw new Error('html.reactive() must be compiled. Ensure vite-plugin is configured.');
6
+ };
7
+ export default html;
package/build/index.d.ts CHANGED
@@ -1,5 +1,11 @@
1
- export { default as html } from './html/index.js';
1
+ import './runtime.js';
2
+ export { default as attributes } from './attributes.js';
3
+ export { default as event } from './event/index.js';
4
+ export { default as html } from './html.js';
2
5
  export { default as render } from './render.js';
6
+ export { default as slot } from './slot/index.js';
3
7
  export { default as svg } from './svg.js';
4
- export type { ArraySlot } from './slot/array.js';
8
+ export { ArraySlot } from './slot/array.js';
9
+ export { EffectSlot } from './slot/effect.js';
5
10
  export type { Attributes, Element, Renderable } from './types.js';
11
+ export * from './utilities.js';
package/build/index.js CHANGED
@@ -1,3 +1,10 @@
1
- export { default as html } from './html/index.js';
1
+ import './runtime.js';
2
+ export { default as attributes } from './attributes.js';
3
+ export { default as event } from './event/index.js';
4
+ export { default as html } from './html.js';
2
5
  export { default as render } from './render.js';
6
+ export { default as slot } from './slot/index.js';
3
7
  export { default as svg } from './svg.js';
8
+ export { ArraySlot } from './slot/array.js';
9
+ export { EffectSlot } from './slot/effect.js';
10
+ export * from './utilities.js';
package/build/render.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { Renderable } from './types.js';
2
- declare const _default: <T>(parent: HTMLElement, renderable: Renderable<T>) => void;
1
+ import { Effect, Renderable } from './types.js';
2
+ declare const _default: <T>(parent: HTMLElement, renderable: Exclude<Renderable<T>, Effect<T>>) => void;
3
3
  export default _default;
package/build/render.js CHANGED
@@ -1,9 +1,8 @@
1
- import { nodeValue } from './utilities/node.js';
2
- import marker from './utilities/marker.js';
1
+ import { marker } from './utilities.js';
3
2
  import slot from './slot/index.js';
4
3
  export default (parent, renderable) => {
5
4
  let anchor = marker.cloneNode();
6
- nodeValue.call(parent, '');
5
+ parent.nodeValue = '';
7
6
  parent.append(anchor);
8
7
  slot(anchor, renderable);
9
8
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import { CLEANUP, STORE } from './constants.js';
2
+ if (typeof Node !== 'undefined') {
3
+ Node.prototype[CLEANUP] = null;
4
+ Node.prototype[STORE] = null;
5
+ }
@@ -1,14 +1,14 @@
1
1
  import { ReactiveArray } from '@esportsplus/reactivity';
2
- import html from '../html/index.js';
2
+ import html from '../html.js';
3
3
  declare class ArraySlot<T> {
4
4
  private array;
5
- private queue;
6
5
  private marker;
7
6
  private nodes;
7
+ private queue;
8
8
  private scheduled;
9
9
  private signal;
10
10
  private template;
11
- readonly fragment: Node;
11
+ readonly fragment: DocumentFragment;
12
12
  constructor(array: ReactiveArray<T>, template: ((value: T) => ReturnType<typeof html>));
13
13
  private anchor;
14
14
  private clear;
@@ -1,22 +1,19 @@
1
1
  import { read, root, set, signal } from '@esportsplus/reactivity';
2
2
  import { ARRAY_SLOT, EMPTY_FRAGMENT } from '../constants.js';
3
- import { append } from '../utilities/fragment.js';
4
- import { cloneNode, firstChild, lastChild, nextSibling } from '../utilities/node.js';
3
+ import { clone, marker, raf } from '../utilities.js';
5
4
  import { ondisconnect, remove } from './cleanup.js';
6
- import marker from '../utilities/marker.js';
7
- import raf from '../utilities/raf.js';
8
5
  class ArraySlot {
9
6
  array;
10
- queue = [];
11
7
  marker;
12
8
  nodes = [];
9
+ queue = [];
13
10
  scheduled = false;
14
11
  signal;
15
12
  template;
16
13
  fragment;
17
14
  constructor(array, template) {
18
15
  this.array = array;
19
- let fragment = this.fragment = cloneNode.call(EMPTY_FRAGMENT);
16
+ let fragment = this.fragment = clone(EMPTY_FRAGMENT);
20
17
  this.marker = marker.cloneNode();
21
18
  this.signal = signal(array.length);
22
19
  this.template = function (data) {
@@ -24,14 +21,14 @@ class ArraySlot {
24
21
  dispose = d;
25
22
  return template(data);
26
23
  }), group = {
27
- head: firstChild.call(frag),
28
- tail: lastChild.call(frag)
24
+ head: frag.firstChild,
25
+ tail: frag.lastChild
29
26
  };
30
- append.call(fragment, frag);
27
+ fragment.append(frag);
31
28
  ondisconnect(group.head, dispose);
32
29
  return group;
33
30
  };
34
- append.call(fragment, this.marker);
31
+ fragment.append(this.marker);
35
32
  if (array.length) {
36
33
  root(() => {
37
34
  this.nodes = array.map(this.template);
@@ -95,7 +92,8 @@ class ArraySlot {
95
92
  this.scheduled = true;
96
93
  raf(() => {
97
94
  let queue = this.queue;
98
- this.queue.length = 0;
95
+ this.queue = [];
96
+ this.scheduled = false;
99
97
  root(() => {
100
98
  for (let i = 0, n = queue.length; i < n; i++) {
101
99
  let op = queue[i];
@@ -132,7 +130,6 @@ class ArraySlot {
132
130
  }
133
131
  });
134
132
  set(this.signal, this.nodes.length);
135
- this.scheduled = false;
136
133
  });
137
134
  }
138
135
  shift() {
@@ -172,8 +169,8 @@ class ArraySlot {
172
169
  for (let i = 0; i < n; i++) {
173
170
  let group = nodes[i], next, node = group.head;
174
171
  while (node) {
175
- next = node === group.tail ? null : nextSibling.call(node);
176
- append.call(this.fragment, node);
172
+ next = node === group.tail ? null : node.nextSibling;
173
+ this.fragment.append(node);
177
174
  node = next;
178
175
  }
179
176
  }
@@ -1,4 +1,4 @@
1
- import { SlotGroup } from '../types.js';
1
+ import { Element, SlotGroup } from '../types.js';
2
2
  declare const ondisconnect: (element: Element, fn: VoidFunction) => void;
3
3
  declare const remove: (...groups: SlotGroup[]) => void;
4
4
  export { ondisconnect, remove };
@@ -1,5 +1,4 @@
1
1
  import { CLEANUP } from '../constants.js';
2
- import { previousSibling } from '../utilities/node.js';
3
2
  const ondisconnect = (element, fn) => {
4
3
  (element[CLEANUP] ??= []).push(fn);
5
4
  };
@@ -13,7 +12,7 @@ const remove = (...groups) => {
13
12
  fn();
14
13
  }
15
14
  }
16
- next = previousSibling.call(tail);
15
+ next = tail.previousSibling;
17
16
  tail.remove();
18
17
  if (head === tail) {
19
18
  break;