@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.
@@ -1,9 +1,7 @@
1
1
  import { Attributes, Element } from './types.js';
2
- declare const apply: (element: Element) => void;
3
2
  declare const spread: (element: Element, value: Attributes | Attributes[]) => void;
4
3
  declare const _default: {
5
- apply: (element: Element) => void;
6
4
  spread: (element: Element, value: Attributes | Attributes[]) => void;
7
5
  };
8
6
  export default _default;
9
- export { apply, spread };
7
+ export { spread };
@@ -5,7 +5,6 @@ import { className, raf, removeAttribute, setAttribute } from './utilities.js';
5
5
  import q from '@esportsplus/queue';
6
6
  import event from './event.js';
7
7
  const EFFECT_KEY = Symbol();
8
- const HYDRATE_KEY = Symbol();
9
8
  const STORE_KEY = Symbol();
10
9
  const UPDATES_KEY = Symbol();
11
10
  const STATE_HYDRATING = 0;
@@ -140,7 +139,7 @@ function update(context, id, name, value, state) {
140
139
  store[name] = value;
141
140
  }
142
141
  if (state === STATE_HYDRATING) {
143
- (context.element[HYDRATE_KEY] ??= {})[name] = value;
142
+ attribute(context.element, name, value);
144
143
  }
145
144
  else {
146
145
  context.updates[name] = value;
@@ -153,16 +152,6 @@ function update(context, id, name, value, state) {
153
152
  }
154
153
  }
155
154
  }
156
- const apply = (element) => {
157
- let attributes = element[HYDRATE_KEY];
158
- if (!attributes) {
159
- return;
160
- }
161
- for (let key in attributes) {
162
- attribute(element, key, attributes[key]);
163
- }
164
- delete element[HYDRATE_KEY];
165
- };
166
155
  const spread = function (element, value) {
167
156
  let cache = (element[STORE_KEY] ??= { [UPDATES_KEY]: {} }), context = {
168
157
  element,
@@ -184,5 +173,5 @@ const spread = function (element, value) {
184
173
  }
185
174
  }
186
175
  };
187
- export default { apply, spread };
188
- export { apply, spread };
176
+ export default { spread };
177
+ export { spread };
@@ -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,20 +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
- path,
36
+ path: p,
30
37
  slot
31
38
  });
32
39
  buffer += parsed[slot++];
@@ -37,22 +44,25 @@ function build(literals, values) {
37
44
  levels[++level] = {
38
45
  children: 0,
39
46
  elements: 0,
40
- path: parent.path.length
41
- ? methods(parent.elements, parent.path, firstElementChild, nextElementSibling)
42
- : methods(parent.children, [], firstChild, nextSibling)
47
+ path
43
48
  };
44
49
  }
45
50
  parent.elements++;
46
51
  }
47
52
  else if (type === NODE_SLOT) {
53
+ let relative = methods(parent.children, [], firstChild, nextSibling);
48
54
  buffer += parsed[slot] + SLOT_HTML;
49
55
  slots.push({
50
56
  fn: s,
51
- path: methods(parent.children, parent.path, firstChild, nextSibling),
57
+ path: {
58
+ absolute: [...parent.path, ...relative],
59
+ parent: parent.path,
60
+ relative
61
+ },
52
62
  slot: slot++
53
63
  });
54
64
  }
55
- if (slot === total) {
65
+ if (slot === n) {
56
66
  buffer += parsed[slot];
57
67
  break;
58
68
  }
@@ -84,7 +94,7 @@ function set(literals, html, slots = null) {
84
94
  cache.set(literals, template);
85
95
  return template;
86
96
  }
87
- const get = ({ literals, values }) => {
88
- return cache.get(literals) || build(literals, values);
97
+ const get = (literals) => {
98
+ return cache.get(literals) || build(literals);
89
99
  };
90
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,63 +1,85 @@
1
1
  import { root } from '@esportsplus/reactivity';
2
- import { cloneNode, firstChild, nextSibling } from '../utilities.js';
3
- import { apply } from '../attributes.js';
2
+ import { EMPTY_FRAGMENT } from '../constants.js';
3
+ import { cloneNode } from '../utilities.js';
4
4
  import cache from './cache.js';
5
- function reactive(renderable, slot) {
5
+ function reactive(elements, fragment, renderable, slot) {
6
6
  let array = renderable.values, factory = renderable.template, refresh = () => {
7
- 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);
8
15
  }, template = function (data, i) {
9
- let renderable = factory.call(this, data, i);
10
- return hydrate(renderable, cache.get(renderable));
16
+ hydrate(elements, fragment, factory.call(this, data, i));
11
17
  };
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
- });
18
+ array.on('clear', () => slot.clear());
19
+ array.on('pop', () => slot.pop());
18
20
  array.on('reverse', refresh);
19
- array.on('shift', () => {
20
- slot.shift();
21
- });
21
+ array.on('shift', () => slot.shift());
22
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
+ });
23
30
  array.on('splice', ({ deleteCount: d, items: i, start: s }) => {
24
- 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();
25
38
  });
26
39
  array.on('unshift', ({ items }) => {
27
- slot.unshift(...root(() => array.map(template, 0, items.length)));
40
+ root(() => array.map(template, 0, items.length));
41
+ slot.unshift(fragment, ...elements);
42
+ reset();
28
43
  });
29
- return array.map(template);
44
+ root(() => array.map(template));
45
+ reset();
30
46
  }
31
- function hydrate(renderable, template) {
32
- 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);
33
49
  if (slots !== null) {
34
- let node, previous, values = renderable.values;
35
- for (let i = slots.length - 1; i >= 0; i--) {
36
- let { fn, path, slot } = slots[i];
37
- if (path !== previous) {
38
- if (node) {
39
- apply(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;
40
58
  }
41
- node = fragment;
42
- previous = path;
43
- for (let o = 0, j = path.length; o < j; o++) {
44
- node = path[o].call(node);
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);
45
72
  }
46
73
  }
47
74
  fn(node, values[slot]);
48
75
  }
49
- apply(node);
50
76
  }
51
- for (let element = firstChild.call(fragment); element; element = nextSibling.call(element)) {
52
- elements.push(element);
77
+ if (elements) {
78
+ elements.push([...clone.childNodes]);
53
79
  }
54
- return { elements, fragment };
80
+ fragment.appendChild(clone);
55
81
  }
56
82
  export default {
57
- reactive: (renderable, slot) => {
58
- return reactive(renderable, slot);
59
- },
60
- static: (renderable) => {
61
- return hydrate(renderable, renderable.template || (renderable.template = cache.get(renderable)));
62
- }
83
+ reactive,
84
+ static: hydrate
63
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;
13
- render(input: unknown): this;
14
- shift(): Elements[] | undefined;
15
- splice(start: number, stop?: number, ...groups: HydrateResult[]): Elements[];
16
- unshift(...groups: HydrateResult[]): number;
10
+ clear(): this;
11
+ pop(): this;
12
+ push(fragment: Fragment, ...nodes: Elements[]): this;
13
+ render(input: unknown, state?: number): this;
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,37 +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
- let cleanup = queue(64), scheduled = false, template = fragment('');
9
- function after(anchor, groups) {
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);
23
- }
24
- }
25
- anchor.after(fragment);
26
- return elements;
27
- }
28
- function remove(...groups) {
29
- for (let i = 0, n = groups.length; i < n; i++) {
30
- let group = groups[i];
31
- for (let j = 0, o = group.length; j < o; j++) {
32
- let item = group[j];
8
+ const CONNECTED = 0;
9
+ const HYDRATING = 1;
10
+ let cleanup = queue(64), scheduled = false;
11
+ function remove(groups) {
12
+ let group, item;
13
+ while (group = groups.pop()) {
14
+ while (item = group.pop()) {
33
15
  if (CLEANUP_KEY in item) {
34
16
  cleanup.add(item[CLEANUP_KEY]);
17
+ item[CLEANUP_KEY] = null;
35
18
  }
36
19
  item.remove();
37
20
  }
@@ -39,51 +22,47 @@ function remove(...groups) {
39
22
  if (!scheduled && cleanup.length) {
40
23
  schedule();
41
24
  }
42
- return groups;
43
25
  }
44
- function render(elements, fragment, input, slot) {
26
+ function render(anchor, elements, fragment, input, slot) {
45
27
  if (input === false || input == null || input === '') {
46
28
  return;
47
29
  }
48
- if (isArray(input)) {
49
- for (let i = 0, n = input.length; i < n; i++) {
50
- render(elements, fragment, input[i]);
51
- }
52
- }
53
- else if (isObject(input) && RENDERABLE in input) {
30
+ let type = typeof input;
31
+ if (type === 'object' && RENDERABLE in input) {
54
32
  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);
60
- }
33
+ slot ??= new Slot(anchor);
34
+ hydrate.reactive(slot.nodes, fragment, input, slot);
61
35
  }
62
36
  else {
63
- let { elements: e, fragment: f } = hydrate.static(input);
64
- append.call(fragment, f);
65
- elements.push(e);
37
+ hydrate.static(elements, fragment, input);
38
+ }
39
+ }
40
+ else if (type === 'string' || type === 'number') {
41
+ let element = text(type === 'string' ? input : String(input));
42
+ if (slot) {
43
+ slot.text = element;
44
+ }
45
+ append.call(fragment, element);
46
+ if (elements) {
47
+ elements.push([element]);
48
+ }
49
+ }
50
+ else if (isArray(input)) {
51
+ for (let i = 0, n = input.length; i < n; i++) {
52
+ render(anchor, elements, fragment, input[i], slot);
66
53
  }
67
54
  }
68
55
  else if (isInstanceOf(input, NodeList)) {
69
- let e = [];
70
- for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
71
- e.push(node);
56
+ append.call(fragment, ...input);
57
+ if (elements) {
58
+ elements.push([...input]);
72
59
  }
73
- append.call(fragment, ...e);
74
- elements.push(e);
75
60
  }
76
61
  else if (isInstanceOf(input, Node)) {
77
62
  append.call(fragment, input);
78
- elements.push([input]);
79
- }
80
- else {
81
- let element = text(typeof input === 'string' ? input : String(input));
82
- if (slot) {
83
- slot.text = element;
63
+ if (elements) {
64
+ elements.push([input]);
84
65
  }
85
- append.call(fragment, element);
86
- elements.push([element]);
87
66
  }
88
67
  }
89
68
  function schedule() {
@@ -121,79 +100,105 @@ class Slot {
121
100
  return this.nodes.length;
122
101
  }
123
102
  set length(n) {
124
- 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
+ }
125
112
  }
126
113
  anchor(index = this.nodes.length - 1) {
127
- let node, nodes = this.nodes[index];
128
- if (nodes) {
129
- node = nodes[nodes.length - 1];
130
- }
131
- return node || this.marker;
114
+ let nodes = this.nodes[index];
115
+ return nodes ? nodes[nodes.length - 1] : this.marker;
132
116
  }
133
117
  clear() {
134
- remove(...this.nodes);
135
- this.nodes.length = 0;
136
- this.text = null;
118
+ if (this.text) {
119
+ this.nodes.push([this.text]);
120
+ this.text = null;
121
+ }
122
+ remove(this.nodes);
123
+ return this;
137
124
  }
138
125
  pop() {
139
126
  let group = this.nodes.pop();
140
- if (!group) {
141
- return undefined;
127
+ if (group) {
128
+ remove([group]);
142
129
  }
143
- return remove(group);
130
+ return this;
144
131
  }
145
- push(...groups) {
146
- 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;
147
136
  }
148
- render(input) {
149
- if (isFunction(input)) {
137
+ render(input, state = HYDRATING) {
138
+ let type = typeof input;
139
+ if (type === 'function') {
150
140
  ondisconnect(this.marker, effect(() => {
151
141
  let v = input();
152
- if (isFunction(v)) {
153
- root(() => this.render(v()));
142
+ if (state === HYDRATING) {
143
+ this.render(v, state);
144
+ state = CONNECTED;
154
145
  }
155
- else {
146
+ else if (state === CONNECTED) {
156
147
  raf.add(() => {
157
- this.render(v);
148
+ this.render(v, state);
158
149
  });
159
150
  }
160
151
  }));
161
152
  return this;
162
153
  }
163
- if (this.text) {
164
- let type = typeof input;
165
- if (type === 'object' && input !== null) {
166
- }
167
- else if (this.text.isConnected) {
168
- nodeValue.call(this.text, (type === 'string' || type === 'number') ? input : '');
169
- return this;
170
- }
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);
171
163
  }
172
- this.clear();
173
- let fragment = cloneNode.call(template), nodes = [];
174
- render(nodes, fragment, input, this);
175
- this.marker.after(fragment);
176
- this.nodes = nodes;
177
164
  return this;
178
165
  }
179
166
  shift() {
180
167
  let group = this.nodes.shift();
181
- if (!group) {
182
- return undefined;
168
+ if (group) {
169
+ remove([group]);
183
170
  }
184
- return remove(group);
171
+ return this;
185
172
  }
186
- splice(start, stop = this.nodes.length, ...groups) {
187
- return remove(...this.nodes.splice(start, stop, ...after(this.anchor(start), groups)));
173
+ splice(start, stop = this.nodes.length, fragment, ...nodes) {
174
+ if (!fragment) {
175
+ remove(this.nodes.splice(start, stop));
176
+ }
177
+ else {
178
+ this.anchor(start).after(fragment);
179
+ remove(this.nodes.splice(start, stop, ...nodes));
180
+ }
181
+ return this;
188
182
  }
189
- unshift(...groups) {
190
- 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;
191
187
  }
192
188
  }
193
189
  const ondisconnect = (element, fn) => {
194
190
  (element[CLEANUP_KEY] ??= []).push(fn);
195
191
  };
196
192
  export default (marker, value) => {
197
- 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
+ ;
198
203
  };
199
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,8 +42,12 @@ type Template = {
45
42
  literals: TemplateStringsArray;
46
43
  slots: {
47
44
  fn: typeof attributes.spread | typeof slot;
48
- path: typeof firstChild[];
45
+ path: {
46
+ absolute: typeof firstChild[];
47
+ parent: typeof firstChild[];
48
+ relative: typeof firstChild[];
49
+ };
49
50
  slot: number;
50
51
  }[] | null;
51
52
  };
52
- 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 };