@esportsplus/template 0.12.12 → 0.14.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,7 +1,9 @@
1
1
  import { Attributes, Element } from './types.js';
2
+ declare const apply: (element: Element) => void;
3
+ declare const spread: (element: Element, attributes: Attributes | Attributes[]) => void;
2
4
  declare const _default: {
3
5
  apply: (element: Element) => void;
4
- set: (element: Element, value: unknown, name: string) => void;
5
6
  spread: (element: Element, attributes: Attributes | Attributes[]) => void;
6
7
  };
7
8
  export default _default;
9
+ export { apply, spread };
@@ -1,11 +1,10 @@
1
1
  import { effect, root } from '@esportsplus/reactivity';
2
- import { ATTRIBUTES } from './constants.js';
3
2
  import { className, isArray, isObject, raf, removeAttribute, setAttribute } from './utilities.js';
4
3
  import event from './event.js';
5
4
  let attributes = {}, delimiters = {
6
5
  class: ' ',
7
6
  style: ';'
8
- };
7
+ }, key = Symbol();
9
8
  function attribute(element, name, value) {
10
9
  if (value === false || value == null) {
11
10
  value = '';
@@ -45,12 +44,22 @@ function reactive(element, id, name, value, wait = false) {
45
44
  }
46
45
  }
47
46
  function set(element, value, name) {
48
- if (typeof value === 'function') {
47
+ if (name === 'style' && isObject(value)) {
48
+ for (let key in value) {
49
+ set(element, value[key], name);
50
+ }
51
+ }
52
+ else if (isArray(value)) {
53
+ for (let i = 0, n = value.length; i < n; i++) {
54
+ set(element, value[i], name);
55
+ }
56
+ }
57
+ else if (typeof value === 'function') {
49
58
  if (name.startsWith('on')) {
50
59
  event(element, name, value);
51
60
  }
52
61
  else {
53
- reactive(element, ('e' + store(element)[ATTRIBUTES]++), name, value, true);
62
+ reactive(element, ('e' + store(element)[key]++), name, value, true);
54
63
  }
55
64
  }
56
65
  else {
@@ -58,7 +67,7 @@ function set(element, value, name) {
58
67
  }
59
68
  }
60
69
  function store(element) {
61
- return (element[ATTRIBUTES] || (element[ATTRIBUTES] = { [ATTRIBUTES]: 0 }));
70
+ return (element[key] || (element[key] = { [key]: 0 }));
62
71
  }
63
72
  function update(element, id, name, value, wait = false) {
64
73
  if (value === false || value == null) {
@@ -119,44 +128,32 @@ function update(element, id, name, value, wait = false) {
119
128
  attribute(element, name, value);
120
129
  }
121
130
  }
122
- export default {
123
- apply: (element) => {
124
- for (let key in attributes) {
125
- attribute(element, key, attributes[key]);
126
- }
127
- attributes = {};
128
- },
129
- set: (element, value, name) => {
130
- if (name === 'style' && isObject(value)) {
131
- for (let key in value) {
132
- set(element, value[key], name);
133
- }
134
- }
135
- else if (isArray(value)) {
136
- for (let i = 0, n = value.length; i < n; i++) {
137
- set(element, value[i], name);
138
- }
139
- }
140
- else {
141
- set(element, value, name);
131
+ const apply = (element) => {
132
+ for (let key in attributes) {
133
+ attribute(element, key, attributes[key]);
134
+ }
135
+ attributes = {};
136
+ };
137
+ const spread = function (element, attributes) {
138
+ if (isObject(attributes)) {
139
+ for (let name in attributes) {
140
+ set(element, attributes[name], name);
142
141
  }
143
- },
144
- spread: function (element, attributes) {
145
- if (isObject(attributes)) {
146
- for (let name in attributes) {
147
- this.set(element, attributes[name], name);
142
+ }
143
+ else if (isArray(attributes)) {
144
+ for (let i = 0, n = attributes.length; i < n; i++) {
145
+ let attrs = attributes[i];
146
+ if (!isObject(attrs)) {
147
+ continue;
148
148
  }
149
- }
150
- else if (isArray(attributes)) {
151
- for (let i = 0, n = attributes.length; i < n; i++) {
152
- let attrs = attributes[i];
153
- if (!isObject(attrs)) {
154
- continue;
155
- }
156
- for (let name in attrs) {
157
- this.set(element, attrs[name], name);
158
- }
149
+ for (let name in attrs) {
150
+ set(element, attrs[name], name);
159
151
  }
160
152
  }
161
153
  }
154
+ else {
155
+ throw new Error('@esportsplus/template: attributes must be of type `Attributes` or `Attributes[]`; Received ' + JSON.stringify(attributes));
156
+ }
162
157
  };
158
+ export default { apply, spread };
159
+ export { apply, spread };
@@ -1,18 +1,16 @@
1
- declare const ATTRIBUTES: unique symbol;
2
1
  declare const NODE_CLOSING = 1;
3
2
  declare const NODE_ELEMENT = 3;
4
3
  declare const NODE_SLOT = 4;
5
4
  declare const NODE_VOID = 5;
6
5
  declare const NODE_WHITELIST: Record<string, number>;
7
6
  declare const REGEX_EMPTY_TEXT_NODES: RegExp;
8
- declare const REGEX_EVENTS: RegExp;
9
- declare const REGEX_EXTRA_WHITESPACE: RegExp;
10
- declare const REGEX_SLOT_ATTRIBUTES: RegExp;
11
7
  declare const REGEX_SLOT_NODES: RegExp;
12
8
  declare const RENDERABLE: unique symbol;
13
9
  declare const RENDERABLE_REACTIVE: unique symbol;
14
10
  declare const RENDERABLE_TEMPLATE: unique symbol;
15
11
  declare const SLOT: unique symbol;
12
+ declare const SLOT_CLEANUP: unique symbol;
16
13
  declare const SLOT_HTML = "<!--$-->";
17
14
  declare const SLOT_MARKER = "{{$}}";
18
- export { ATTRIBUTES, NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_EVENTS, REGEX_EXTRA_WHITESPACE, REGEX_SLOT_ATTRIBUTES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT, SLOT_HTML, SLOT_MARKER };
15
+ declare const SLOT_MARKER_LENGTH: number;
16
+ export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT, SLOT_CLEANUP, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
@@ -1,4 +1,3 @@
1
- const ATTRIBUTES = Symbol();
2
1
  const NODE_CLOSING = 1;
3
2
  const NODE_COMMENT = 2;
4
3
  const NODE_ELEMENT = 3;
@@ -25,14 +24,13 @@ const NODE_WHITELIST = {
25
24
  'wbr': NODE_VOID
26
25
  };
27
26
  const REGEX_EMPTY_TEXT_NODES = /(>|})\s+(<|{)/g;
28
- const REGEX_EVENTS = /(?:\s*on[\w-:]+\s*=\s*["'][^"']*["'])/g;
29
- const REGEX_EXTRA_WHITESPACE = /\s\s+/g;
30
- const REGEX_SLOT_ATTRIBUTES = /<[\w-]+([^><]*{{\$}}[^><]*)>/g;
31
27
  const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{{\$}}/g;
32
28
  const RENDERABLE = Symbol();
33
29
  const RENDERABLE_REACTIVE = Symbol();
34
30
  const RENDERABLE_TEMPLATE = Symbol();
35
31
  const SLOT = Symbol();
32
+ const SLOT_CLEANUP = Symbol();
36
33
  const SLOT_HTML = '<!--$-->';
37
34
  const SLOT_MARKER = '{{$}}';
38
- export { ATTRIBUTES, NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_EVENTS, REGEX_EXTRA_WHITESPACE, REGEX_SLOT_ATTRIBUTES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT, SLOT_HTML, SLOT_MARKER };
35
+ const SLOT_MARKER_LENGTH = SLOT_MARKER.length;
36
+ export { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT, SLOT_CLEANUP, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH };
package/build/event.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { Element } from './types.js';
2
- declare const _default: (element: Element, event: string, listener: Function) => void;
2
+ declare const _default: (element: Element, event: `on${string}`, listener: Function) => any;
3
3
  export default _default;
package/build/event.js CHANGED
@@ -1,33 +1,15 @@
1
1
  import { root } from '@esportsplus/reactivity';
2
+ import { SLOT_CLEANUP } from './constants.js';
2
3
  import { addEventListener, defineProperty, parentElement } from './utilities.js';
3
- let capture = new Set(['blur', 'focus', 'scroll']), keys = {}, passive = new Set([
4
- 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'mousewheel',
5
- 'scroll',
6
- 'touchcancel', 'touchend', 'touchleave', 'touchmove', 'touchstart',
7
- 'wheel'
4
+ let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(), keys = {}, passive = new Set([
5
+ 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel',
6
+ 'onscroll',
7
+ 'ontouchcancel', 'ontouchend', 'ontouchleave', 'ontouchmove', 'ontouchstart',
8
+ 'onwheel'
8
9
  ]);
9
- function register(event) {
10
- let key = keys[event] = Symbol(), type = event.slice(2);
11
- addEventListener.call(window.document, type, (e) => {
12
- let node = e.target;
13
- defineProperty(e, 'currentTarget', {
14
- configurable: true,
15
- get() {
16
- return node || window.document;
17
- }
18
- });
19
- while (node) {
20
- if (key in node) {
21
- return node[key].call(node, e);
22
- }
23
- node = parentElement.call(node);
24
- }
25
- }, {
26
- capture: capture.has(type),
27
- passive: passive.has(type)
28
- });
29
- return key;
30
- }
10
+ ['onmousemove', 'onmousewheel', 'onscroll', 'ontouchend', 'ontouchmove', 'ontouchstart', 'onwheel'].map(event => {
11
+ controllers.set(event, null);
12
+ });
31
13
  export default (element, event, listener) => {
32
14
  if (event === 'onmount') {
33
15
  let interval = setInterval(() => {
@@ -45,5 +27,48 @@ export default (element, event, listener) => {
45
27
  else if (event === 'onrender') {
46
28
  return root(() => listener(element));
47
29
  }
48
- element[keys[event] || register(event)] = listener;
30
+ let controller = controllers.get(event), signal;
31
+ if (controller === null) {
32
+ let { abort, signal } = new AbortController();
33
+ controllers.set(event, controller = {
34
+ abort,
35
+ signal,
36
+ listeners: 0,
37
+ });
38
+ }
39
+ if (controller) {
40
+ controller.listeners++;
41
+ (element[SLOT_CLEANUP] ??= []).push(() => {
42
+ if (--controller.listeners) {
43
+ return;
44
+ }
45
+ controller.abort();
46
+ controllers.set(event, null);
47
+ });
48
+ signal = controller.signal;
49
+ }
50
+ let key = keys[event];
51
+ if (!key) {
52
+ key = keys[event] = Symbol();
53
+ addEventListener.call(window.document, event.slice(2), (e) => {
54
+ let node = e.target;
55
+ defineProperty(e, 'currentTarget', {
56
+ configurable: true,
57
+ get() {
58
+ return node || window.document;
59
+ }
60
+ });
61
+ while (node) {
62
+ if (key in node) {
63
+ return node[key].call(node, e);
64
+ }
65
+ node = parentElement.call(node);
66
+ }
67
+ }, {
68
+ capture: capture.has(event),
69
+ passive: passive.has(event),
70
+ signal
71
+ });
72
+ }
73
+ element[key] = listener;
49
74
  };
@@ -1,67 +1,19 @@
1
- import { NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_EVENTS, REGEX_EXTRA_WHITESPACE, REGEX_SLOT_ATTRIBUTES, REGEX_SLOT_NODES, SLOT_HTML, SLOT_MARKER } from '../constants.js';
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 { firstChild, firstElementChild, fragment, nextElementSibling, nextSibling } from '../utilities.js';
3
- import a from '../attributes.js';
3
+ import { spread } from '../attributes.js';
4
4
  import s from '../slot.js';
5
5
  let cache = new WeakMap();
6
6
  function build(literals, values) {
7
7
  if (values.length === 0) {
8
8
  return set(literals, literals[0]);
9
9
  }
10
- let attributes = {}, buffer = '', html = minify(literals.join(SLOT_MARKER)), index = 0, level = 0, levels = [{
10
+ let buffer = '', html = literals.join(SLOT_MARKER)
11
+ .replace(REGEX_EMPTY_TEXT_NODES, '$1$2')
12
+ .trim(), index = 0, level = 0, levels = [{
11
13
  children: 0,
12
14
  elements: 0,
13
15
  path: []
14
- }], slot = 0, slots = [], total = values.length;
15
- {
16
- let attribute = '', buffer = '', char = '', quote = '';
17
- for (let match of html.matchAll(REGEX_SLOT_ATTRIBUTES)) {
18
- let found = match[1], metadata = attributes[found];
19
- if (metadata) {
20
- continue;
21
- }
22
- metadata = attributes[found] = [];
23
- for (let i = 0, n = found.length; i < n; i++) {
24
- char = found[i];
25
- if (char === ' ') {
26
- buffer = '';
27
- }
28
- else if (char === '=') {
29
- attribute = buffer;
30
- buffer = '';
31
- }
32
- else if (char === '"' || char === "'") {
33
- if (!attribute) {
34
- }
35
- else if (!quote) {
36
- quote = char;
37
- }
38
- else if (quote === char) {
39
- attribute = '';
40
- buffer = '';
41
- quote = '';
42
- }
43
- }
44
- else if (char === '{' && char !== buffer) {
45
- buffer = char;
46
- }
47
- else {
48
- buffer += char;
49
- if (buffer === SLOT_MARKER) {
50
- buffer = '';
51
- if (attribute) {
52
- metadata.push(attribute);
53
- if (!quote) {
54
- attribute = '';
55
- }
56
- }
57
- else {
58
- metadata.push(null);
59
- }
60
- }
61
- }
62
- }
63
- }
64
- }
16
+ }], parsed = html.split(SLOT_MARKER), slot = 0, slots = [], total = values.length;
65
17
  for (let match of html.matchAll(REGEX_SLOT_NODES)) {
66
18
  let parent = levels[level], type = match[1] === undefined ? NODE_SLOT : (NODE_WHITELIST[match[1].toLowerCase()] || NODE_ELEMENT);
67
19
  if ((match.index || 1) - 1 > index) {
@@ -70,19 +22,15 @@ function build(literals, values) {
70
22
  if (type === NODE_ELEMENT || type === NODE_VOID) {
71
23
  let attr = match[2];
72
24
  if (attr) {
73
- let metadata = attributes[attr], path = methods(parent.children, parent.path, firstChild, nextSibling);
74
- if (!metadata) {
75
- throw new Error(`Template: attribute metadata could not be found for '${attr}'`);
76
- }
77
- for (let i = 0, n = metadata.length; i < n; i++) {
78
- let name = metadata[i];
25
+ let i = attr.indexOf(SLOT_MARKER), path = methods(parent.children, parent.path, firstChild, nextSibling);
26
+ while (i !== -1) {
79
27
  slots.push({
80
- fn: name === null ? a.spread : a.set,
81
- name,
28
+ fn: spread,
82
29
  path,
83
30
  slot
84
31
  });
85
- buffer += literals[slot++];
32
+ buffer += parsed[slot++];
33
+ i = attr.indexOf(SLOT_MARKER, i + SLOT_MARKER_LENGTH);
86
34
  }
87
35
  }
88
36
  if (type === NODE_ELEMENT) {
@@ -97,16 +45,15 @@ function build(literals, values) {
97
45
  parent.elements++;
98
46
  }
99
47
  else if (type === NODE_SLOT) {
100
- buffer += literals[slot] + SLOT_HTML;
48
+ buffer += parsed[slot] + SLOT_HTML;
101
49
  slots.push({
102
50
  fn: s,
103
- name: null,
104
51
  path: methods(parent.children, parent.path, firstChild, nextSibling),
105
52
  slot: slot++
106
53
  });
107
54
  }
108
55
  if (slot === total) {
109
- buffer += literals[slot];
56
+ buffer += parsed[slot];
110
57
  break;
111
58
  }
112
59
  if (type === NODE_CLOSING) {
@@ -117,7 +64,7 @@ function build(literals, values) {
117
64
  }
118
65
  index = (match.index || 0) + match[0].length;
119
66
  }
120
- return set(literals, minify(buffer.replace(REGEX_EVENTS, '')), slots);
67
+ return set(literals, buffer, slots);
121
68
  }
122
69
  function methods(children, copy, first, next) {
123
70
  let methods = copy.slice();
@@ -127,9 +74,6 @@ function methods(children, copy, first, next) {
127
74
  }
128
75
  return methods;
129
76
  }
130
- function minify(html) {
131
- return html.replace(REGEX_EMPTY_TEXT_NODES, '$1$2').replace(REGEX_EXTRA_WHITESPACE, ' ').trim();
132
- }
133
77
  function set(literals, html, slots = null) {
134
78
  let template = {
135
79
  fragment: fragment(html),
@@ -1,6 +1,6 @@
1
1
  import { root } from '@esportsplus/reactivity';
2
2
  import { cloneNode, firstChild, nextSibling } from '../utilities.js';
3
- import a from '../attributes.js';
3
+ 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 = () => {
@@ -23,10 +23,10 @@ function render(renderable, template) {
23
23
  if (slots !== null) {
24
24
  let node, previous, values = renderable.values;
25
25
  for (let i = slots.length - 1; i >= 0; i--) {
26
- let { fn, name, path, slot } = slots[i];
26
+ let { fn, path, slot } = slots[i];
27
27
  if (path === previous) { }
28
28
  else {
29
- a.apply(node);
29
+ apply(node);
30
30
  node = fragment;
31
31
  previous = path;
32
32
  for (let o = 0, j = path.length; o < j; o++) {
@@ -35,7 +35,9 @@ function render(renderable, template) {
35
35
  }
36
36
  fn(node, values[slot], name);
37
37
  }
38
- a.apply(node);
38
+ if (node) {
39
+ apply(node);
40
+ }
39
41
  }
40
42
  for (let element = firstChild.call(fragment); element; element = nextSibling.call(element)) {
41
43
  elements.push(element);
package/build/slot.d.ts CHANGED
@@ -10,10 +10,10 @@ declare class Slot {
10
10
  set length(n: number);
11
11
  anchor(index?: number): Element;
12
12
  clear(): void;
13
- pop(): Elements | undefined;
13
+ pop(): Elements[] | undefined;
14
14
  push(...groups: Elements[]): number;
15
15
  render(input: unknown): this;
16
- shift(): Elements | undefined;
16
+ shift(): Elements[] | undefined;
17
17
  splice(start: number, stop?: number, ...groups: Elements[]): Elements[];
18
18
  unshift(...groups: Elements[]): number;
19
19
  }
package/build/slot.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { effect, root, DIRTY } from '@esportsplus/reactivity';
2
- import { RENDERABLE, RENDERABLE_REACTIVE, SLOT } from './constants.js';
2
+ import { RENDERABLE, RENDERABLE_REACTIVE, SLOT, SLOT_CLEANUP } from './constants.js';
3
3
  import { hydrate } from './html/index.js';
4
4
  import { firstChild, isArray, isObject, nextSibling, nodeValue, raf, text } from './utilities.js';
5
- let cleanup = [], key = Symbol(), scheduled = false;
6
- function afterGroups(anchor, groups) {
5
+ let cleanup = [], scheduled = false;
6
+ function after(anchor, groups) {
7
7
  for (let i = 0, n = groups.length; i < n; i++) {
8
8
  let group = groups[i];
9
9
  if (group.length) {
@@ -13,29 +13,13 @@ function afterGroups(anchor, groups) {
13
13
  }
14
14
  return groups;
15
15
  }
16
- function removeGroup(group) {
17
- if (group === undefined) {
18
- return group;
19
- }
20
- for (let i = 0, n = group.length; i < n; i++) {
21
- let item = group[i];
22
- if (key in item) {
23
- cleanup.push(item[key]);
24
- }
25
- item.remove();
26
- }
27
- if (!scheduled && cleanup.length) {
28
- schedule();
29
- }
30
- return group;
31
- }
32
- function removeGroups(groups) {
16
+ function remove(...groups) {
33
17
  for (let i = 0, n = groups.length; i < n; i++) {
34
18
  let group = groups[i];
35
19
  for (let j = 0, o = group.length; j < o; j++) {
36
20
  let item = group[j];
37
- if (key in item) {
38
- cleanup.push(item[key]);
21
+ if (item[SLOT_CLEANUP]) {
22
+ cleanup.push(...item[SLOT_CLEANUP]);
39
23
  }
40
24
  item.remove();
41
25
  }
@@ -55,12 +39,12 @@ function render(anchor, input, slot) {
55
39
  for (let i = 0, n = input.length; i < n; i++) {
56
40
  groups.push(render(null, input[i]));
57
41
  }
58
- return anchor ? afterGroups(anchor, groups) : groups;
42
+ return anchor ? after(anchor, groups) : groups;
59
43
  }
60
44
  let nodes = [];
61
45
  if (RENDERABLE in input) {
62
46
  if (input[RENDERABLE] === RENDERABLE_REACTIVE) {
63
- return afterGroups(anchor, hydrate.reactive(input, slot));
47
+ return after(anchor, hydrate.reactive(input, slot));
64
48
  }
65
49
  else {
66
50
  nodes = hydrate.static(input);
@@ -98,13 +82,16 @@ function schedule() {
98
82
  scheduled = true;
99
83
  raf.add(() => {
100
84
  try {
101
- let slot;
102
- while (slot = cleanup.pop()) {
103
- slot.clear();
85
+ let fn;
86
+ while (fn = cleanup.pop()) {
87
+ fn();
104
88
  }
105
89
  }
106
90
  catch (e) { }
107
91
  scheduled = false;
92
+ if (cleanup.length) {
93
+ schedule();
94
+ }
108
95
  });
109
96
  }
110
97
  class Slot {
@@ -113,7 +100,9 @@ class Slot {
113
100
  nodes;
114
101
  text = null;
115
102
  constructor(marker) {
116
- marker[key] = this;
103
+ (marker[SLOT_CLEANUP] ??= []).push(() => {
104
+ this.clear();
105
+ });
117
106
  this.marker = marker;
118
107
  this.nodes = [];
119
108
  }
@@ -131,14 +120,18 @@ class Slot {
131
120
  return node || this.marker;
132
121
  }
133
122
  clear() {
134
- removeGroups(this.nodes);
123
+ remove(...this.nodes);
135
124
  this.text = null;
136
125
  }
137
126
  pop() {
138
- return removeGroup(this.nodes.pop());
127
+ let group = this.nodes.pop();
128
+ if (!group) {
129
+ return undefined;
130
+ }
131
+ return remove(group);
139
132
  }
140
133
  push(...groups) {
141
- afterGroups(this.anchor(), groups);
134
+ after(this.anchor(), groups);
142
135
  for (let i = 0, n = groups.length; i < n; i++) {
143
136
  this.nodes.push(groups[i]);
144
137
  }
@@ -182,13 +175,17 @@ class Slot {
182
175
  return this;
183
176
  }
184
177
  shift() {
185
- return removeGroup(this.nodes.shift());
178
+ let group = this.nodes.shift();
179
+ if (!group) {
180
+ return undefined;
181
+ }
182
+ return remove(group);
186
183
  }
187
184
  splice(start, stop = this.nodes.length, ...groups) {
188
- return removeGroups(this.nodes.splice(start, stop, ...afterGroups(this.anchor(start), groups)));
185
+ return remove(...this.nodes.splice(start, stop, ...after(this.anchor(start), groups)));
189
186
  }
190
187
  unshift(...groups) {
191
- return this.nodes.unshift(...afterGroups(this.marker, groups));
188
+ return this.nodes.unshift(...after(this.marker, groups));
192
189
  }
193
190
  }
194
191
  export default (marker, value) => {
package/build/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ReactiveArray } from '@esportsplus/reactivity';
2
- import { RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE } from './constants.js';
2
+ import { RENDERABLE, RENDERABLE_REACTIVE, RENDERABLE_TEMPLATE, SLOT_CLEANUP } from './constants.js';
3
3
  import { firstChild } from './utilities.js';
4
4
  import attributes from './attributes.js';
5
5
  import event from './event.js';
@@ -12,10 +12,14 @@ type Attributes = {
12
12
  } & {
13
13
  [key: `aria-${string}`]: string | number | boolean | undefined;
14
14
  [key: `data-${string}`]: string | undefined;
15
+ onmount?: (element: Element) => void;
16
+ onrender?: (element: Element) => void;
15
17
  } & Record<PropertyKey, unknown>;
16
18
  type Effect<T> = () => EffectResponse<T>;
17
19
  type EffectResponse<T> = T extends [] ? EffectResponse<T[number]>[] : Primitive | Renderable<T>;
18
- type Element = HTMLElement & Attributes & Record<PropertyKey, unknown>;
20
+ type Element = HTMLElement & Attributes & {
21
+ [SLOT_CLEANUP]?: VoidFunction[];
22
+ } & Record<PropertyKey, unknown>;
19
23
  type Elements = Element[];
20
24
  type Primitive = bigint | boolean | null | number | string | undefined;
21
25
  type Renderable<T = unknown> = RenderableReactive<T> | RenderableTemplate<T>;
@@ -37,8 +41,7 @@ type Template = {
37
41
  html: string;
38
42
  literals: TemplateStringsArray;
39
43
  slots: {
40
- fn: typeof attributes.set | typeof attributes.spread | typeof event | typeof slot;
41
- name: PropertyKey | null;
44
+ fn: typeof attributes.spread | typeof event | typeof slot;
42
45
  path: typeof firstChild[];
43
46
  slot: number;
44
47
  }[] | null;
package/build/types.js CHANGED
@@ -1 +1 @@
1
- import { RENDERABLE } from './constants.js';
1
+ import { RENDERABLE, SLOT_CLEANUP } from './constants.js';
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "dependencies": {
4
4
  "@esportsplus/reactivity": "^0.4.6",
5
5
  "@esportsplus/tasks": "^0.1.9",
6
- "@esportsplus/utilities": "^0.18.2"
6
+ "@esportsplus/utilities": "^0.19.0"
7
7
  },
8
8
  "devDependencies": {
9
9
  "@esportsplus/typescript": "^0.9.1"
@@ -13,7 +13,7 @@
13
13
  "private": false,
14
14
  "type": "module",
15
15
  "types": "./build/index.d.ts",
16
- "version": "0.12.12",
16
+ "version": "0.14.0",
17
17
  "scripts": {
18
18
  "build": "tsc && tsc-alias",
19
19
  "-": "-"