ripple 0.1.1 → 0.2.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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +56 -24
  3. package/src/ai.js +292 -0
  4. package/src/compiler/errors.js +26 -0
  5. package/src/compiler/index.js +26 -0
  6. package/src/compiler/phases/1-parse/index.js +543 -0
  7. package/src/compiler/phases/1-parse/style.js +566 -0
  8. package/src/compiler/phases/2-analyze/index.js +509 -0
  9. package/src/compiler/phases/2-analyze/prune.js +572 -0
  10. package/src/compiler/phases/3-transform/index.js +1572 -0
  11. package/src/compiler/phases/3-transform/segments.js +91 -0
  12. package/src/compiler/phases/3-transform/stylesheet.js +372 -0
  13. package/src/compiler/scope.js +421 -0
  14. package/src/compiler/utils.js +552 -0
  15. package/src/constants.js +4 -0
  16. package/src/jsx-runtime.d.ts +94 -0
  17. package/src/jsx-runtime.js +46 -0
  18. package/src/runtime/array.js +215 -0
  19. package/src/runtime/index.js +39 -0
  20. package/src/runtime/internal/client/blocks.js +247 -0
  21. package/src/runtime/internal/client/constants.js +23 -0
  22. package/src/runtime/internal/client/events.js +223 -0
  23. package/src/runtime/internal/client/for.js +388 -0
  24. package/src/runtime/internal/client/if.js +35 -0
  25. package/src/runtime/internal/client/index.js +53 -0
  26. package/src/runtime/internal/client/operations.js +72 -0
  27. package/src/runtime/internal/client/portal.js +33 -0
  28. package/src/runtime/internal/client/render.js +156 -0
  29. package/src/runtime/internal/client/runtime.js +909 -0
  30. package/src/runtime/internal/client/template.js +51 -0
  31. package/src/runtime/internal/client/try.js +139 -0
  32. package/src/runtime/internal/client/utils.js +16 -0
  33. package/src/utils/ast.js +214 -0
  34. package/src/utils/builders.js +733 -0
  35. package/src/utils/patterns.js +23 -0
  36. package/src/utils/sanitize_template_string.js +7 -0
  37. package/test-mappings.js +0 -0
  38. package/types/index.d.ts +2 -0
  39. package/.npmignore +0 -2
  40. package/History.md +0 -3
  41. package/Readme.md +0 -151
  42. package/lib/exec/index.js +0 -60
  43. package/ripple.js +0 -645
@@ -0,0 +1,223 @@
1
+ import { is_passive_event } from '../../../compiler/utils';
2
+ import {
3
+ active_block,
4
+ active_reaction,
5
+ set_active_block,
6
+ set_active_reaction,
7
+ set_tracking,
8
+ tracking
9
+ } from './runtime';
10
+ import { array_from, define_property, is_array } from './utils';
11
+
12
+ /** @type {Set<string>} */
13
+ var all_registered_events = new Set();
14
+
15
+ /** @type {Set<(events: Array<string>) => void>} */
16
+ var root_event_handles = new Set();
17
+
18
+ export function handle_event_propagation(event) {
19
+ var handler_element = this;
20
+ var owner_document = /** @type {Node} */ (handler_element).ownerDocument;
21
+ var event_name = event.type;
22
+ var path = event.composedPath?.() || [];
23
+ var current_target = /** @type {null | Element} */ (path[0] || event.target);
24
+
25
+ // composedPath contains list of nodes the event has propagated through.
26
+ // We check __root to skip all nodes below it in case this is a
27
+ // parent of the __root node, which indicates that there's nested
28
+ // mounted apps. In this case we don't want to trigger events multiple times.
29
+ var path_idx = 0;
30
+
31
+ // @ts-expect-error is added below
32
+ var handled_at = event.__root;
33
+
34
+ if (handled_at) {
35
+ var at_idx = path.indexOf(handled_at);
36
+ if (
37
+ at_idx !== -1 &&
38
+ (handler_element === document || handler_element === /** @type {any} */ (window))
39
+ ) {
40
+ // This is the fallback document listener or a window listener, but the event was already handled
41
+ // -> ignore, but set handle_at to document/window so that we're resetting the event
42
+ // chain in case someone manually dispatches the same event object again.
43
+ // @ts-expect-error
44
+ event.__root = handler_element;
45
+ return;
46
+ }
47
+
48
+ // We're deliberately not skipping if the index is higher, because
49
+ // someone could create an event programmatically and emit it multiple times,
50
+ // in which case we want to handle the whole propagation chain properly each time.
51
+ // (this will only be a false negative if the event is dispatched multiple times and
52
+ // the fallback document listener isn't reached in between, but that's super rare)
53
+ var handler_idx = path.indexOf(handler_element);
54
+ if (handler_idx === -1) {
55
+ // handle_idx can theoretically be -1 (happened in some JSDOM testing scenarios with an event listener on the window object)
56
+ // so guard against that, too, and assume that everything was handled at this point.
57
+ return;
58
+ }
59
+
60
+ if (at_idx <= handler_idx) {
61
+ path_idx = at_idx;
62
+ }
63
+ }
64
+
65
+ current_target = /** @type {Element} */ (path[path_idx] || event.target);
66
+ // there can only be one delegated event per element, and we either already handled the current target,
67
+ // or this is the very first target in the chain which has a non-delegated listener, in which case it's safe
68
+ // to handle a possible delegated event on it later (through the root delegation listener for example).
69
+ if (current_target === handler_element) return;
70
+
71
+ // Proxy currentTarget to correct target
72
+ define_property(event, 'currentTarget', {
73
+ configurable: true,
74
+ get() {
75
+ return current_target || owner_document;
76
+ }
77
+ });
78
+
79
+ var previous_block = active_block;
80
+ var previous_reaction = active_reaction;
81
+ var previous_tracking = tracking;
82
+
83
+ set_active_block(null);
84
+ set_active_reaction(null);
85
+ set_tracking(false);
86
+
87
+ try {
88
+ /**
89
+ * @type {unknown}
90
+ */
91
+ var throw_error;
92
+ /**
93
+ * @type {unknown[]}
94
+ */
95
+ var other_errors = [];
96
+
97
+ while (current_target !== null) {
98
+ /** @type {null | Element} */
99
+ var parent_element =
100
+ current_target.assignedSlot ||
101
+ current_target.parentNode ||
102
+ /** @type {any} */ (current_target).host ||
103
+ null;
104
+
105
+ try {
106
+ // @ts-expect-error
107
+ var delegated = current_target['__' + event_name];
108
+
109
+ if (delegated !== undefined && !(/** @type {any} */ (current_target).disabled)) {
110
+ if (is_array(delegated)) {
111
+ var [fn, block, ...data] = delegated;
112
+ fn.apply(current_target, [event, ...data, block]);
113
+ } else {
114
+ delegated.call(current_target, event);
115
+ }
116
+ }
117
+ } catch (error) {
118
+ if (throw_error) {
119
+ other_errors.push(error);
120
+ } else {
121
+ throw_error = error;
122
+ }
123
+ }
124
+ if (event.cancelBubble || parent_element === handler_element || parent_element === null) {
125
+ break;
126
+ }
127
+ current_target = parent_element;
128
+ }
129
+
130
+ if (throw_error) {
131
+ for (let error of other_errors) {
132
+ // Throw the rest of the errors, one-by-one on a microtask
133
+ queueMicrotask(() => {
134
+ throw error;
135
+ });
136
+ }
137
+ throw throw_error;
138
+ }
139
+ } finally {
140
+ set_active_block(previous_block);
141
+ // @ts-expect-error is used above
142
+ event.__root = handler_element;
143
+ // @ts-ignore remove proxy on currentTarget
144
+ delete event.currentTarget;
145
+ set_active_block(previous_block);
146
+ set_active_reaction(previous_reaction);
147
+ set_tracking(previous_tracking);
148
+ }
149
+ }
150
+
151
+ function create_event(event_name, dom, handler, options = {}) {
152
+ var block = active_block;
153
+
154
+ function target_handler(/** @type {Event} */ event) {
155
+ var previous_block = active_block;
156
+ var previous_reaction = active_reaction;
157
+ var previous_tracking = tracking;
158
+
159
+ try {
160
+ set_active_block(null);
161
+ set_active_reaction(null);
162
+ set_tracking(false);
163
+
164
+ if (!options.capture) {
165
+ // Only call in the bubble phase, else delegated events would be called before the capturing events
166
+ handle_event_propagation.call(dom, event);
167
+ }
168
+ if (!event.cancelBubble) {
169
+ return handler?.call(this, event);
170
+ }
171
+ } finally {
172
+ set_active_block(previous_block);
173
+ set_active_reaction(previous_reaction);
174
+ set_tracking(previous_tracking);
175
+ }
176
+ }
177
+
178
+ dom.addEventListener(event_name, target_handler, options);
179
+
180
+ return target_handler;
181
+ }
182
+
183
+ export function event(event_name, dom, handler, capture, passive) {
184
+ var options = { capture, passive };
185
+ create_event(event_name, dom, handler, options);
186
+ }
187
+
188
+ export function delegate(events) {
189
+ for (var i = 0; i < events.length; i++) {
190
+ all_registered_events.add(events[i]);
191
+ }
192
+
193
+ for (var fn of root_event_handles) {
194
+ fn(events);
195
+ }
196
+ }
197
+
198
+ export function handle_root_events(target) {
199
+ var registered_events = new Set();
200
+
201
+ var event_handle = (events) => {
202
+ for (var i = 0; i < events.length; i++) {
203
+ var event_name = events[i];
204
+
205
+ if (registered_events.has(event_name)) continue;
206
+ registered_events.add(event_name);
207
+
208
+ var passive = is_passive_event(event_name);
209
+
210
+ target.addEventListener(event_name, handle_event_propagation, { passive });
211
+ }
212
+ };
213
+
214
+ event_handle(array_from(all_registered_events));
215
+ root_event_handles.add(event_handle);
216
+
217
+ return () => {
218
+ for (var event_name of registered_events) {
219
+ target.removeEventListener(event_name, handle_event_propagation);
220
+ }
221
+ root_event_handles.delete(event_handle);
222
+ };
223
+ }
@@ -0,0 +1,388 @@
1
+ import { IS_CONTROLLED } from '../../../constants';
2
+ import { get_all_elements } from '../../array';
3
+ import { branch, destroy_block, destroy_block_children, render } from './blocks';
4
+ import { FOR_BLOCK, TRACKED_OBJECT } from './constants';
5
+ import { create_text } from './operations';
6
+ import { active_block, untrack } from './runtime';
7
+ import { array_from, is_array } from './utils';
8
+
9
+ function create_item(anchor, value, render_fn) {
10
+ var b = branch(() => {
11
+ render_fn(anchor, value);
12
+ });
13
+ return b;
14
+ }
15
+
16
+ function move(block, anchor) {
17
+ var node = block.s.start;
18
+ var end = block.s.end;
19
+
20
+ if (node === end) {
21
+ anchor.before(node);
22
+ return;
23
+ }
24
+ while (node !== end) {
25
+ var next_node = /** @type {TemplateNode} */ (get_next_sibling(node));
26
+ anchor.before(node);
27
+ node = next_node;
28
+ }
29
+ }
30
+
31
+ export function for_block(node, get_collection, render_fn, flags) {
32
+ var is_controlled = (flags & IS_CONTROLLED) !== 0;
33
+ var anchor = node;
34
+
35
+ if (is_controlled) {
36
+ anchor = node.appendChild(create_text());
37
+ }
38
+
39
+ render(() => {
40
+ var block = active_block;
41
+ var collection = get_collection();
42
+ var array = is_array(collection)
43
+ ? collection
44
+ : collection == null
45
+ ? []
46
+ : array_from(collection);
47
+
48
+ if (array[TRACKED_OBJECT] !== undefined) {
49
+ // TODO we previously assigned array to this, but why?
50
+ get_all_elements(collection);
51
+ collection.$length;
52
+ }
53
+
54
+ untrack(() => reconcile(anchor, block, array, render_fn, is_controlled));
55
+ }, FOR_BLOCK);
56
+ }
57
+
58
+ function reconcile_fast_clear(anchor, block, array) {
59
+ var state = block.s;
60
+ var parent_node = anchor.parentNode;
61
+ parent_node.textContent = '';
62
+ destroy_block_children(block);
63
+ parent_node.append(anchor);
64
+ state.array = array;
65
+ state.blocks = [];
66
+ }
67
+
68
+ function reconcile(anchor, block, b, render_fn, is_controlled) {
69
+ var state = block.s;
70
+
71
+ if (state === null) {
72
+ state = block.s = {
73
+ array: [],
74
+ blocks: []
75
+ };
76
+ }
77
+
78
+ var a = state.array;
79
+ var a_length = a.length;
80
+ var b_length = b.length;
81
+ var j = 0;
82
+
83
+ // Fast-path for clear
84
+ if (is_controlled && b_length === 0) {
85
+ if (a_length > 0) {
86
+ reconcile_fast_clear(anchor, block, b);
87
+ }
88
+ return;
89
+ }
90
+ var b_blocks = Array(b_length);
91
+
92
+ // Fast-path for create
93
+ if (a_length === 0) {
94
+ for (; j < b_length; j++) {
95
+ b_blocks[j] = create_item(anchor, b[j], render_fn);
96
+ }
97
+ state.array = b;
98
+ state.blocks = b_blocks;
99
+ return;
100
+ }
101
+
102
+ var a_blocks = state.blocks;
103
+ var a_val = a[j];
104
+ var b_val = b[j];
105
+ var a_end = a_length - 1;
106
+ var b_end = b_length - 1;
107
+
108
+ outer: {
109
+ while (a_val === b_val) {
110
+ a[j] = b_val;
111
+ b_blocks[j] = a_blocks[j];
112
+ ++j;
113
+ if (j > a_end || j > b_end) {
114
+ break outer;
115
+ }
116
+ a_val = a[j];
117
+ b_val = b[j];
118
+ }
119
+
120
+ a_val = a[a_end];
121
+ b_val = b[b_end];
122
+
123
+ while (a_val === b_val) {
124
+ a[a_end] = b_val;
125
+ b_blocks[b_end] = a_blocks[a_end];
126
+ a_end--;
127
+ b_end--;
128
+ if (j > a_end || j > b_end) {
129
+ break outer;
130
+ }
131
+ a_val = a[a_end];
132
+ b_val = b[b_end];
133
+ }
134
+ }
135
+
136
+ if (j > a_end) {
137
+ if (j <= b_end) {
138
+ while (j <= b_end) {
139
+ b_val = b[j];
140
+ var target = j >= a_length ? anchor : a_blocks[j].s.start;
141
+ b_blocks[j++] = create_item(target, b_val, render_fn);
142
+ }
143
+ }
144
+ } else if (j > b_end) {
145
+ while (j <= a_end) {
146
+ destroy_block(a_blocks[j++]);
147
+ }
148
+ } else {
149
+ var a_start = j;
150
+ var b_start = j;
151
+ var a_left = a_end - j + 1;
152
+ var b_left = b_end - j + 1;
153
+ var fast_path_removal = is_controlled && a_left === a_length;
154
+ var sources = new Int32Array(b_left + 1);
155
+ var moved = false;
156
+ var pos = 0;
157
+ var patched = 0;
158
+ var i = 0;
159
+
160
+ // When sizes are small, just loop them through
161
+ if (b_length < 4 || (a_left | b_left) < 32) {
162
+ for (i = a_start; i <= a_end; ++i) {
163
+ a_val = a[i];
164
+ if (patched < b_left) {
165
+ for (j = b_start; j <= b_end; j++) {
166
+ b_val = b[j];
167
+ if (a_val === b_val) {
168
+ sources[j - b_start] = i + 1;
169
+ if (fast_path_removal) {
170
+ fast_path_removal = false;
171
+ // while (a_start < i) {
172
+ // debugger
173
+ // destroy_block(a_blocks[a_start++]);
174
+ // }
175
+ }
176
+ if (pos > j) {
177
+ moved = true;
178
+ } else {
179
+ pos = j;
180
+ }
181
+ b_blocks[j] = a_blocks[i];
182
+ ++patched;
183
+ break;
184
+ }
185
+ }
186
+ if (!fast_path_removal && j > b_end) {
187
+ destroy_block(a_blocks[i]);
188
+ }
189
+ } else if (!fast_path_removal) {
190
+ destroy_block(a_blocks[i]);
191
+ }
192
+ }
193
+ } else {
194
+ var map = new Map();
195
+
196
+ for (i = b_start; i <= b_end; ++i) {
197
+ map.set(b[i], i);
198
+ }
199
+
200
+ for (i = a_start; i <= a_end; ++i) {
201
+ a_val = a[i];
202
+
203
+ if (patched < b_left) {
204
+ j = map.get(a_val);
205
+
206
+ if (j !== undefined) {
207
+ if (fast_path_removal) {
208
+ fast_path_removal = false;
209
+ // while (i > aStart) {
210
+ // remove(a[aStart++], dom, animations);
211
+ // }
212
+ }
213
+ sources[j - b_start] = i + 1;
214
+ if (pos > j) {
215
+ moved = true;
216
+ } else {
217
+ pos = j;
218
+ }
219
+ b_val = b[j];
220
+ b_blocks[j] = a_blocks[i];
221
+ ++patched;
222
+ } else if (!fast_path_removal) {
223
+ destroy_block(a_blocks[i]);
224
+ }
225
+ } else if (!fast_path_removal) {
226
+ destroy_block(a_blocks[i]);
227
+ }
228
+ }
229
+ }
230
+ }
231
+
232
+ if (fast_path_removal) {
233
+ reconcile_fast_clear(anchor, block, []);
234
+ reconcile(anchor, block, b, render_fn, is_controlled);
235
+ return;
236
+ } else if (moved) {
237
+ var next_pos = 0;
238
+ var seq = lis_algorithm(sources);
239
+ j = seq.length - 1;
240
+
241
+ for (i = b_left - 1; i >= 0; i--) {
242
+ if (sources[i] === 0) {
243
+ pos = i + b_start;
244
+ b_val = b[pos];
245
+ next_pos = pos + 1;
246
+
247
+ var target = next_pos < b_length ? b_blocks[next_pos].s.start : anchor;
248
+ b_blocks[pos] = create_item(target, b_val, render_fn);
249
+ } else if (j < 0 || i !== seq[j]) {
250
+ pos = i + b_start;
251
+ b_val = b[pos];
252
+ next_pos = pos + 1;
253
+
254
+ var target = next_pos < b_length ? b_blocks[next_pos].s.start : anchor;
255
+ move(b_blocks[pos], target);
256
+ } else {
257
+ j--;
258
+ }
259
+ }
260
+ } else if (patched !== b_left) {
261
+ for (i = b_left - 1; i >= 0; i--) {
262
+ if (sources[i] === 0) {
263
+ pos = i + b_start;
264
+ b_val = b[pos];
265
+ next_pos = pos + 1;
266
+
267
+ var target = next_pos < b_length ? b_blocks[next_pos].s.start : anchor;
268
+ b_blocks[pos] = create_item(target, b_val, render_fn);
269
+ }
270
+ }
271
+ }
272
+
273
+ state.array = b;
274
+ state.blocks = b_blocks;
275
+ }
276
+
277
+ let result;
278
+ let p;
279
+ let maxLen = 0;
280
+ // https://en.wikipedia.org/wiki/Longest_increasing_subsequence
281
+ function lis_algorithm(arr) {
282
+ let arrI = 0;
283
+ let i = 0;
284
+ let j = 0;
285
+ let k = 0;
286
+ let u = 0;
287
+ let v = 0;
288
+ let c = 0;
289
+ var len = arr.length;
290
+
291
+ if (len > maxLen) {
292
+ maxLen = len;
293
+ result = new Int32Array(len);
294
+ p = new Int32Array(len);
295
+ }
296
+
297
+ for (; i < len; ++i) {
298
+ arrI = arr[i];
299
+
300
+ if (arrI !== 0) {
301
+ j = result[k];
302
+ if (arr[j] < arrI) {
303
+ p[i] = j;
304
+ result[++k] = i;
305
+ continue;
306
+ }
307
+
308
+ u = 0;
309
+ v = k;
310
+
311
+ while (u < v) {
312
+ c = (u + v) >> 1;
313
+ if (arr[result[c]] < arrI) {
314
+ u = c + 1;
315
+ } else {
316
+ v = c;
317
+ }
318
+ }
319
+
320
+ if (arrI < arr[result[u]]) {
321
+ if (u > 0) {
322
+ p[i] = result[u - 1];
323
+ }
324
+ result[u] = i;
325
+ }
326
+ }
327
+ }
328
+
329
+ u = k + 1;
330
+ var seq = new Int32Array(u);
331
+ v = result[u - 1];
332
+
333
+ while (u-- > 0) {
334
+ seq[u] = v;
335
+ v = p[v];
336
+ result[u] = 0;
337
+ }
338
+
339
+ return seq;
340
+ }
341
+
342
+ export function keyed(collection, key_fn) {
343
+ var block = active_block;
344
+ if (block === null || (block.f & FOR_BLOCK) === 0) {
345
+ throw new Error('keyed() must be used inside a for block');
346
+ }
347
+ var state = block.s;
348
+
349
+ if (state === null) {
350
+ return collection;
351
+ }
352
+
353
+ var a_array = state.array;
354
+ var a_keys = a_array.map(key_fn);
355
+ var a = new Map();
356
+
357
+ for (let i = 0; i < a_keys.length; i++) {
358
+ a.set(a_keys[i], i);
359
+ }
360
+
361
+ if (a.size !== a_keys.length) {
362
+ throw new Error('Duplicate keys are not allowed');
363
+ }
364
+
365
+ var b_array = is_array(collection)
366
+ ? collection
367
+ : collection == null
368
+ ? []
369
+ : array_from(collection);
370
+ var b_keys = b_array.map(key_fn);
371
+
372
+ // We only need to do this in DEV
373
+ var b = new Set(b_keys);
374
+ if (b.size !== b_keys.length) {
375
+ throw new Error('Duplicate keys are not allowed');
376
+ }
377
+
378
+ for (let i = 0; i < b_keys.length; i++) {
379
+ var b_val = b_keys[i];
380
+ var index = a.get(b_val);
381
+
382
+ if (index !== undefined) {
383
+ b_array[i] = a_array[index];
384
+ }
385
+ }
386
+
387
+ return b_array;
388
+ }
@@ -0,0 +1,35 @@
1
+ import { branch, destroy_block, render } from './blocks';
2
+ import { IF_BLOCK, UNINITIALIZED } from './constants';
3
+
4
+ export function if_block(node, fn) {
5
+ var anchor = node;
6
+ var has_branch = false;
7
+ var condition = UNINITIALIZED;
8
+ var b = null;
9
+
10
+ var set_branch = (fn, flag = true) => {
11
+ has_branch = true;
12
+ update_branch(flag, fn);
13
+ };
14
+
15
+ var update_branch = (new_condition, fn) => {
16
+ if (condition === (condition = new_condition)) return;
17
+
18
+ if (b !== null) {
19
+ destroy_block(b);
20
+ b = null;
21
+ }
22
+
23
+ if (fn !== null) {
24
+ b = branch(() => fn(anchor));
25
+ }
26
+ };
27
+
28
+ render(() => {
29
+ has_branch = false;
30
+ fn(set_branch);
31
+ if (!has_branch) {
32
+ update_branch(null, null);
33
+ }
34
+ }, IF_BLOCK);
35
+ }
@@ -0,0 +1,53 @@
1
+ export { first_child as child, child_frag, next_sibling as sibling } from './operations.js';
2
+
3
+ export {
4
+ set_text,
5
+ set_class,
6
+ set_attribute,
7
+ set_value,
8
+ set_checked,
9
+ set_selected,
10
+ set_ref
11
+ } from './render.js';
12
+
13
+ export { render, async } from './blocks.js';
14
+
15
+ export { event, delegate } from './events.js';
16
+
17
+ export {
18
+ active_block,
19
+ scope,
20
+ with_scope,
21
+ get_tracked,
22
+ get_computed,
23
+ set,
24
+ computed,
25
+ async_computed,
26
+ tracked,
27
+ tracked_object,
28
+ computed_property,
29
+ get_property,
30
+ set_property,
31
+ update,
32
+ update_pre,
33
+ update_property,
34
+ update_pre_property,
35
+ object_values,
36
+ object_entries,
37
+ object_keys,
38
+ spread_object,
39
+ structured_clone,
40
+ push_component,
41
+ pop_component,
42
+ untrack
43
+ } from './runtime.js';
44
+
45
+ export { for_block as for } from './for.js';
46
+
47
+ export { if_block as if } from './if.js';
48
+
49
+ export { try_block as try, resume_context, aborted } from './try.js';
50
+
51
+ export { template, append } from './template.js';
52
+
53
+