@esportsplus/template 0.15.19 → 0.16.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.

Potentially problematic release.


This version of @esportsplus/template might be problematic. Click here for more details.

package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "ICJR",
3
3
  "dependencies": {
4
4
  "@esportsplus/queue": "^0.1.0",
5
- "@esportsplus/reactivity": "^0.12.4",
5
+ "@esportsplus/reactivity": "^0.13.2",
6
6
  "@esportsplus/tasks": "^0.2.1",
7
7
  "@esportsplus/utilities": "^0.22.1"
8
8
  },
@@ -14,7 +14,7 @@
14
14
  "private": false,
15
15
  "type": "module",
16
16
  "types": "./build/index.d.ts",
17
- "version": "0.15.19",
17
+ "version": "0.16.1",
18
18
  "scripts": {
19
19
  "build": "tsc && tsc-alias",
20
20
  "-": "-"
package/src/attributes.ts CHANGED
@@ -9,8 +9,6 @@ import event from './event';
9
9
 
10
10
  const EFFECT_KEY = Symbol();
11
11
 
12
- const HYDRATE_KEY = Symbol();
13
-
14
12
  const STORE_KEY = Symbol();
15
13
 
16
14
  const UPDATES_KEY = Symbol();
@@ -216,7 +214,7 @@ function update(
216
214
  }
217
215
 
218
216
  if (state === STATE_HYDRATING) {
219
- ((context.element[HYDRATE_KEY] ??= {}) as Record<PropertyKey, unknown>)[name] = value;
217
+ attribute(context.element, name, value);
220
218
  }
221
219
  else {
222
220
  context.updates[name] = value;
@@ -233,20 +231,6 @@ function update(
233
231
  }
234
232
 
235
233
 
236
- const apply = (element: Element) => {
237
- let attributes = element[HYDRATE_KEY] as Record<PropertyKey, unknown> | undefined;
238
-
239
- if (!attributes) {
240
- return;
241
- }
242
-
243
- for (let key in attributes) {
244
- attribute(element, key, attributes[key]);
245
- }
246
-
247
- delete element[HYDRATE_KEY];
248
- };
249
-
250
234
  const spread = function (element: Element, value: Attributes | Attributes[]) {
251
235
  let cache = (element[STORE_KEY] ??= { [UPDATES_KEY]: {} }) as Record<PropertyKey, unknown>,
252
236
  context = {
@@ -273,5 +257,5 @@ const spread = function (element: Element, value: Attributes | Attributes[]) {
273
257
  };
274
258
 
275
259
 
276
- export default { apply, spread };
277
- export { apply, spread };
260
+ export default { spread };
261
+ export { spread };
package/src/constants.ts CHANGED
@@ -1,3 +1,9 @@
1
+ import { fragment } from './utilities';
2
+
3
+
4
+ const EMPTY_FRAGMENT = fragment('');
5
+
6
+
1
7
  const NODE_CLOSING = 1;
2
8
 
3
9
  const NODE_COMMENT = 2;
@@ -51,6 +57,7 @@ const SLOT_MARKER_LENGTH = SLOT_MARKER.length;
51
57
 
52
58
 
53
59
  export {
60
+ EMPTY_FRAGMENT,
54
61
  NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST,
55
62
  REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES,
56
63
  RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE,
package/src/html/cache.ts CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES,
3
3
  REGEX_SLOT_NODES, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH
4
4
  } from '~/constants';
5
- import { RenderableTemplate, Template } from '~/types';
5
+ import { Template } from '~/types';
6
6
  import { firstChild, firstElementChild, fragment, nextElementSibling, nextSibling } from '~/utilities';
7
7
  import { spread } from '~/attributes';
8
8
  import s from '~/slot';
@@ -11,8 +11,10 @@ import s from '~/slot';
11
11
  let cache = new WeakMap<TemplateStringsArray, Template>();
12
12
 
13
13
 
14
- function build(literals: TemplateStringsArray, values: unknown[]) {
15
- if (values.length === 0) {
14
+ function build(literals: TemplateStringsArray) {
15
+ let n = literals.length - 1;
16
+
17
+ if (n === 0) {
16
18
  return set(literals, literals[0]);
17
19
  }
18
20
 
@@ -25,12 +27,11 @@ function build(literals: TemplateStringsArray, values: unknown[]) {
25
27
  levels = [{
26
28
  children: 0,
27
29
  elements: 0,
28
- path: [] as NonNullable<Template['slots']>[0]['path']
30
+ path: [] as NonNullable<Template['slots']>[number]['path']['parent']
29
31
  }],
30
32
  parsed = html.split(SLOT_MARKER),
31
33
  slot = 0,
32
- slots: Template['slots'] = [],
33
- total = values.length;
34
+ slots: Template['slots'] = [];
34
35
 
35
36
  for (let match of html.matchAll(REGEX_SLOT_NODES)) {
36
37
  let parent = levels[level],
@@ -42,16 +43,23 @@ function build(literals: TemplateStringsArray, values: unknown[]) {
42
43
  }
43
44
 
44
45
  if (type === NODE_ELEMENT || type === NODE_VOID) {
45
- let attr = match[2];
46
+ let attr = match[2],
47
+ path = parent.path.length
48
+ ? methods(parent.elements, parent.path, firstElementChild, nextElementSibling)
49
+ : methods(parent.children, [], firstChild, nextSibling);
46
50
 
47
51
  if (attr) {
48
52
  let i = attr.indexOf(SLOT_MARKER),
49
- path = methods(parent.children, parent.path, firstChild, nextSibling);
53
+ p = {
54
+ absolute: path,
55
+ parent: parent.path,
56
+ relative: path.slice(parent.path.length)
57
+ };
50
58
 
51
59
  while (i !== -1) {
52
60
  slots.push({
53
61
  fn: spread,
54
- path,
62
+ path: p,
55
63
  slot
56
64
  });
57
65
 
@@ -64,24 +72,28 @@ function build(literals: TemplateStringsArray, values: unknown[]) {
64
72
  levels[++level] = {
65
73
  children: 0,
66
74
  elements: 0,
67
- path: parent.path.length
68
- ? methods(parent.elements, parent.path, firstElementChild, nextElementSibling)
69
- : methods(parent.children, [], firstChild, nextSibling)
75
+ path
70
76
  };
71
77
  }
72
78
 
73
79
  parent.elements++;
74
80
  }
75
81
  else if (type === NODE_SLOT) {
82
+ let relative = methods(parent.children, [], firstChild, nextSibling);
83
+
76
84
  buffer += parsed[slot] + SLOT_HTML;
77
85
  slots.push({
78
86
  fn: s,
79
- path: methods(parent.children, parent.path, firstChild, nextSibling),
87
+ path: {
88
+ absolute: [...parent.path, ...relative],
89
+ parent: parent.path,
90
+ relative
91
+ },
80
92
  slot: slot++
81
93
  });
82
94
  }
83
95
 
84
- if (slot === total) {
96
+ if (slot === n) {
85
97
  buffer += parsed[slot];
86
98
  break;
87
99
  }
@@ -125,8 +137,8 @@ function set(literals: TemplateStringsArray, html: string, slots: Template['slot
125
137
  }
126
138
 
127
139
 
128
- const get = <T>({ literals, values }: RenderableTemplate<T>) => {
129
- return cache.get(literals) || build(literals, values);
140
+ const get = (literals: TemplateStringsArray) => {
141
+ return cache.get(literals) || build(literals);
130
142
  };
131
143
 
132
144
 
@@ -1,90 +1,125 @@
1
1
  import { root } from '@esportsplus/reactivity';
2
- import { Element, Elements, HydrateResult, Renderable, RenderableReactive, RenderableTemplate, Template } from '~/types';
2
+ import { EMPTY_FRAGMENT } from '~/constants';
3
+ import { Elements, Fragment, RenderableReactive, RenderableTemplate } from '~/types';
3
4
  import { Slot } from '~/slot';
4
- import { cloneNode, firstChild, nextSibling } from '~/utilities';
5
- import { apply } from '~/attributes';
5
+ import { cloneNode } from '~/utilities';
6
6
  import cache from './cache';
7
7
 
8
8
 
9
- function reactive<T>(renderable: RenderableReactive<T>, slot: Slot) {
9
+ function reactive<T>(elements: Elements[], fragment: Fragment, renderable: RenderableReactive<T>, slot: Slot) {
10
10
  let array = renderable.values,
11
11
  factory = renderable.template,
12
12
  refresh = () => {
13
- slot.render( root(() => array.map(template)) );
13
+ root(() => array.map(template));
14
+
15
+ slot.clear();
16
+ slot.anchor().after(fragment);
17
+ slot.nodes = elements;
18
+
19
+ reset();
20
+ },
21
+ reset = () => {
22
+ elements = [];
23
+ fragment = cloneNode.call(EMPTY_FRAGMENT);
14
24
  },
15
25
  template = function(data, i) {
16
- let renderable = factory.call(this, data, i);
26
+ hydrate(elements, fragment, factory.call(this, data, i));
27
+ } as (this: typeof array, ...args: Parameters<Parameters<typeof array['map']>[0]>) => void;
17
28
 
18
- return hydrate<T>(renderable, cache.get(renderable));
19
- } as (this: typeof array, ...args: Parameters<Parameters<typeof array['map']>[0]>) => HydrateResult;
29
+ array.on('clear', () => slot.clear());
30
+ array.on('pop', () => slot.pop());
31
+ array.on('reverse', refresh);
32
+ array.on('shift', () => slot.shift());
33
+ array.on('sort', refresh);
20
34
 
21
- array.on('pop', () => {
22
- slot.pop();
23
- });
24
35
  array.on('push', ({ items }) => {
25
- slot.push( ...root(() => array.map(template, array.length - items.length)) );
26
- });
27
- array.on('reverse', refresh);
28
- array.on('shift', () => {
29
- slot.shift();
36
+ let anchor = slot.anchor();
37
+
38
+ elements = slot.nodes;
39
+
40
+ root(() => array.map(template, array.length - items.length));
41
+
42
+ anchor.after(fragment);
43
+ reset();
30
44
  });
31
- array.on('sort', refresh);
32
45
  array.on('splice', ({ deleteCount: d, items: i, start: s }) => {
33
- slot.splice(s, d, ...root(() => array.map(template, s, i.length)));
46
+ if (array.length === 0) {
47
+ slot.clear();
48
+ return;
49
+ }
50
+
51
+ root(() => array.map(template, s, i.length))
52
+
53
+ slot.splice(s, d, fragment, ...elements);
54
+ reset();
34
55
  });
35
56
  array.on('unshift', ({ items }) => {
36
- slot.unshift( ...root(() => array.map(template, 0, items.length)) );
57
+ root(() => array.map(template, 0, items.length))
58
+
59
+ slot.unshift(fragment, ...elements);
60
+ reset();
37
61
  });
38
62
 
39
- return array.map(template);
63
+ root(() => array.map(template));
64
+ reset();
40
65
  }
41
66
 
42
- function hydrate<T>(renderable: Renderable<T>, template: Template): HydrateResult {
43
- let elements: Elements = [],
44
- fragment = cloneNode.call(template.fragment, true),
45
- slots = template.slots;
67
+ function hydrate<T>(elements: Elements[] | null, fragment: Fragment, renderable: RenderableTemplate<T>) {
68
+ let { fragment: frag, slots } = cache.get(renderable.literals),
69
+ clone = cloneNode.call(frag, true);
46
70
 
47
71
  if (slots !== null) {
48
72
  let node,
49
- previous,
73
+ nodePath,
74
+ parent,
75
+ parentPath,
50
76
  values = renderable.values;
51
77
 
52
- for (let i = slots.length - 1; i >= 0; i--) {
53
- let { fn, path, slot } = slots[i];
78
+ for (let i = 0, n = slots.length; i < n; i++) {
79
+ let { fn, path, slot } = slots[i],
80
+ pp = path.parent,
81
+ pr = path.relative;
82
+
83
+ if (pp !== parentPath) {
84
+ if (pp === nodePath) {
85
+ parent = node;
86
+ parentPath = nodePath;
54
87
 
55
- if (path !== previous) {
56
- if (node) {
57
- apply(node);
88
+ nodePath = undefined;
58
89
  }
90
+ else {
91
+ parent = clone;
92
+ parentPath = pp;
59
93
 
60
- node = fragment;
61
- previous = path;
94
+ for (let o = 0, j = pp.length; o < j; o++) {
95
+ parent = pp[o].call(parent);
96
+ }
97
+ }
98
+ }
99
+
100
+ if (pr !== nodePath) {
101
+ node = parent;
102
+ nodePath = path.absolute;
62
103
 
63
- for (let o = 0, j = path.length; o < j; o++) {
64
- node = path[o].call(node as Element);
104
+ for (let o = 0, j = pr.length; o < j; o++) {
105
+ node = pr[o].call(node);
65
106
  }
66
107
  }
67
108
 
68
109
  // @ts-ignore
69
110
  fn(node, values[slot]);
70
111
  }
71
-
72
- apply(node);
73
112
  }
74
113
 
75
- for (let element = firstChild.call(fragment as Element); element; element = nextSibling.call(element)) {
76
- elements.push(element);
114
+ if (elements) {
115
+ elements.push([...clone.childNodes] as Elements);
77
116
  }
78
117
 
79
- return { elements, fragment };
118
+ fragment.appendChild(clone)
80
119
  }
81
120
 
82
121
 
83
122
  export default {
84
- reactive: <T>(renderable: RenderableReactive<T>, slot: Slot) => {
85
- return reactive(renderable, slot);
86
- },
87
- static: <T>(renderable: RenderableTemplate<T>) => {
88
- return hydrate(renderable, renderable.template || (renderable.template = cache.get(renderable)));
89
- }
123
+ reactive,
124
+ static: hydrate
90
125
  };