rasti 4.0.0-alpha.3 → 4.0.0-alpha.5

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.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <p align="center">
2
2
  <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="docs/logo-dark.svg">
4
- <img alt="Rasti.js" src="docs/logo.svg" height="120">
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.0.0-alpha.5/docs/logo-dark.svg">
4
+ <img alt="Rasti.js" src="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.0.0-alpha.5/docs/logo.svg" height="120">
5
5
  </picture>
6
6
  </p>
7
7
 
package/dist/rasti.js CHANGED
@@ -1088,19 +1088,6 @@
1088
1088
  }
1089
1089
  }
1090
1090
 
1091
- /**
1092
- * Wrapper for interpolation results with markers.
1093
- * @param {number} interpolationUid The interpolation UID for markers.
1094
- * @param {any} result The interpolation result.
1095
- * @private
1096
- */
1097
- class InterpolationWrapper {
1098
- constructor(interpolationUid, result) {
1099
- this.interpolationUid = interpolationUid;
1100
- this.result = result;
1101
- }
1102
- }
1103
-
1104
1091
  /**
1105
1092
  * Manager for delegated events.
1106
1093
  * @private
@@ -1482,6 +1469,7 @@
1482
1469
  this.expression = options.expression;
1483
1470
  this.isComponent = options.isComponent;
1484
1471
  this.isElement = options.isElement;
1472
+ this.previousItems = [];
1485
1473
  }
1486
1474
 
1487
1475
  /**
@@ -1503,21 +1491,32 @@
1503
1491
  * Update the interpolation content with a new fragment.
1504
1492
  * Optimizes updates by syncing single non-component elements or replacing content entirely.
1505
1493
  * @param {DocumentFragment} fragment The new content fragment to insert.
1494
+ * @param {Element} targetElement The target element to replace with the new fragment.
1506
1495
  */
1507
- update(fragment) {
1496
+ update(fragment, targetElement) {
1497
+ if (targetElement) {
1498
+ targetElement.replaceWith(fragment.firstChild);
1499
+ return;
1500
+ }
1501
+
1508
1502
  const [startComment, endComment] = this.ref;
1509
1503
 
1510
1504
  const currentFirstElement = startComment.nextSibling;
1511
- const currentSingleChildElement = currentFirstElement.nextSibling === endComment;
1512
- const currentEmpty = currentFirstElement == endComment;
1505
+ const currentEmpty = currentFirstElement === endComment;
1506
+ const currentSingleChildElement = !currentEmpty && currentFirstElement.nextSibling === endComment;
1513
1507
  const fragmentChildren = fragment.children;
1514
1508
 
1515
- if (currentSingleChildElement && fragmentChildren.length === 1 && !this.isElement(currentFirstElement)) {
1516
- // There is a single child element that is not a component's root element. Sync node attributes and content.
1517
- syncNode(currentFirstElement, fragmentChildren[0]);
1518
- } else if (currentEmpty) {
1509
+ if (currentEmpty) {
1519
1510
  // Interpolation is empty. Insert the fragment.
1520
1511
  endComment.parentNode.insertBefore(fragment, endComment);
1512
+ } else if (currentSingleChildElement && fragmentChildren.length === 1) {
1513
+ if (!this.isElement(currentFirstElement)) {
1514
+ // There is a single child element that is not a component's root element. Sync node attributes and content.
1515
+ syncNode(currentFirstElement, fragmentChildren[0]);
1516
+ } else {
1517
+ // There is a single child element that is a component's root element. Replace it with the new child element.
1518
+ currentFirstElement.replaceWith(fragmentChildren[0]);
1519
+ }
1521
1520
  } else {
1522
1521
  // Interpolation is not empty. Replace the interpolation content.
1523
1522
  const range = document.createRange();
@@ -1596,7 +1595,7 @@
1596
1595
  * @return {boolean} True if the element is a component root element.
1597
1596
  * @private
1598
1597
  */
1599
- const isComponent = (el) => !!el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1');
1598
+ const isComponent = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_ELEMENT] && el.dataset[Component.DATASET_ELEMENT].endsWith('-1'));
1600
1599
 
1601
1600
  /**
1602
1601
  * Check if an element has the Rasti data attribute.
@@ -1605,7 +1604,7 @@
1605
1604
  * @return {boolean} True if the element has the data attribute.
1606
1605
  * @private
1607
1606
  */
1608
- const isElement = (el) => !!el.dataset[Component.DATASET_ELEMENT];
1607
+ const isElement = (el) => !!(el && el.dataset && el.dataset[Component.DATASET_ELEMENT]);
1609
1608
 
1610
1609
  /**
1611
1610
  * Generate string with placeholders for interpolated expressions.
@@ -1634,6 +1633,9 @@
1634
1633
  */
1635
1634
  const splitPlaceholders = (main, expressions) => {
1636
1635
  const PH = Component.PLACEHOLDER('(\\d+)');
1636
+ const matchSinglePlaceholder = main.match(new RegExp(`^${PH}$`));
1637
+ if (matchSinglePlaceholder) return [expressions[parseInt(matchSinglePlaceholder[1], 10)]];
1638
+
1637
1639
  const regExp = new RegExp(`${PH}`, 'g');
1638
1640
  const out = [];
1639
1641
  let lastIndex = 0;
@@ -1642,7 +1644,7 @@
1642
1644
  // so all the components are added as children by the parent component.
1643
1645
  while ((match = regExp.exec(main)) !== null) {
1644
1646
  const before = main.slice(lastIndex, match.index);
1645
- out.push(Component.markAsSafeHTML(before), expressions[match[1]]);
1647
+ out.push(Component.markAsSafeHTML(before), expressions[parseInt(match[1], 10)]);
1646
1648
  lastIndex = match.index + match[0].length;
1647
1649
  }
1648
1650
  out.push(Component.markAsSafeHTML(main.slice(lastIndex)));
@@ -1857,6 +1859,7 @@
1857
1859
  const getSelector = function() {
1858
1860
  return `[${Component.ATTRIBUTE_ELEMENT}="${generateElementUid(this.uid)}"]`;
1859
1861
  };
1862
+ const elementIndex = elements.length;
1860
1863
  // Add element reference to elements array.
1861
1864
  elements.push({
1862
1865
  getSelector,
@@ -1864,7 +1867,9 @@
1864
1867
  });
1865
1868
  // Add new expression to expressions array.
1866
1869
  expressions.push(function() {
1867
- const attributes = getAttributes.call(this);
1870
+ const element = this.template.elements[elementIndex];
1871
+ const attributes = element.getAttributes.call(this);
1872
+ element.previousAttributes = attributes;
1868
1873
  return Component.markAsSafeHTML(getAttributesHTML(attributes));
1869
1874
  });
1870
1875
  // Replace attributes with placeholder.
@@ -1946,6 +1951,7 @@
1946
1951
  function getEnd() {
1947
1952
  return Component.MARKER_END(`${this.uid}-${currentInterpolationUid}`);
1948
1953
  }
1954
+ const interpolationIndex = interpolations.length;
1949
1955
  // Add interpolation reference to interpolations array.
1950
1956
  interpolations.push({
1951
1957
  getStart,
@@ -1954,9 +1960,7 @@
1954
1960
  });
1955
1961
  // Add new expression to expressions array.
1956
1962
  expressions.push(function() {
1957
- const result = getExpressionResult(expressions[expressionIndex], this);
1958
- const uid = `${this.uid}-${currentInterpolationUid}`;
1959
- return new InterpolationWrapper(uid, result);
1963
+ return this.template.interpolations[interpolationIndex];
1960
1964
  });
1961
1965
  // Replace with new placeholder.
1962
1966
  return Component.PLACEHOLDER(expressions.length - 1);
@@ -1997,7 +2001,7 @@
1997
2001
  /*
1998
2002
  * These option keys will be extended on the component instance.
1999
2003
  */
2000
- const componentOptions = ['key', 'state', 'onCreate', 'onChange', 'onHydrate', 'onMount', 'onRecycle', 'onUpdate'];
2004
+ const componentOptions = ['key', 'state', 'onCreate', 'onChange', 'onHydrate', 'onRecycle', 'onUpdate'];
2001
2005
 
2002
2006
  /**
2003
2007
  * @lends module:Component
@@ -2130,8 +2134,7 @@
2130
2134
  });
2131
2135
 
2132
2136
  if (this.isContainer()) {
2133
- // Get references for interpolation marker comments
2134
- this.template.interpolations[0].hydrate(parent);
2137
+ // Don't hydrate interpolation markers for container components as we know they will have only one child.
2135
2138
  // Call hydrate on children.
2136
2139
  this.children[0].hydrate(parent);
2137
2140
  // Set the first element as the component's element.
@@ -2165,14 +2168,21 @@
2165
2168
  * Reuse a `Component` by replacing the placeholder comment with the real nodes.
2166
2169
  * Call `onRecycle` lifecycle method.
2167
2170
  * @param parent {node} The parent node.
2171
+ * @param props {object} The props to set on the recycled component.
2168
2172
  * @return {Component} The component instance.
2169
2173
  * @private
2170
2174
  */
2171
- recycle(parent) {
2172
- // Locate the placeholder comment and replace it with the real nodes
2173
- const toBeReplaced = findComment(parent, Component.MARKER_RECYCLED(this.uid), isComponent);
2174
- // Replace it with this.el.
2175
- toBeReplaced.replaceWith(...this.getNodes());
2175
+ recycle(parent, props) {
2176
+ if (parent) {
2177
+ // Locate the placeholder comment and replace it with the real nodes
2178
+ const toBeReplaced = findComment(parent, Component.MARKER_RECYCLED(this.uid), isComponent);
2179
+ // Replace it with this.el.
2180
+ toBeReplaced.replaceWith(this.el);
2181
+ }
2182
+ // Update props.
2183
+ if (props) {
2184
+ this.props.set(props);
2185
+ }
2176
2186
  // Call `onRecycle` lifecycle method.
2177
2187
  this.onRecycle.call(this);
2178
2188
  // Return `this` for chaining.
@@ -2189,35 +2199,6 @@
2189
2199
  return `<!--${Component.MARKER_RECYCLED(this.uid)}-->`;
2190
2200
  }
2191
2201
 
2192
- /**
2193
- * Get the component nodes to be inserted into the DOM.
2194
- * Used internally during the render process, you usually don't need to call it if you use
2195
- * `mount()`.
2196
- * For components that render HTML elements you can safely rely on `this.el`.
2197
- * For container components that render another component you need the wrapper nodes to insert
2198
- * them into the DOM; use `getNodes()` for that.
2199
- * @return {Node[]} The component nodes.
2200
- */
2201
- getNodes() {
2202
- return this.isContainer() ?
2203
- [this.template.interpolations[0].ref[0], ...this.children[0].getNodes(), this.template.interpolations[0].ref[1]] :
2204
- [this.el];
2205
- }
2206
-
2207
- /**
2208
- * Call onMount lifecycle method on children and self.
2209
- * Used internally during the mount and render process.
2210
- * @private
2211
- */
2212
- callOnMount() {
2213
- // Call onMount on children first.
2214
- this.children.forEach(child => child.callOnMount());
2215
- // Call onMount on self.
2216
- this.onMount.call(this);
2217
- // Return `this` for chaining.
2218
- return this;
2219
- }
2220
-
2221
2202
  /**
2222
2203
  * Tagged template helper method.
2223
2204
  * Used to create a partial template.
@@ -2255,7 +2236,10 @@
2255
2236
  const items = splitPlaceholders(
2256
2237
  parsePartialElements(
2257
2238
  expandComponents(
2258
- addPlaceholders(strings, expressions),
2239
+ addPlaceholders(
2240
+ strings,
2241
+ expressions
2242
+ ).trim(),
2259
2243
  expressions
2260
2244
  ),
2261
2245
  expressions
@@ -2270,42 +2254,58 @@
2270
2254
  * Render a template part.
2271
2255
  * @param {any} part - The template part.
2272
2256
  * @param {function} addChild - The addChild function.
2257
+ * @param {Array} items - The items array.
2273
2258
  * @return {string} The rendered template part.
2274
2259
  * @private
2275
2260
  */
2276
- renderTemplatePart(part, addChild) {
2261
+ renderTemplatePart(part, addChild, items = []) {
2277
2262
  const result = getExpressionResult(part, this);
2278
2263
 
2279
2264
  const parse = item => {
2280
- if (typeof item !== 'undefined' && item !== null && item !== false && item !== true) {
2281
- if (item instanceof SafeHTML) return item;
2282
- if (item instanceof Component) return addChild(item);
2283
-
2284
- if (item instanceof Partial) {
2285
- this.pathManager.push();
2286
- const out = item.items.map(subItem => { this.pathManager.increment(); return parse(subItem); }).join('');
2287
- this.pathManager.pop();
2288
- return out;
2289
- }
2290
- // Handle arrays (user loops) - disable tracking.
2291
- if (Array.isArray(item)) {
2292
- this.pathManager.pause();
2293
- const out = deepFlat(item).map(parse).join('');
2294
- this.pathManager.resume();
2295
- return out;
2296
- }
2297
- // InterpolationWrapper: add markers and process maintaining tracking.
2298
- if (item instanceof InterpolationWrapper) {
2299
- this.pathManager.increment();
2300
- const startMarker = `<!--${Component.MARKER_START(item.interpolationUid)}-->`;
2301
- const endMarker = `<!--${Component.MARKER_END(item.interpolationUid)}-->`;
2302
- return `${startMarker}${parse(item.result)}${endMarker}`;
2303
- }
2265
+ if (typeof item === 'undefined' || item === null || item === false || item === true) {
2266
+ return '';
2267
+ }
2304
2268
 
2305
- return Component.sanitize(item);
2269
+ if (item instanceof SafeHTML) {
2270
+ items.push(item);
2271
+ return item;
2272
+ }
2273
+
2274
+ if (item instanceof Component) {
2275
+ items.push(item);
2276
+ return addChild(item);
2277
+ }
2278
+
2279
+ if (item instanceof Partial) {
2280
+ // Single item.
2281
+ if (item.items.length === 1) return parse(item.items[0]);
2282
+ // Several items.
2283
+ this.pathManager.push();
2284
+ const out = item.items.map(subItem => { this.pathManager.increment(); return parse(subItem); }).join('');
2285
+ this.pathManager.pop();
2286
+ return out;
2287
+ }
2288
+ // Handle arrays (user loops) - disable tracking.
2289
+ if (Array.isArray(item)) {
2290
+ this.pathManager.pause();
2291
+ const out = deepFlat(item).map(parse).join('');
2292
+ this.pathManager.resume();
2293
+ return out;
2306
2294
  }
2307
- // Return empty string if item is undefined, null, false, or true.
2308
- return '';
2295
+ // Interpolation: add markers and process maintaining tracking.
2296
+ if (item instanceof Interpolation) {
2297
+ this.pathManager.increment();
2298
+ // Add Interpolation markers.
2299
+ const startMarker = this.isContainer() ? '' : `<!--${item.getStart()}-->`;
2300
+ const endMarker = this.isContainer() ? '' : `<!--${item.getEnd()}-->`;
2301
+ const interpolationResult = parse(getExpressionResult(item.expression, this));
2302
+ item.previousItems = items;
2303
+ return `${startMarker}${interpolationResult}${endMarker}`;
2304
+ }
2305
+
2306
+ const sanitized = Component.sanitize(item);
2307
+ items.push(sanitized);
2308
+ return sanitized;
2309
2309
  };
2310
2310
 
2311
2311
  return `${parse(result)}`;
@@ -2343,7 +2343,6 @@
2343
2343
  * - Components with a `key` are recycled if a previous child with the same key exists.
2344
2344
  * - Unkeyed components are recycled if they have the same type and position in the template or partial.
2345
2345
  * A recycled `Component` will call the `onRecycle` lifecycle method.
2346
- * - All child components will have their `onMount` lifecycle method called after they are added to the DOM. New children will be hydrated first (calling their `onHydrate` lifecycle method).
2347
2346
  * - If the active element is inside the component, it will retain focus after the render.
2348
2347
  * @return {Component} The component instance.
2349
2348
  */
@@ -2402,23 +2401,35 @@
2402
2401
  // Return the component or placeholder.
2403
2402
  return out;
2404
2403
  };
2405
-
2406
- const fragment = parseHTML(this.renderTemplatePart(interpolation.expression, addChild));
2407
- // Replace children root elements with recycled components.
2408
- recycledChildren.forEach(([recycled, discarded]) => {
2409
- this.addChild(recycled).recycle(fragment);
2410
- // Update props.
2411
- recycled.props.set(discarded.props.toJSON());
2404
+ // Render the interpolation content and get the items.
2405
+ const previousItems = interpolation.previousItems;
2406
+ const items = [];
2407
+ const rendered = this.renderTemplatePart(interpolation.expression, addChild, items);
2408
+ interpolation.previousItems = items;
2409
+
2410
+ const recycle = ([recycled, discarded], fragment) => {
2411
+ // Add child, update props and recycle (move to new position if needed).
2412
+ this.addChild(recycled).recycle(fragment, discarded.props.toJSON());
2412
2413
  // Destroy discarded component.
2413
2414
  discarded.destroy();
2414
- });
2415
- // Add new children. Hydrate them.
2415
+ };
2416
+ // Same single component in the same position. Don't move it.
2417
+ if (previousItems.length === 1 && previousItems[0] instanceof Component &&
2418
+ items.length === 1 && items[0] instanceof Component &&
2419
+ recycledChildren.length === 1) {
2420
+ recycle(recycledChildren[0], null);
2421
+ return;
2422
+ }
2423
+ // Parse the rendered content and get the fragment.
2424
+ const fragment = parseHTML(rendered);
2425
+ // Add recycled components to children and move them to the new template in the fragment.
2426
+ recycledChildren.forEach(recycled => recycle(recycled, fragment));
2427
+ // Add new children. Hydrate them and update the interpolation.
2416
2428
  nextChildren.forEach(child => this.addChild(child).hydrate(fragment));
2417
-
2418
- interpolation.update(fragment);
2429
+ // Update the interpolation.
2430
+ const targetElement = this.isContainer() ? this.el : null;
2431
+ interpolation.update(fragment, targetElement);
2419
2432
  });
2420
- // Call onMount lifecycle method on all children after interpolations update.
2421
- this.children.forEach(child => child.callOnMount());
2422
2433
  // Destroy unused children.
2423
2434
  previousChildren.forEach(prev => {
2424
2435
  if (this.children.indexOf(prev) < 0) prev.destroy();
@@ -2443,8 +2454,11 @@
2443
2454
  }
2444
2455
 
2445
2456
  /**
2446
- * Lifecycle method. Called when the view is created, at the end of the `constructor`.
2447
- * @param options {object} The view options.
2457
+ * Lifecycle method. Called when the component is created, at the end of the constructor.
2458
+ * This method receives the same arguments passed to the constructor (options and any additional parameters).
2459
+ * It executes both on client and server.
2460
+ * Use this method to define models or state that will be used later in `onHydrate`.
2461
+ * @param {...*} args The constructor arguments (options and any additional parameters).
2448
2462
  */
2449
2463
  onCreate() {}
2450
2464
 
@@ -2463,31 +2477,35 @@
2463
2477
  }
2464
2478
 
2465
2479
  /**
2466
- * Lifecycle method. Called when the component is rendered for the first time and hydrated.
2480
+ * Lifecycle method. Called when the component is rendered for the first time and hydrated in a DocumentFragment.
2481
+ * This method only executes on the client and only during the first render.
2482
+ * Use this method for client-only operations like making API requests or setting up browser-specific functionality.
2467
2483
  */
2468
2484
  onHydrate() {}
2469
2485
 
2470
2486
  /**
2471
- * Lifecycle method. Called when the component is mounted to the DOM.
2472
- * This method is called after `onHydrate` and only when the component's element is actually present in the document.
2473
- * It is called during the initial mount process (when using `Component.mount()`) and when new child components are added during render.
2474
- * Use this method to perform operations that require the element to be in the DOM, such as measuring dimensions or focusing elements.
2475
- */
2476
- onMount() {}
2477
-
2478
- /**
2479
- * Lifecycle method. Called when the component is recycled (reused with the same key) and added to the DOM again.
2487
+ * Lifecycle method. Called when the component is recycled and reused between renders.
2488
+ *
2489
+ * A component is recycled when:
2490
+ * - It has a `key` and a previous child with the same key exists
2491
+ * - It doesn't have a `key` but has the same type and position in the template or partial
2492
+ *
2493
+ * During recycling, the component instance is reused and its props are updated with new values.
2494
+ * The component's element may be moved in the DOM if the new template structure differs from the previous one.
2480
2495
  */
2481
2496
  onRecycle() {}
2482
2497
 
2483
2498
  /**
2484
2499
  * Lifecycle method. Called when the component is updated or re-rendered.
2500
+ * This method is called when the component's state, model, or props change and trigger a re-render.
2501
+ * Use this method to perform operations that need to happen on every update.
2485
2502
  */
2486
2503
  onUpdate() {}
2487
2504
 
2488
2505
  /**
2489
2506
  * Lifecycle method. Called when the component is destroyed.
2490
- * @param {object} options Options object or any arguments passed to `destroy` method.
2507
+ * Use this method to clean up resources, cancel timers, remove event listeners, etc.
2508
+ * @param {...*} args Options object or any arguments passed to `destroy` method.
2491
2509
  */
2492
2510
  onDestroy() {}
2493
2511
 
@@ -2547,10 +2565,8 @@
2547
2565
  component.hydrate(el);
2548
2566
  } else {
2549
2567
  // Append element to the DOM.
2550
- el.append(...component.render().getNodes());
2568
+ el.append(component.render().el);
2551
2569
  }
2552
- // Call onMount lifecycle method after nodes are in the DOM.
2553
- component.callOnMount();
2554
2570
  }
2555
2571
  // Return component instance.
2556
2572
  return component;
package/dist/rasti.min.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Rasti={})}(this,(function(t){"use strict";function e(t){if("function"!=typeof t)throw new TypeError("Listener must be a function")}class s{on(t,s){return e(s),this.listeners||(this.listeners={}),this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(s),()=>this.off(t,s)}once(t,s){e(s);const i=(...e)=>{s(...e),this.off(t,i)};return this.on(t,i)}off(t,e){this.listeners&&(t?this.listeners[t]&&(e?(this.listeners[t]=this.listeners[t].filter((t=>t!==e)),this.listeners[t].length||delete this.listeners[t]):delete this.listeners[t],Object.keys(this.listeners).length||delete this.listeners):delete this.listeners)}emit(t,...e){this.listeners&&this.listeners[t]&&this.listeners[t].slice().forEach((t=>t(...e)))}listenTo(t,e,s){return t.on(e,s),this.listeningTo||(this.listeningTo=[]),this.listeningTo.push({emitter:t,type:e,listener:s}),()=>this.stopListening(t,e,s)}listenToOnce(t,s,i){e(i);const n=(...e)=>{i(...e),this.stopListening(t,s,n)};return this.listenTo(t,s,n)}stopListening(t,e,s){this.listeningTo&&(this.listeningTo=this.listeningTo.filter((i=>!(!t||t===i.emitter&&!e||t===i.emitter&&e===i.type&&!s||t===i.emitter&&e===i.type&&s===i.listener)||(i.emitter.off(i.type,i.listener),!1))),this.listeningTo.length||delete this.listeningTo)}}const i=(t,e,...s)=>"function"!=typeof t?t:t.apply(e,s);class n extends s{constructor(){super(),this.preinitialize.apply(this,arguments),this.attributes=Object.assign({},i(this.defaults,this),this.parse.apply(this,arguments)),this.previous={},Object.keys(this.attributes).forEach(this.defineAttribute.bind(this))}preinitialize(){}defineAttribute(t){Object.defineProperty(this,`${this.constructor.attributePrefix}${t}`,{get:()=>this.get(t),set:e=>{this.set(t,e)}})}get(t){return this.attributes[t]}set(t,e,...s){let i,n;"object"==typeof t?(i=t,n=[e,...s]):(i={[t]:e},n=s);const r=this._changing;this._changing=!0;const h={};r||(this.previous=Object.assign({},this.attributes)),Object.keys(i).forEach((t=>{i[t]!==this.attributes[t]&&(h[t]=i[t],this.attributes[t]=i[t])}));const o=Object.keys(h);if(o.length&&(this._pending=["change",this,h,...n]),o.forEach((t=>{this.emit(`change:${t}`,this,i[t],...n)})),r)return this;for(;this._pending;){const t=this._pending;this._pending=null,this.emit.apply(this,t)}return this._pending=null,this._changing=!1,this}parse(t){return t}toJSON(){return Object.assign({},this.attributes)}}n.attributePrefix="";const r=["el","tag","attributes","events","model","template","onDestroy"];class h extends s{constructor(t={}){super(),this.preinitialize.apply(this,arguments),this.delegatedEventListeners=[],this.children=[],this.destroyQueue=[],this.viewOptions=[],r.forEach((e=>{e in t&&(this[e]=t[e],this.viewOptions.push(e))})),this.ensureUid(),this.ensureElement()}preinitialize(){}$(t){return this.el.querySelector(t)}$$(t){return this.el.querySelectorAll(t)}destroy(){return this.destroyChildren(),this.undelegateEvents(),this.stopListening(),this.off(),this.destroyQueue.forEach((t=>t())),this.destroyQueue=[],this.onDestroy.apply(this,arguments),this.destroyed=!0,this}onDestroy(){}addChild(t){return this.children.push(t),t}destroyChildren(){this.children.forEach((t=>t.destroy())),this.children=[]}ensureUid(){this.uid||(this.uid="r-"+ ++h.uid)}ensureElement(){if(this.el)this.el=i(this.el,this);else{const t=i(this.tag,this),e=i(this.attributes,this);this.el=this.createElement(t,e)}this.delegateEvents()}createElement(t="div",e={}){let s=document.createElement(t);return Object.keys(e).forEach((t=>s.setAttribute(t,e[t]))),s}removeElement(){return this.el.parentNode.removeChild(this.el),this}delegateEvents(t){if(t||(t=i(this.events,this)),!t)return this;this.delegatedEventListeners.length&&this.undelegateEvents();let s={};return Object.keys(t).forEach((i=>{const n=i.split(" "),r=n.shift(),h=n.join(" ");let o=t[i];"string"==typeof o&&(o=this[o]),e(o),s[r]||(s[r]=[]),s[r].push({selector:h,listener:o})})),Object.keys(s).forEach((t=>{const e=e=>{s[t].forEach((({selector:t,listener:s})=>{if(!t)return void s.call(this,e,this,this.el);let i=e.target;for(;i&&i!==this.el;)i.matches&&i.matches(t)&&s.call(this,e,this,i),i=i.parentElement}))};this.delegatedEventListeners.push({type:t,listener:e}),this.el.addEventListener(t,e)})),this}undelegateEvents(){return this.delegatedEventListeners.forEach((({type:t,listener:e})=>{this.el.removeEventListener(t,e)})),this.delegatedEventListeners=[],this}render(){return this.template&&(this.el.innerHTML=this.template(this.model)),this}static sanitize(t){return`${t}`.replace(/[&<>"']/g,(t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"}[t])))}}h.uid=0;class o{constructor(t){this.value=t}toString(){return this.value}}class a{constructor(t){this.items=t}}class l{constructor(t,e){this.interpolationUid=t,this.result=e}}class c{constructor(){this.listeners=[],this.types=new Set,this.previousSize=0}addListener(t,e){return this.types.add(e),this.listeners.push(t),this.listeners.length-1}reset(){this.listeners=[],this.previousSize=this.types.size}hasPendingTypes(){return this.types.size>this.previousSize}}class u{constructor(){}reset(){this.paused=0,this.previous=this.tracked||new Map,this.tracked=new Map,this.positionStack=[0]}push(){this.positionStack.push(0)}pop(){this.positionStack.pop()}increment(){this.positionStack[this.positionStack.length-1]++}pause(){this.paused++}resume(){this.paused--}getPath(){return this.positionStack.join("-")}track(t){return 0===this.paused&&this.tracked.set(this.getPath(),t),t}findRecyclable(t){const e=this.previous.get(this.getPath());return e&&e.constructor===t&&!e.key?e:null}}const d=["value","checked","selected"];class p{constructor(t){this.getSelector=t.getSelector,this.getAttributes=t.getAttributes,this.previousAttributes={}}hydrate(t){this.ref=t.querySelector(this.getSelector())}update(){const t=this.getAttributes(),{remove:e,add:s}=function(t,e={}){const s={},i=[];return Object.keys(t).forEach((i=>{let n=t[i];n!==e[i]&&(!0===n?s[i]="":!1!==n&&(null==n&&(n=""),s[i]=n))})),Object.keys(e).forEach((s=>{(!(s in t)||e[s]!==t[s]&&!1===t[s])&&i.push(s)})),{add:s,remove:i}}(t,this.previousAttributes);this.previousAttributes=t,e.forEach((t=>{this.ref.removeAttribute(t),d.includes(t)&&t in this.ref&&(this.ref[t]="value"===t&&"")})),Object.keys(s).forEach((t=>{const e=s[t];this.ref.setAttribute(t,e),d.includes(t)&&t in this.ref&&(this.ref[t]="value"===t?e:!1!==e&&"false"!==e)}))}}const f=["value","checked","selected"];function E(t,e){t.nodeType===e.nodeType?t.nodeType!==Node.TEXT_NODE?t.tagName===e.tagName?(((t,e)=>{const s=e.attributes,i=t.attributes,n=new Set;for(let e=0,i=s.length;e<i;e++){const{name:i,value:r}=s[e];n.add(i),t.getAttribute(i)!==r&&t.setAttribute(i,r)}for(let e=i.length-1;e>=0;e--){const{name:s}=i[e];n.has(s)||t.removeAttribute(s)}for(let s=0,i=f.length;s<i;s++){const i=f[s];i in t&&t[i]!==e[i]&&(t[i]=e[i])}})(t,e),((t,e)=>{const s=t.childNodes,i=e.childNodes,n=s.length;if(n!==i.length)return!1;for(let t=0;t<n;t++)if(!s[t].isEqualNode(i[t]))return!1;return!0})(t,e)||((t,e)=>{const s=Array.from(e.childNodes);t.replaceChildren(...s)})(t,e)):t.replaceWith(e):t.nodeValue!==e.nodeValue&&(t.nodeValue=e.nodeValue):t.replaceWith(e)}function g(t,e,s=(()=>!1),i){let n=i||t.firstChild;for(;n;){if(n.nodeType===Node.COMMENT_NODE&&n.data.trim()===e)return n;if(n.nodeType!==Node.ELEMENT_NODE||s(n)||!n.firstChild){for(;n&&!n.nextSibling;)if(n=n.parentNode,!n||n===t)return null;n&&(n=n.nextSibling)}else n=n.firstChild}return null}class m{constructor(t){this.getStart=t.getStart,this.getEnd=t.getEnd,this.expression=t.expression,this.isComponent=t.isComponent,this.isElement=t.isElement}hydrate(t){const e=g(t,this.getStart(),this.isComponent),s=g(t,this.getEnd(),this.isComponent,e);this.ref=[e,s]}update(t){const[e,s]=this.ref,i=e.nextSibling,n=i.nextSibling===s,r=i==s,h=t.children;if(n&&1===h.length&&!this.isElement(i))E(i,h[0]);else if(r)s.parentNode.insertBefore(t,s);else{const i=document.createRange();i.setStartAfter(e),i.setEndBefore(s),i.deleteContents(),i.insertNode(t)}}}const y=t=>t.reduce(((t,e)=>(Array.isArray(e)?t.push(...y(e)):t.push(e),t)),[]);function T(t){const e=document.createElement("template");return e.innerHTML=`${t}`.trim(),e.content}function b(t){const e=[];return Object.keys(t).forEach((s=>{let i=t[s];!0===i?e.push(s):!1!==i&&(null==i&&(i=""),e.push(`${s}="${i}"`))})),e.join(" ")}const A=(t,e)=>i(t,e,e),v=t=>!!t.dataset[j.DATASET_ELEMENT]&&t.dataset[j.DATASET_ELEMENT].endsWith("-1"),R=t=>!!t.dataset[j.DATASET_ELEMENT],M=(t,e)=>t.reduce(((t,s,i)=>(t.push(s),void 0!==e[i]&&t.push(j.PLACEHOLDER(i)),t)),[]).join(""),L=(t,e)=>{const s=j.PLACEHOLDER("(\\d+)"),i=new RegExp(`${s}`,"g"),n=[];let r,h=0;for(;null!==(r=i.exec(t));){const s=t.slice(h,r.index);n.push(j.markAsSafeHTML(s),e[r[1]]),h=r.index+r[0].length}return n.push(j.markAsSafeHTML(t.slice(h))),n},$=(t,e)=>t.reduce(((t,s)=>{const i=e(s[0]);if(1===s.length)"object"==typeof i?t=Object.assign(t,i):"string"==typeof i&&(t[i]=!0);else{const n=s[2]?e(s[1]):s[1];t[i]=n}return t}),{}),C=(t,e,s)=>{const i={};return Object.keys(t).forEach((n=>{const r=n.match(/on(([A-Z]{1}[a-z]+)+)/);if(r&&r[1]){const h=r[1].toLowerCase(),o=t[n];if(o){const t=e.addListener(o,h);i[s(h)]=t}}else i[n]=t[n]})),i},S=(t,e,s=!1)=>{const i=j.PLACEHOLDER("(\\d+)"),n=new Map;return s||(t=t.replace(new RegExp(i,"g"),((t,s)=>{const i=e[s];if(i&&i.prototype instanceof j){if(n.has(i))return n.get(i);n.set(i,t)}return t}))),t.replace(new RegExp(`<(${i})([^>]*)>([\\s\\S]*?)</\\1>|<(${i})([^>]*)/>`,"g"),((t,s,i,n,r,h,o,l)=>{let c,u,d;if(s?(c=e[i],u=n):(c=void 0!==o?e[o]:h,u=l),!(c.prototype instanceof j))return t;if(s){const t=S(r,e,!0),s=k(t,e);d=L(s,e)}const p=w(u,e);return e.push((function(){const t=$(p,(t=>A(t,this)));return d&&(t.renderChildren=()=>new a(d.map((t=>A(t,this))))),c.mount(t)})),j.PLACEHOLDER(e.length-1)}))},O=(t,e)=>{const s=j.PLACEHOLDER("(?:\\d+)");return t.replace(new RegExp(`<(${s}|[a-z]+[1-6]?)(?:\\s*)((?:"[^"]*"|'[^']*'|[^>])*)(/?>)`,"gi"),e)},x=(t,e,s)=>{const n=j.PLACEHOLDER("(?:\\d+)");if(t.match(new RegExp(`^\\s*${n}\\s*$`)))return t;if(!t.match(new RegExp(`^\\s*<([a-z]+[1-6]?|${n})([^>]*)>([\\s\\S]*?)</(\\1|${n})>\\s*$|^\\s*<([a-z]+[1-6]?|${n})([^>]*)/>\\s*$`)))throw new SyntaxError(`Template must have a single root element or be a container component: "${t.trim()}"`);let r=0;return O(t,((t,h,o,a)=>{const l=0===r,c=++r;if(!l&&!o.match(new RegExp(n)))return t;const u=w(o,e),d=t=>`${t}-${c}`,p=function(){const t=C($(u,(t=>A(t,this))),this.eventsManager,(t=>j.ATTRIBUTE_EVENT(t,this.uid)));return l&&this.attributes&&Object.assign(t,i(this.attributes,this)),t[j.ATTRIBUTE_ELEMENT]=d(this.uid),t};s.push({getSelector:function(){return`[${j.ATTRIBUTE_ELEMENT}="${d(this.uid)}"]`},getAttributes:p}),e.push((function(){const t=p.call(this);return j.markAsSafeHTML(b(t))}));return`<${h} ${j.PLACEHOLDER(e.length-1)}${a}`}))},k=(t,e)=>{const s=j.PLACEHOLDER("(?:\\d+)");return O(t,((t,i,n,r)=>{if(!n.match(new RegExp(s)))return t;const h=w(n,e),o=function(){return C($(h,(t=>A(t,this))),this.eventsManager,(t=>j.ATTRIBUTE_EVENT(t,this.uid)))};e.push((function(){const t=o.call(this);return j.markAsSafeHTML(b(t))}));return`<${i} ${j.PLACEHOLDER(e.length-1)}${r}`}))},N=(t,e,s)=>{const i=j.PLACEHOLDER("(\\d+)");let n=0;return t.replace(new RegExp(i,"g"),(function(i,r,h){const o=t.substring(0,h);if(o.lastIndexOf("<")>o.lastIndexOf(">"))return i;const a=++n;return s.push({getStart:function(){return j.MARKER_START(`${this.uid}-${a}`)},getEnd:function(){return j.MARKER_END(`${this.uid}-${a}`)},expression:e[r]}),e.push((function(){const t=A(e[r],this),s=`${this.uid}-${a}`;return new l(s,t)})),j.PLACEHOLDER(e.length-1)}))},w=(t,e)=>{const s=j.PLACEHOLDER("(\\d+)"),i=[],n=new RegExp(`(${s}|[\\w-]+)(?:=(["']?)(?:${s}|((?:.?(?!["']?\\s+(?:\\S+)=|\\s*/?[>"']))+.))\\3)?`,"g");let r;for(;null!==(r=n.exec(t));){const[,t,s,n,h,o]=r,a=void 0!==s?e[parseInt(s,10)]:t,l=void 0!==h?e[parseInt(h,10)]:o;void 0!==l?i.push([a,l,!!n]):i.push([a])}return i},_=["key","state","onCreate","onChange","onHydrate","onMount","onRecycle","onUpdate"];class j extends h{constructor(t={}){super(...arguments),this.componentOptions=[],_.forEach((e=>{e in t&&(this[e]=t[e],this.componentOptions.push(e))}));const e={};Object.keys(t).forEach((s=>{this.viewOptions.includes(s)||this.componentOptions.includes(s)||(e[s]=t[s])})),this.props=new n(e),this.options=t,this.partial=this.partial.bind(this),this.onChange=this.onChange.bind(this),this.onCreate.apply(this,arguments)}events(){const t={};return this.eventsManager.types.forEach((s=>{const i=j.ATTRIBUTE_EVENT(s,this.uid),n=function(t,s,n){const r=n.getAttribute(i);if(r){let i=this.eventsManager.listeners[parseInt(r,10)];"string"==typeof i&&(i=this[i]),e(i),i.call(this,t,s,n)}};t[`${s} [${i}]`]=n,t[s]=n})),t}ensureElement(){this.eventsManager=new c,this.pathManager=new u,this.template=i(this.template,this),this.el&&(this.el=i(this.el,this),this.toString(),this.hydrate(this.el.parentNode))}isContainer(){return 0===this.template.elements.length&&1===this.template.interpolations.length}subscribe(t,e="change",s=this.onChange){return t.on&&this.listenTo(t,e,s),this}hydrate(t){return["model","state","props"].forEach((t=>{this[t]&&this.subscribe(this[t])})),this.isContainer()?(this.template.interpolations[0].hydrate(t),this.children[0].hydrate(t),this.el=this.children[0].el):(this.template.elements.forEach(((e,s)=>{0===s?(e.hydrate(t),this.el?e.ref=this.el:this.el=e.ref):e.hydrate(this.el)})),this.delegateEvents(),this.template.interpolations.forEach((t=>t.hydrate(this.el))),this.children.forEach((t=>t.hydrate(this.el)))),this.onHydrate.call(this),this}recycle(t){return g(t,j.MARKER_RECYCLED(this.uid),v).replaceWith(...this.getNodes()),this.onRecycle.call(this),this}getRecycledMarker(){return`\x3c!--${j.MARKER_RECYCLED(this.uid)}--\x3e`}getNodes(){return this.isContainer()?[this.template.interpolations[0].ref[0],...this.children[0].getNodes(),this.template.interpolations[0].ref[1]]:[this.el]}callOnMount(){return this.children.forEach((t=>t.callOnMount())),this.onMount.call(this),this}partial(t,...e){const s=L(k(S(M(t,e),e),e),e).map((t=>A(t,this)));return new a(s)}renderTemplatePart(t,e){const s=A(t,this),i=t=>{if(null!=t&&!1!==t&&!0!==t){if(t instanceof o)return t;if(t instanceof j)return e(t);if(t instanceof a){this.pathManager.push();const e=t.items.map((t=>(this.pathManager.increment(),i(t)))).join("");return this.pathManager.pop(),e}if(Array.isArray(t)){this.pathManager.pause();const e=y(t).map(i).join("");return this.pathManager.resume(),e}if(t instanceof l){this.pathManager.increment();const e=`\x3c!--${j.MARKER_START(t.interpolationUid)}--\x3e`,s=`\x3c!--${j.MARKER_END(t.interpolationUid)}--\x3e`;return`${e}${i(t.result)}${s}`}return j.sanitize(t)}return""};return`${i(s)}`}toString(){this.destroyChildren(),this.eventsManager.reset(),this.pathManager.reset();const t=t=>(this.pathManager.track(t),this.addChild(t));return this.template.parts.map((e=>this.renderTemplatePart(e,t))).join("")}render(){if(this.destroyed)return this;if(!this.el){const t=T(this);return this.hydrate(t),this}this.eventsManager.reset(),this.pathManager.reset();const t=this.isContainer()?null:document.activeElement;this.template.elements.forEach((t=>t.update()));const e=this.children;return this.children=[],this.template.interpolations.forEach((t=>{const s=[],i=[];this.pathManager.increment();const n=T(this.renderTemplatePart(t.expression,(t=>{let n=t,r=null;return r=t.key?e.find((e=>e.key===t.key)):this.pathManager.findRecyclable(t.constructor),r?(n=r.getRecycledMarker(),i.push([r,t]),r.key||this.pathManager.track(r)):(s.push(t),this.pathManager.track(t)),n})));i.forEach((([t,e])=>{this.addChild(t).recycle(n),t.props.set(e.props.toJSON()),e.destroy()})),s.forEach((t=>this.addChild(t).hydrate(n))),t.update(n)})),this.children.forEach((t=>t.callOnMount())),e.forEach((t=>{this.children.indexOf(t)<0&&t.destroy()})),this.isContainer()?this.el=this.children[0].el:this.eventsManager.hasPendingTypes()&&this.delegateEvents(),t&&this.el.contains(t)&&t.focus(),this.onUpdate.call(this),this}onCreate(){}onChange(){this.render()}onHydrate(){}onMount(){}onRecycle(){}onUpdate(){}onDestroy(){}static markAsSafeHTML(t){return new o(t)}static extend(t){const e=this;class s extends e{}return Object.assign(s.prototype,"function"==typeof t?t(e.prototype):t),s}static mount(t,e,s){const i=new this(t);return e&&(s?(i.toString(),i.hydrate(e)):e.append(...i.render().getNodes()),i.callOnMount()),i}static create(t,...e){"function"==typeof t&&(e=[t],t=["",""]);const s=[],i=[],n=L(N(x(S(M(t,e).trim(),e),e,s),e,i),e);return this.extend({template(){return{elements:s.map((t=>new p({getSelector:t.getSelector.bind(this),getAttributes:t.getAttributes.bind(this)}))),interpolations:i.map((t=>new m({getStart:t.getStart.bind(this),getEnd:t.getEnd.bind(this),expression:t.expression,isComponent:v,isElement:R}))),parts:n}}})}}j.ATTRIBUTE_ELEMENT="data-rasti-el",j.ATTRIBUTE_EVENT=(t,e)=>`data-rasti-on-${t}-${e}`,j.DATASET_ELEMENT="rastiEl",j.PLACEHOLDER=t=>`__RASTI-${t}__`,j.MARKER_RECYCLED=t=>`rasti-recycled-${t}`,j.MARKER_START=t=>`rasti-start-${t}`,j.MARKER_END=t=>`rasti-end-${t}`;var D=j.create`<div></div>`;t.Component=D,t.Emitter=s,t.Model=n,t.View=h}));
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Rasti={})}(this,(function(t){"use strict";function e(t){if("function"!=typeof t)throw new TypeError("Listener must be a function")}class s{on(t,s){return e(s),this.listeners||(this.listeners={}),this.listeners[t]||(this.listeners[t]=[]),this.listeners[t].push(s),()=>this.off(t,s)}once(t,s){e(s);const i=(...e)=>{s(...e),this.off(t,i)};return this.on(t,i)}off(t,e){this.listeners&&(t?this.listeners[t]&&(e?(this.listeners[t]=this.listeners[t].filter((t=>t!==e)),this.listeners[t].length||delete this.listeners[t]):delete this.listeners[t],Object.keys(this.listeners).length||delete this.listeners):delete this.listeners)}emit(t,...e){this.listeners&&this.listeners[t]&&this.listeners[t].slice().forEach((t=>t(...e)))}listenTo(t,e,s){return t.on(e,s),this.listeningTo||(this.listeningTo=[]),this.listeningTo.push({emitter:t,type:e,listener:s}),()=>this.stopListening(t,e,s)}listenToOnce(t,s,i){e(i);const n=(...e)=>{i(...e),this.stopListening(t,s,n)};return this.listenTo(t,s,n)}stopListening(t,e,s){this.listeningTo&&(this.listeningTo=this.listeningTo.filter((i=>!(!t||t===i.emitter&&!e||t===i.emitter&&e===i.type&&!s||t===i.emitter&&e===i.type&&s===i.listener)||(i.emitter.off(i.type,i.listener),!1))),this.listeningTo.length||delete this.listeningTo)}}const i=(t,e,...s)=>"function"!=typeof t?t:t.apply(e,s);class n extends s{constructor(){super(),this.preinitialize.apply(this,arguments),this.attributes=Object.assign({},i(this.defaults,this),this.parse.apply(this,arguments)),this.previous={},Object.keys(this.attributes).forEach(this.defineAttribute.bind(this))}preinitialize(){}defineAttribute(t){Object.defineProperty(this,`${this.constructor.attributePrefix}${t}`,{get:()=>this.get(t),set:e=>{this.set(t,e)}})}get(t){return this.attributes[t]}set(t,e,...s){let i,n;"object"==typeof t?(i=t,n=[e,...s]):(i={[t]:e},n=s);const r=this._changing;this._changing=!0;const h={};r||(this.previous=Object.assign({},this.attributes)),Object.keys(i).forEach((t=>{i[t]!==this.attributes[t]&&(h[t]=i[t],this.attributes[t]=i[t])}));const o=Object.keys(h);if(o.length&&(this._pending=["change",this,h,...n]),o.forEach((t=>{this.emit(`change:${t}`,this,i[t],...n)})),r)return this;for(;this._pending;){const t=this._pending;this._pending=null,this.emit.apply(this,t)}return this._pending=null,this._changing=!1,this}parse(t){return t}toJSON(){return Object.assign({},this.attributes)}}n.attributePrefix="";const r=["el","tag","attributes","events","model","template","onDestroy"];class h extends s{constructor(t={}){super(),this.preinitialize.apply(this,arguments),this.delegatedEventListeners=[],this.children=[],this.destroyQueue=[],this.viewOptions=[],r.forEach((e=>{e in t&&(this[e]=t[e],this.viewOptions.push(e))})),this.ensureUid(),this.ensureElement()}preinitialize(){}$(t){return this.el.querySelector(t)}$$(t){return this.el.querySelectorAll(t)}destroy(){return this.destroyChildren(),this.undelegateEvents(),this.stopListening(),this.off(),this.destroyQueue.forEach((t=>t())),this.destroyQueue=[],this.onDestroy.apply(this,arguments),this.destroyed=!0,this}onDestroy(){}addChild(t){return this.children.push(t),t}destroyChildren(){this.children.forEach((t=>t.destroy())),this.children=[]}ensureUid(){this.uid||(this.uid="r-"+ ++h.uid)}ensureElement(){if(this.el)this.el=i(this.el,this);else{const t=i(this.tag,this),e=i(this.attributes,this);this.el=this.createElement(t,e)}this.delegateEvents()}createElement(t="div",e={}){let s=document.createElement(t);return Object.keys(e).forEach((t=>s.setAttribute(t,e[t]))),s}removeElement(){return this.el.parentNode.removeChild(this.el),this}delegateEvents(t){if(t||(t=i(this.events,this)),!t)return this;this.delegatedEventListeners.length&&this.undelegateEvents();let s={};return Object.keys(t).forEach((i=>{const n=i.split(" "),r=n.shift(),h=n.join(" ");let o=t[i];"string"==typeof o&&(o=this[o]),e(o),s[r]||(s[r]=[]),s[r].push({selector:h,listener:o})})),Object.keys(s).forEach((t=>{const e=e=>{s[t].forEach((({selector:t,listener:s})=>{if(!t)return void s.call(this,e,this,this.el);let i=e.target;for(;i&&i!==this.el;)i.matches&&i.matches(t)&&s.call(this,e,this,i),i=i.parentElement}))};this.delegatedEventListeners.push({type:t,listener:e}),this.el.addEventListener(t,e)})),this}undelegateEvents(){return this.delegatedEventListeners.forEach((({type:t,listener:e})=>{this.el.removeEventListener(t,e)})),this.delegatedEventListeners=[],this}render(){return this.template&&(this.el.innerHTML=this.template(this.model)),this}static sanitize(t){return`${t}`.replace(/[&<>"']/g,(t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"}[t])))}}h.uid=0;class o{constructor(t){this.value=t}toString(){return this.value}}class a{constructor(t){this.items=t}}class l{constructor(){this.listeners=[],this.types=new Set,this.previousSize=0}addListener(t,e){return this.types.add(e),this.listeners.push(t),this.listeners.length-1}reset(){this.listeners=[],this.previousSize=this.types.size}hasPendingTypes(){return this.types.size>this.previousSize}}class c{constructor(){}reset(){this.paused=0,this.previous=this.tracked||new Map,this.tracked=new Map,this.positionStack=[0]}push(){this.positionStack.push(0)}pop(){this.positionStack.pop()}increment(){this.positionStack[this.positionStack.length-1]++}pause(){this.paused++}resume(){this.paused--}getPath(){return this.positionStack.join("-")}track(t){return 0===this.paused&&this.tracked.set(this.getPath(),t),t}findRecyclable(t){const e=this.previous.get(this.getPath());return e&&e.constructor===t&&!e.key?e:null}}const u=["value","checked","selected"];class p{constructor(t){this.getSelector=t.getSelector,this.getAttributes=t.getAttributes,this.previousAttributes={}}hydrate(t){this.ref=t.querySelector(this.getSelector())}update(){const t=this.getAttributes(),{remove:e,add:s}=function(t,e={}){const s={},i=[];return Object.keys(t).forEach((i=>{let n=t[i];n!==e[i]&&(!0===n?s[i]="":!1!==n&&(null==n&&(n=""),s[i]=n))})),Object.keys(e).forEach((s=>{(!(s in t)||e[s]!==t[s]&&!1===t[s])&&i.push(s)})),{add:s,remove:i}}(t,this.previousAttributes);this.previousAttributes=t,e.forEach((t=>{this.ref.removeAttribute(t),u.includes(t)&&t in this.ref&&(this.ref[t]="value"===t&&"")})),Object.keys(s).forEach((t=>{const e=s[t];this.ref.setAttribute(t,e),u.includes(t)&&t in this.ref&&(this.ref[t]="value"===t?e:!1!==e&&"false"!==e)}))}}const d=["value","checked","selected"];function f(t,e){t.nodeType===e.nodeType?t.nodeType!==Node.TEXT_NODE?t.tagName===e.tagName?(((t,e)=>{const s=e.attributes,i=t.attributes,n=new Set;for(let e=0,i=s.length;e<i;e++){const{name:i,value:r}=s[e];n.add(i),t.getAttribute(i)!==r&&t.setAttribute(i,r)}for(let e=i.length-1;e>=0;e--){const{name:s}=i[e];n.has(s)||t.removeAttribute(s)}for(let s=0,i=d.length;s<i;s++){const i=d[s];i in t&&t[i]!==e[i]&&(t[i]=e[i])}})(t,e),((t,e)=>{const s=t.childNodes,i=e.childNodes,n=s.length;if(n!==i.length)return!1;for(let t=0;t<n;t++)if(!s[t].isEqualNode(i[t]))return!1;return!0})(t,e)||((t,e)=>{const s=Array.from(e.childNodes);t.replaceChildren(...s)})(t,e)):t.replaceWith(e):t.nodeValue!==e.nodeValue&&(t.nodeValue=e.nodeValue):t.replaceWith(e)}function g(t,e,s=(()=>!1),i){let n=i||t.firstChild;for(;n;){if(n.nodeType===Node.COMMENT_NODE&&n.data.trim()===e)return n;if(n.nodeType!==Node.ELEMENT_NODE||s(n)||!n.firstChild){for(;n&&!n.nextSibling;)if(n=n.parentNode,!n||n===t)return null;n&&(n=n.nextSibling)}else n=n.firstChild}return null}class E{constructor(t){this.getStart=t.getStart,this.getEnd=t.getEnd,this.expression=t.expression,this.isComponent=t.isComponent,this.isElement=t.isElement,this.previousItems=[]}hydrate(t){const e=g(t,this.getStart(),this.isComponent),s=g(t,this.getEnd(),this.isComponent,e);this.ref=[e,s]}update(t,e){if(e)return void e.replaceWith(t.firstChild);const[s,i]=this.ref,n=s.nextSibling,r=n===i,h=!r&&n.nextSibling===i,o=t.children;if(r)i.parentNode.insertBefore(t,i);else if(h&&1===o.length)this.isElement(n)?n.replaceWith(o[0]):f(n,o[0]);else{const e=document.createRange();e.setStartAfter(s),e.setEndBefore(i),e.deleteContents(),e.insertNode(t)}}}const m=t=>t.reduce(((t,e)=>(Array.isArray(e)?t.push(...m(e)):t.push(e),t)),[]);function y(t){const e=document.createElement("template");return e.innerHTML=`${t}`.trim(),e.content}function T(t){const e=[];return Object.keys(t).forEach((s=>{let i=t[s];!0===i?e.push(s):!1!==i&&(null==i&&(i=""),e.push(`${s}="${i}"`))})),e.join(" ")}const b=(t,e)=>i(t,e,e),v=t=>!!(t&&t.dataset&&t.dataset[_.DATASET_ELEMENT]&&t.dataset[_.DATASET_ELEMENT].endsWith("-1")),A=t=>!!(t&&t.dataset&&t.dataset[_.DATASET_ELEMENT]),R=(t,e)=>t.reduce(((t,s,i)=>(t.push(s),void 0!==e[i]&&t.push(_.PLACEHOLDER(i)),t)),[]).join(""),L=(t,e)=>{const s=_.PLACEHOLDER("(\\d+)"),i=t.match(new RegExp(`^${s}$`));if(i)return[e[parseInt(i[1],10)]];const n=new RegExp(`${s}`,"g"),r=[];let h,o=0;for(;null!==(h=n.exec(t));){const s=t.slice(o,h.index);r.push(_.markAsSafeHTML(s),e[parseInt(h[1],10)]),o=h.index+h[0].length}return r.push(_.markAsSafeHTML(t.slice(o))),r},C=(t,e)=>t.reduce(((t,s)=>{const i=e(s[0]);if(1===s.length)"object"==typeof i?t=Object.assign(t,i):"string"==typeof i&&(t[i]=!0);else{const n=s[2]?e(s[1]):s[1];t[i]=n}return t}),{}),$=(t,e,s)=>{const i={};return Object.keys(t).forEach((n=>{const r=n.match(/on(([A-Z]{1}[a-z]+)+)/);if(r&&r[1]){const h=r[1].toLowerCase(),o=t[n];if(o){const t=e.addListener(o,h);i[s(h)]=t}}else i[n]=t[n]})),i},S=(t,e,s=!1)=>{const i=_.PLACEHOLDER("(\\d+)"),n=new Map;return s||(t=t.replace(new RegExp(i,"g"),((t,s)=>{const i=e[s];if(i&&i.prototype instanceof _){if(n.has(i))return n.get(i);n.set(i,t)}return t}))),t.replace(new RegExp(`<(${i})([^>]*)>([\\s\\S]*?)</\\1>|<(${i})([^>]*)/>`,"g"),((t,s,i,n,r,h,o,l)=>{let c,u,p;if(s?(c=e[i],u=n):(c=void 0!==o?e[o]:h,u=l),!(c.prototype instanceof _))return t;if(s){const t=S(r,e,!0),s=x(t,e);p=L(s,e)}const d=w(u,e);return e.push((function(){const t=C(d,(t=>b(t,this)));return p&&(t.renderChildren=()=>new a(p.map((t=>b(t,this))))),c.mount(t)})),_.PLACEHOLDER(e.length-1)}))},M=(t,e)=>{const s=_.PLACEHOLDER("(?:\\d+)");return t.replace(new RegExp(`<(${s}|[a-z]+[1-6]?)(?:\\s*)((?:"[^"]*"|'[^']*'|[^>])*)(/?>)`,"gi"),e)},O=(t,e,s)=>{const n=_.PLACEHOLDER("(?:\\d+)");if(t.match(new RegExp(`^\\s*${n}\\s*$`)))return t;if(!t.match(new RegExp(`^\\s*<([a-z]+[1-6]?|${n})([^>]*)>([\\s\\S]*?)</(\\1|${n})>\\s*$|^\\s*<([a-z]+[1-6]?|${n})([^>]*)/>\\s*$`)))throw new SyntaxError(`Template must have a single root element or be a container component: "${t.trim()}"`);let r=0;return M(t,((t,h,o,a)=>{const l=0===r,c=++r;if(!l&&!o.match(new RegExp(n)))return t;const u=w(o,e),p=t=>`${t}-${c}`,d=s.length;s.push({getSelector:function(){return`[${_.ATTRIBUTE_ELEMENT}="${p(this.uid)}"]`},getAttributes:function(){const t=$(C(u,(t=>b(t,this))),this.eventsManager,(t=>_.ATTRIBUTE_EVENT(t,this.uid)));return l&&this.attributes&&Object.assign(t,i(this.attributes,this)),t[_.ATTRIBUTE_ELEMENT]=p(this.uid),t}}),e.push((function(){const t=this.template.elements[d],e=t.getAttributes.call(this);return t.previousAttributes=e,_.markAsSafeHTML(T(e))}));return`<${h} ${_.PLACEHOLDER(e.length-1)}${a}`}))},x=(t,e)=>{const s=_.PLACEHOLDER("(?:\\d+)");return M(t,((t,i,n,r)=>{if(!n.match(new RegExp(s)))return t;const h=w(n,e),o=function(){return $(C(h,(t=>b(t,this))),this.eventsManager,(t=>_.ATTRIBUTE_EVENT(t,this.uid)))};e.push((function(){const t=o.call(this);return _.markAsSafeHTML(T(t))}));return`<${i} ${_.PLACEHOLDER(e.length-1)}${r}`}))},k=(t,e,s)=>{const i=_.PLACEHOLDER("(\\d+)");let n=0;return t.replace(new RegExp(i,"g"),(function(i,r,h){const o=t.substring(0,h);if(o.lastIndexOf("<")>o.lastIndexOf(">"))return i;const a=++n;const l=s.length;return s.push({getStart:function(){return _.MARKER_START(`${this.uid}-${a}`)},getEnd:function(){return _.MARKER_END(`${this.uid}-${a}`)},expression:e[r]}),e.push((function(){return this.template.interpolations[l]})),_.PLACEHOLDER(e.length-1)}))},w=(t,e)=>{const s=_.PLACEHOLDER("(\\d+)"),i=[],n=new RegExp(`(${s}|[\\w-]+)(?:=(["']?)(?:${s}|((?:.?(?!["']?\\s+(?:\\S+)=|\\s*/?[>"']))+.))\\3)?`,"g");let r;for(;null!==(r=n.exec(t));){const[,t,s,n,h,o]=r,a=void 0!==s?e[parseInt(s,10)]:t,l=void 0!==h?e[parseInt(h,10)]:o;void 0!==l?i.push([a,l,!!n]):i.push([a])}return i},N=["key","state","onCreate","onChange","onHydrate","onRecycle","onUpdate"];class _ extends h{constructor(t={}){super(...arguments),this.componentOptions=[],N.forEach((e=>{e in t&&(this[e]=t[e],this.componentOptions.push(e))}));const e={};Object.keys(t).forEach((s=>{this.viewOptions.includes(s)||this.componentOptions.includes(s)||(e[s]=t[s])})),this.props=new n(e),this.options=t,this.partial=this.partial.bind(this),this.onChange=this.onChange.bind(this),this.onCreate.apply(this,arguments)}events(){const t={};return this.eventsManager.types.forEach((s=>{const i=_.ATTRIBUTE_EVENT(s,this.uid),n=function(t,s,n){const r=n.getAttribute(i);if(r){let i=this.eventsManager.listeners[parseInt(r,10)];"string"==typeof i&&(i=this[i]),e(i),i.call(this,t,s,n)}};t[`${s} [${i}]`]=n,t[s]=n})),t}ensureElement(){this.eventsManager=new l,this.pathManager=new c,this.template=i(this.template,this),this.el&&(this.el=i(this.el,this),this.toString(),this.hydrate(this.el.parentNode))}isContainer(){return 0===this.template.elements.length&&1===this.template.interpolations.length}subscribe(t,e="change",s=this.onChange){return t.on&&this.listenTo(t,e,s),this}hydrate(t){return["model","state","props"].forEach((t=>{this[t]&&this.subscribe(this[t])})),this.isContainer()?(this.children[0].hydrate(t),this.el=this.children[0].el):(this.template.elements.forEach(((e,s)=>{0===s?(e.hydrate(t),this.el?e.ref=this.el:this.el=e.ref):e.hydrate(this.el)})),this.delegateEvents(),this.template.interpolations.forEach((t=>t.hydrate(this.el))),this.children.forEach((t=>t.hydrate(this.el)))),this.onHydrate.call(this),this}recycle(t,e){if(t){g(t,_.MARKER_RECYCLED(this.uid),v).replaceWith(this.el)}return e&&this.props.set(e),this.onRecycle.call(this),this}getRecycledMarker(){return`\x3c!--${_.MARKER_RECYCLED(this.uid)}--\x3e`}partial(t,...e){const s=L(x(S(R(t,e).trim(),e),e),e).map((t=>b(t,this)));return new a(s)}renderTemplatePart(t,e,s=[]){const i=b(t,this),n=t=>{if(null==t||!1===t||!0===t)return"";if(t instanceof o)return s.push(t),t;if(t instanceof _)return s.push(t),e(t);if(t instanceof a){if(1===t.items.length)return n(t.items[0]);this.pathManager.push();const e=t.items.map((t=>(this.pathManager.increment(),n(t)))).join("");return this.pathManager.pop(),e}if(Array.isArray(t)){this.pathManager.pause();const e=m(t).map(n).join("");return this.pathManager.resume(),e}if(t instanceof E){this.pathManager.increment();const e=this.isContainer()?"":`\x3c!--${t.getStart()}--\x3e`,i=this.isContainer()?"":`\x3c!--${t.getEnd()}--\x3e`,r=n(b(t.expression,this));return t.previousItems=s,`${e}${r}${i}`}const i=_.sanitize(t);return s.push(i),i};return`${n(i)}`}toString(){this.destroyChildren(),this.eventsManager.reset(),this.pathManager.reset();const t=t=>(this.pathManager.track(t),this.addChild(t));return this.template.parts.map((e=>this.renderTemplatePart(e,t))).join("")}render(){if(this.destroyed)return this;if(!this.el){const t=y(this);return this.hydrate(t),this}this.eventsManager.reset(),this.pathManager.reset();const t=this.isContainer()?null:document.activeElement;this.template.elements.forEach((t=>t.update()));const e=this.children;return this.children=[],this.template.interpolations.forEach((t=>{const s=[],i=[];this.pathManager.increment();const n=t.previousItems,r=[],h=this.renderTemplatePart(t.expression,(t=>{let n=t,r=null;return r=t.key?e.find((e=>e.key===t.key)):this.pathManager.findRecyclable(t.constructor),r?(n=r.getRecycledMarker(),i.push([r,t]),r.key||this.pathManager.track(r)):(s.push(t),this.pathManager.track(t)),n}),r);t.previousItems=r;const o=([t,e],s)=>{this.addChild(t).recycle(s,e.props.toJSON()),e.destroy()};if(1===n.length&&n[0]instanceof _&&1===r.length&&r[0]instanceof _&&1===i.length)return void o(i[0],null);const a=y(h);i.forEach((t=>o(t,a))),s.forEach((t=>this.addChild(t).hydrate(a)));const l=this.isContainer()?this.el:null;t.update(a,l)})),e.forEach((t=>{this.children.indexOf(t)<0&&t.destroy()})),this.isContainer()?this.el=this.children[0].el:this.eventsManager.hasPendingTypes()&&this.delegateEvents(),t&&this.el.contains(t)&&t.focus(),this.onUpdate.call(this),this}onCreate(){}onChange(){this.render()}onHydrate(){}onRecycle(){}onUpdate(){}onDestroy(){}static markAsSafeHTML(t){return new o(t)}static extend(t){const e=this;class s extends e{}return Object.assign(s.prototype,"function"==typeof t?t(e.prototype):t),s}static mount(t,e,s){const i=new this(t);return e&&(s?(i.toString(),i.hydrate(e)):e.append(i.render().el)),i}static create(t,...e){"function"==typeof t&&(e=[t],t=["",""]);const s=[],i=[],n=L(k(O(S(R(t,e).trim(),e),e,s),e,i),e);return this.extend({template(){return{elements:s.map((t=>new p({getSelector:t.getSelector.bind(this),getAttributes:t.getAttributes.bind(this)}))),interpolations:i.map((t=>new E({getStart:t.getStart.bind(this),getEnd:t.getEnd.bind(this),expression:t.expression,isComponent:v,isElement:A}))),parts:n}}})}}_.ATTRIBUTE_ELEMENT="data-rasti-el",_.ATTRIBUTE_EVENT=(t,e)=>`data-rasti-on-${t}-${e}`,_.DATASET_ELEMENT="rastiEl",_.PLACEHOLDER=t=>`__RASTI-${t}__`,_.MARKER_RECYCLED=t=>`rasti-recycled-${t}`,_.MARKER_START=t=>`rasti-start-${t}`,_.MARKER_END=t=>`rasti-end-${t}`;var j=_.create`<div></div>`;t.Component=j,t.Emitter=s,t.Model=n,t.View=h}));