@esportsplus/template 0.15.15 → 0.15.17

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,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 };
@@ -1,12 +1,19 @@
1
1
  import { effect } from '@esportsplus/reactivity';
2
2
  import { isArray, isFunction, isObject, isString } from '@esportsplus/utilities';
3
+ import { ATTRIBUTE_STORE } from './constants.js';
3
4
  import { ondisconnect } from './slot.js';
4
5
  import { className, raf, removeAttribute, setAttribute } from './utilities.js';
6
+ import q from '@esportsplus/queue';
5
7
  import event from './event.js';
6
- let attributes = {}, delimiters = {
8
+ const EFFECT_KEY = Symbol();
9
+ const UPDATES_KEY = Symbol();
10
+ const STATE_HYDRATING = 0;
11
+ const STATE_NONE = 1;
12
+ const STATE_WAITING = 2;
13
+ let delimiters = {
7
14
  class: ' ',
8
15
  style: ';'
9
- }, key = Symbol();
16
+ }, hydrating = {}, queue = q(64), scheduled = false;
10
17
  function attribute(element, name, value) {
11
18
  if (value === '' || value === false || value == null) {
12
19
  removeAttribute.call(element, name);
@@ -21,55 +28,79 @@ function attribute(element, name, value) {
21
28
  element[name] = value;
22
29
  }
23
30
  }
24
- function set(element, value, name, wait = false) {
31
+ function schedule() {
32
+ if (scheduled) {
33
+ return;
34
+ }
35
+ scheduled = true;
36
+ raf.add(task);
37
+ }
38
+ function set(context, name, value, state) {
25
39
  if (isArray(value)) {
26
40
  for (let i = 0, n = value.length; i < n; i++) {
27
- set(element, value[i], name, wait);
41
+ set(context, name, value[i], state);
28
42
  }
29
43
  }
30
44
  else if (isFunction(value)) {
31
45
  if (name.startsWith('on')) {
32
- event(element, name, value);
46
+ event(context.element, name, value);
33
47
  }
34
48
  else {
35
- let id = ('e' + store(element)[key]++);
36
- ondisconnect(element, effect(() => {
37
- let v = value(element);
49
+ context.store[EFFECT_KEY] ??= 0;
50
+ let id = context.store[EFFECT_KEY]++;
51
+ ondisconnect(context.element, effect(() => {
52
+ let v = value(context.element);
38
53
  if (isArray(v)) {
39
54
  let last = v.length - 1;
40
55
  for (let i = 0, n = v.length; i < n; i++) {
41
- update(element, id, name, v[i], wait || i !== last);
56
+ update(context, id, name, v[i], state === STATE_HYDRATING
57
+ ? state
58
+ : i !== last ? STATE_WAITING : state);
42
59
  }
43
60
  }
44
61
  else {
45
- update(element, id, name, v, wait);
62
+ update(context, id, name, v, state);
46
63
  }
47
64
  }));
48
- wait = false;
65
+ state = STATE_NONE;
49
66
  }
50
67
  }
51
68
  else {
52
- update(element, null, name, value, wait);
69
+ update(context, null, name, value, state);
53
70
  }
54
71
  }
55
- function store(element) {
56
- return (element[key] || (element[key] = { [key]: 0 }));
72
+ function task() {
73
+ let context, n = queue.length;
74
+ while ((context = queue.next()) && n--) {
75
+ let { element, updates } = context;
76
+ for (let name in updates) {
77
+ attribute(element, name, updates[name]);
78
+ delete updates[name];
79
+ }
80
+ context.updating = false;
81
+ }
82
+ if (queue.length) {
83
+ raf.add(task);
84
+ }
85
+ else {
86
+ scheduled = false;
87
+ }
57
88
  }
58
- function update(element, id, name, value, wait = false) {
89
+ function update(context, id, name, value, state) {
59
90
  if (value === false || value == null) {
60
91
  value = '';
61
92
  }
62
- let data = store(element);
93
+ let store = context.store;
63
94
  if (name in delimiters) {
64
- let cache = name + '.static', delimiter = delimiters[name], dynamic = data[name];
95
+ let cache = name + '.static', delimiter = delimiters[name], dynamic = store[name];
65
96
  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 = {};
97
+ let value = (context.element.getAttribute(name) || '').trim();
98
+ store[cache] = value;
99
+ store[name] = dynamic = {};
69
100
  }
70
101
  if (id === null) {
71
102
  if (value && isString(value)) {
72
- data[cache] += (data[cache] ? delimiter : '') + value;
103
+ store[cache] += (store[cache] ? delimiter : '') + value;
73
104
  }
74
105
  }
75
106
  else {
@@ -85,7 +116,7 @@ function update(element, id, name, value, wait = false) {
85
116
  hot[part] = null;
86
117
  }
87
118
  }
88
- let cold = data[id];
119
+ let cold = store[id];
89
120
  if (cold !== undefined) {
90
121
  for (let part in cold) {
91
122
  if (part in hot) {
@@ -94,48 +125,57 @@ function update(element, id, name, value, wait = false) {
94
125
  delete dynamic[part];
95
126
  }
96
127
  }
97
- data[id] = hot;
128
+ store[id] = hot;
98
129
  }
99
- value = data[cache];
130
+ value = store[cache];
100
131
  for (let key in dynamic) {
101
132
  value += (value ? delimiter : '') + key;
102
133
  }
103
134
  }
104
- else if (isString(id)) {
105
- if (data[name] === value) {
135
+ else if (id !== null) {
136
+ if (store[name] === value) {
106
137
  return;
107
138
  }
108
- data[name] = value;
139
+ store[name] = value;
109
140
  }
110
- if (wait) {
111
- if (id === null) {
112
- attributes[name] = value;
113
- }
141
+ if (state === STATE_HYDRATING) {
142
+ hydrating[name] = value;
114
143
  }
115
144
  else {
116
- raf.add(() => {
117
- attribute(element, name, value);
118
- });
145
+ context.updates[name] = value;
146
+ if (state === STATE_NONE && !context.updating) {
147
+ context.updating = true;
148
+ queue.add(context);
149
+ }
150
+ if (!scheduled) {
151
+ schedule();
152
+ }
119
153
  }
120
154
  }
121
155
  const apply = (element) => {
122
- for (let key in attributes) {
123
- attribute(element, key, attributes[key]);
156
+ for (let key in hydrating) {
157
+ attribute(element, key, hydrating[key]);
124
158
  }
125
- attributes = {};
159
+ hydrating = {};
126
160
  };
127
- const spread = function (element, attributes) {
128
- if (isObject(attributes)) {
129
- for (let name in attributes) {
130
- set(element, attributes[name], name, true);
161
+ const spread = function (element, value) {
162
+ let cache = element[ATTRIBUTE_STORE] ??= { [UPDATES_KEY]: {} }, context = {
163
+ element,
164
+ store: cache,
165
+ updates: cache[UPDATES_KEY],
166
+ updating: false
167
+ };
168
+ if (isArray(value)) {
169
+ for (let i = 0, n = value.length; i < n; i++) {
170
+ let v = value[i];
171
+ for (let name in v) {
172
+ set(context, name, v[name], STATE_HYDRATING);
173
+ }
131
174
  }
132
175
  }
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
- }
176
+ else if (isObject(value)) {
177
+ for (let name in value) {
178
+ set(context, name, value[name], STATE_HYDRATING);
139
179
  }
140
180
  }
141
181
  };
@@ -1,3 +1,4 @@
1
+ declare const ATTRIBUTE_STORE: unique symbol;
1
2
  declare const NODE_CLOSING = 1;
2
3
  declare const NODE_ELEMENT = 3;
3
4
  declare const NODE_SLOT = 4;
@@ -12,4 +13,4 @@ declare const SLOT_CLEANUP: unique symbol;
12
13
  declare const SLOT_HTML = "<!--$-->";
13
14
  declare const SLOT_MARKER = "{{$}}";
14
15
  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 };
16
+ export { ATTRIBUTE_STORE, 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 };
@@ -1,3 +1,4 @@
1
+ const ATTRIBUTE_STORE = Symbol();
1
2
  const NODE_CLOSING = 1;
2
3
  const NODE_COMMENT = 2;
3
4
  const NODE_ELEMENT = 3;
@@ -32,4 +33,4 @@ const SLOT_CLEANUP = Symbol();
32
33
  const SLOT_HTML = '<!--$-->';
33
34
  const SLOT_MARKER = '{{$}}';
34
35
  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 };
36
+ export { ATTRIBUTE_STORE, 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 };
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,10 @@
1
- import { Elements, RenderableReactive, RenderableTemplate } from '../types.js';
1
+ import { Elements, RenderableReactive, RenderableTemplate, RenderedGroup } 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) => RenderedGroup[];
5
+ static: <T>(renderable: RenderableTemplate<T>) => {
6
+ elements: Elements;
7
+ fragment: Node;
8
+ };
6
9
  };
7
10
  export default _default;
@@ -4,19 +4,31 @@ 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
+ }, renderer = (i, n) => {
9
+ return root(() => array.map(template, i, n));
10
+ }, template = function (data, i) {
11
+ let renderable = factory.call(this, data, i);
12
+ return render(renderable, cache.get(renderable));
13
+ };
14
+ array.on('pop', () => {
15
+ slot.pop();
16
+ });
17
+ array.on('push', ({ items }) => {
18
+ slot.push(...renderer(array.length - items.length));
19
+ });
14
20
  array.on('reverse', refresh);
15
- array.on('shift', () => slot.shift());
21
+ array.on('shift', () => {
22
+ slot.shift();
23
+ });
16
24
  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);
25
+ array.on('splice', ({ deleteCount: d, items: i, start: s }) => {
26
+ slot.splice(s, d, ...renderer(s, i.length));
27
+ });
28
+ array.on('unshift', ({ items }) => {
29
+ slot.unshift(...renderer(0, items.length));
30
+ });
31
+ return array.map(template);
20
32
  }
21
33
  function render(renderable, template) {
22
34
  let elements = [], fragment = cloneNode.call(template.fragment, true), slots = template.slots;
@@ -24,8 +36,7 @@ function render(renderable, template) {
24
36
  let node, previous, values = renderable.values;
25
37
  for (let i = slots.length - 1; i >= 0; i--) {
26
38
  let { fn, path, slot } = slots[i];
27
- if (path === previous) { }
28
- else {
39
+ if (path !== previous) {
29
40
  apply(node);
30
41
  node = fragment;
31
42
  previous = path;
@@ -33,22 +44,14 @@ function render(renderable, template) {
33
44
  node = path[o].call(node);
34
45
  }
35
46
  }
36
- fn(node, values[slot], name);
47
+ fn(node, values[slot]);
37
48
  }
38
49
  apply(node);
39
50
  }
40
51
  for (let element = firstChild.call(fragment); element; element = nextSibling.call(element)) {
41
52
  elements.push(element);
42
53
  }
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;
54
+ return { elements, fragment };
52
55
  }
53
56
  export default {
54
57
  reactive: (renderable, slot) => {
package/build/slot.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Element, Elements } from './types.js';
1
+ import { Element, Elements, RenderedGroup } 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: RenderedGroup[]): 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: RenderedGroup[]): Elements[];
16
+ unshift(...groups: RenderedGroup[]): 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
@@ -2,18 +2,30 @@ import { effect, root } from '@esportsplus/reactivity';
2
2
  import { isArray, isFunction, isInstanceOf, isObject } from '@esportsplus/utilities';
3
3
  import { RENDERABLE, RENDERABLE_REACTIVE, SLOT_CLEANUP } 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, 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
+ let cleanup = queue(64), fallback = fragment(''), scheduled = false;
8
8
  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);
9
+ let elements = [], n = groups.length;
10
+ if (n) {
11
+ let fragment = groups[0].fragment || fallback;
12
+ if (n === 1) {
13
+ elements.push(groups[0].elements);
14
+ }
15
+ else {
16
+ for (let i = 1; i < n; i++) {
17
+ let group = groups[i];
18
+ if (group.fragment) {
19
+ append.call(fragment, group.fragment);
20
+ group.fragment = null;
21
+ }
22
+ elements.push(group.elements);
23
+ }
14
24
  }
25
+ anchor.after(fragment);
26
+ groups[0].fragment = null;
15
27
  }
16
- return groups;
28
+ return elements;
17
29
  }
18
30
  function remove(...groups) {
19
31
  for (let i = 0, n = groups.length; i < n; i++) {
@@ -31,51 +43,47 @@ function remove(...groups) {
31
43
  }
32
44
  return groups;
33
45
  }
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
- }
46
+ function render(groups, input, slot) {
47
+ if (input === false || input == null || input === '') {
48
+ return groups;
49
+ }
50
+ if (isArray(input)) {
51
+ for (let i = 0, n = input.length; i < n; i++) {
52
+ render(groups, input[i]);
54
53
  }
55
- else if (isInstanceOf(input, NodeList)) {
56
- for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
57
- nodes.push(node);
58
- }
54
+ }
55
+ else if (isObject(input) && RENDERABLE in input) {
56
+ if (input[RENDERABLE] === RENDERABLE_REACTIVE) {
57
+ groups.push(...hydrate.reactive(input, slot));
59
58
  }
60
- else if (isInstanceOf(input, Node)) {
61
- nodes = [input];
59
+ else {
60
+ groups.push(hydrate.static(input));
62
61
  }
63
- if (anchor) {
64
- anchor.after(...nodes);
62
+ }
63
+ else if (isInstanceOf(input, NodeList)) {
64
+ let elements = [];
65
+ for (let node = firstChild.call(input); node; node = nextSibling.call(node)) {
66
+ elements.push(node);
65
67
  }
66
- return nodes;
68
+ groups.push({ elements, fragment: null });
67
69
  }
68
- if (input === '') {
69
- return [];
70
+ else if (isInstanceOf(input, Node)) {
71
+ groups.push({
72
+ elements: [input],
73
+ fragment: input
74
+ });
70
75
  }
71
- let node = text(input);
72
- if (anchor) {
73
- anchor.after(node);
76
+ else {
77
+ let element = text(typeof input === 'string' ? input : String(input));
74
78
  if (slot) {
75
- slot.text = node;
79
+ slot.text = element;
76
80
  }
81
+ groups.push({
82
+ elements: [element],
83
+ fragment: element
84
+ });
77
85
  }
78
- return [node];
86
+ return groups;
79
87
  }
80
88
  function schedule() {
81
89
  if (scheduled) {
@@ -85,14 +93,14 @@ function schedule() {
85
93
  microtask.add(task);
86
94
  }
87
95
  function task() {
88
- let fns;
96
+ let fn, fns;
89
97
  while (fns = cleanup.next()) {
90
- for (let i = 0, n = fns.length; i < n; i++) {
91
- try {
92
- fns[i]();
98
+ try {
99
+ while (fn = fns.pop()) {
100
+ fn();
93
101
  }
94
- catch { }
95
102
  }
103
+ catch { }
96
104
  }
97
105
  scheduled = false;
98
106
  if (cleanup.length) {
@@ -123,6 +131,7 @@ class Slot {
123
131
  }
124
132
  clear() {
125
133
  remove(...this.nodes);
134
+ this.nodes.length = 0;
126
135
  this.text = null;
127
136
  }
128
137
  pop() {
@@ -133,11 +142,7 @@ class Slot {
133
142
  return remove(group);
134
143
  }
135
144
  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;
145
+ return this.nodes.push(...after(this.anchor(), groups));
141
146
  }
142
147
  render(input) {
143
148
  if (isFunction(input)) {
@@ -156,19 +161,15 @@ class Slot {
156
161
  }
157
162
  if (this.text) {
158
163
  let type = typeof input;
159
- if (type === 'object' && input !== null) { }
164
+ if (type === 'object' && input !== null) {
165
+ }
160
166
  else if (this.text.isConnected) {
161
167
  nodeValue.call(this.text, (type === 'string' || type === 'number') ? input : '');
162
168
  return this;
163
169
  }
164
170
  }
165
171
  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
- }
172
+ this.nodes = after(this.marker, render([], input, this));
172
173
  return this;
173
174
  }
174
175
  shift() {
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 { ATTRIBUTE_STORE, 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
- import event from './event.js';
6
5
  import slot from './slot.js';
7
6
  type Attribute = Primitive | Effect<Primitive | Primitive[]>;
8
7
  type Attributes = {
@@ -20,6 +19,7 @@ type Attributes = {
20
19
  type Effect<T> = () => EffectResponse<T>;
21
20
  type EffectResponse<T> = T extends [] ? EffectResponse<T[number]>[] : Primitive | Renderable<T>;
22
21
  type Element = HTMLElement & Attributes & {
22
+ [ATTRIBUTE_STORE]?: Record<PropertyKey, unknown>;
23
23
  [SLOT_CLEANUP]?: VoidFunction[];
24
24
  } & Record<PropertyKey, unknown>;
25
25
  type Elements = Element[];
@@ -38,14 +38,18 @@ type RenderableTemplate<T> = {
38
38
  values: (RenderableValue<T> | RenderableValue<T>[])[];
39
39
  };
40
40
  type RenderableValue<T = unknown> = Attributes | Readonly<Attributes> | Readonly<Attributes[]> | Effect<T> | Primitive | Renderable;
41
+ type RenderedGroup = {
42
+ elements: Elements;
43
+ fragment: DocumentFragment | Node | null;
44
+ };
41
45
  type Template = {
42
46
  fragment: DocumentFragment;
43
47
  html: string;
44
48
  literals: TemplateStringsArray;
45
49
  slots: {
46
- fn: typeof attributes.spread | typeof event | typeof slot;
50
+ fn: typeof attributes.spread | typeof slot;
47
51
  path: typeof firstChild[];
48
52
  slot: number;
49
53
  }[] | null;
50
54
  };
51
- export type { Attributes, Effect, Element, Elements, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, Template };
55
+ export type { Attributes, Effect, Element, Elements, Renderable, RenderableReactive, RenderableTemplate, RenderableValue, RenderedGroup, Template };
package/build/types.js CHANGED
@@ -1 +1 @@
1
- import { RENDERABLE, SLOT_CLEANUP } from './constants.js';
1
+ import { ATTRIBUTE_STORE, RENDERABLE, SLOT_CLEANUP } from './constants.js';
@@ -3,6 +3,7 @@ declare const addEventListener: {
3
3
  <K extends keyof ElementEventMap>(type: K, listener: (this: Element, ev: ElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
4
4
  (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
5
5
  };
6
+ declare const append: (...nodes: (Node | string)[]) => void;
6
7
  declare const removeEventListener: {
7
8
  <K extends keyof ElementEventMap>(type: K, listener: (this: Element, ev: ElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
8
9
  (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
@@ -24,4 +25,4 @@ declare const fragment: (html: string) => DocumentFragment;
24
25
  declare const microtask: import("@esportsplus/tasks/build/factory").Scheduler;
25
26
  declare const raf: import("@esportsplus/tasks/build/factory").Scheduler;
26
27
  declare const text: (value: string) => E;
27
- export { addEventListener, className, cloneNode, firstChild, firstElementChild, fragment, innerHTML, microtask, nextElementSibling, nextSibling, nodeValue, parentElement, parentNode, prepend, raf, removeAttribute, removeEventListener, setAttribute, text };
28
+ export { addEventListener, append, className, cloneNode, firstChild, firstElementChild, fragment, innerHTML, microtask, nextElementSibling, nextSibling, nodeValue, parentElement, parentNode, prepend, raf, removeAttribute, removeEventListener, setAttribute, text };
@@ -2,6 +2,7 @@ import { micro as m, raf as r } from '@esportsplus/tasks';
2
2
  let prototype, template = document.createElement('template'), t = document.createTextNode('');
3
3
  prototype = Element.prototype;
4
4
  const addEventListener = prototype.addEventListener;
5
+ const append = prototype.append;
5
6
  const removeEventListener = prototype.removeEventListener;
6
7
  const className = Object.getOwnPropertyDescriptor(prototype, 'className').set;
7
8
  const innerHTML = Object.getOwnPropertyDescriptor(prototype, 'innerHTML').set;
@@ -32,4 +33,4 @@ const text = (value) => {
32
33
  }
33
34
  return element;
34
35
  };
35
- export { addEventListener, className, cloneNode, firstChild, firstElementChild, fragment, innerHTML, microtask, nextElementSibling, nextSibling, nodeValue, parentElement, parentNode, prepend, raf, removeAttribute, removeEventListener, setAttribute, text };
36
+ export { addEventListener, append, className, cloneNode, firstChild, firstElementChild, fragment, innerHTML, microtask, nextElementSibling, nextSibling, nodeValue, parentElement, parentNode, prepend, raf, removeAttribute, removeEventListener, setAttribute, text };