@esportsplus/template 0.15.16 → 0.15.18

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.

@@ -1,9 +1,9 @@
1
1
  import { Attributes, Element } from './types.js';
2
2
  declare const apply: (element: Element) => void;
3
- declare const spread: (element: Element, attributes: Attributes | Attributes[]) => void;
3
+ declare const spread: (element: Element, value: Attributes | Attributes[]) => void;
4
4
  declare const _default: {
5
5
  apply: (element: Element) => void;
6
- spread: (element: Element, attributes: Attributes | Attributes[]) => void;
6
+ spread: (element: Element, value: Attributes | Attributes[]) => void;
7
7
  };
8
8
  export default _default;
9
9
  export { apply, spread };
@@ -2,11 +2,19 @@ import { effect } from '@esportsplus/reactivity';
2
2
  import { isArray, isFunction, isObject, isString } from '@esportsplus/utilities';
3
3
  import { ondisconnect } from './slot.js';
4
4
  import { className, raf, removeAttribute, setAttribute } from './utilities.js';
5
+ import q from '@esportsplus/queue';
5
6
  import event from './event.js';
6
- let attributes = {}, delimiters = {
7
+ const EFFECT_KEY = Symbol();
8
+ const HYDRATE_KEY = Symbol();
9
+ const STORE_KEY = Symbol();
10
+ const UPDATES_KEY = Symbol();
11
+ const STATE_HYDRATING = 0;
12
+ const STATE_NONE = 1;
13
+ const STATE_WAITING = 2;
14
+ let delimiters = {
7
15
  class: ' ',
8
16
  style: ';'
9
- }, key = Symbol();
17
+ }, queue = q(64), scheduled = false;
10
18
  function attribute(element, name, value) {
11
19
  if (value === '' || value === false || value == null) {
12
20
  removeAttribute.call(element, name);
@@ -21,55 +29,79 @@ function attribute(element, name, value) {
21
29
  element[name] = value;
22
30
  }
23
31
  }
24
- function set(element, value, name, wait = false) {
32
+ function schedule() {
33
+ if (scheduled) {
34
+ return;
35
+ }
36
+ scheduled = true;
37
+ raf.add(task);
38
+ }
39
+ function set(context, name, value, state) {
25
40
  if (isArray(value)) {
26
41
  for (let i = 0, n = value.length; i < n; i++) {
27
- set(element, value[i], name, wait);
42
+ set(context, name, value[i], state);
28
43
  }
29
44
  }
30
45
  else if (isFunction(value)) {
31
46
  if (name.startsWith('on')) {
32
- event(element, name, value);
47
+ event(context.element, name, value);
33
48
  }
34
49
  else {
35
- let id = ('e' + store(element)[key]++);
36
- ondisconnect(element, effect(() => {
37
- let v = value(element);
50
+ context.store[EFFECT_KEY] ??= 0;
51
+ let id = context.store[EFFECT_KEY]++;
52
+ ondisconnect(context.element, effect(() => {
53
+ let v = value(context.element);
38
54
  if (isArray(v)) {
39
55
  let last = v.length - 1;
40
56
  for (let i = 0, n = v.length; i < n; i++) {
41
- update(element, id, name, v[i], wait || i !== last);
57
+ update(context, id, name, v[i], state === STATE_HYDRATING
58
+ ? state
59
+ : i !== last ? STATE_WAITING : state);
42
60
  }
43
61
  }
44
62
  else {
45
- update(element, id, name, v, wait);
63
+ update(context, id, name, v, state);
46
64
  }
47
65
  }));
48
- wait = false;
66
+ state = STATE_NONE;
49
67
  }
50
68
  }
51
69
  else {
52
- update(element, null, name, value, wait);
70
+ update(context, null, name, value, state);
53
71
  }
54
72
  }
55
- function store(element) {
56
- return (element[key] || (element[key] = { [key]: 0 }));
73
+ function task() {
74
+ let context, n = queue.length;
75
+ while ((context = queue.next()) && n--) {
76
+ let { element, updates } = context;
77
+ for (let name in updates) {
78
+ attribute(element, name, updates[name]);
79
+ delete updates[name];
80
+ }
81
+ context.updating = false;
82
+ }
83
+ if (queue.length) {
84
+ raf.add(task);
85
+ }
86
+ else {
87
+ scheduled = false;
88
+ }
57
89
  }
58
- function update(element, id, name, value, wait = false) {
90
+ function update(context, id, name, value, state) {
59
91
  if (value === false || value == null) {
60
92
  value = '';
61
93
  }
62
- let data = store(element);
94
+ let store = context.store;
63
95
  if (name in delimiters) {
64
- let cache = name + '.static', delimiter = delimiters[name], dynamic = data[name];
96
+ let cache = name + '.static', delimiter = delimiters[name], dynamic = store[name];
65
97
  if (dynamic === undefined) {
66
- let value = (element.getAttribute(name) || '').trim();
67
- data[cache] = value.endsWith(delimiter) ? value.slice(0, -1) : value;
68
- data[name] = dynamic = {};
98
+ let value = (context.element.getAttribute(name) || '').trim();
99
+ store[cache] = value;
100
+ store[name] = dynamic = {};
69
101
  }
70
102
  if (id === null) {
71
103
  if (value && isString(value)) {
72
- data[cache] += (data[cache] ? delimiter : '') + value;
104
+ store[cache] += (store[cache] ? delimiter : '') + value;
73
105
  }
74
106
  }
75
107
  else {
@@ -85,7 +117,7 @@ function update(element, id, name, value, wait = false) {
85
117
  hot[part] = null;
86
118
  }
87
119
  }
88
- let cold = data[id];
120
+ let cold = store[id];
89
121
  if (cold !== undefined) {
90
122
  for (let part in cold) {
91
123
  if (part in hot) {
@@ -94,48 +126,61 @@ function update(element, id, name, value, wait = false) {
94
126
  delete dynamic[part];
95
127
  }
96
128
  }
97
- data[id] = hot;
129
+ store[id] = hot;
98
130
  }
99
- value = data[cache];
131
+ value = store[cache];
100
132
  for (let key in dynamic) {
101
133
  value += (value ? delimiter : '') + key;
102
134
  }
103
135
  }
104
- else if (isString(id)) {
105
- if (data[name] === value) {
136
+ else if (id !== null) {
137
+ if (store[name] === value) {
106
138
  return;
107
139
  }
108
- data[name] = value;
140
+ store[name] = value;
109
141
  }
110
- if (wait) {
111
- if (id === null) {
112
- attributes[name] = value;
113
- }
142
+ if (state === STATE_HYDRATING) {
143
+ (context.element[HYDRATE_KEY] ??= {})[name] = value;
114
144
  }
115
145
  else {
116
- raf.add(() => {
117
- attribute(element, name, value);
118
- });
146
+ context.updates[name] = value;
147
+ if (state === STATE_NONE && !context.updating) {
148
+ context.updating = true;
149
+ queue.add(context);
150
+ }
151
+ if (!scheduled) {
152
+ schedule();
153
+ }
119
154
  }
120
155
  }
121
156
  const apply = (element) => {
157
+ let attributes = element[HYDRATE_KEY];
158
+ if (!attributes) {
159
+ return;
160
+ }
122
161
  for (let key in attributes) {
123
162
  attribute(element, key, attributes[key]);
124
163
  }
125
- attributes = {};
164
+ delete element[HYDRATE_KEY];
126
165
  };
127
- const spread = function (element, attributes) {
128
- if (isObject(attributes)) {
129
- for (let name in attributes) {
130
- set(element, attributes[name], name, true);
166
+ const spread = function (element, value) {
167
+ let cache = (element[STORE_KEY] ??= { [UPDATES_KEY]: {} }), context = {
168
+ element,
169
+ store: cache,
170
+ updates: cache[UPDATES_KEY],
171
+ updating: false
172
+ };
173
+ if (isArray(value)) {
174
+ for (let i = 0, n = value.length; i < n; i++) {
175
+ let v = value[i];
176
+ for (let name in v) {
177
+ set(context, name, v[name], STATE_HYDRATING);
178
+ }
131
179
  }
132
180
  }
133
- else if (isArray(attributes)) {
134
- for (let i = 0, n = attributes.length; i < n; i++) {
135
- let attrs = attributes[i];
136
- for (let name in attrs) {
137
- set(element, attrs[name], name, true);
138
- }
181
+ else if (isObject(value)) {
182
+ for (let name in value) {
183
+ set(context, name, value[name], STATE_HYDRATING);
139
184
  }
140
185
  }
141
186
  };
@@ -8,8 +8,7 @@ declare const REGEX_SLOT_NODES: RegExp;
8
8
  declare const RENDERABLE: unique symbol;
9
9
  declare const RENDERABLE_REACTIVE: unique symbol;
10
10
  declare const RENDERABLE_TEMPLATE: unique symbol;
11
- declare const SLOT_CLEANUP: unique symbol;
12
11
  declare const SLOT_HTML = "<!--$-->";
13
12
  declare const SLOT_MARKER = "{{$}}";
14
13
  declare const SLOT_MARKER_LENGTH: number;
15
- export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT_CLEANUP, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
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 };
@@ -28,8 +28,7 @@ const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{
28
28
  const RENDERABLE = Symbol();
29
29
  const RENDERABLE_REACTIVE = Symbol();
30
30
  const RENDERABLE_TEMPLATE = Symbol();
31
- const SLOT_CLEANUP = Symbol();
32
31
  const SLOT_HTML = '<!--$-->';
33
32
  const SLOT_MARKER = '{{$}}';
34
33
  const SLOT_MARKER_LENGTH = SLOT_MARKER.length;
35
- export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT_CLEANUP, SLOT_HTML, SLOT_MARKER, 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 };
package/build/event.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { root } from '@esportsplus/reactivity';
2
2
  import { defineProperty } from '@esportsplus/utilities';
3
3
  import { ondisconnect } from './slot.js';
4
- import { addEventListener, parentElement } from './utilities.js';
4
+ import { addEventListener, parentElement, raf } from './utilities.js';
5
5
  let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(), keys = {}, passive = new Set([
6
6
  'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel',
7
7
  'onscroll',
@@ -13,16 +13,17 @@ let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(
13
13
  });
14
14
  export default (element, event, listener) => {
15
15
  if (event === 'onconnect') {
16
- let interval = setInterval(() => {
16
+ let retry = 60, task = () => {
17
17
  retry--;
18
18
  if (element.isConnected) {
19
19
  retry = 0;
20
20
  root(() => listener(element));
21
21
  }
22
- if (!retry) {
23
- clearInterval(interval);
22
+ if (retry) {
23
+ raf.add(task);
24
24
  }
25
- }, 1000 / 60), retry = 60;
25
+ };
26
+ raf.add(task);
26
27
  return;
27
28
  }
28
29
  else if (event === 'ondisconnect') {
@@ -1,7 +1,7 @@
1
- import { Elements, RenderableReactive, RenderableTemplate } from '../types.js';
1
+ import { HydrateResult, RenderableReactive, RenderableTemplate } from '../types.js';
2
2
  import { Slot } from '../slot.js';
3
3
  declare const _default: {
4
- reactive: <T>(renderable: RenderableReactive<T>, slot: Slot) => Elements[];
5
- static: <T>(renderable: RenderableTemplate<T>) => Elements;
4
+ reactive: <T>(renderable: RenderableReactive<T>, slot: Slot) => HydrateResult[];
5
+ static: <T>(renderable: RenderableTemplate<T>) => HydrateResult;
6
6
  };
7
7
  export default _default;
@@ -4,28 +4,37 @@ import { apply } from '../attributes.js';
4
4
  import cache from './cache.js';
5
5
  function reactive(renderable, slot) {
6
6
  let array = renderable.values, factory = renderable.template, refresh = () => {
7
- slot.length = 0;
8
- reactive(renderable, slot);
9
- }, render = (i, n) => {
10
- return root(() => template(array, factory, i, n));
11
- }, renderables = array.map(factory);
12
- array.on('pop', () => slot.pop());
13
- array.on('push', ({ items }) => slot.push(...render(array.length - items.length)));
7
+ slot.render(root(() => array.map(template)));
8
+ }, template = function (data, i) {
9
+ let renderable = factory.call(this, data, i);
10
+ return hydrate(renderable, cache.get(renderable));
11
+ };
12
+ array.on('pop', () => {
13
+ slot.pop();
14
+ });
15
+ array.on('push', ({ items }) => {
16
+ slot.push(...root(() => array.map(template, array.length - items.length)));
17
+ });
14
18
  array.on('reverse', refresh);
15
- array.on('shift', () => slot.shift());
19
+ array.on('shift', () => {
20
+ slot.shift();
21
+ });
16
22
  array.on('sort', refresh);
17
- array.on('splice', ({ deleteCount: d, items: i, start: s }) => slot.splice(s, d, ...render(s, i.length)));
18
- array.on('unshift', ({ items }) => slot.unshift(...render(0, items.length)));
19
- return template(array, factory, 0, renderables.length);
23
+ array.on('splice', ({ deleteCount: d, items: i, start: s }) => {
24
+ slot.splice(s, d, ...root(() => array.map(template, s, i.length)));
25
+ });
26
+ array.on('unshift', ({ items }) => {
27
+ slot.unshift(...root(() => array.map(template, 0, items.length)));
28
+ });
29
+ return array.map(template);
20
30
  }
21
- function render(renderable, template) {
31
+ function hydrate(renderable, template) {
22
32
  let elements = [], fragment = cloneNode.call(template.fragment, true), slots = template.slots;
23
33
  if (slots !== null) {
24
34
  let node, previous, values = renderable.values;
25
35
  for (let i = slots.length - 1; i >= 0; i--) {
26
36
  let { fn, path, slot } = slots[i];
27
- if (path === previous) { }
28
- else {
37
+ if (path !== previous) {
29
38
  apply(node);
30
39
  node = fragment;
31
40
  previous = path;
@@ -33,28 +42,20 @@ function render(renderable, template) {
33
42
  node = path[o].call(node);
34
43
  }
35
44
  }
36
- fn(node, values[slot], name);
45
+ fn(node, values[slot]);
37
46
  }
38
47
  apply(node);
39
48
  }
40
49
  for (let element = firstChild.call(fragment); element; element = nextSibling.call(element)) {
41
50
  elements.push(element);
42
51
  }
43
- return elements;
44
- }
45
- function template(array, template, i, n) {
46
- let groups = [], renderables = array.map(template, i, n);
47
- for (let i = 0, n = renderables.length; i < n; i++) {
48
- let renderable = renderables[i];
49
- groups.push(render(renderable, cache.get(renderable)));
50
- }
51
- return groups;
52
+ return { elements, fragment };
52
53
  }
53
54
  export default {
54
55
  reactive: (renderable, slot) => {
55
56
  return reactive(renderable, slot);
56
57
  },
57
58
  static: (renderable) => {
58
- return render(renderable, renderable.template || (renderable.template = cache.get(renderable)));
59
+ return hydrate(renderable, renderable.template || (renderable.template = cache.get(renderable)));
59
60
  }
60
61
  };
package/build/slot.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Element, Elements } from './types.js';
1
+ import { Element, Elements, HydrateResult } from './types.js';
2
2
  declare class Slot {
3
3
  marker: Element;
4
4
  nodes: Elements[];
@@ -9,11 +9,11 @@ declare class Slot {
9
9
  anchor(index?: number): Element;
10
10
  clear(): void;
11
11
  pop(): Elements[] | undefined;
12
- push(...groups: Elements[]): number;
12
+ push(...groups: HydrateResult[]): number;
13
13
  render(input: unknown): this;
14
14
  shift(): Elements[] | undefined;
15
- splice(start: number, stop?: number, ...groups: Elements[]): Elements[];
16
- unshift(...groups: Elements[]): number;
15
+ splice(start: number, stop?: number, ...groups: HydrateResult[]): Elements[];
16
+ unshift(...groups: HydrateResult[]): number;
17
17
  }
18
18
  declare const ondisconnect: (element: Element, fn: VoidFunction) => void;
19
19
  declare const _default: (marker: Element, value: unknown) => Slot;
package/build/slot.js CHANGED
@@ -1,27 +1,37 @@
1
1
  import { effect, root } from '@esportsplus/reactivity';
2
2
  import { isArray, isFunction, isInstanceOf, isObject } from '@esportsplus/utilities';
3
- import { RENDERABLE, RENDERABLE_REACTIVE, SLOT_CLEANUP } from './constants.js';
3
+ import { RENDERABLE, RENDERABLE_REACTIVE } from './constants.js';
4
4
  import { hydrate } from './html/index.js';
5
- import { firstChild, microtask, nextSibling, nodeValue, raf, text } from './utilities.js';
5
+ import { append, cloneNode, firstChild, fragment, microtask, nextSibling, nodeValue, raf, text } from './utilities.js';
6
6
  import queue from '@esportsplus/queue';
7
- let cleanup = queue(1024), scheduled = false;
7
+ const CLEANUP_KEY = Symbol();
8
+ let cleanup = queue(64), scheduled = false, template = fragment('');
8
9
  function after(anchor, groups) {
9
- for (let i = 0, n = groups.length; i < n; i++) {
10
- let group = groups[i];
11
- if (group.length) {
12
- anchor.after(anchor, ...group);
13
- anchor = group.at(-1);
10
+ let n = groups.length;
11
+ if (n === 0) {
12
+ return [];
13
+ }
14
+ let elements = [], fragment = groups[0].fragment || cloneNode.call(template);
15
+ if (n === 1) {
16
+ elements.push(groups[0].elements);
17
+ }
18
+ else {
19
+ for (let i = 1; i < n; i++) {
20
+ let { elements: e, fragment: f } = groups[i];
21
+ append.call(fragment, f);
22
+ elements.push(e);
14
23
  }
15
24
  }
16
- return groups;
25
+ anchor.after(fragment);
26
+ return elements;
17
27
  }
18
28
  function remove(...groups) {
19
29
  for (let i = 0, n = groups.length; i < n; i++) {
20
30
  let group = groups[i];
21
31
  for (let j = 0, o = group.length; j < o; j++) {
22
32
  let item = group[j];
23
- if (item[SLOT_CLEANUP]) {
24
- cleanup.add(item[SLOT_CLEANUP]);
33
+ if (CLEANUP_KEY in item) {
34
+ cleanup.add(item[CLEANUP_KEY]);
25
35
  }
26
36
  item.remove();
27
37
  }
@@ -31,51 +41,50 @@ function remove(...groups) {
31
41
  }
32
42
  return groups;
33
43
  }
34
- function render(anchor, input, slot) {
35
- if (input === false || input == null) {
36
- input = '';
37
- }
38
- else if (isObject(input)) {
39
- if (isArray(input)) {
40
- let groups = [];
41
- for (let i = 0, n = input.length; i < n; i++) {
42
- groups.push(render(null, input[i]));
43
- }
44
- return anchor ? after(anchor, groups) : groups;
45
- }
46
- let nodes = [];
47
- if (RENDERABLE in input) {
48
- if (input[RENDERABLE] === RENDERABLE_REACTIVE) {
49
- return after(anchor, hydrate.reactive(input, slot));
50
- }
51
- else {
52
- nodes = hydrate.static(input);
53
- }
44
+ function render(elements, fragment, input, slot) {
45
+ if (input === false || input == null || input === '') {
46
+ return;
47
+ }
48
+ if (isArray(input)) {
49
+ for (let i = 0, n = input.length; i < n; i++) {
50
+ render(elements, fragment, input[i]);
54
51
  }
55
- else if (isInstanceOf(input, NodeList)) {
56
- for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
57
- nodes.push(node);
52
+ }
53
+ else if (isObject(input) && RENDERABLE in input) {
54
+ if (input[RENDERABLE] === RENDERABLE_REACTIVE) {
55
+ let response = hydrate.reactive(input, slot);
56
+ for (let i = 0, n = response.length; i < n; i++) {
57
+ let { elements: e, fragment: f } = response[i];
58
+ append.call(fragment, f);
59
+ elements.push(e);
58
60
  }
59
61
  }
60
- else if (isInstanceOf(input, Node)) {
61
- nodes = [input];
62
+ else {
63
+ let { elements: e, fragment: f } = hydrate.static(input);
64
+ append.call(fragment, f);
65
+ elements.push(e);
62
66
  }
63
- if (anchor) {
64
- anchor.after(...nodes);
67
+ }
68
+ else if (isInstanceOf(input, NodeList)) {
69
+ let e = [];
70
+ for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
71
+ e.push(node);
65
72
  }
66
- return nodes;
73
+ append.call(fragment, ...e);
74
+ elements.push(e);
67
75
  }
68
- if (input === '') {
69
- return [];
76
+ else if (isInstanceOf(input, Node)) {
77
+ append.call(fragment, input);
78
+ elements.push([input]);
70
79
  }
71
- let node = text(input);
72
- if (anchor) {
73
- anchor.after(node);
80
+ else {
81
+ let element = text(typeof input === 'string' ? input : String(input));
74
82
  if (slot) {
75
- slot.text = node;
83
+ slot.text = element;
76
84
  }
85
+ append.call(fragment, element);
86
+ elements.push([element]);
77
87
  }
78
- return [node];
79
88
  }
80
89
  function schedule() {
81
90
  if (scheduled) {
@@ -85,14 +94,14 @@ function schedule() {
85
94
  microtask.add(task);
86
95
  }
87
96
  function task() {
88
- let fns;
97
+ let fn, fns;
89
98
  while (fns = cleanup.next()) {
90
- for (let i = 0, n = fns.length; i < n; i++) {
91
- try {
92
- fns[i]();
99
+ try {
100
+ while (fn = fns.pop()) {
101
+ fn();
93
102
  }
94
- catch { }
95
103
  }
104
+ catch { }
96
105
  }
97
106
  scheduled = false;
98
107
  if (cleanup.length) {
@@ -117,12 +126,13 @@ class Slot {
117
126
  anchor(index = this.nodes.length - 1) {
118
127
  let node, nodes = this.nodes[index];
119
128
  if (nodes) {
120
- node = nodes.at(-1);
129
+ node = nodes[nodes.length - 1];
121
130
  }
122
131
  return node || this.marker;
123
132
  }
124
133
  clear() {
125
134
  remove(...this.nodes);
135
+ this.nodes.length = 0;
126
136
  this.text = null;
127
137
  }
128
138
  pop() {
@@ -133,11 +143,7 @@ class Slot {
133
143
  return remove(group);
134
144
  }
135
145
  push(...groups) {
136
- after(this.anchor(), groups);
137
- for (let i = 0, n = groups.length; i < n; i++) {
138
- this.nodes.push(groups[i]);
139
- }
140
- return this.nodes.length;
146
+ return this.nodes.push(...after(this.anchor(), groups));
141
147
  }
142
148
  render(input) {
143
149
  if (isFunction(input)) {
@@ -156,19 +162,18 @@ class Slot {
156
162
  }
157
163
  if (this.text) {
158
164
  let type = typeof input;
159
- if (type === 'object' && input !== null) { }
165
+ if (type === 'object' && input !== null) {
166
+ }
160
167
  else if (this.text.isConnected) {
161
168
  nodeValue.call(this.text, (type === 'string' || type === 'number') ? input : '');
162
169
  return this;
163
170
  }
164
171
  }
165
172
  this.clear();
166
- if (isArray(input) || (isObject(input) && input[RENDERABLE] === RENDERABLE_REACTIVE)) {
167
- this.nodes = render(this.marker, input, this);
168
- }
169
- else {
170
- this.nodes = [render(this.marker, input, this)];
171
- }
173
+ let fragment = cloneNode.call(template), nodes = [];
174
+ render(nodes, fragment, input, this);
175
+ this.marker.after(fragment);
176
+ this.nodes = nodes;
172
177
  return this;
173
178
  }
174
179
  shift() {
@@ -186,7 +191,7 @@ class Slot {
186
191
  }
187
192
  }
188
193
  const ondisconnect = (element, fn) => {
189
- (element[SLOT_CLEANUP] ??= []).push(fn);
194
+ (element[CLEANUP_KEY] ??= []).push(fn);
190
195
  };
191
196
  export default (marker, value) => {
192
197
  return new Slot(marker).render(value);
package/build/types.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { ReactiveArray } from '@esportsplus/reactivity';
2
- import { RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT_CLEANUP } from './constants.js';
2
+ import { RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE } from './constants.js';
3
3
  import { firstChild } from './utilities.js';
4
4
  import attributes from './attributes.js';
5
- import event from './event.js';
6
5
  import slot from './slot.js';
7
6
  type Attribute = Primitive | Effect<Primitive | Primitive[]>;
8
7
  type Attributes = {
@@ -19,10 +18,12 @@ type Attributes = {
19
18
  } & Record<PropertyKey, unknown>;
20
19
  type Effect<T> = () => EffectResponse<T>;
21
20
  type EffectResponse<T> = T extends [] ? EffectResponse<T[number]>[] : Primitive | Renderable<T>;
22
- type Element = HTMLElement & Attributes & {
23
- [SLOT_CLEANUP]?: VoidFunction[];
24
- } & Record<PropertyKey, unknown>;
21
+ type Element = HTMLElement & Attributes & Record<PropertyKey, unknown>;
25
22
  type Elements = Element[];
23
+ type HydrateResult = {
24
+ elements: Elements;
25
+ fragment: DocumentFragment | Node;
26
+ };
26
27
  type Primitive = bigint | boolean | null | number | string | undefined;
27
28
  type Renderable<T = unknown> = RenderableReactive<T> | RenderableTemplate<T>;
28
29
  type RenderableReactive<T = unknown> = Readonly<{
@@ -43,9 +44,9 @@ type Template = {
43
44
  html: string;
44
45
  literals: TemplateStringsArray;
45
46
  slots: {
46
- fn: typeof attributes.spread | typeof event | typeof slot;
47
+ fn: typeof attributes.spread | typeof slot;
47
48
  path: typeof firstChild[];
48
49
  slot: number;
49
50
  }[] | null;
50
51
  };
51
- export type { Attributes, Effect, Element, Elements, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, Template };
52
+ export type { Attributes, Effect, Element, Elements, HydrateResult, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, Template };
package/build/types.js CHANGED
@@ -1 +1 @@
1
- import { RENDERABLE, SLOT_CLEANUP } from './constants.js';
1
+ import { RENDERABLE } from './constants.js';