@esportsplus/template 0.16.1 → 0.18.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.
Files changed (60) hide show
  1. package/build/attributes.js +29 -24
  2. package/build/constants.d.ts +13 -3
  3. package/build/constants.js +14 -4
  4. package/build/event.js +48 -46
  5. package/build/html/hydrate.d.ts +2 -8
  6. package/build/html/hydrate.js +28 -79
  7. package/build/html/index.d.ts +2106 -5
  8. package/build/html/index.js +12 -4
  9. package/build/html/{cache.d.ts → parser.d.ts} +1 -1
  10. package/build/html/{cache.js → parser.js} +6 -4
  11. package/build/render.d.ts +1 -2
  12. package/build/render.js +7 -10
  13. package/build/slot/cleanup.d.ts +4 -0
  14. package/build/slot/cleanup.js +52 -0
  15. package/build/slot/effect.d.ts +3 -0
  16. package/build/slot/effect.js +56 -0
  17. package/build/slot/index.d.ts +3 -0
  18. package/build/slot/index.js +8 -0
  19. package/build/slot/reactive.d.ts +3 -0
  20. package/build/slot/reactive.js +125 -0
  21. package/build/slot/render.d.ts +2 -0
  22. package/build/slot/render.js +81 -0
  23. package/build/svg.d.ts +1 -2
  24. package/build/types.d.ts +21 -17
  25. package/build/utilities/element.d.ts +11 -0
  26. package/build/utilities/element.js +9 -0
  27. package/build/utilities/fragment.d.ts +3 -0
  28. package/build/utilities/fragment.js +11 -0
  29. package/build/utilities/node.d.ts +8 -0
  30. package/build/utilities/node.js +9 -0
  31. package/build/utilities/queue.d.ts +3 -0
  32. package/build/utilities/queue.js +4 -0
  33. package/build/utilities/text.d.ts +3 -0
  34. package/build/utilities/text.js +9 -0
  35. package/package.json +2 -2
  36. package/src/attributes.ts +32 -29
  37. package/src/constants.ts +32 -5
  38. package/src/event.ts +55 -52
  39. package/src/html/hydrate.ts +36 -108
  40. package/src/html/index.ts +16 -8
  41. package/src/html/{cache.ts → parser.ts} +5 -3
  42. package/src/render.ts +8 -12
  43. package/src/slot/cleanup.ts +74 -0
  44. package/src/slot/effect.ts +74 -0
  45. package/src/slot/index.ts +12 -0
  46. package/src/slot/reactive.ts +177 -0
  47. package/src/slot/render.ts +117 -0
  48. package/src/svg.ts +1 -2
  49. package/src/types.ts +25 -18
  50. package/src/utilities/element.ts +28 -0
  51. package/src/utilities/fragment.ts +22 -0
  52. package/src/utilities/node.ts +26 -0
  53. package/src/utilities/queue.ts +9 -0
  54. package/src/utilities/text.ts +16 -0
  55. package/build/slot.d.ts +0 -21
  56. package/build/slot.js +0 -204
  57. package/build/utilities.d.ts +0 -28
  58. package/build/utilities.js +0 -37
  59. package/src/slot.ts +0 -277
  60. package/src/utilities.ts +0 -87
@@ -1,15 +1,14 @@
1
1
  import { effect } from '@esportsplus/reactivity';
2
- import { isArray, isFunction, isObject, isString } from '@esportsplus/utilities';
3
- import { ondisconnect } from './slot.js';
4
- import { className, raf, removeAttribute, setAttribute } from './utilities.js';
2
+ import { isArray, isObject, isString } from '@esportsplus/utilities';
3
+ import { ondisconnect } from './slot/cleanup.js';
4
+ import { STATE_HYDRATING, STATE_NONE, STATE_WAITING } from './constants.js';
5
+ import { className, removeAttribute, setAttribute } from './utilities/element.js';
6
+ import { raf } from './utilities/queue.js';
5
7
  import q from '@esportsplus/queue';
6
8
  import event from './event.js';
7
- const EFFECT_KEY = Symbol();
8
- const STORE_KEY = Symbol();
9
- const UPDATES_KEY = Symbol();
10
- const STATE_HYDRATING = 0;
11
- const STATE_NONE = 1;
12
- const STATE_WAITING = 2;
9
+ const EFFECT = Symbol();
10
+ const STORE = Symbol();
11
+ const UPDATES = Symbol();
13
12
  let delimiters = {
14
13
  class: ' ',
15
14
  style: ';'
@@ -36,18 +35,17 @@ function schedule() {
36
35
  raf.add(task);
37
36
  }
38
37
  function set(context, name, value, state) {
39
- if (isArray(value)) {
40
- for (let i = 0, n = value.length; i < n; i++) {
41
- set(context, name, value[i], state);
42
- }
38
+ if (value === false || value == null) {
39
+ value = '';
43
40
  }
44
- else if (isFunction(value)) {
41
+ let type = typeof value;
42
+ if (type === 'function') {
45
43
  if (name.startsWith('on')) {
46
44
  event(context.element, name, value);
47
45
  }
48
46
  else {
49
- context.store[EFFECT_KEY] ??= 0;
50
- let id = context.store[EFFECT_KEY]++;
47
+ context.store[EFFECT] ??= 0;
48
+ let id = context.store[EFFECT]++;
51
49
  ondisconnect(context.element, effect(() => {
52
50
  let v = value(context.element);
53
51
  if (isArray(v)) {
@@ -65,6 +63,13 @@ function set(context, name, value, state) {
65
63
  state = STATE_NONE;
66
64
  }
67
65
  }
66
+ else if (type === 'object') {
67
+ if (isArray(value)) {
68
+ for (let i = 0, n = value.length; i < n; i++) {
69
+ set(context, name, value[i], state);
70
+ }
71
+ }
72
+ }
68
73
  else {
69
74
  update(context, null, name, value, state);
70
75
  }
@@ -153,13 +158,18 @@ function update(context, id, name, value, state) {
153
158
  }
154
159
  }
155
160
  const spread = function (element, value) {
156
- let cache = (element[STORE_KEY] ??= { [UPDATES_KEY]: {} }), context = {
161
+ let cache = (element[STORE] ??= { [UPDATES]: {} }), context = {
157
162
  element,
158
163
  store: cache,
159
- updates: cache[UPDATES_KEY],
164
+ updates: cache[UPDATES],
160
165
  updating: false
161
166
  };
162
- if (isArray(value)) {
167
+ if (isObject(value)) {
168
+ for (let name in value) {
169
+ set(context, name, value[name], STATE_HYDRATING);
170
+ }
171
+ }
172
+ else if (isArray(value)) {
163
173
  for (let i = 0, n = value.length; i < n; i++) {
164
174
  let v = value[i];
165
175
  for (let name in v) {
@@ -167,11 +177,6 @@ const spread = function (element, value) {
167
177
  }
168
178
  }
169
179
  }
170
- else if (isObject(value)) {
171
- for (let name in value) {
172
- set(context, name, value[name], STATE_HYDRATING);
173
- }
174
- }
175
180
  };
176
181
  export default { spread };
177
182
  export { spread };
@@ -1,3 +1,4 @@
1
+ declare const CLEANUP: unique symbol;
1
2
  declare const EMPTY_FRAGMENT: DocumentFragment;
2
3
  declare const NODE_CLOSING = 1;
3
4
  declare const NODE_ELEMENT = 3;
@@ -7,9 +8,18 @@ declare const NODE_WHITELIST: Record<string, number>;
7
8
  declare const REGEX_EMPTY_TEXT_NODES: RegExp;
8
9
  declare const REGEX_SLOT_NODES: RegExp;
9
10
  declare const RENDERABLE: unique symbol;
10
- declare const RENDERABLE_REACTIVE: unique symbol;
11
- declare const RENDERABLE_TEMPLATE: unique symbol;
11
+ declare const RENDERABLE_ARRAY = 0;
12
+ declare const RENDERABLE_FRAGMENT = 1;
13
+ declare const RENDERABLE_HTML_FRAGMENT = 2;
14
+ declare const RENDERABLE_HTML_REACTIVE_ARRAY = 3;
15
+ declare const RENDERABLE_NODE = 4;
16
+ declare const RENDERABLE_NODE_LIST = 5;
17
+ declare const RENDERABLE_TEXT = 6;
18
+ declare const RENDERABLE_VOID = 7;
12
19
  declare const SLOT_HTML = "<!--$-->";
13
20
  declare const SLOT_MARKER = "{{$}}";
14
21
  declare const SLOT_MARKER_LENGTH: number;
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 };
22
+ declare const STATE_HYDRATING = 0;
23
+ declare const STATE_NONE = 1;
24
+ declare const STATE_WAITING = 2;
25
+ export { CLEANUP, EMPTY_FRAGMENT, NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_ARRAY, RENDERABLE_FRAGMENT, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY, RENDERABLE_NODE, RENDERABLE_NODE_LIST, RENDERABLE_TEXT, RENDERABLE_VOID, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH, STATE_HYDRATING, STATE_NONE, STATE_WAITING };
@@ -1,4 +1,5 @@
1
- import { fragment } from './utilities.js';
1
+ import { fragment } from './utilities/fragment.js';
2
+ const CLEANUP = Symbol();
2
3
  const EMPTY_FRAGMENT = fragment('');
3
4
  const NODE_CLOSING = 1;
4
5
  const NODE_COMMENT = 2;
@@ -28,9 +29,18 @@ const NODE_WHITELIST = {
28
29
  const REGEX_EMPTY_TEXT_NODES = /(>|})\s+(<|{)/g;
29
30
  const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{{\$}}/g;
30
31
  const RENDERABLE = Symbol();
31
- const RENDERABLE_REACTIVE = Symbol();
32
- const RENDERABLE_TEMPLATE = Symbol();
32
+ const RENDERABLE_ARRAY = 0;
33
+ const RENDERABLE_FRAGMENT = 1;
34
+ const RENDERABLE_HTML_FRAGMENT = 2;
35
+ const RENDERABLE_HTML_REACTIVE_ARRAY = 3;
36
+ const RENDERABLE_NODE = 4;
37
+ const RENDERABLE_NODE_LIST = 5;
38
+ const RENDERABLE_TEXT = 6;
39
+ const RENDERABLE_VOID = 7;
33
40
  const SLOT_HTML = '<!--$-->';
34
41
  const SLOT_MARKER = '{{$}}';
35
42
  const SLOT_MARKER_LENGTH = 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 };
43
+ const STATE_HYDRATING = 0;
44
+ const STATE_NONE = 1;
45
+ const STATE_WAITING = 2;
46
+ export { CLEANUP, EMPTY_FRAGMENT, NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_ARRAY, RENDERABLE_FRAGMENT, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY, RENDERABLE_NODE, RENDERABLE_NODE_LIST, RENDERABLE_TEXT, RENDERABLE_VOID, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH, STATE_HYDRATING, STATE_NONE, STATE_WAITING };
package/build/event.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { root } from '@esportsplus/reactivity';
2
2
  import { defineProperty } from '@esportsplus/utilities';
3
- import { ondisconnect } from './slot.js';
4
- import { addEventListener, parentElement, raf } from './utilities.js';
3
+ import { addEventListener } from './utilities/element.js';
4
+ import { parentElement } from './utilities/node.js';
5
+ import { raf } from './utilities/queue.js';
6
+ import { ondisconnect } from './slot/cleanup.js';
5
7
  let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(), keys = {}, passive = new Set([
6
8
  'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel',
7
9
  'onscroll',
@@ -11,6 +13,49 @@ let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(
11
13
  ['onmousemove', 'onmousewheel', 'onscroll', 'ontouchend', 'ontouchmove', 'ontouchstart', 'onwheel'].map(event => {
12
14
  controllers.set(event, null);
13
15
  });
16
+ function register(element, event) {
17
+ let controller = controllers.get(event), signal;
18
+ if (controller === null) {
19
+ let { abort, signal } = new AbortController();
20
+ controllers.set(event, controller = {
21
+ abort,
22
+ signal,
23
+ listeners: 0,
24
+ });
25
+ }
26
+ if (controller) {
27
+ controller.listeners++;
28
+ ondisconnect(element, () => {
29
+ if (--controller.listeners) {
30
+ return;
31
+ }
32
+ controller.abort();
33
+ controllers.set(event, null);
34
+ });
35
+ signal = controller.signal;
36
+ }
37
+ let key = keys[event] = Symbol();
38
+ addEventListener.call(window.document, event.slice(2), (e) => {
39
+ let node = e.target;
40
+ while (node) {
41
+ if (key in node) {
42
+ defineProperty(e, 'currentTarget', {
43
+ configurable: true,
44
+ get() {
45
+ return node || window.document;
46
+ }
47
+ });
48
+ return node[key].call(node, e);
49
+ }
50
+ node = parentElement.call(node);
51
+ }
52
+ }, {
53
+ capture: capture.has(event),
54
+ passive: passive.has(event),
55
+ signal
56
+ });
57
+ return key;
58
+ }
14
59
  export default (element, event, listener) => {
15
60
  if (event === 'onconnect') {
16
61
  let retry = 60, task = () => {
@@ -34,48 +79,5 @@ export default (element, event, listener) => {
34
79
  root(() => listener(element));
35
80
  return;
36
81
  }
37
- let controller = controllers.get(event), signal;
38
- if (controller === null) {
39
- let { abort, signal } = new AbortController();
40
- controllers.set(event, controller = {
41
- abort,
42
- signal,
43
- listeners: 0,
44
- });
45
- }
46
- if (controller) {
47
- controller.listeners++;
48
- ondisconnect(element, () => {
49
- if (--controller.listeners) {
50
- return;
51
- }
52
- controller.abort();
53
- controllers.set(event, null);
54
- });
55
- signal = controller.signal;
56
- }
57
- let key = keys[event];
58
- if (!key) {
59
- key = keys[event] = Symbol();
60
- addEventListener.call(window.document, event.slice(2), (e) => {
61
- let node = e.target;
62
- defineProperty(e, 'currentTarget', {
63
- configurable: true,
64
- get() {
65
- return node || window.document;
66
- }
67
- });
68
- while (node) {
69
- if (key in node) {
70
- return node[key].call(node, e);
71
- }
72
- node = parentElement.call(node);
73
- }
74
- }, {
75
- capture: capture.has(event),
76
- passive: passive.has(event),
77
- signal
78
- });
79
- }
80
- element[key] = listener;
82
+ element[keys[event] || register(element, event)] = listener;
81
83
  };
@@ -1,9 +1,3 @@
1
- import { Elements, Fragment, RenderableReactive, RenderableTemplate } from '../types.js';
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;
5
- declare const _default: {
6
- reactive: typeof reactive;
7
- static: typeof hydrate;
8
- };
1
+ import { Fragment, RenderableValues, Template } from '../types.js';
2
+ declare const _default: ({ fragment, slots }: Template, values: RenderableValues[]) => Fragment;
9
3
  export default _default;
@@ -1,85 +1,34 @@
1
- import { root } from '@esportsplus/reactivity';
2
- import { EMPTY_FRAGMENT } from '../constants.js';
3
- import { cloneNode } from '../utilities.js';
4
- import cache from './cache.js';
5
- function reactive(elements, fragment, renderable, slot) {
6
- let array = renderable.values, factory = renderable.template, refresh = () => {
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);
15
- }, template = function (data, i) {
16
- hydrate(elements, fragment, factory.call(this, data, i));
17
- };
18
- array.on('clear', () => slot.clear());
19
- array.on('pop', () => slot.pop());
20
- array.on('reverse', refresh);
21
- array.on('shift', () => slot.shift());
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
- });
30
- array.on('splice', ({ deleteCount: d, items: i, start: s }) => {
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();
38
- });
39
- array.on('unshift', ({ items }) => {
40
- root(() => array.map(template, 0, items.length));
41
- slot.unshift(fragment, ...elements);
42
- reset();
43
- });
44
- root(() => array.map(template));
45
- reset();
46
- }
47
- function hydrate(elements, fragment, renderable) {
48
- let { fragment: frag, slots } = cache.get(renderable.literals), clone = cloneNode.call(frag, true);
49
- if (slots !== null) {
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
- }
1
+ import { cloneNode } from '../utilities/node.js';
2
+ export default ({ fragment, slots }, values) => {
3
+ let clone = cloneNode.call(fragment, true);
4
+ if (slots === null) {
5
+ return clone;
6
+ }
7
+ let node, nodePath, parent, parentPath;
8
+ for (let i = 0, n = slots.length; i < n; i++) {
9
+ let { fn, path, slot } = slots[i], pp = path.parent, pr = path.relative;
10
+ if (pp !== parentPath) {
11
+ if (pp === nodePath) {
12
+ parent = node;
13
+ parentPath = nodePath;
14
+ nodePath = undefined;
66
15
  }
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);
16
+ else {
17
+ parent = clone;
18
+ parentPath = pp;
19
+ for (let i = 0, n = pp.length; i < n; i++) {
20
+ parent = pp[i].call(parent);
72
21
  }
73
22
  }
74
- fn(node, values[slot]);
75
23
  }
24
+ if (pr !== nodePath) {
25
+ node = parent;
26
+ nodePath = path.absolute;
27
+ for (let i = 0, n = pr.length; i < n; i++) {
28
+ node = pr[i].call(node);
29
+ }
30
+ }
31
+ fn(node, values[slot]);
76
32
  }
77
- if (elements) {
78
- elements.push([...clone.childNodes]);
79
- }
80
- fragment.appendChild(clone);
81
- }
82
- export default {
83
- reactive,
84
- static: hydrate
33
+ return clone;
85
34
  };