@esportsplus/template 0.15.20 → 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.
@@ -1,3 +1,4 @@
1
+ declare const EMPTY_FRAGMENT: DocumentFragment;
1
2
  declare const NODE_CLOSING = 1;
2
3
  declare const NODE_ELEMENT = 3;
3
4
  declare const NODE_SLOT = 4;
@@ -11,4 +12,4 @@ declare const RENDERABLE_TEMPLATE: unique symbol;
11
12
  declare const SLOT_HTML = "<!--$-->";
12
13
  declare const SLOT_MARKER = "{{$}}";
13
14
  declare const SLOT_MARKER_LENGTH: number;
14
- export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
15
+ export { EMPTY_FRAGMENT, NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
@@ -1,3 +1,5 @@
1
+ import { fragment } from './utilities.js';
2
+ const EMPTY_FRAGMENT = fragment('');
1
3
  const NODE_CLOSING = 1;
2
4
  const NODE_COMMENT = 2;
3
5
  const NODE_ELEMENT = 3;
@@ -31,4 +33,4 @@ const RENDERABLE_TEMPLATE = Symbol();
31
33
  const SLOT_HTML = '<!--$-->';
32
34
  const SLOT_MARKER = '{{$}}';
33
35
  const SLOT_MARKER_LENGTH = SLOT_MARKER.length;
34
- export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
36
+ export { EMPTY_FRAGMENT, NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
@@ -1,5 +1,5 @@
1
- import { RenderableTemplate, Template } from '../types.js';
1
+ import { Template } from '../types.js';
2
2
  declare const _default: {
3
- get: <T>({ literals, values }: RenderableTemplate<T>) => Template;
3
+ get: (literals: TemplateStringsArray) => Template;
4
4
  };
5
5
  export default _default;
@@ -3,8 +3,9 @@ import { firstChild, firstElementChild, fragment, nextElementSibling, nextSiblin
3
3
  import { spread } from '../attributes.js';
4
4
  import s from '../slot.js';
5
5
  let cache = new WeakMap();
6
- function build(literals, values) {
7
- if (values.length === 0) {
6
+ function build(literals) {
7
+ let n = literals.length - 1;
8
+ if (n === 0) {
8
9
  return set(literals, literals[0]);
9
10
  }
10
11
  let buffer = '', html = literals.join(SLOT_MARKER)
@@ -13,21 +14,26 @@ function build(literals, values) {
13
14
  children: 0,
14
15
  elements: 0,
15
16
  path: []
16
- }], parsed = html.split(SLOT_MARKER), slot = 0, slots = [], total = values.length;
17
+ }], parsed = html.split(SLOT_MARKER), slot = 0, slots = [];
17
18
  for (let match of html.matchAll(REGEX_SLOT_NODES)) {
18
19
  let parent = levels[level], type = match[1] === undefined ? NODE_SLOT : (NODE_WHITELIST[match[1].toLowerCase()] || NODE_ELEMENT);
19
20
  if ((match.index || 1) - 1 > index) {
20
21
  parent.children++;
21
22
  }
22
23
  if (type === NODE_ELEMENT || type === NODE_VOID) {
23
- let attr = match[2];
24
+ let attr = match[2], path = parent.path.length
25
+ ? methods(parent.elements, parent.path, firstElementChild, nextElementSibling)
26
+ : methods(parent.children, [], firstChild, nextSibling);
24
27
  if (attr) {
25
- let i = attr.indexOf(SLOT_MARKER), path = methods(parent.children, parent.path, firstChild, nextSibling);
28
+ let i = attr.indexOf(SLOT_MARKER), p = {
29
+ absolute: path,
30
+ parent: parent.path,
31
+ relative: path.slice(parent.path.length)
32
+ };
26
33
  while (i !== -1) {
27
34
  slots.push({
28
35
  fn: spread,
29
- parent: parent.path,
30
- path,
36
+ path: p,
31
37
  slot
32
38
  });
33
39
  buffer += parsed[slot++];
@@ -38,23 +44,25 @@ function build(literals, values) {
38
44
  levels[++level] = {
39
45
  children: 0,
40
46
  elements: 0,
41
- path: parent.path.length
42
- ? methods(parent.elements, parent.path, firstElementChild, nextElementSibling)
43
- : methods(parent.children, [], firstChild, nextSibling)
47
+ path
44
48
  };
45
49
  }
46
50
  parent.elements++;
47
51
  }
48
52
  else if (type === NODE_SLOT) {
53
+ let relative = methods(parent.children, [], firstChild, nextSibling);
49
54
  buffer += parsed[slot] + SLOT_HTML;
50
55
  slots.push({
51
56
  fn: s,
52
- parent: parent.path,
53
- path: methods(parent.children, [], firstChild, nextSibling),
57
+ path: {
58
+ absolute: [...parent.path, ...relative],
59
+ parent: parent.path,
60
+ relative
61
+ },
54
62
  slot: slot++
55
63
  });
56
64
  }
57
- if (slot === total) {
65
+ if (slot === n) {
58
66
  buffer += parsed[slot];
59
67
  break;
60
68
  }
@@ -86,7 +94,7 @@ function set(literals, html, slots = null) {
86
94
  cache.set(literals, template);
87
95
  return template;
88
96
  }
89
- const get = ({ literals, values }) => {
90
- return cache.get(literals) || build(literals, values);
97
+ const get = (literals) => {
98
+ return cache.get(literals) || build(literals);
91
99
  };
92
100
  export default { get };
@@ -1,7 +1,9 @@
1
- import { HydrateResult, RenderableReactive, RenderableTemplate } from '../types.js';
1
+ import { Elements, Fragment, RenderableReactive, RenderableTemplate } from '../types.js';
2
2
  import { Slot } from '../slot.js';
3
+ declare function reactive<T>(elements: Elements[], fragment: Fragment, renderable: RenderableReactive<T>, slot: Slot): void;
4
+ declare function hydrate<T>(elements: Elements[] | null, fragment: Fragment, renderable: RenderableTemplate<T>): void;
3
5
  declare const _default: {
4
- reactive: <T>(renderable: RenderableReactive<T>, slot: Slot) => HydrateResult[];
5
- static: <T>(renderable: RenderableTemplate<T>) => HydrateResult;
6
+ reactive: typeof reactive;
7
+ static: typeof hydrate;
6
8
  };
7
9
  export default _default;
@@ -1,58 +1,85 @@
1
1
  import { root } from '@esportsplus/reactivity';
2
- import { cloneNode, firstChild, nextSibling } from '../utilities.js';
2
+ import { EMPTY_FRAGMENT } from '../constants.js';
3
+ import { cloneNode } from '../utilities.js';
3
4
  import cache from './cache.js';
4
- function reactive(renderable, slot) {
5
+ function reactive(elements, fragment, renderable, slot) {
5
6
  let array = renderable.values, factory = renderable.template, refresh = () => {
6
- slot.render(root(() => array.map(template)));
7
+ root(() => array.map(template));
8
+ slot.clear();
9
+ slot.anchor().after(fragment);
10
+ slot.nodes = elements;
11
+ reset();
12
+ }, reset = () => {
13
+ elements = [];
14
+ fragment = cloneNode.call(EMPTY_FRAGMENT);
7
15
  }, template = function (data, i) {
8
- let renderable = factory.call(this, data, i);
9
- return hydrate(renderable, cache.get(renderable));
16
+ hydrate(elements, fragment, factory.call(this, data, i));
10
17
  };
11
- array.on('pop', () => {
12
- slot.pop();
13
- });
14
- array.on('push', ({ items }) => {
15
- slot.push(...root(() => array.map(template, array.length - items.length)));
16
- });
18
+ array.on('clear', () => slot.clear());
19
+ array.on('pop', () => slot.pop());
17
20
  array.on('reverse', refresh);
18
- array.on('shift', () => {
19
- slot.shift();
20
- });
21
+ array.on('shift', () => slot.shift());
21
22
  array.on('sort', refresh);
23
+ array.on('push', ({ items }) => {
24
+ let anchor = slot.anchor();
25
+ elements = slot.nodes;
26
+ root(() => array.map(template, array.length - items.length));
27
+ anchor.after(fragment);
28
+ reset();
29
+ });
22
30
  array.on('splice', ({ deleteCount: d, items: i, start: s }) => {
23
- slot.splice(s, d, ...root(() => array.map(template, s, i.length)));
31
+ if (array.length === 0) {
32
+ slot.clear();
33
+ return;
34
+ }
35
+ root(() => array.map(template, s, i.length));
36
+ slot.splice(s, d, fragment, ...elements);
37
+ reset();
24
38
  });
25
39
  array.on('unshift', ({ items }) => {
26
- slot.unshift(...root(() => array.map(template, 0, items.length)));
40
+ root(() => array.map(template, 0, items.length));
41
+ slot.unshift(fragment, ...elements);
42
+ reset();
27
43
  });
28
- return array.map(template);
44
+ root(() => array.map(template));
45
+ reset();
29
46
  }
30
- function hydrate(renderable, template) {
31
- let elements = [], fragment = cloneNode.call(template.fragment, true), slots = template.slots;
47
+ function hydrate(elements, fragment, renderable) {
48
+ let { fragment: frag, slots } = cache.get(renderable.literals), clone = cloneNode.call(frag, true);
32
49
  if (slots !== null) {
33
- let node, previous, values = renderable.values;
34
- for (let i = slots.length - 1; i >= 0; i--) {
35
- let { fn, path, slot } = slots[i];
36
- if (path !== previous) {
37
- node = fragment;
38
- previous = path;
39
- for (let o = 0, j = path.length; o < j; o++) {
40
- node = path[o].call(node);
50
+ let node, nodePath, parent, parentPath, values = renderable.values;
51
+ for (let i = 0, n = slots.length; i < n; i++) {
52
+ let { fn, path, slot } = slots[i], pp = path.parent, pr = path.relative;
53
+ if (pp !== parentPath) {
54
+ if (pp === nodePath) {
55
+ parent = node;
56
+ parentPath = nodePath;
57
+ nodePath = undefined;
58
+ }
59
+ else {
60
+ parent = clone;
61
+ parentPath = pp;
62
+ for (let o = 0, j = pp.length; o < j; o++) {
63
+ parent = pp[o].call(parent);
64
+ }
65
+ }
66
+ }
67
+ if (pr !== nodePath) {
68
+ node = parent;
69
+ nodePath = path.absolute;
70
+ for (let o = 0, j = pr.length; o < j; o++) {
71
+ node = pr[o].call(node);
41
72
  }
42
73
  }
43
74
  fn(node, values[slot]);
44
75
  }
45
76
  }
46
- for (let element = firstChild.call(fragment); element; element = nextSibling.call(element)) {
47
- elements.push(element);
77
+ if (elements) {
78
+ elements.push([...clone.childNodes]);
48
79
  }
49
- return { elements, fragment };
80
+ fragment.appendChild(clone);
50
81
  }
51
82
  export default {
52
- reactive: (renderable, slot) => {
53
- return reactive(renderable, slot);
54
- },
55
- static: (renderable) => {
56
- return hydrate(renderable, renderable.template || (renderable.template = cache.get(renderable)));
57
- }
83
+ reactive,
84
+ static: hydrate
58
85
  };
package/build/render.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { Slot } from './slot.js';
2
2
  import { Renderable } from './types.js';
3
- declare const _default: (renderable: Renderable, parent: HTMLElement | Slot) => Slot;
3
+ declare const _default: (renderable: Renderable, parent: HTMLElement | Slot) => void | Slot;
4
4
  export default _default;
package/build/slot.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Element, Elements, HydrateResult } from './types.js';
1
+ import { Element, Elements, Fragment } from './types.js';
2
2
  declare class Slot {
3
3
  marker: Element;
4
4
  nodes: Elements[];
@@ -7,15 +7,15 @@ declare class Slot {
7
7
  get length(): number;
8
8
  set length(n: number);
9
9
  anchor(index?: number): Element;
10
- clear(): void;
11
- pop(): Elements[] | undefined;
12
- push(...groups: HydrateResult[]): number;
10
+ clear(): this;
11
+ pop(): this;
12
+ push(fragment: Fragment, ...nodes: Elements[]): this;
13
13
  render(input: unknown, state?: number): this;
14
- shift(): Elements[] | undefined;
15
- splice(start: number, stop?: number, ...groups: HydrateResult[]): Elements[];
16
- unshift(...groups: HydrateResult[]): number;
14
+ shift(): this;
15
+ splice(start: number, stop?: number, fragment?: Fragment, ...nodes: Elements[]): this;
16
+ unshift(fragment: Fragment, ...nodes: Elements[]): this;
17
17
  }
18
18
  declare const ondisconnect: (element: Element, fn: VoidFunction) => void;
19
- declare const _default: (marker: Element, value: unknown) => Slot;
19
+ declare const _default: (marker: Element, value: unknown) => void;
20
20
  export default _default;
21
21
  export { ondisconnect, Slot };
package/build/slot.js CHANGED
@@ -1,34 +1,20 @@
1
- import { effect, root } from '@esportsplus/reactivity';
2
- import { isArray, isFunction, isInstanceOf, isObject } from '@esportsplus/utilities';
3
- import { RENDERABLE, RENDERABLE_REACTIVE } from './constants.js';
1
+ import { effect } from '@esportsplus/reactivity';
2
+ import { isArray, isInstanceOf } from '@esportsplus/utilities';
3
+ import { EMPTY_FRAGMENT, RENDERABLE, RENDERABLE_REACTIVE } from './constants.js';
4
4
  import { hydrate } from './html/index.js';
5
- import { append, cloneNode, firstChild, fragment, microtask, nextSibling, nodeValue, raf, text } from './utilities.js';
5
+ import { append, cloneNode, microtask, nodeValue, raf, text } from './utilities.js';
6
6
  import queue from '@esportsplus/queue';
7
7
  const CLEANUP_KEY = Symbol();
8
8
  const CONNECTED = 0;
9
9
  const HYDRATING = 1;
10
- let cleanup = queue(64), scheduled = false, template = fragment('');
11
- function after(anchor, groups) {
12
- let n = groups.length;
13
- if (n === 0) {
14
- return [];
15
- }
16
- let fragment = cloneNode.call(template), elements = new Array(n);
17
- for (let i = 0; i < n; i++) {
18
- let { elements: e, fragment: f } = groups[i];
19
- append.call(fragment, f);
20
- elements[i] = e;
21
- }
22
- anchor.after(fragment);
23
- return elements;
24
- }
10
+ let cleanup = queue(64), scheduled = false;
25
11
  function remove(groups) {
26
- for (let i = 0, n = groups.length; i < n; i++) {
27
- let group = groups[i];
28
- for (let j = 0, o = group.length; j < o; j++) {
29
- let item = group[j];
12
+ let group, item;
13
+ while (group = groups.pop()) {
14
+ while (item = group.pop()) {
30
15
  if (CLEANUP_KEY in item) {
31
16
  cleanup.add(item[CLEANUP_KEY]);
17
+ item[CLEANUP_KEY] = null;
32
18
  }
33
19
  item.remove();
34
20
  }
@@ -36,52 +22,47 @@ function remove(groups) {
36
22
  if (!scheduled && cleanup.length) {
37
23
  schedule();
38
24
  }
39
- return groups;
40
25
  }
41
- function render(elements, fragment, input, slot) {
26
+ function render(anchor, elements, fragment, input, slot) {
42
27
  if (input === false || input == null || input === '') {
43
28
  return;
44
29
  }
45
30
  let type = typeof input;
46
- if (type === 'string' || type === 'number') {
31
+ if (type === 'object' && RENDERABLE in input) {
32
+ if (input[RENDERABLE] === RENDERABLE_REACTIVE) {
33
+ slot ??= new Slot(anchor);
34
+ hydrate.reactive(slot.nodes, fragment, input, slot);
35
+ }
36
+ else {
37
+ hydrate.static(elements, fragment, input);
38
+ }
39
+ }
40
+ else if (type === 'string' || type === 'number') {
47
41
  let element = text(type === 'string' ? input : String(input));
48
42
  if (slot) {
49
43
  slot.text = element;
50
44
  }
51
45
  append.call(fragment, element);
52
- elements.push([element]);
46
+ if (elements) {
47
+ elements.push([element]);
48
+ }
53
49
  }
54
50
  else if (isArray(input)) {
55
51
  for (let i = 0, n = input.length; i < n; i++) {
56
- render(elements, fragment, input[i]);
57
- }
58
- }
59
- else if (isObject(input) && RENDERABLE in input) {
60
- if (input[RENDERABLE] === RENDERABLE_REACTIVE) {
61
- let response = hydrate.reactive(input, slot);
62
- for (let i = 0, n = response.length; i < n; i++) {
63
- let { elements: e, fragment: f } = response[i];
64
- append.call(fragment, f);
65
- elements.push(e);
66
- }
67
- }
68
- else {
69
- let { elements: e, fragment: f } = hydrate.static(input);
70
- append.call(fragment, f);
71
- elements.push(e);
52
+ render(anchor, elements, fragment, input[i], slot);
72
53
  }
73
54
  }
74
55
  else if (isInstanceOf(input, NodeList)) {
75
- let e = new Array(input.length), i = 0;
76
- for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
77
- e[i++] = node;
56
+ append.call(fragment, ...input);
57
+ if (elements) {
58
+ elements.push([...input]);
78
59
  }
79
- append.call(fragment, ...e);
80
- elements.push(e);
81
60
  }
82
61
  else if (isInstanceOf(input, Node)) {
83
62
  append.call(fragment, input);
84
- elements.push([input]);
63
+ if (elements) {
64
+ elements.push([input]);
65
+ }
85
66
  }
86
67
  }
87
68
  function schedule() {
@@ -119,36 +100,46 @@ class Slot {
119
100
  return this.nodes.length;
120
101
  }
121
102
  set length(n) {
122
- this.splice(n);
103
+ if (n >= this.nodes.length) {
104
+ return;
105
+ }
106
+ else if (n === 0) {
107
+ this.clear();
108
+ }
109
+ else {
110
+ this.splice(n);
111
+ }
123
112
  }
124
113
  anchor(index = this.nodes.length - 1) {
125
114
  let nodes = this.nodes[index];
126
115
  return nodes ? nodes[nodes.length - 1] : this.marker;
127
116
  }
128
117
  clear() {
118
+ if (this.text) {
119
+ this.nodes.push([this.text]);
120
+ this.text = null;
121
+ }
129
122
  remove(this.nodes);
130
- this.nodes.length = 0;
131
- this.text = null;
123
+ return this;
132
124
  }
133
125
  pop() {
134
126
  let group = this.nodes.pop();
135
- if (!group) {
136
- return undefined;
127
+ if (group) {
128
+ remove([group]);
137
129
  }
138
- return remove([group]);
130
+ return this;
139
131
  }
140
- push(...groups) {
141
- return this.nodes.push(...after(this.anchor(), groups));
132
+ push(fragment, ...nodes) {
133
+ this.anchor().after(fragment);
134
+ this.nodes.push(...nodes);
135
+ return this;
142
136
  }
143
137
  render(input, state = HYDRATING) {
144
- if (isFunction(input)) {
138
+ let type = typeof input;
139
+ if (type === 'function') {
145
140
  ondisconnect(this.marker, effect(() => {
146
141
  let v = input();
147
- if (isFunction(v)) {
148
- root(() => this.render(v(), state));
149
- state = CONNECTED;
150
- }
151
- else if (state === HYDRATING) {
142
+ if (state === HYDRATING) {
152
143
  this.render(v, state);
153
144
  state = CONNECTED;
154
145
  }
@@ -160,41 +151,54 @@ class Slot {
160
151
  }));
161
152
  return this;
162
153
  }
163
- if (this.text && this.text.isConnected) {
164
- let type = typeof input;
165
- if (input == null || type !== 'object') {
166
- nodeValue.call(this.text, (type === 'number' || type === 'string') ? input : '');
167
- return this;
168
- }
154
+ let text = this.text;
155
+ if (text && text.isConnected && (input == null || type !== 'object')) {
156
+ nodeValue.call(text, (type === 'number' || type === 'string') ? input : '');
157
+ }
158
+ else {
159
+ this.clear();
160
+ let fragment = cloneNode.call(EMPTY_FRAGMENT);
161
+ render(this.marker, this.nodes, fragment, input, this);
162
+ this.marker.after(fragment);
169
163
  }
170
- this.clear();
171
- let fragment = cloneNode.call(template), nodes = [];
172
- render(nodes, fragment, input, this);
173
- this.marker.after(fragment);
174
- this.nodes = nodes;
175
164
  return this;
176
165
  }
177
166
  shift() {
178
167
  let group = this.nodes.shift();
179
- if (!group) {
180
- return undefined;
168
+ if (group) {
169
+ remove([group]);
181
170
  }
182
- return remove([group]);
171
+ return this;
183
172
  }
184
- splice(start, stop = this.nodes.length, ...groups) {
185
- if (!groups.length) {
186
- return remove(this.nodes.splice(start, stop));
173
+ splice(start, stop = this.nodes.length, fragment, ...nodes) {
174
+ if (!fragment) {
175
+ remove(this.nodes.splice(start, stop));
187
176
  }
188
- return remove(this.nodes.splice(start, stop, ...after(this.anchor(start), groups)));
177
+ else {
178
+ this.anchor(start).after(fragment);
179
+ remove(this.nodes.splice(start, stop, ...nodes));
180
+ }
181
+ return this;
189
182
  }
190
- unshift(...groups) {
191
- return this.nodes.unshift(...after(this.marker, groups));
183
+ unshift(fragment, ...nodes) {
184
+ this.marker.after(fragment);
185
+ this.nodes.unshift(...nodes);
186
+ return this;
192
187
  }
193
188
  }
194
189
  const ondisconnect = (element, fn) => {
195
190
  (element[CLEANUP_KEY] ??= []).push(fn);
196
191
  };
197
192
  export default (marker, value) => {
198
- return new Slot(marker).render(value);
193
+ let type = typeof value;
194
+ if (type === 'function') {
195
+ new Slot(marker).render(value);
196
+ }
197
+ else {
198
+ let fragment = cloneNode.call(EMPTY_FRAGMENT);
199
+ render(marker, null, fragment, value);
200
+ marker.after(fragment);
201
+ }
202
+ ;
199
203
  };
200
204
  export { ondisconnect, Slot };
package/build/types.d.ts CHANGED
@@ -20,10 +20,7 @@ type Effect<T> = () => EffectResponse<T>;
20
20
  type EffectResponse<T> = T extends [] ? EffectResponse<T[number]>[] : Primitive | Renderable<T>;
21
21
  type Element = HTMLElement & Attributes & Record<PropertyKey, unknown>;
22
22
  type Elements = Element[];
23
- type HydrateResult = {
24
- elements: Elements;
25
- fragment: DocumentFragment | Node;
26
- };
23
+ type Fragment = DocumentFragment | Node;
27
24
  type Primitive = bigint | boolean | null | number | string | undefined;
28
25
  type Renderable<T = unknown> = RenderableReactive<T> | RenderableTemplate<T>;
29
26
  type RenderableReactive<T = unknown> = Readonly<{
@@ -32,7 +29,7 @@ type RenderableReactive<T = unknown> = Readonly<{
32
29
  template: (this: ThisParameterType<Parameters<ReactiveArray<T>['map']>[0]>, ...args: Parameters<Parameters<ReactiveArray<T>['map']>[0]>) => RenderableTemplate<T>;
33
30
  values: ReactiveArray<T>;
34
31
  }>;
35
- type RenderableTemplate<T> = {
32
+ type RenderableTemplate<T = unknown> = {
36
33
  [RENDERABLE]: typeof RENDERABLE_TEMPLATE;
37
34
  literals: TemplateStringsArray;
38
35
  template: Template | null;
@@ -45,9 +42,12 @@ type Template = {
45
42
  literals: TemplateStringsArray;
46
43
  slots: {
47
44
  fn: typeof attributes.spread | typeof slot;
48
- parent: typeof firstChild[];
49
- path: typeof firstChild[];
45
+ path: {
46
+ absolute: typeof firstChild[];
47
+ parent: typeof firstChild[];
48
+ relative: typeof firstChild[];
49
+ };
50
50
  slot: number;
51
51
  }[] | null;
52
52
  };
53
- export type { Attributes, Effect, Element, Elements, HydrateResult, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, Template };
53
+ export type { Attributes, Effect, Element, Elements, Fragment, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, Template };
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.20",
17
+ "version": "0.16.1",
18
18
  "scripts": {
19
19
  "build": "tsc && tsc-alias",
20
20
  "-": "-"
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,17 +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
- parent: parent.path,
55
- path,
62
+ path: p,
56
63
  slot
57
64
  });
58
65
 
@@ -65,25 +72,28 @@ function build(literals: TemplateStringsArray, values: unknown[]) {
65
72
  levels[++level] = {
66
73
  children: 0,
67
74
  elements: 0,
68
- path: parent.path.length
69
- ? methods(parent.elements, parent.path, firstElementChild, nextElementSibling)
70
- : methods(parent.children, [], firstChild, nextSibling)
75
+ path
71
76
  };
72
77
  }
73
78
 
74
79
  parent.elements++;
75
80
  }
76
81
  else if (type === NODE_SLOT) {
82
+ let relative = methods(parent.children, [], firstChild, nextSibling);
83
+
77
84
  buffer += parsed[slot] + SLOT_HTML;
78
85
  slots.push({
79
86
  fn: s,
80
- parent: parent.path,
81
- path: methods(parent.children, [], firstChild, nextSibling),
87
+ path: {
88
+ absolute: [...parent.path, ...relative],
89
+ parent: parent.path,
90
+ relative
91
+ },
82
92
  slot: slot++
83
93
  });
84
94
  }
85
95
 
86
- if (slot === total) {
96
+ if (slot === n) {
87
97
  buffer += parsed[slot];
88
98
  break;
89
99
  }
@@ -127,8 +137,8 @@ function set(literals: TemplateStringsArray, html: string, slots: Template['slot
127
137
  }
128
138
 
129
139
 
130
- const get = <T>({ literals, values }: RenderableTemplate<T>) => {
131
- return cache.get(literals) || build(literals, values);
140
+ const get = (literals: TemplateStringsArray) => {
141
+ return cache.get(literals) || build(literals);
132
142
  };
133
143
 
134
144
 
@@ -1,62 +1,108 @@
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 { cloneNode } from '~/utilities';
5
6
  import cache from './cache';
6
7
 
7
8
 
8
- function reactive<T>(renderable: RenderableReactive<T>, slot: Slot) {
9
+ function reactive<T>(elements: Elements[], fragment: Fragment, renderable: RenderableReactive<T>, slot: Slot) {
9
10
  let array = renderable.values,
10
11
  factory = renderable.template,
11
12
  refresh = () => {
12
- 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);
13
24
  },
14
25
  template = function(data, i) {
15
- 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;
16
28
 
17
- return hydrate<T>(renderable, cache.get(renderable));
18
- } 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);
19
34
 
20
- array.on('pop', () => {
21
- slot.pop();
22
- });
23
35
  array.on('push', ({ items }) => {
24
- slot.push( ...root(() => array.map(template, array.length - items.length)) );
25
- });
26
- array.on('reverse', refresh);
27
- array.on('shift', () => {
28
- 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();
29
44
  });
30
- array.on('sort', refresh);
31
45
  array.on('splice', ({ deleteCount: d, items: i, start: s }) => {
32
- 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();
33
55
  });
34
56
  array.on('unshift', ({ items }) => {
35
- 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();
36
61
  });
37
62
 
38
- return array.map(template);
63
+ root(() => array.map(template));
64
+ reset();
39
65
  }
40
66
 
41
- function hydrate<T>(renderable: Renderable<T>, template: Template): HydrateResult {
42
- let elements: Elements = [],
43
- fragment = cloneNode.call(template.fragment, true),
44
- 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);
45
70
 
46
71
  if (slots !== null) {
47
72
  let node,
48
- previous,
73
+ nodePath,
74
+ parent,
75
+ parentPath,
49
76
  values = renderable.values;
50
77
 
51
- for (let i = slots.length - 1; i >= 0; i--) {
52
- 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;
53
87
 
54
- if (path !== previous) {
55
- node = fragment;
56
- previous = path;
88
+ nodePath = undefined;
89
+ }
90
+ else {
91
+ parent = clone;
92
+ parentPath = pp;
57
93
 
58
- for (let o = 0, j = path.length; o < j; o++) {
59
- node = path[o].call(node as Element);
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;
103
+
104
+ for (let o = 0, j = pr.length; o < j; o++) {
105
+ node = pr[o].call(node);
60
106
  }
61
107
  }
62
108
 
@@ -65,19 +111,15 @@ function hydrate<T>(renderable: Renderable<T>, template: Template): HydrateResul
65
111
  }
66
112
  }
67
113
 
68
- for (let element = firstChild.call(fragment as Element); element; element = nextSibling.call(element)) {
69
- elements.push(element);
114
+ if (elements) {
115
+ elements.push([...clone.childNodes] as Elements);
70
116
  }
71
117
 
72
- return { elements, fragment };
118
+ fragment.appendChild(clone)
73
119
  }
74
120
 
75
121
 
76
122
  export default {
77
- reactive: <T>(renderable: RenderableReactive<T>, slot: Slot) => {
78
- return reactive(renderable, slot);
79
- },
80
- static: <T>(renderable: RenderableTemplate<T>) => {
81
- return hydrate(renderable, renderable.template || (renderable.template = cache.get(renderable)));
82
- }
123
+ reactive,
124
+ static: hydrate
83
125
  };
package/src/slot.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { effect, root } from '@esportsplus/reactivity';
2
- import { isArray, isFunction, isInstanceOf, isObject } from '@esportsplus/utilities';
3
- import { RENDERABLE, RENDERABLE_REACTIVE } from './constants';
1
+ import { effect } from '@esportsplus/reactivity';
2
+ import { isArray, isInstanceOf } from '@esportsplus/utilities';
3
+ import { EMPTY_FRAGMENT, RENDERABLE, RENDERABLE_REACTIVE } from './constants';
4
4
  import { hydrate } from './html';
5
- import { Element, Elements, HydrateResult, RenderableReactive, RenderableTemplate } from './types';
6
- import { append, cloneNode, firstChild, fragment, microtask, nextSibling, nodeValue, raf, text } from './utilities'
5
+ import { Element, Elements, Fragment, RenderableReactive, RenderableTemplate } from './types';
6
+ import { append, cloneNode, microtask, nodeValue, raf, text } from './utilities'
7
7
  import queue from '@esportsplus/queue';
8
8
 
9
9
 
@@ -15,41 +15,18 @@ const HYDRATING = 1;
15
15
 
16
16
 
17
17
  let cleanup = queue<VoidFunction[]>(64),
18
- scheduled = false,
19
- template = fragment('');
20
-
21
-
22
- function after(anchor: Element, groups: HydrateResult[]) {
23
- let n = groups.length;
24
-
25
- if (n === 0) {
26
- return [];
27
- }
28
-
29
- let fragment = cloneNode.call(template),
30
- elements = new Array(n);
31
-
32
- for (let i = 0; i < n; i++) {
33
- let { elements: e, fragment: f } = groups[i];
34
-
35
- append.call(fragment, f);
36
- elements[i] = e;
37
- }
38
-
39
- anchor.after(fragment);
18
+ scheduled = false;
40
19
 
41
- return elements;
42
- }
43
20
 
44
21
  function remove(groups: Elements[]) {
45
- for (let i = 0, n = groups.length; i < n; i++) {
46
- let group = groups[i];
47
-
48
- for (let j = 0, o = group.length; j < o; j++) {
49
- let item = group[j];
22
+ let group,
23
+ item;
50
24
 
25
+ while (group = groups.pop()) {
26
+ while (item = group.pop()) {
51
27
  if (CLEANUP_KEY in item) {
52
28
  cleanup.add(item[CLEANUP_KEY] as VoidFunction[]);
29
+ item[CLEANUP_KEY] = null;
53
30
  }
54
31
 
55
32
  item.remove();
@@ -59,64 +36,55 @@ function remove(groups: Elements[]) {
59
36
  if (!scheduled && cleanup.length) {
60
37
  schedule();
61
38
  }
62
-
63
- return groups;
64
39
  }
65
40
 
66
- function render(elements: Elements[], fragment: DocumentFragment | Node, input: unknown, slot?: Slot) {
41
+ function render(anchor: Element, elements: Elements[] | null, fragment: Fragment, input: unknown, slot?: Slot) {
67
42
  if (input === false || input == null || input === '') {
68
43
  return;
69
44
  }
70
45
 
71
46
  let type = typeof input;
72
47
 
73
- if (type === 'string' || type === 'number') {
74
- let element = text(type === 'string' ? input as string : String(input));
48
+ if (type === 'object' && RENDERABLE in (input as Record<PropertyKey, unknown>)) {
49
+ if ((input as Record<PropertyKey, unknown>)[RENDERABLE] === RENDERABLE_REACTIVE) {
50
+ slot ??= new Slot(anchor);
51
+ hydrate.reactive(slot.nodes, fragment, input as RenderableReactive, slot);
52
+ }
53
+ else {
54
+ hydrate.static(elements, fragment, input as RenderableTemplate);
55
+ }
56
+ }
57
+ else if (type === 'string' || type === 'number') {
58
+ let element = text( type === 'string' ? input as string : String(input) );
75
59
 
76
60
  if (slot) {
77
61
  slot.text = element;
78
62
  }
79
63
 
80
64
  append.call(fragment, element);
81
- elements.push([element]);
65
+
66
+ if (elements) {
67
+ elements.push([element]);
68
+ }
82
69
  }
83
70
  else if (isArray(input)) {
84
71
  for (let i = 0, n = input.length; i < n; i++) {
85
- render(elements, fragment, input[i]);
86
- }
87
- }
88
- else if (isObject(input) && RENDERABLE in input) {
89
- if (input[RENDERABLE] === RENDERABLE_REACTIVE) {
90
- let response = hydrate.reactive(input as RenderableReactive, slot!);
91
-
92
- for (let i = 0, n = response.length; i < n; i++) {
93
- let { elements: e, fragment: f } = response[i];
94
-
95
- append.call(fragment, f);
96
- elements.push(e);
97
- }
98
- }
99
- else {
100
- let { elements: e, fragment: f } = hydrate.static(input as RenderableTemplate<unknown>);
101
-
102
- append.call(fragment, f);
103
- elements.push(e);
72
+ render(anchor, elements, fragment, input[i], slot);
104
73
  }
105
74
  }
106
75
  else if (isInstanceOf(input, NodeList)) {
107
- let e: Elements = new Array(input.length),
108
- i = 0;
76
+ append.call(fragment, ...input);
109
77
 
110
- for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
111
- e[i++] = node;
78
+ if (elements) {
79
+ elements.push([...input] as Elements);
112
80
  }
113
-
114
- append.call(fragment, ...e);
115
- elements.push(e);
116
81
  }
117
82
  else if (isInstanceOf(input, Node)) {
118
83
  append.call(fragment, input);
119
- elements.push([ input as Element ]);
84
+
85
+ if (elements) {
86
+ elements.push([ input as Element ]);
87
+ }
120
88
  }
121
89
  }
122
90
 
@@ -168,7 +136,15 @@ class Slot {
168
136
  }
169
137
 
170
138
  set length(n: number) {
171
- this.splice(n);
139
+ if (n >= this.nodes.length) {
140
+ return;
141
+ }
142
+ else if (n === 0) {
143
+ this.clear();
144
+ }
145
+ else {
146
+ this.splice(n);
147
+ }
172
148
  }
173
149
 
174
150
 
@@ -179,37 +155,43 @@ class Slot {
179
155
  }
180
156
 
181
157
  clear() {
158
+ if (this.text) {
159
+ this.nodes.push([this.text]);
160
+ this.text = null;
161
+ }
162
+
182
163
  remove(this.nodes);
183
- this.nodes.length = 0;
184
- this.text = null;
164
+
165
+ return this;
185
166
  }
186
167
 
187
168
  pop() {
188
169
  let group = this.nodes.pop();
189
170
 
190
- if (!group) {
191
- return undefined;
171
+ if (group) {
172
+ remove([group]);
192
173
  }
193
174
 
194
- return remove([group]);
175
+ return this;
195
176
  }
196
177
 
197
- push(...groups: HydrateResult[]) {
198
- return this.nodes.push( ...after(this.anchor(), groups) );
178
+ push(fragment: Fragment, ...nodes: Elements[]) {
179
+ this.anchor().after(fragment);
180
+ this.nodes.push( ...nodes );
181
+
182
+ return this;
199
183
  }
200
184
 
201
185
  render(input: unknown, state = HYDRATING) {
202
- if (isFunction(input)) {
186
+ let type = typeof input;
187
+
188
+ if (type === 'function') {
203
189
  ondisconnect(
204
190
  this.marker,
205
191
  effect(() => {
206
- let v = input();
192
+ let v = (input as Function)();
207
193
 
208
- if (isFunction(v)) {
209
- root(() => this.render(v(), state));
210
- state = CONNECTED;
211
- }
212
- else if (state === HYDRATING) {
194
+ if (state === HYDRATING) {
213
195
  this.render(v, state);
214
196
  state = CONNECTED;
215
197
  }
@@ -224,24 +206,20 @@ class Slot {
224
206
  return this;
225
207
  }
226
208
 
227
- if (this.text && this.text.isConnected) {
228
- let type = typeof input;
209
+ let text = this.text;
229
210
 
230
- if (input == null || type !== 'object') {
231
- nodeValue.call(this.text, (type === 'number' || type === 'string') ? input : '');
232
- return this;
233
- }
211
+ if (text && text.isConnected && (input == null || type !== 'object')) {
212
+ nodeValue.call(text, (type === 'number' || type === 'string') ? input : '');
234
213
  }
214
+ else {
215
+ this.clear();
235
216
 
236
- this.clear();
237
-
238
- let fragment = cloneNode.call(template),
239
- nodes: Elements[] = [];
217
+ let fragment = cloneNode.call(EMPTY_FRAGMENT);
240
218
 
241
- render(nodes, fragment, input, this);
219
+ render(this.marker, this.nodes, fragment, input, this);
242
220
 
243
- this.marker.after(fragment);
244
- this.nodes = nodes;
221
+ this.marker.after(fragment);
222
+ }
245
223
 
246
224
  return this;
247
225
  }
@@ -249,29 +227,30 @@ class Slot {
249
227
  shift() {
250
228
  let group = this.nodes.shift();
251
229
 
252
- if (!group) {
253
- return undefined;
230
+ if (group) {
231
+ remove([group]);
254
232
  }
255
233
 
256
- return remove([group]);
234
+ return this;
257
235
  }
258
236
 
259
- splice(start: number, stop: number = this.nodes.length, ...groups: HydrateResult[]) {
260
- if (!groups.length) {
261
- return remove(this.nodes.splice(start, stop));
237
+ splice(start: number, stop: number = this.nodes.length, fragment?: Fragment, ...nodes: Elements[]) {
238
+ if (!fragment) {
239
+ remove( this.nodes.splice(start, stop) );
240
+ }
241
+ else {
242
+ this.anchor(start).after(fragment);
243
+ remove( this.nodes.splice(start, stop, ...nodes) )
262
244
  }
263
245
 
264
- return remove(
265
- this.nodes.splice(
266
- start,
267
- stop,
268
- ...after(this.anchor(start), groups)
269
- )
270
- );
246
+ return this;
271
247
  }
272
248
 
273
- unshift(...groups: HydrateResult[]) {
274
- return this.nodes.unshift( ...after(this.marker, groups) );
249
+ unshift(fragment: Fragment, ...nodes: Elements[]) {
250
+ this.marker.after(fragment);
251
+ this.nodes.unshift( ...nodes );
252
+
253
+ return this;
275
254
  }
276
255
  }
277
256
 
@@ -282,6 +261,17 @@ const ondisconnect = (element: Element, fn: VoidFunction) => {
282
261
 
283
262
 
284
263
  export default (marker: Element, value: unknown) => {
285
- return new Slot(marker).render(value);
264
+ let type = typeof value;
265
+
266
+ if (type === 'function') {
267
+ new Slot(marker).render(value);
268
+ }
269
+ else {
270
+ let fragment = cloneNode.call(EMPTY_FRAGMENT);
271
+
272
+ render(marker, null, fragment, value);
273
+
274
+ marker.after(fragment);
275
+ };
286
276
  };
287
277
  export { ondisconnect, Slot };
package/src/types.ts CHANGED
@@ -30,7 +30,7 @@ type Element = HTMLElement & Attributes & Record<PropertyKey, unknown>;
30
30
 
31
31
  type Elements = Element[];
32
32
 
33
- type HydrateResult = { elements: Elements, fragment: DocumentFragment | Node };
33
+ type Fragment = DocumentFragment | Node;
34
34
 
35
35
  // Copied from '@esportsplus/utilities'
36
36
  // - Importing from ^ causes 'cannot be named without a reference to...' error
@@ -48,7 +48,7 @@ type RenderableReactive<T = unknown> = Readonly<{
48
48
  values: ReactiveArray<T>;
49
49
  }>;
50
50
 
51
- type RenderableTemplate<T> = {
51
+ type RenderableTemplate<T = unknown> = {
52
52
  [RENDERABLE]: typeof RENDERABLE_TEMPLATE;
53
53
  literals: TemplateStringsArray;
54
54
  template: Template | null;
@@ -63,8 +63,11 @@ type Template = {
63
63
  literals: TemplateStringsArray;
64
64
  slots: {
65
65
  fn: typeof attributes.spread | typeof slot;
66
- parent: typeof firstChild[];
67
- path: typeof firstChild[];
66
+ path: {
67
+ absolute: typeof firstChild[],
68
+ parent: typeof firstChild[],
69
+ relative: typeof firstChild[]
70
+ };
68
71
  slot: number;
69
72
  }[] | null;
70
73
  };
@@ -73,7 +76,7 @@ type Template = {
73
76
  export type {
74
77
  Attributes,
75
78
  Effect, Element, Elements,
76
- HydrateResult,
79
+ Fragment,
77
80
  Renderable, RenderableReactive, RenderableTemplate, RenderableValue,
78
81
  Template
79
82
  };