@esportsplus/template 0.18.0 → 0.19.0

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,12 +1,38 @@
1
- import { RENDERABLE, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY } from '../constants.js';
2
- import hydrate from './hydrate.js';
1
+ import { RENDERABLE, RENDERABLE_HTML_REACTIVE_ARRAY } from '../constants.js';
2
+ import { cloneNode } from '../utilities/node.js';
3
3
  import parser from './parser.js';
4
4
  const html = (literals, ...values) => {
5
- return {
6
- [RENDERABLE]: RENDERABLE_HTML_FRAGMENT,
7
- fragment: hydrate(parser.parse(literals), values),
8
- literals
9
- };
5
+ let { fragment, slots } = parser.parse(literals);
6
+ fragment = cloneNode.call(fragment, true);
7
+ if (slots !== null) {
8
+ let node, nodePath, parent, parentPath;
9
+ for (let i = 0, n = slots.length; i < n; i++) {
10
+ let { fn, path, slot } = slots[i], pp = path.parent, pr = path.relative;
11
+ if (pp !== parentPath) {
12
+ if (pp === nodePath) {
13
+ parent = node;
14
+ parentPath = nodePath;
15
+ nodePath = undefined;
16
+ }
17
+ else {
18
+ parent = fragment;
19
+ parentPath = pp;
20
+ for (let i = 0, n = pp.length; i < n; i++) {
21
+ parent = pp[i].call(parent);
22
+ }
23
+ }
24
+ }
25
+ if (pr !== nodePath) {
26
+ node = parent;
27
+ nodePath = path.absolute;
28
+ for (let i = 0, n = pr.length; i < n; i++) {
29
+ node = pr[i].call(node);
30
+ }
31
+ }
32
+ fn(node, values[slot]);
33
+ }
34
+ }
35
+ return fragment;
10
36
  };
11
37
  html.reactive = (array, template) => {
12
38
  return {
@@ -1,8 +1,8 @@
1
1
  import { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH } from '../constants.js';
2
2
  import { firstElementChild, nextElementSibling } from '../utilities/element.js';
3
- import { fragment } from '../utilities/fragment.js';
4
3
  import { firstChild, nextSibling } from '../utilities/node.js';
5
4
  import { spread } from '../attributes.js';
5
+ import { fragment } from '../utilities/fragment.js';
6
6
  import s from '../slot/index.js';
7
7
  let cache = new WeakMap();
8
8
  function build(literals) {
@@ -87,16 +87,20 @@ function methods(children, copy, first, next) {
87
87
  return methods;
88
88
  }
89
89
  function set(literals, html, slots = null) {
90
- let template = {
90
+ let value = {
91
91
  fragment: fragment(html),
92
92
  html,
93
93
  literals,
94
94
  slots
95
95
  };
96
- cache.set(literals, template);
97
- return template;
96
+ cache.set(literals, value);
97
+ return value;
98
98
  }
99
99
  const parse = (literals) => {
100
- return cache.get(literals) || build(literals);
100
+ let result = cache.get(literals);
101
+ if (result === undefined) {
102
+ result = build(literals);
103
+ }
104
+ return result;
101
105
  };
102
106
  export default { parse };
package/build/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { default as html } from './html/index.js';
2
2
  export { default as render } from './render.js';
3
3
  export { default as svg } from './svg.js';
4
- export type { Attributes, Element, Elements, Renderable, RenderableValue } from './types.js';
4
+ export type { Attributes, Element, Renderable, RenderableValue } from './types.js';
@@ -2,17 +2,18 @@ import { effect } from '@esportsplus/reactivity';
2
2
  import { STATE_HYDRATING, STATE_NONE } from '../constants.js';
3
3
  import { firstChild, lastChild, nodeValue } from '../utilities/node.js';
4
4
  import { raf } from '../utilities/queue.js';
5
- import { ondisconnect } from '../slot/cleanup.js';
6
5
  import { remove } from './cleanup.js';
7
6
  import text from '../utilities/text.js';
8
7
  import render from './render.js';
9
8
  function update(anchor, value) {
10
- let type = typeof value;
11
9
  if (this.group) {
12
10
  remove([this.group]);
13
11
  this.group = undefined;
14
12
  }
15
- if (value == null || type !== 'object') {
13
+ if (value == null || value === false) {
14
+ value = '';
15
+ }
16
+ if (typeof value !== 'object') {
16
17
  let textnode = this.textnode;
17
18
  if (textnode) {
18
19
  nodeValue.call(textnode, String(value));
@@ -25,15 +26,14 @@ function update(anchor, value) {
25
26
  }
26
27
  }
27
28
  else {
28
- let fragment = render(anchor, value);
29
- if (!fragment) {
30
- return;
29
+ let fragment = render(anchor, value), head = firstChild.call(fragment);
30
+ if (head) {
31
+ this.group = {
32
+ head,
33
+ tail: lastChild.call(fragment)
34
+ };
35
+ anchor.after(fragment);
31
36
  }
32
- this.group = {
33
- head: firstChild.call(fragment),
34
- tail: lastChild.call(fragment)
35
- };
36
- anchor.after(fragment);
37
37
  }
38
38
  }
39
39
  export default (anchor, fn) => {
@@ -41,7 +41,7 @@ export default (anchor, fn) => {
41
41
  group: undefined,
42
42
  textnode: undefined
43
43
  }, state = STATE_HYDRATING;
44
- ondisconnect(anchor, effect(() => {
44
+ effect(() => {
45
45
  let value = fn();
46
46
  if (state === STATE_HYDRATING) {
47
47
  update.call(context, anchor, value);
@@ -52,5 +52,5 @@ export default (anchor, fn) => {
52
52
  update.call(context, anchor, value);
53
53
  });
54
54
  }
55
- }));
55
+ });
56
56
  };
@@ -2,7 +2,9 @@ import effect from './effect.js';
2
2
  import render from './render.js';
3
3
  export default (anchor, value) => {
4
4
  if (typeof value === 'function') {
5
- return effect(anchor, value);
5
+ effect(anchor, value);
6
+ }
7
+ else {
8
+ anchor.after(render(anchor, value));
6
9
  }
7
- anchor.after(render(anchor, value));
8
10
  };
@@ -1,3 +1,3 @@
1
- import { Fragment, RenderableReactive } from '../types.js';
2
- declare const _default: (anchor: Element, renderable: RenderableReactive) => Fragment;
1
+ import { RenderableReactive } from '../types.js';
2
+ declare const _default: (anchor: Element, renderable: RenderableReactive) => Node;
3
3
  export default _default;
@@ -2,45 +2,47 @@ import { root } from '@esportsplus/reactivity';
2
2
  import { EMPTY_FRAGMENT } from '../constants.js';
3
3
  import { append } from '../utilities/fragment.js';
4
4
  import { cloneNode, firstChild, lastChild } from '../utilities/node.js';
5
- import { remove } from './cleanup.js';
5
+ import { ondisconnect, remove } from './cleanup.js';
6
6
  class ReactiveArraySlot {
7
7
  array;
8
- fragment = cloneNode.call(EMPTY_FRAGMENT);
8
+ fragment;
9
9
  marker;
10
10
  nodes = [];
11
11
  template;
12
12
  constructor(anchor, array, template) {
13
- let fragment = this.fragment;
13
+ let fragment = this.fragment = cloneNode.call(EMPTY_FRAGMENT);
14
14
  this.array = array;
15
15
  this.marker = anchor;
16
16
  this.template = function (data, i) {
17
- let frag = template.call(this, data, i).fragment, group = {
17
+ let dispose, frag = root((d) => {
18
+ dispose = d;
19
+ return template.call(this, data, i);
20
+ }), group = {
18
21
  head: firstChild.call(frag),
19
22
  tail: lastChild.call(frag)
20
23
  };
21
24
  append.call(fragment, frag);
25
+ ondisconnect(group.head, dispose);
22
26
  return group;
23
27
  };
24
- let render = () => {
25
- root(() => this.render());
26
- };
27
28
  array.on('clear', () => this.clear());
28
- array.on('reverse', render);
29
+ array.on('reverse', () => {
30
+ root(() => this.render());
31
+ });
29
32
  array.on('pop', () => this.pop());
30
33
  array.on('push', ({ items }) => {
31
34
  root(() => this.push(items));
32
35
  });
33
36
  array.on('shift', () => this.shift());
34
- array.on('sort', render);
37
+ array.on('sort', () => {
38
+ root(() => this.render());
39
+ });
35
40
  array.on('splice', ({ deleteCount, items, start }) => {
36
41
  root(() => this.splice(start, deleteCount, ...items));
37
42
  });
38
43
  array.on('unshift', ({ items }) => {
39
44
  root(() => this.unshift(items));
40
45
  });
41
- if (array.length) {
42
- render();
43
- }
44
46
  }
45
47
  get length() {
46
48
  return this.nodes.length;
@@ -1,81 +1,37 @@
1
1
  import { isArray } from '@esportsplus/utilities';
2
- import { EMPTY_FRAGMENT, RENDERABLE, RENDERABLE_ARRAY, RENDERABLE_FRAGMENT, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY, RENDERABLE_NODE, RENDERABLE_NODE_LIST, RENDERABLE_TEXT, RENDERABLE_VOID } from '../constants.js';
3
- import { cloneNode } from '../utilities/node.js';
2
+ import { EMPTY_FRAGMENT, RENDERABLE } from '../constants.js';
3
+ import { cloneNode, lastChild } from '../utilities/node.js';
4
4
  import { append } from '../utilities/fragment.js';
5
5
  import text from '../utilities/text.js';
6
6
  import reactive from './reactive.js';
7
- function type(input) {
8
- if (input === false || input == null || input === '') {
9
- return RENDERABLE_VOID;
7
+ export default function render(anchor, input) {
8
+ if (input == null || input === false || input === '') {
9
+ return EMPTY_FRAGMENT;
10
10
  }
11
11
  if (typeof input !== 'object') {
12
- return RENDERABLE_TEXT;
12
+ return text(input);
13
+ }
14
+ if ('nodeType' in input) {
15
+ return input;
13
16
  }
14
17
  if (RENDERABLE in input) {
15
- return input[RENDERABLE];
18
+ return reactive(anchor, input);
16
19
  }
17
20
  if (isArray(input)) {
18
- return RENDERABLE_ARRAY;
19
- }
20
- let nodeType = input.nodeType;
21
- if (nodeType === 11) {
22
- return RENDERABLE_FRAGMENT;
23
- }
24
- if (nodeType !== undefined) {
25
- return RENDERABLE_NODE;
21
+ let fragment = cloneNode.call(EMPTY_FRAGMENT);
22
+ for (let i = 0, n = input.length; i < n; i++) {
23
+ append.call(fragment, render(anchor, input[i]));
24
+ anchor = lastChild.call(fragment);
25
+ }
26
+ return fragment;
26
27
  }
27
28
  if (input instanceof NodeList) {
28
- return RENDERABLE_NODE_LIST;
29
- }
30
- return RENDERABLE_TEXT;
31
- }
32
- function loop(fragment, input) {
33
- let t = type(input);
34
- switch (t) {
35
- case RENDERABLE_HTML_REACTIVE_ARRAY:
36
- throw new Error('@esportsplus/template: reactive arrays cannot be defined within an slot array value');
37
- case RENDERABLE_VOID:
38
- return;
39
- case RENDERABLE_ARRAY:
40
- for (let i = 0, n = input.length; i < n; i++) {
41
- loop(fragment, input[i]);
42
- }
43
- return;
44
- case RENDERABLE_NODE_LIST:
45
- append.call(fragment, ...input);
46
- return;
47
- default:
48
- append.call(fragment, input);
49
- return;
50
- }
51
- }
52
- let scratchpad = cloneNode.call(EMPTY_FRAGMENT);
53
- export default function render(anchor, input) {
54
- let fragment = scratchpad, t = type(input);
55
- switch (t) {
56
- case RENDERABLE_VOID:
57
- break;
58
- case RENDERABLE_TEXT:
59
- append.call(fragment, text(input));
60
- break;
61
- case RENDERABLE_HTML_FRAGMENT:
62
- return input.fragment;
63
- case RENDERABLE_HTML_REACTIVE_ARRAY:
64
- return reactive(anchor, input);
65
- case RENDERABLE_ARRAY:
66
- for (let i = 0, n = input.length; i < n; i++) {
67
- loop(fragment, input[i]);
68
- }
69
- break;
70
- case RENDERABLE_FRAGMENT:
71
- return input;
72
- case RENDERABLE_NODE:
73
- append.call(fragment, input);
74
- break;
75
- case RENDERABLE_NODE_LIST:
76
- append.call(fragment, ...input);
77
- break;
29
+ let fragment = cloneNode.call(EMPTY_FRAGMENT), nodes = Array.from(input);
30
+ for (let i = 0, n = nodes.length; i < n; i++) {
31
+ append.call(fragment, nodes[i]);
32
+ }
33
+ return fragment;
78
34
  }
79
- return fragment;
35
+ return text(input);
80
36
  }
81
37
  ;
package/build/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ReactiveArray } from '@esportsplus/reactivity';
2
- import { RENDERABLE, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY } from './constants.js';
2
+ import { RENDERABLE, RENDERABLE_HTML_REACTIVE_ARRAY } from './constants.js';
3
3
  import { firstChild } from './utilities/node.js';
4
4
  import attributes from './attributes.js';
5
5
  import slot from './slot/index.js';
@@ -20,22 +20,14 @@ type Attributes = {
20
20
  type Effect<T> = () => EffectResponse<T>;
21
21
  type EffectResponse<T> = T extends [] ? (Primitive | Renderable)[] : Primitive | Renderable;
22
22
  type Element = HTMLElement & Attributes & Record<PropertyKey, unknown>;
23
- type Elements = Element[];
24
- type Fragment = (DocumentFragment | Node) & Record<PropertyKey, unknown>;
25
23
  type Primitive = bigint | boolean | null | number | string | undefined;
26
- type Renderable = Fragment | Primitive | RenderableReactive | RenderableTemplate;
24
+ type Renderable = DocumentFragment | Node | NodeList | Primitive | RenderableReactive | Renderable[];
27
25
  type RenderableReactive = Readonly<{
28
26
  [RENDERABLE]: typeof RENDERABLE_HTML_REACTIVE_ARRAY;
29
27
  array: ReactiveArray<unknown[]>;
30
28
  template: (this: ReactiveArray<unknown[]>, ...args: Parameters<Parameters<ReactiveArray<unknown[]>['map']>[0]>) => ReturnType<typeof html>;
31
29
  }>;
32
- type RenderableTemplate = {
33
- [RENDERABLE]: typeof RENDERABLE_HTML_FRAGMENT;
34
- fragment: Fragment;
35
- literals: TemplateStringsArray;
36
- };
37
- type RenderableValue<T = unknown> = Attributes | Readonly<Attributes> | Readonly<Attributes[]> | Effect<T> | Fragment | Primitive | RenderableReactive;
38
- type RenderableValues = RenderableValue | RenderableValue[];
30
+ type RenderableValue<T = unknown> = Attributes | Readonly<Attributes> | Readonly<Attributes[]> | Effect<T> | Primitive | RenderableReactive;
39
31
  type SlotGroup = {
40
32
  head: Element;
41
33
  tail: Element;
@@ -54,4 +46,4 @@ type Template = {
54
46
  slot: number;
55
47
  }[] | null;
56
48
  };
57
- export type { Attributes, Effect, Element, Elements, Fragment, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, RenderableValues, SlotGroup, Template };
49
+ export type { Attributes, Effect, Element, Renderable, RenderableReactive, RenderableValue, SlotGroup, Template };
@@ -1,11 +1,11 @@
1
1
  import { innerHTML } from './element.js';
2
2
  import { cloneNode } from './node.js';
3
- let prototype = DocumentFragment.prototype, template = document.createElement('template');
4
- const append = prototype.append;
3
+ let scratchpad = document.createElement('template');
4
+ const append = DocumentFragment.prototype.append;
5
5
  const fragment = (html) => {
6
- innerHTML.call(template, html);
7
- let content = template.content;
8
- template = cloneNode.call(template);
6
+ innerHTML.call(scratchpad, html);
7
+ let content = scratchpad.content;
8
+ scratchpad = cloneNode.call(scratchpad);
9
9
  return content;
10
10
  };
11
11
  export { append, fragment };
@@ -1,3 +1,4 @@
1
+ declare const appendChild: <T extends Node>(node: T) => T;
1
2
  declare const cloneNode: (subtree?: boolean) => Node;
2
3
  declare const firstChild: () => any;
3
4
  declare const lastChild: () => any;
@@ -5,4 +6,4 @@ declare const nextSibling: () => any;
5
6
  declare const nodeValue: (v: any) => void;
6
7
  declare const parentElement: () => any;
7
8
  declare const previousSibling: () => any;
8
- export { cloneNode, firstChild, lastChild, nextSibling, nodeValue, parentElement, previousSibling };
9
+ export { appendChild, cloneNode, firstChild, lastChild, nextSibling, nodeValue, parentElement, previousSibling };
@@ -1,4 +1,5 @@
1
1
  let getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, prototype = Node.prototype;
2
+ const appendChild = prototype.appendChild;
2
3
  const cloneNode = prototype.cloneNode;
3
4
  const firstChild = getOwnPropertyDescriptor(prototype, 'firstChild').get;
4
5
  const lastChild = getOwnPropertyDescriptor(prototype, 'lastChild').get;
@@ -6,4 +7,4 @@ const nextSibling = getOwnPropertyDescriptor(prototype, 'nextSibling').get;
6
7
  const nodeValue = getOwnPropertyDescriptor(prototype, 'nodeValue').set;
7
8
  const parentElement = getOwnPropertyDescriptor(prototype, 'parentElement').get;
8
9
  const previousSibling = getOwnPropertyDescriptor(prototype, 'previousSibling').get;
9
- export { cloneNode, firstChild, lastChild, nextSibling, nodeValue, parentElement, previousSibling };
10
+ export { appendChild, cloneNode, firstChild, lastChild, nextSibling, nodeValue, parentElement, previousSibling };
@@ -1,3 +1,2 @@
1
- import { Element } from '../types.js';
2
- declare const _default: (value: string) => Element;
1
+ declare const _default: (value: string) => Node;
3
2
  export default _default;
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.15.0",
5
+ "@esportsplus/reactivity": "^0.16.1",
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.18.0",
17
+ "version": "0.19.0",
18
18
  "scripts": {
19
19
  "build": "tsc && tsc-alias",
20
20
  "-": "-"
package/src/attributes.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { effect } from '@esportsplus/reactivity';
2
2
  import { isArray, isObject, isString } from '@esportsplus/utilities';
3
- import { ondisconnect } from './slot/cleanup';
4
3
  import { STATE_HYDRATING, STATE_NONE, STATE_WAITING } from './constants';
5
4
  import { Attributes, Element } from './types';
6
5
  import { className, removeAttribute, setAttribute } from './utilities/element';
@@ -74,31 +73,28 @@ function set(context: Context, name: string, value: unknown, state: State) {
74
73
 
75
74
  let id = (context.store[EFFECT] as number)++;
76
75
 
77
- ondisconnect(
78
- context.element,
79
- effect(() => {
80
- let v = (value as Function)(context.element);
81
-
82
- if (isArray(v)) {
83
- let last = v.length - 1;
84
-
85
- for (let i = 0, n = v.length; i < n; i++) {
86
- update(
87
- context,
88
- id,
89
- name,
90
- v[i],
91
- state === STATE_HYDRATING
92
- ? state
93
- : i !== last ? STATE_WAITING : state
94
- );
95
- }
76
+ effect(() => {
77
+ let v = (value as Function)(context.element);
78
+
79
+ if (isArray(v)) {
80
+ let last = v.length - 1;
81
+
82
+ for (let i = 0, n = v.length; i < n; i++) {
83
+ update(
84
+ context,
85
+ id,
86
+ name,
87
+ v[i],
88
+ state === STATE_HYDRATING
89
+ ? state
90
+ : i !== last ? STATE_WAITING : state
91
+ );
96
92
  }
97
- else {
98
- update(context, id, name, v, state);
99
- }
100
- })
101
- );
93
+ }
94
+ else {
95
+ update(context, id, name, v, state);
96
+ }
97
+ });
102
98
 
103
99
  state = STATE_NONE;
104
100
  }
package/src/constants.ts CHANGED
@@ -47,21 +47,7 @@ const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{
47
47
 
48
48
  const RENDERABLE = Symbol();
49
49
 
50
- const RENDERABLE_ARRAY = 0;
51
-
52
- const RENDERABLE_FRAGMENT = 1;
53
-
54
- const RENDERABLE_HTML_FRAGMENT = 2;
55
-
56
- const RENDERABLE_HTML_REACTIVE_ARRAY = 3;
57
-
58
- const RENDERABLE_NODE = 4;
59
-
60
- const RENDERABLE_NODE_LIST = 5;
61
-
62
- const RENDERABLE_TEXT = 6;
63
-
64
- const RENDERABLE_VOID = 7;
50
+ const RENDERABLE_HTML_REACTIVE_ARRAY = 1;
65
51
 
66
52
 
67
53
  const SLOT_HTML = '<!--$-->';
@@ -83,10 +69,7 @@ export {
83
69
  EMPTY_FRAGMENT,
84
70
  NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST,
85
71
  REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES,
86
- RENDERABLE, RENDERABLE_ARRAY, RENDERABLE_FRAGMENT,
87
- RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY,
88
- RENDERABLE_NODE, RENDERABLE_NODE_LIST, RENDERABLE_TEXT,
89
- RENDERABLE_VOID,
72
+ RENDERABLE, RENDERABLE_HTML_REACTIVE_ARRAY,
90
73
  SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH,
91
74
  STATE_HYDRATING, STATE_NONE, STATE_WAITING
92
75
  };
package/src/html/index.ts CHANGED
@@ -1,19 +1,58 @@
1
1
  import { ReactiveArray } from '@esportsplus/reactivity';
2
- import { RENDERABLE, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY } from '~/constants';
3
- import { RenderableReactive, RenderableTemplate, RenderableValues } from '~/types';
4
- import hydrate from './hydrate';
2
+ import { RENDERABLE, RENDERABLE_HTML_REACTIVE_ARRAY } from '~/constants';
3
+ import { RenderableReactive, RenderableValue } from '~/types';
4
+ import { cloneNode } from '~/utilities/node';
5
5
  import parser from './parser';
6
6
 
7
7
 
8
- const html = (literals: TemplateStringsArray, ...values: RenderableValues[]): RenderableTemplate => {
9
- return {
10
- [RENDERABLE]: RENDERABLE_HTML_FRAGMENT,
11
- fragment: hydrate(parser.parse(literals), values),
12
- literals
13
- };
8
+ const html = (literals: TemplateStringsArray, ...values: (RenderableValue | RenderableValue[])[]): DocumentFragment => {
9
+ let { fragment, slots } = parser.parse(literals);
10
+
11
+ fragment = cloneNode.call(fragment, true) as DocumentFragment;
12
+
13
+ if (slots !== null) {
14
+ let node, nodePath, parent, parentPath;
15
+
16
+ for (let i = 0, n = slots.length; i < n; i++) {
17
+ let { fn, path, slot } = slots[i],
18
+ pp = path.parent,
19
+ pr = path.relative;
20
+
21
+ if (pp !== parentPath) {
22
+ if (pp === nodePath) {
23
+ parent = node;
24
+ parentPath = nodePath;
25
+
26
+ nodePath = undefined;
27
+ }
28
+ else {
29
+ parent = fragment;
30
+ parentPath = pp;
31
+
32
+ for (let i = 0, n = pp.length; i < n; i++) {
33
+ parent = pp[i].call(parent);
34
+ }
35
+ }
36
+ }
37
+
38
+ if (pr !== nodePath) {
39
+ node = parent;
40
+ nodePath = path.absolute;
41
+
42
+ for (let i = 0, n = pr.length; i < n; i++) {
43
+ node = pr[i].call(node);
44
+ }
45
+ }
46
+
47
+ // @ts-ignore
48
+ fn(node, values[slot]);
49
+ }
50
+ }
51
+
52
+ return fragment;
14
53
  };
15
54
 
16
- html.reactive = <T>(array: ReactiveArray<T[]>, template: RenderableReactive['template']) => {
55
+ html.reactive = <T>(array: ReactiveArray<T[]>, template: RenderableReactive['template']): RenderableReactive => {
17
56
  return {
18
57
  [RENDERABLE]: RENDERABLE_HTML_REACTIVE_ARRAY,
19
58
  array,
@@ -4,9 +4,9 @@ import {
4
4
  } from '~/constants';
5
5
  import { Template } from '~/types';
6
6
  import { firstElementChild, nextElementSibling } from '~/utilities/element';
7
- import { fragment } from '~/utilities/fragment';
8
7
  import { firstChild, nextSibling } from '~/utilities/node';
9
8
  import { spread } from '~/attributes';
9
+ import { fragment } from '~/utilities/fragment';
10
10
  import s from '~/slot';
11
11
 
12
12
 
@@ -126,21 +126,27 @@ function methods(children: number, copy: (typeof firstChild)[], first: (typeof f
126
126
  }
127
127
 
128
128
  function set(literals: TemplateStringsArray, html: string, slots: Template['slots'] = null) {
129
- let template = {
129
+ let value = {
130
130
  fragment: fragment(html),
131
131
  html,
132
132
  literals,
133
133
  slots
134
134
  };
135
135
 
136
- cache.set(literals, template);
136
+ cache.set(literals, value);
137
137
 
138
- return template;
138
+ return value;
139
139
  }
140
140
 
141
141
 
142
142
  const parse = (literals: TemplateStringsArray) => {
143
- return cache.get(literals) || build(literals);
143
+ let result = cache.get(literals);
144
+
145
+ if (result === undefined) {
146
+ result = build(literals);
147
+ }
148
+
149
+ return result;
144
150
  };
145
151
 
146
152
 
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { default as html } from './html';
2
2
  export { default as render } from './render';
3
3
  export { default as svg } from './svg';
4
- export type { Attributes, Element, Elements, Renderable, RenderableValue } from './types';
4
+ export type { Attributes, Element, Renderable, RenderableValue } from './types';