solarite 0.5.0 → 0.5.2

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.
@@ -876,6 +876,9 @@ class PathToAttribValue extends Path {
876
876
  * @type {?string[]} Used only if type=AttribType.Value. If null, use one expr to set the whole attribute value. */
877
877
  attrValue;
878
878
 
879
+ /** @type {boolean} Provides value for attribute on a component. */
880
+ isComponent;
881
+
879
882
  isHtmlProperty;
880
883
 
881
884
  constructor(nodeBefore, nodeMarker, attrName=null, attrValue=null) {
@@ -1140,6 +1143,14 @@ class PathToEvent extends PathToAttribValue {
1140
1143
  assert(Array.isArray(exprs));
1141
1144
  //#ENDIF
1142
1145
 
1146
+ // Tested by Solariate.events.classicWithExpr
1147
+ // We have expressions within a string attribute value that's not a Solarite event. E.g.
1148
+ // <div onclick="alert(${1});"
1149
+ if (this.attrValue?.length > 1) {
1150
+ super.apply(exprs);
1151
+ return;
1152
+ }
1153
+
1143
1154
  // Don't bind events to component placeholders.
1144
1155
  // PathToComponent will do the binding later when it instantiates the component.
1145
1156
  if (this.isComponentAttrib && this.nodeMarker.tagName.endsWith('-SOLARITE-PLACEHOLDER'))
@@ -1182,6 +1193,9 @@ class PathToAttribs extends Path {
1182
1193
  * @type {Set<string>} Used for type=AttribType.Multiple to remember the attributes that were added. */
1183
1194
  attrNames;
1184
1195
 
1196
+ /** @type {boolean} Provides one or more attributes on a component. */
1197
+ isComponent;
1198
+
1185
1199
  constructor(nodeBefore, nodeMarker) {
1186
1200
  super(null, null);
1187
1201
  this.nodeMarker = nodeMarker;
@@ -1248,6 +1262,7 @@ class PathToAttribs extends Path {
1248
1262
 
1249
1263
 
1250
1264
  getExpressionCount() { return 1 }
1265
+ getValue(exprs) { return exprs[0]; }
1251
1266
  }
1252
1267
 
1253
1268
  /**
@@ -2088,8 +2103,27 @@ class PathToComponent extends Path {
2088
2103
  // 1. Attributes
2089
2104
  let attribs = Util.attribsToObject(el, '_is');
2090
2105
  for (let i=0, attribPath; attribPath = this.attribPaths[i]; i++) {
2091
- let name = Util.dashesToCamel(attribPath.attrName);
2092
- attribs[name] = attribPath.getValue(exprs[i]);
2106
+ if (attribPath instanceof PathToAttribValue) {
2107
+ let name = Util.dashesToCamel(attribPath.attrName);
2108
+ attribs[name] = attribPath.getValue(exprs[i]);
2109
+ }
2110
+ else { // PathToAttribs
2111
+ let val = attribPath.getValue(exprs[i]);
2112
+ if (typeof val === 'object')
2113
+ for (let name in val)
2114
+ attribs[Util.dashesToCamel(name)] = val[name];
2115
+ else if (typeof val === 'string') {
2116
+ let attrs = val.split(/([\w-]+\s*=\s*(?:"[^"]*"|'[^']*'|\S+))/g)
2117
+ .map(text => text.trim())
2118
+ .filter(text => text.length);
2119
+
2120
+ for (let attr of attrs) {
2121
+ let [name, value] = attr.split(/\s*=\s*/); // split on first equals.
2122
+ value = (value || '').replace(/^(['"])(.*)\1$/, '$2'); // trim value quotes if they match.
2123
+ attribs[Util.dashesToCamel(name)] = value;
2124
+ }
2125
+ }
2126
+ }
2093
2127
  }
2094
2128
 
2095
2129
  // 2. Instantiate component on first time.
@@ -2281,13 +2315,15 @@ class Shell {
2281
2315
 
2282
2316
  for (let attr of [...node.attributes]) { // Copy the attributes array b/c we remove attributes with placeholders as we go.
2283
2317
 
2284
- // Whole attribute
2318
+ // One or more whole attributes
2285
2319
  let matches = attr.name.match(/^[\ue000-\uf8ff]$/);
2286
2320
  if (matches) {
2287
2321
  let path = new PathToAttribs(null, node);
2288
2322
  this.paths.push(path);
2289
- if (isComponent)
2323
+ if (isComponent) {
2324
+ path.isComponentAttrib = true;
2290
2325
  componentAttribPaths.push(path);
2326
+ }
2291
2327
 
2292
2328
  placeholdersUsed ++;
2293
2329
  node.removeAttribute(matches[0]); // TODO: Is this necessary?
@@ -2310,7 +2346,12 @@ class Shell {
2310
2346
  }
2311
2347
 
2312
2348
  placeholdersUsed += parts.length - 1;
2313
- node.setAttribute(attr.name, parts.join(''));
2349
+ try {
2350
+ node.setAttribute(attr.name, parts.join(''));
2351
+ }
2352
+ catch (e) {
2353
+ throw new Error(`Error setting attribute "${attr.name}" on node <${node.tagName}>: ${e.message}`);
2354
+ }
2314
2355
  }
2315
2356
  }
2316
2357
  }
@@ -3018,6 +3059,9 @@ class Template {
3018
3059
  /** @type {Array} Used for toJSON() and getObjectHash(). Stores values used to quickly create a string hash of this template. */
3019
3060
  hashedFields;
3020
3061
 
3062
+ closeKey;
3063
+ exactKey;
3064
+
3021
3065
  isText;
3022
3066
 
3023
3067
  /**
@@ -3730,7 +3774,145 @@ class Solarite extends HTMLElementAutoDefine {
3730
3774
  }
3731
3775
  return result;
3732
3776
  }
3777
+
3778
+
3779
+ // TODO: Do we want to use this to get the tag name from the render() function, instead of having the user define it?
3780
+ /**
3781
+ * Get the tag name for a class, as defined by the tag used in render().
3782
+ *
3783
+ * This will parse the JavaScript code of the render() function to find the tag name.
3784
+ * It will itarage every character, keeping track of quotes and comments so it can
3785
+ * skip them until it finds the tag name passed to h(this)`<tagname>` inside the render() function.
3786
+ *
3787
+ * */
3788
+ /*
3789
+ static getTagName(Class) {
3790
+ let code = Class.prototype.render.toString();
3791
+ let i = 0;
3792
+ while (i < code.length) {
3793
+ let char = code[i];
3794
+ let next = code[i + 1];
3795
+
3796
+ // Skip single line comments
3797
+ if (char === '/' && next === '/') {
3798
+ i = code.indexOf('\n', i);
3799
+ if (i === -1) break;
3800
+ continue;
3801
+ }
3802
+ // Skip multi-line comments
3803
+ if (char === '/' && next === '*') {
3804
+ i = code.indexOf('*'+'/', i + 2);
3805
+ if (i === -1) break;
3806
+ i += 2;
3807
+ continue;
3808
+ }
3809
+ // Skip strings and template literals
3810
+ if (char === "'" || char === '"' || char === '`') {
3811
+ let quote = char;
3812
+ i++;
3813
+ while (i < code.length) {
3814
+ if (code[i] === '\\') i += 2;
3815
+ else if (code[i] === quote) { i++; break; }
3816
+ else i++;
3817
+ }
3818
+ continue;
3819
+ }
3820
+ // Skip regex literals (simple heuristic)
3821
+ if (char === '/') {
3822
+ let prev = code.slice(Math.max(0, i - 10), i).trim();
3823
+ // If / is preceded by something that indicates an operator or start of expression
3824
+ if (/[=(,;:[!&|?]$|return$|yield$|case$/.test(prev)) {
3825
+ i++;
3826
+ while (i < code.length) {
3827
+ if (code[i] === '\\') i += 2;
3828
+ else if (code[i] === '[') { // Skip character classes
3829
+ i++;
3830
+ while (i < code.length && code[i] !== ']') {
3831
+ if (code[i] === '\\') i += 2;
3832
+ else i++;
3833
+ }
3834
+ i++;
3835
+ }
3836
+ else if (code[i] === '/') { i++; break; }
3837
+ else i++;
3838
+ }
3839
+ continue;
3840
+ }
3841
+ }
3842
+ // Check for h(this)`
3843
+ if (char === 'h' && code.slice(i, i + 8) === 'h(this)`') {
3844
+ i += 8;
3845
+ // We are now inside the template literal.
3846
+ // Skip whitespace and HTML comments
3847
+ while (i < code.length) {
3848
+ // Skip JS template literal end (shouldn't happen before tag, but for safety)
3849
+ if (code[i] === '`') return null;
3850
+
3851
+ // Skip whitespace
3852
+ if (/\s/.test(code[i])) { i++; continue; }
3853
+
3854
+ // Skip HTML comments <!-- ... -->
3855
+ if (code.slice(i, i + 4) === '<!--') {
3856
+ i = code.indexOf('-->', i + 4);
3857
+ if (i === -1) return null;
3858
+ i += 3;
3859
+ continue;
3860
+ }
3861
+
3862
+ // Find the first tag
3863
+ if (code[i] === '<') {
3864
+ let start = ++i;
3865
+ while (i < code.length && /[a-zA-Z0-9-]/.test(code[i])) i++;
3866
+ return code.slice(start, i);
3867
+ }
3868
+
3869
+ // If we encounter anything else (like text before a tag),
3870
+ // we can keep looking or return null depending on how strict we want to be.
3871
+ // For now, let's just skip non-tag characters.
3872
+ i++;
3873
+ }
3874
+ }
3875
+ i++;
3876
+ }
3877
+ return null;
3878
+ }
3879
+ */
3880
+ }
3881
+
3882
+
3883
+ /**
3884
+ * Assign fields from `src` to `dest` if they exist in `dest` and their names are not in the `ignore` list.
3885
+ * When a value in `src` is a string and the existing value in `dest` is a boolean, number, or Date,
3886
+ * it will be converted to that type.
3887
+ * This is often used in class constructors that accept an object of arguments.
3888
+ * @param {object} dest
3889
+ * @param {?object} src
3890
+ * @param {string[]} [ignore=[]] */
3891
+ function assignFields(dest, src, ignore=[]) {
3892
+ for (let name in src || {}) {
3893
+ if (name in dest && !ignore.includes(name)) {
3894
+ const descriptor = Object.getOwnPropertyDescriptor(dest, name)
3895
+ || Object.getOwnPropertyDescriptor(Object.getPrototypeOf(dest), name); // Also find (parent?) setters. Is this necssary?
3896
+ if (!descriptor || descriptor.writable || descriptor.set) {
3897
+ let srcVal = src[name];
3898
+ let destVal = dest[name];
3899
+ if (typeof src[name] === 'string') {
3900
+ if (typeof destVal === 'boolean') // empty string (when an attribute is present with no value) is true
3901
+ dest[name] = ![false, 'false', 0, '0'].includes(srcVal);
3902
+ else if (typeof destVal === 'number')
3903
+ dest[name] = Number(srcVal);
3904
+ else if (destVal instanceof Date) {
3905
+ dest[name] = new Date(srcVal); // TODO: read it as UTC 0 by default.
3906
+ }
3907
+ else
3908
+ dest[name] = srcVal;
3909
+ }
3910
+ else
3911
+ dest[name] = srcVal;
3912
+ }
3913
+ }
3914
+ }
3733
3915
  }
3734
3916
 
3735
3917
  export default h;
3736
- export { ArgType, Globals$1 as Globals, HtmlParser, NodeGroup, Shell, Solarite, Util as SolariteUtil, Template, delve, getArg, h, h as r, setArgs, t, toEl };
3918
+ export { ArgType, Globals$1 as Globals, HtmlParser, NodeGroup, Shell, Solarite, Util as SolariteUtil, Template, assignFields, delve, getArg, h, h as r, setArgs, t, toEl };
package/dist/Solarite.js CHANGED
@@ -774,6 +774,9 @@ class PathToAttribValue extends Path {
774
774
  * @type {?string[]} Used only if type=AttribType.Value. If null, use one expr to set the whole attribute value. */
775
775
  attrValue;
776
776
 
777
+ /** @type {boolean} Provides value for attribute on a component. */
778
+ isComponent;
779
+
777
780
  isHtmlProperty;
778
781
 
779
782
  constructor(nodeBefore, nodeMarker, attrName=null, attrValue=null) {
@@ -1030,6 +1033,14 @@ class PathToEvent extends PathToAttribValue {
1030
1033
  apply(exprs) {
1031
1034
 
1032
1035
 
1036
+ // Tested by Solariate.events.classicWithExpr
1037
+ // We have expressions within a string attribute value that's not a Solarite event. E.g.
1038
+ // <div onclick="alert(${1});"
1039
+ if (this.attrValue?.length > 1) {
1040
+ super.apply(exprs);
1041
+ return;
1042
+ }
1043
+
1033
1044
  // Don't bind events to component placeholders.
1034
1045
  // PathToComponent will do the binding later when it instantiates the component.
1035
1046
  if (this.isComponentAttrib && this.nodeMarker.tagName.endsWith('-SOLARITE-PLACEHOLDER'))
@@ -1070,6 +1081,9 @@ class PathToAttribs extends Path {
1070
1081
  * @type {Set<string>} Used for type=AttribType.Multiple to remember the attributes that were added. */
1071
1082
  attrNames;
1072
1083
 
1084
+ /** @type {boolean} Provides one or more attributes on a component. */
1085
+ isComponent;
1086
+
1073
1087
  constructor(nodeBefore, nodeMarker) {
1074
1088
  super(null, null);
1075
1089
  this.nodeMarker = nodeMarker;
@@ -1134,6 +1148,7 @@ class PathToAttribs extends Path {
1134
1148
 
1135
1149
 
1136
1150
  getExpressionCount() { return 1 }
1151
+ getValue(exprs) { return exprs[0]; }
1137
1152
  }
1138
1153
 
1139
1154
  /**
@@ -1936,8 +1951,27 @@ class PathToComponent extends Path {
1936
1951
  // 1. Attributes
1937
1952
  let attribs = Util.attribsToObject(el, '_is');
1938
1953
  for (let i=0, attribPath; attribPath = this.attribPaths[i]; i++) {
1939
- let name = Util.dashesToCamel(attribPath.attrName);
1940
- attribs[name] = attribPath.getValue(exprs[i]);
1954
+ if (attribPath instanceof PathToAttribValue) {
1955
+ let name = Util.dashesToCamel(attribPath.attrName);
1956
+ attribs[name] = attribPath.getValue(exprs[i]);
1957
+ }
1958
+ else { // PathToAttribs
1959
+ let val = attribPath.getValue(exprs[i]);
1960
+ if (typeof val === 'object')
1961
+ for (let name in val)
1962
+ attribs[Util.dashesToCamel(name)] = val[name];
1963
+ else if (typeof val === 'string') {
1964
+ let attrs = val.split(/([\w-]+\s*=\s*(?:"[^"]*"|'[^']*'|\S+))/g)
1965
+ .map(text => text.trim())
1966
+ .filter(text => text.length);
1967
+
1968
+ for (let attr of attrs) {
1969
+ let [name, value] = attr.split(/\s*=\s*/); // split on first equals.
1970
+ value = (value || '').replace(/^(['"])(.*)\1$/, '$2'); // trim value quotes if they match.
1971
+ attribs[Util.dashesToCamel(name)] = value;
1972
+ }
1973
+ }
1974
+ }
1941
1975
  }
1942
1976
 
1943
1977
  // 2. Instantiate component on first time.
@@ -2115,13 +2149,15 @@ class Shell {
2115
2149
 
2116
2150
  for (let attr of [...node.attributes]) { // Copy the attributes array b/c we remove attributes with placeholders as we go.
2117
2151
 
2118
- // Whole attribute
2152
+ // One or more whole attributes
2119
2153
  let matches = attr.name.match(/^[\ue000-\uf8ff]$/);
2120
2154
  if (matches) {
2121
2155
  let path = new PathToAttribs(null, node);
2122
2156
  this.paths.push(path);
2123
- if (isComponent)
2157
+ if (isComponent) {
2158
+ path.isComponentAttrib = true;
2124
2159
  componentAttribPaths.push(path);
2160
+ }
2125
2161
 
2126
2162
  placeholdersUsed ++;
2127
2163
  node.removeAttribute(matches[0]); // TODO: Is this necessary?
@@ -2144,7 +2180,12 @@ class Shell {
2144
2180
  }
2145
2181
 
2146
2182
  placeholdersUsed += parts.length - 1;
2147
- node.setAttribute(attr.name, parts.join(''));
2183
+ try {
2184
+ node.setAttribute(attr.name, parts.join(''));
2185
+ }
2186
+ catch (e) {
2187
+ throw new Error(`Error setting attribute "${attr.name}" on node <${node.tagName}>: ${e.message}`);
2188
+ }
2148
2189
  }
2149
2190
  }
2150
2191
  }
@@ -2773,6 +2814,9 @@ class Template {
2773
2814
  /** @type {Array} Used for toJSON() and getObjectHash(). Stores values used to quickly create a string hash of this template. */
2774
2815
  hashedFields;
2775
2816
 
2817
+ closeKey;
2818
+ exactKey;
2819
+
2776
2820
  isText;
2777
2821
 
2778
2822
  /**
@@ -3476,7 +3520,145 @@ class Solarite extends HTMLElementAutoDefine {
3476
3520
  }
3477
3521
  return result;
3478
3522
  }
3523
+
3524
+
3525
+ // TODO: Do we want to use this to get the tag name from the render() function, instead of having the user define it?
3526
+ /**
3527
+ * Get the tag name for a class, as defined by the tag used in render().
3528
+ *
3529
+ * This will parse the JavaScript code of the render() function to find the tag name.
3530
+ * It will itarage every character, keeping track of quotes and comments so it can
3531
+ * skip them until it finds the tag name passed to h(this)`<tagname>` inside the render() function.
3532
+ *
3533
+ * */
3534
+ /*
3535
+ static getTagName(Class) {
3536
+ let code = Class.prototype.render.toString();
3537
+ let i = 0;
3538
+ while (i < code.length) {
3539
+ let char = code[i];
3540
+ let next = code[i + 1];
3541
+
3542
+ // Skip single line comments
3543
+ if (char === '/' && next === '/') {
3544
+ i = code.indexOf('\n', i);
3545
+ if (i === -1) break;
3546
+ continue;
3547
+ }
3548
+ // Skip multi-line comments
3549
+ if (char === '/' && next === '*') {
3550
+ i = code.indexOf('*'+'/', i + 2);
3551
+ if (i === -1) break;
3552
+ i += 2;
3553
+ continue;
3554
+ }
3555
+ // Skip strings and template literals
3556
+ if (char === "'" || char === '"' || char === '`') {
3557
+ let quote = char;
3558
+ i++;
3559
+ while (i < code.length) {
3560
+ if (code[i] === '\\') i += 2;
3561
+ else if (code[i] === quote) { i++; break; }
3562
+ else i++;
3563
+ }
3564
+ continue;
3565
+ }
3566
+ // Skip regex literals (simple heuristic)
3567
+ if (char === '/') {
3568
+ let prev = code.slice(Math.max(0, i - 10), i).trim();
3569
+ // If / is preceded by something that indicates an operator or start of expression
3570
+ if (/[=(,;:[!&|?]$|return$|yield$|case$/.test(prev)) {
3571
+ i++;
3572
+ while (i < code.length) {
3573
+ if (code[i] === '\\') i += 2;
3574
+ else if (code[i] === '[') { // Skip character classes
3575
+ i++;
3576
+ while (i < code.length && code[i] !== ']') {
3577
+ if (code[i] === '\\') i += 2;
3578
+ else i++;
3579
+ }
3580
+ i++;
3581
+ }
3582
+ else if (code[i] === '/') { i++; break; }
3583
+ else i++;
3584
+ }
3585
+ continue;
3586
+ }
3587
+ }
3588
+ // Check for h(this)`
3589
+ if (char === 'h' && code.slice(i, i + 8) === 'h(this)`') {
3590
+ i += 8;
3591
+ // We are now inside the template literal.
3592
+ // Skip whitespace and HTML comments
3593
+ while (i < code.length) {
3594
+ // Skip JS template literal end (shouldn't happen before tag, but for safety)
3595
+ if (code[i] === '`') return null;
3596
+
3597
+ // Skip whitespace
3598
+ if (/\s/.test(code[i])) { i++; continue; }
3599
+
3600
+ // Skip HTML comments <!-- ... -->
3601
+ if (code.slice(i, i + 4) === '<!--') {
3602
+ i = code.indexOf('-->', i + 4);
3603
+ if (i === -1) return null;
3604
+ i += 3;
3605
+ continue;
3606
+ }
3607
+
3608
+ // Find the first tag
3609
+ if (code[i] === '<') {
3610
+ let start = ++i;
3611
+ while (i < code.length && /[a-zA-Z0-9-]/.test(code[i])) i++;
3612
+ return code.slice(start, i);
3613
+ }
3614
+
3615
+ // If we encounter anything else (like text before a tag),
3616
+ // we can keep looking or return null depending on how strict we want to be.
3617
+ // For now, let's just skip non-tag characters.
3618
+ i++;
3619
+ }
3620
+ }
3621
+ i++;
3622
+ }
3623
+ return null;
3624
+ }
3625
+ */
3626
+ }
3627
+
3628
+
3629
+ /**
3630
+ * Assign fields from `src` to `dest` if they exist in `dest` and their names are not in the `ignore` list.
3631
+ * When a value in `src` is a string and the existing value in `dest` is a boolean, number, or Date,
3632
+ * it will be converted to that type.
3633
+ * This is often used in class constructors that accept an object of arguments.
3634
+ * @param {object} dest
3635
+ * @param {?object} src
3636
+ * @param {string[]} [ignore=[]] */
3637
+ function assignFields(dest, src, ignore=[]) {
3638
+ for (let name in src || {}) {
3639
+ if (name in dest && !ignore.includes(name)) {
3640
+ const descriptor = Object.getOwnPropertyDescriptor(dest, name)
3641
+ || Object.getOwnPropertyDescriptor(Object.getPrototypeOf(dest), name); // Also find (parent?) setters. Is this necssary?
3642
+ if (!descriptor || descriptor.writable || descriptor.set) {
3643
+ let srcVal = src[name];
3644
+ let destVal = dest[name];
3645
+ if (typeof src[name] === 'string') {
3646
+ if (typeof destVal === 'boolean') // empty string (when an attribute is present with no value) is true
3647
+ dest[name] = ![false, 'false', 0, '0'].includes(srcVal);
3648
+ else if (typeof destVal === 'number')
3649
+ dest[name] = Number(srcVal);
3650
+ else if (destVal instanceof Date) {
3651
+ dest[name] = new Date(srcVal); // TODO: read it as UTC 0 by default.
3652
+ }
3653
+ else
3654
+ dest[name] = srcVal;
3655
+ }
3656
+ else
3657
+ dest[name] = srcVal;
3658
+ }
3659
+ }
3660
+ }
3479
3661
  }
3480
3662
 
3481
3663
  export default h;
3482
- export { ArgType, Globals$1 as Globals, HtmlParser, NodeGroup, Shell, Solarite, Util as SolariteUtil, Template, delve, getArg, h, h as r, setArgs, t, toEl };
3664
+ export { ArgType, Globals$1 as Globals, HtmlParser, NodeGroup, Shell, Solarite, Util as SolariteUtil, Template, assignFields, delve, getArg, h, h as r, setArgs, t, toEl };
@@ -1,4 +1,4 @@
1
- // Version 0.5.0
1
+ // Version 0.5.2
2
2
  // License: MIT
3
3
  // http://vorticode.github.io/solarite
4
- function assert(t){}let lastObjectId=1,objectIds=new WeakMap;function getObjectId(t){let e=objectIds.get(t);return void 0===e&&(e="~@"+lastObjectId++,objectIds.set(t,e)),e}let isHashing=!0;function toJSON(){return isHashing?getObjectId(this):this}function getObjectHash(t){Node.prototype.toJSON!==toJSON&&(Node.prototype.toJSON=toJSON,(()=>{}).toJSON!==toJSON&&(Function.prototype.toJSON=toJSON)),isHashing=!0;try{return JSON.stringify(t)}catch(e){return getObjectHashCircular(t)}finally{isHashing=!1}}function getObjectHashCircular(t){const e=new Set;return JSON.stringify(t,((t,l)=>{if("object"==typeof l&&null!==l){if(e.has(l))return getObjectId(l);e.add(l)}return l}))}var Globals;function reset(){Globals={connected:new WeakSet,t:null,l:null,div:document.createElement("div"),i:document,o:{},h:{},u:new WeakMap,p:new WeakMap,m:new WeakMap,$:new WeakSet,v:new WeakMap,reset}}reset();var Globals$1=Globals;function delve(t,e,l=d){let s=l!==d,i=e.length;if(!t&&!s&&i)return;let r=0;for(let o of e){if(void 0===t[o]){if(!s)return;i-1>r&&(t[o]=(e[r+1]+"").match(/^\d+$/)?[]:{})}s&&r===i-1&&(t[o]=l),t=t[o],r++}return t}let d={},Util={T(t,e){let l=t.length;if(l!==e.length)return!1;for(let s=0;l>s;s++)if(t[s]!==e[s])return!1;return!0},P(t,e=null){let l={};for(let s of t.attributes)s.name!==e&&(l[Util.G(s.name)]=s.value);return l},A(t,e){let l=e.getAttribute("data-id")||e.getAttribute("id");if(l){if(t[l]&&!t[l]?.nodeType)throw Error(`${t.constructor.name}.${l} already has a value. Can't set it as a reference to <${e.tagName.toLowerCase()} id="${l}">`);delve(t,l.split(/\./g),e)}},N(t,e){let l,s,i=e.tagName.toLowerCase();if(t.hasAttribute("global")||t.hasAttribute("data-global")){l=i,s="";let r=Globals$1.i||e.ownerDocument||document;r.head.querySelector(`style[data-style="${l}"]`)?t.remove():(r.head.append(t),t.setAttribute("data-style",l))}else{let t=e.getAttribute("data-style");t||(e.constructor.S||(e.constructor.S=1),t=e.constructor.S++,e.setAttribute("data-style",t)),s=`[data-style="${t}"]`}for(let e of t.childNodes)if(3===e.nodeType){let t=e.textContent,l=t.replace(/:host(?=[^a-z0-9_])/gi,`${i}${s}`);t!==l&&(e.textContent=l)}},O:t=>(t=(t=(t=t.replace(/([a-z0-9])([A-Z])/g,"$1-$2")).replace(/([A-Z])([A-Z][a-z])/g,"$1-$2")).replace(/([a-zA-Z])([0-9])/g,"$1-$2")).toLowerCase(),G:t=>t.replace(/-([a-z])/g,(t=>t[1].toUpperCase())),H(t,e){customElements[getName](t)||((e=e||Util.O(t.name)).includes("-")||(e+="-element"),customElements[define](e,t))},C:t=>"checkbox"===t.type||"radio"===t.type?t.checked:"file"===t.type?[...t.files]:"number"===t.type||"range"===t.type?t.valueAsNumber:"date"===t.type||"time"===t.type||"datetime-local"===t.type?t.valueAsDate:"select-multiple"===t.type?[...t.selectedOptions].map((t=>t.value)):t.hasAttribute("contenteditable")?t.innerHTML:t.value,j:t=>t.startsWith("on")&&t in Globals$1.div,U(t,e){let l=t.tagName+"."+e,s=Globals$1.h[l];if(void 0===s){let i=Object.getPrototypeOf(t);for(;i;){const t=i.constructor.name;if(t.startsWith("HTML")&&t.endsWith("Element"))break;i=Object.getPrototypeOf(i)}Globals$1.h[l]=s=!!i&&!!Object.getOwnPropertyDescriptor(i,e)?.set}return s},M:t=>Array.isArray(t)&&t.length>=2&&("object"==typeof t[0]||void 0===t[0])&&!t.slice(1).find((t=>"string"!=typeof t&&"number"!=typeof t)),L:t=>void 0===t||!1===t||null===t,I:t=>"function"==typeof t?Util.I(t()):t instanceof Date?t.toISOString().replace(/T/," "):Array.isArray(t)||"object"==typeof t?"":t,R(t,e,l){let s=t.get(e);s?s.push(l):(s=[l],t.set(e,s))},k(t){Globals$1.i.createDocumentFragment().append(...t)},F(t){const e=t=>t.nodeType!==Node.ELEMENT_NODE&&(t.nodeType!==Node.TEXT_NODE||""===t.textContent.trim()),l=[...t];for(;l.length>0&&e(l[0]);)l.shift();for(;l.length>0&&e(l[l.length-1]);)l.pop();return l}},define="define",getName="getName";class Path{J;V;D;W=[];Z;_;B;K;constructor(t,e){this.J=t,this.V=e}apply(t,e=!0){}q(){return 1}X(t,e){let l=t,s=this.B,i=s.length-e;for(let t=i-1;t>0;t--)l=l.childNodes[s[t]];return i?l.childNodes[s[0]]:t}clone(t,e=0){let l,s,i=t,r=this.B,o=r.length-e;for(let t=o-1;t>0;t--)i=i.childNodes[r[t]];let n=i.childNodes;l=o?n[r[0]]:t,this.J&&(s=n[this._]);let a=new this.constructor(s,l,this.attrName,this.Y);return a.tt=this.tt,a.et=this.et,a}lt(){return[this.V]}static get(t){let e=[];for(;;){let l=t.parentNode;if(!l)break;e.push([].indexOf.call(t.parentNode.childNodes,t)),t=l}return e}static resolve(t,e){for(let l=e.length-1;l>=0;l--)t=t.childNodes[e[l]];return t}}class HtmlParser{constructor(){this.st={context:HtmlParser.Text,quote:null,buffer:"",it:null},this.state={...this.st}}reset(){return this.state={...this.st},this.state.context}parse(t,e=null){if(null===t)return this.reset();for(let l=0;t.length>l;l++){const s=t[l];switch(this.state.context){case HtmlParser.Text:"<"===s&&t[l+1].match(/[/a-z!]/i)&&(e?.(t,l,this.state.context,HtmlParser.rt),this.state.context=HtmlParser.rt,this.state.buffer="");break;case HtmlParser.rt:if(">"===s)e?.(t,l+1,this.state.context,HtmlParser.Text),this.state.context=HtmlParser.Text,this.state.quote=null,this.state.buffer="";else{if(" "===s&&!this.state.buffer)continue;" "===s||"/"===s||"?"===s?this.state.buffer="":'"'===s||"'"===s||"="===s?(e?.(t,l,this.state.context,HtmlParser.ot),this.state.context=HtmlParser.ot,this.state.quote="="===s?null:s,this.state.buffer=""):this.state.buffer+=s}break;case HtmlParser.ot:this.state.quote||this.state.buffer.length||'"'!==s&&"'"!==s?s===this.state.quote||!this.state.quote&&this.state.buffer.length?(e?.(t,l,this.state.context,HtmlParser.rt),this.state.context=HtmlParser.rt,this.state.quote=null,this.state.buffer=""):this.state.quote||">"!==s?" "!==s&&(this.state.buffer+=s):(e?.(t,l+1,this.state.context,HtmlParser.Text),this.state.context=HtmlParser.Text,this.state.quote=null,this.state.buffer=""):this.state.quote=s}}return e?.(t,t.length,this.state.context,null),this.state.context}}HtmlParser.ot="Attribute",HtmlParser.Text="Text",HtmlParser.rt="Tag";class PathToAttribValue extends Path{attrName;Y;et;constructor(t,e,l=null,s=null){super(null,e),this.attrName=l,this.Y=s}apply(t){let e=this.V,l=t[0],s=this.Y;if(!s&&Util.M(l)){if(this.tt&&e.tagName.endsWith("-SOLARITE-PLACEHOLDER"))return;let[t,s]=[l[0],l.slice(1)];if(!t)throw Error(`Solarite cannot bind to <${e.tagName.toLowerCase()} ${this.attrName}=\${[${l.map((t=>t?`'${t}'`:t+"")).join(", ")}]}>.`);let i=delve(t,s);if("value"===this.attrName&&"select-multiple"===e.type&&Array.isArray(i)){let t=i.map((t=>t+""));for(let l of e.options)l.selected=t.includes(l.value)}else{const t=Util.L(i)?"":i;"value"===this.attrName&&e.hasAttribute("contenteditable")?t!==e.innerHTML&&(e.innerHTML=t):t!==e[this.attrName]&&(e[this.attrName]=t)}let r=()=>{let l="value"===this.attrName?Util.C(e):e[this.attrName];delve(t,s,l)};this.nt(e,this.D.getRootNode(),this.attrName,"input",r,[],!0)}else{let i=this.et;if(!s){if(Globals$1.t=this,"function"==typeof l){if(this.tt)return;this.K=l,l=l()}else l=Util.I(l);Globals$1.t=null}if(s||void 0!==l&&!1!==l&&null!==l)if(s||!0!==l){let r=s?this.ht(t):l;(i?e[this.attrName]:e.getAttribute(this.attrName))!==r&&(i?e[this.attrName]=r:"value"===this.attrName&&e.hasAttribute("contenteditable")&&(e.innerHTML=r),e.setAttribute(this.attrName,r))}else i&&(e[this.attrName]=!0),e.setAttribute(this.attrName,"");else i&&(e[this.attrName]=!1),e.removeAttribute(this.attrName)}}q(){return this.Y?this.Y.length-1:1}ht(t){if(!this.Y)return t[0];let e=[],l=this.Y;for(let s=0;l.length>s;s++)if(e.push(l[s]),l.length-1>s){Globals$1.t=this;let l=Util.I(t[s]);Globals$1.t=null,Util.L(l)||e.push(l)}return e.join("")}nt(t,e,l,s,i,r,o=!1){let n=Globals$1.u.get(t);n||(n={[l]:[,,,]},Globals$1.u.set(t,n));let a=n[l];if(a||(n[l]=a=[,,,]),"function"!=typeof i)throw Error(`Solarite cannot bind to <${t.tagName.toLowerCase()} ${this.attrName}=\${${i}}> because it's not a function.`);if(a[0]!==i){let[l,r,n]=a;l&&t.removeEventListener(s,r,o);let h=i,f=l=>h.call(e,...a[2],l,t);a[0]=h,a[1]=f,t.addEventListener(s,f,o)}n[l][2]=r}}class PathToEvent extends PathToAttribValue{constructor(t,e,l=null,s=null){super(null,e,l,s)}apply(t){if(this.tt&&this.V.tagName.endsWith("-SOLARITE-PLACEHOLDER"))return;let e,l=t[0],s=this.D.ft.root,i=this.V,r=this.attrName.slice(2),o=[];if(Array.isArray(l)&&"function"==typeof l[0])e=l[0],o=l.slice(1);else{if("function"!=typeof l)throw Error(`Invalid event binding: <${i.tagName.toLowerCase()} ${this.attrName}=\${${JSON.stringify(l)}}>`);e=l}this.nt(i,s,r,r,e,o)}}class PathToAttribs extends Path{ut;constructor(t,e){super(null,null),this.V=e,this.ut=new Set}apply(t,e){let l=t[0],s=this.V;Array.isArray(l)&&(l=l.flat().join(" "));let i=this.ut;if(this.ut=new Set,l)if("function"==typeof l&&(Globals$1.t=this,this.K=l,l=l(),Globals$1.t=null),"object"==typeof l)for(let t in l){let e=l[t];void 0!==e&&!1!==e&&null!==e&&(s.setAttribute(t,e),this.ut.add(t))}else{let t=(l+"").split(/([\w-]+\s*=\s*(?:"[^"]*"|'[^']*'|\S+))/g).map((t=>t.trim())).filter((t=>t.length));for(let e of t){let[t,l]=e.split(/\s*=\s*/);l=(l||"").replace(/^(['"])(.*)\1$/,"$2"),s.setAttribute(t,l),this.ut.add(t)}}for(let t of i)this.ut.has(t)||s.removeAttribute(t)}q(){return 1}}const udomdiff=(t,e,l,s)=>{const i=l.length;let r=e.length,o=i,n=0,a=0,h=null;for(;r>n||o>a;)if(r===n){const e=i>o?a?l[a-1].nextSibling:l[o-a]:s;for(;o>a;){let s=l[a++];t.insertBefore(s,e)}}else if(o===a)for(;r>n;){let l=e[n];h&&h.has(l)||t.removeChild(l),n++}else if(e[n]===l[a])n++,a++;else if(e[r-1]===l[o-1])r--,o--;else if(e[n]===l[o-1]&&l[a]===e[r-1]){const s=e[--r].nextSibling;let i=l[a++],h=e[n++];t.insertBefore(i,h.nextSibling);let f=l[--o];t.insertBefore(f,s),e[r]=l[o]}else{if(!h){h=new Map;let t=a;for(;o>t;)h.set(l[t],t++)}if(h.has(e[n])){const s=h.get(e[n]);if(s>a&&o>s){let i=n,f=1;for(;++i<r&&o>i&&h.get(e[i])===s+f;)f++;if(f>s-a){const i=e[n];for(;s>a;){let e=l[a++];t.insertBefore(e,i)}}else{let s=e[n++],i=l[a++];t.replaceChild(i,s)}}else n++}else{let l=e[n++];t.removeChild(l)}}return l};class MultiValueMap{data={};add(t,e){let l=this.data,s=l[t];s||(s=new Set,l[t]=s),s.add(e)}ct(){for(let t in this.data)return!0;return!1}getAll(t){return this.data[t]||[]}delete(t,e=void 0){let l,s=this.data,i=s[t];if(i)return void 0===e?([l]=i,i.delete(l)):(i.delete(e),l=e),0===i.size&&delete s[t],l}dt(t){let e,l=this.data,s=l[t];if(s)return[e]=s,s.delete(e),0===s.size&&delete l[t],e}bt(t,e){let l,s=this.data,i=s[t];if(i)return i.delete(e),l=e,0===i.size&&delete s[t],l}yt(t){let e=this.data,l=[];for(let s in e)e[s].has(t)&&l.push(s);return l}}class PathToNodes extends Path{gt;$t=[];Et=new MultiValueMap;vt=new MultiValueMap;constructor(t,e){super(t,e)}apply(t,e=!0){let l=this,s=t[0];e&&l.Tt();let i=[],r=l.W,o=[];l.W=[],l.Pt(s,i,o);let n=!1;if(o.length){for(let[t,e]of o){let s=l.Gt(i[t],!1),r=s.lt();1===r.length?i[t]=r[0]:(i[t]=r,n=!0),l.W[e]=s}n&&(i=i.flat())}let a=l.lt();if(!Util.T(a,i)){l.Z=i,this.D.wt&&this.D.wt.At(),a.length&&!i.length&&l.Nt()||udomdiff(l.V.parentNode,a,i,l.V);for(let t of r)t.St.parentNode||Util.k(t.lt())}}Pt(t,e,l){if(t instanceof Template){let s=this.Gt(t,!0);if(s){let l=s.lt();return e.push(...l),s.Ot(t.exprs,!1,!1),this.W.push(s),s}l.push([e.length,this.W.length]),e.push(t),this.W.push(null)}else t instanceof NodeList?e.push(...t):t?.nodeType?11===t?.nodeType?e.push(...t.childNodes):e.push(t):this.Ht(t,(t=>{this.Pt(t,e,l)}))}Ct(t){let e=Math.min(t.xt,t.items.length),l=t.xt-e;for(let l=0;e>l;l++){let e=this.W[t.index+l],s=(this.gt||this.K)(t.items[l]);this.Ht(s,(s=>{let i=this.Gt(s,!0);if(i&&i===e);else{i||(i=this.Gt(s,!1)),this.W[t.index+l]=i;let r=e.St;for(let t of i.lt())r.parentNode.insertBefore(t,r);i!==e&&Util.k(e.lt())}}))}if(l>0){for(let s=0;l>s;s++)Util.k(this.W[t.index+e+s].lt());this.W.splice(t.index+e,l)}else{let l=t.items.slice(e),s=this.W[t.index+e]?.St||this.V;for(let t=0;l.length>t;t++){let e=this.gt(l[t]),i=this.Gt(e,!0);i||(i=this.Gt(e,!1)),this.W.push(i);for(let t of i.lt())s.parentNode.insertBefore(t,s)}}this.Z=null}At(){let t=this,e=this.V.parentNode;for(;t&&t.V.parentNode===e;)t.Z=null,t=t.D?.wt}Nt(){let t=this.J.parentNode;return this.J===t.firstChild&&this.V===t.lastChild&&(t.innerHTML="",t.append(this.J,this.V),!0)}Ht(t,e){if(Array.isArray(t))for(let l of t)this.Ht(l,e);else if("function"==typeof t)Globals$1.t=this,this.K=t,t=t(),Globals$1.t=null,this.Ht(t,e);else if(t instanceof Template||t?.nodeType)e(t);else{void 0===t||!1===t||null===t?t="":"string"!=typeof t&&(t+="");let l=new Template([t],[]);l.jt=!0,this.Ht(l,e)}}Gt(t,e=!0){let l,s=this.Et;if(e){if(l=s.dt(t.Ut()),l||(s=this.vt,l=s.dt(t.Ut())),!l)return null;s.bt(t.Mt(),l)}else t.exprs.length&&(l=s.dt(t.Mt()),l||(s=this.vt,l=s.dt(t.Mt())),l&&(s.bt(l.Lt,l),l.Ot(t.exprs),l.Lt=t.Ut()));return l||(l=new NodeGroup(t,this),l.Ot(t.exprs),l.Lt=t.Ut()),this.$t.push(l),l}Tt(){let t=this.Et.data,e=this.vt.data;for(let l in t){let s=e[l];if(s)for(let e of t[l])s.add(e);else e[l]=t[l]}this.Et=new MultiValueMap;let l=this.Et;for(let t of this.$t)l.add(t.Lt,t),l.add(t.It,t);this.$t=[]}lt(){let t;if(t=this.Z,t)return t;t=[];let e=this.J.nextSibling,l=this.V;for(;e&&e!==l;)t.push(e),e=e.nextSibling;return this.Z=t,t}}class PathToComponent extends Path{Rt;constructor(t,e){super(null,e)}apply(t,e=!0,l=!0){let s=this.V,i=Util.P(s,"_is");for(let e,l=0;e=this.Rt[l];l++)i[Util.G(e.attrName)]=e.ht(t[l]);let r=s.getAttribute("_is");if(s.tagName.endsWith("-SOLARITE-PLACEHOLDER")||r){let e=(r||s.tagName.slice(0,-21)).toLowerCase(),o=customElements.get(e);if(!o)throw Error(`Must call customElements.define('${e}', Class) before using it.`);Globals$1.l=[...s.childNodes];let n=new o(i);r&&n.setAttribute("is",r);for(let t of s.attributes)"_is"!==t.name&&n.setAttribute(t.name,t.value);for(let t in i){let e=i[t],l=typeof e;"boolean"===l?!1!==e&&null!=e&&n.setAttribute(t,""):"string"!==l&&"number"!==l&&"bigint"!==l||n.setAttribute(t,e)}let a=n.getAttribute("data-id")||n.getAttribute("id");a&&delve(this.D.getRootNode(),a.split(/\./g),n);let h=this.D;this.V=n;for(let t of h.kt)t.V===s&&(t.V=n),t.J===s&&(t.J=n);h.St===s&&(h.St=n),h.Ft===s&&(h.Ft=n),"function"!=typeof n.render||Globals$1.$.has(n)||n.render(i,l);for(let e,l=0;e=this.Rt[l];l++)e.D=this.D,e.V=n,e.apply(t[l]);s.replaceWith(n)}else"function"==typeof s.render&&s.render(i,l);Globals$1.l=null}clone(t,e=0){let l=this.X(t,e),s=new PathToComponent(null,l);return s.Rt=this.Rt.map((l=>l.clone(t,e))),s}q(){return 0}}class Shell{fragment;kt=[];Jt=[];scripts=[];Vt=[];constructor(t=null){if(!t)return;if(1===t.length&&!t[0].match(/[<&]/))return void(this.fragment=Globals$1.i.createTextNode(t[0]));let e,l=Shell.Dt(t),s=Globals$1.i.createElement("template");l?s.innerHTML=l:s.content.append(Globals$1.i.createTextNode("")),this.fragment=s.content;let i=[],r=0;const o=Globals$1.i.createTreeWalker(this.fragment,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT|NodeFilter.SHOW_TEXT);for(;e=o.nextNode();)if(i.map((t=>t.remove())),i=[],1===e.nodeType){const t=e.hasAttribute("is"),l=t||e.tagName.includes("-"),s=[];for(let t of[...e.attributes]){let i=t.name.match(/^[\ue000-\uf8ff]$/);if(i){let t=new PathToAttribs(null,e);this.kt.push(t),l&&s.push(t),r++,e.removeAttribute(i[0])}else{let i=t.value.split(/[\ue000-\uf8ff]/g);if(i.length>1){let o=2!==i.length||i[0].length||i[1].length?i:null,n=Util.j(t.name)?new PathToEvent(null,e,t.name,o):new PathToAttribValue(null,e,t.name,o);n.et=Util.U(e,t.name),this.kt.push(n),l&&(n.tt=!0,s.push(n)),r+=i.length-1,e.setAttribute(t.name,i.join(""))}}}if(l){let l=new PathToComponent(null,e);l.Rt=s,this.kt.splice(this.kt.length-s.length,0,l),t&&(e.setAttribute("_is",e.getAttribute("is")),e.removeAttribute("is"))}}else if(8===e.nodeType&&"!✨!"===e.nodeValue){if(e?.parentNode?.closest&&e?.parentNode?.closest("[contenteditable]"))throw Error('Contenteditable can\'t have expressions inside them. Use <div contenteditable value="${...}"> instead.');let t,l=e.previousSibling;l||(l=Globals$1.i.createComment("Path:"+this.kt.length),e.parentNode.insertBefore(l,e)),!e.nextSibling||8===e.nextSibling.nodeType&&"!✨!"===e.nextSibling.textContent?(t=e,t.textContent="PathEnd:"+this.kt.length):(t=e.nextSibling,i.push(e));let s=new PathToNodes(l,t);this.kt.push(s),r++}else{if(3===e.nodeType&&"TEXTAREA"===e.parentNode?.tagName&&e.textContent.includes("\x3c!--!✨!--\x3e"))throw Error('Textarea can\'t have expressions inside them. Use <textarea value="${...}"> instead.');if(8===e.nodeType){let t=e.textContent.split(/[\ue000-\uf8ff]/g);for(let l=0;t.length-1>l;l++){let t=new Path(e.previousSibling,e);this.kt.push(t),r++}}else if(3===e.nodeType&&["SCRIPT","STYLE"].includes(e.parentNode?.nodeName)){let t=e.textContent.split(commentPlaceholder);if(t.length>1){let l=[];for(let s=0;t.length>s;s++){let i=Globals$1.i.createTextNode(t[s]);e.parentNode.insertBefore(i,e),s>0&&l.push(i)}for(let t,e=0;t=l[e];e++){let e=new PathToNodes(t.previousSibling,t);this.kt.push(e),r++}i.push(e)}}}if(i.map((t=>t.remove())),r!==t.length-1)throw Error("Could not parse expressions in template. Check for duplicate attributes or malformed html: "+t.join("${...}"));for(let t of this.kt)t.J&&(t._=[].indexOf.call(t.J.parentNode.childNodes,t.J)),t.B=Path.get(t.V);this.zt()}static Dt(t){let e=[],l=new HtmlParser;for(let s=0;t.length>s;s++){let i=0,r=l.parse(t[s],((t,l,s)=>{if(i!==l){let r=t.slice(i,l);s===HtmlParser.rt&&(r=r.replace(/^<\/?[a-z][a-z0-9]*-[a-z0-9-]+/i,(t=>t+"-SOLARITE-PLACEHOLDER"))),e.push(r)}i=l}));t.length-1>s&&e.push(r===HtmlParser.Text?commentPlaceholder:String.fromCharCode(attribPlaceholder+s))}return e.join("")}zt(){this.scripts=[].map.call(this.fragment.querySelectorAll("scripts"),(t=>Path.get(t))),this.Vt=[].map.call(this.fragment.querySelectorAll("style"),(t=>Path.get(t)));let t=this.fragment.querySelectorAll("[id],[data-id]");for(let e of t){let t=e.getAttribute("data-id")||e.getAttribute("id");if(Globals$1.div.hasOwnProperty(t))throw Error(`<${e.tagName.toLowerCase()} id="${t}"> can't override existing HTMLElement id property.`)}this.Jt=[].map.call(t,(t=>Path.get(t)))}static get(t){let e=Globals$1.v.get(t);return e||(e=new Shell(t),Globals$1.v.set(t,e)),e}}const commentPlaceholder="\x3c!--!✨!--\x3e",attribPlaceholder=57344;class NodeGroup{ft;wt;St;Ft;kt=[];Lt;It;Z;Vt;Wt;root;constructor(t,e=null,l=null,s=null){if(this.ft=e?.D?.ft||this,this.wt=e,this.Wt=t,this.It=t.Mt(),t.jt)this.St=this.Ft=Globals$1.i.createTextNode(t.html[0]);else{const e=Shell.get(t.html),i=e.fragment.cloneNode(!0);if(11===i.nodeType?(this.St=i.firstChild,this.Ft=i.lastChild):this.St=this.Ft=i,this instanceof RootNodeGroup){let t=0;if(this.options=s,i instanceof Text){if(!l)throw Error("Cannot create a standalone text node");this.root=l,i.nodeValue.length&&this.root.append(i)}else{if(l){let e;if(this.root=l,(Globals$1.l||l.childNodes.length)&&(e=Globals$1.i.createDocumentFragment(),e.append(...Globals$1.l||l.childNodes)),isReplaceEl(i,this.root.tagName)){this.root.append(...i.children[0].childNodes);for(let t of i.children[0].attributes)this.root.hasAttribute(t.name)||this.root.setAttribute(t.name,t.value);t=1}else 1===i.childNodes.length&&3===i.childNodes[0].nodeType&&""===i.childNodes[0].textContent||this.root.append(...i.childNodes);if(e){for(let t of l.querySelectorAll("slot[name]")){let l=t.getAttribute("name");if(l){let s=e.querySelectorAll(`[slot='${l}']`);t.append(...s)}}let t=l.querySelector("slot:not([name])");t?t.append(e):l.append(e)}}else{let e=getSingleEl(i);this.root=e||i,e&&(t=1)}this.Zt(this.root,e.kt,t),this._t(this.root,e,t)}this.St=this.Ft=this.root,Globals$1.p.set(this.root,this)}else e&&(e.kt.length&&this.Zt(i,e.kt),this._t(i,e))}}Ot(t,e=!0,l=!0){let s=this.kt,i=t.length,r=Array(s.length);for(let o,n=s.length-1;o=s[n];n--){if(0===n&&o instanceof PathToComponent&&o.V===this.getRootNode())continue;let s=o.q();if(r[n]=t.slice(i-s,i),i-=s,o instanceof PathToComponent){let t=r.slice(n+1,n+1+o.Rt.length);o.apply(t,!0,e)}else l&&o.apply(r[n])}l&&(this.Bt(),this.Z=null)}Kt(t){}lt(){let t=this.Z;if(t)return t;t=[];let e=this.St,l=this.Ft?.nextSibling;for(;e&&e!==l;)t.push(e),e=e.nextSibling;return this.Z=t,t}getRootNode(){return this.ft.root}qt(){return this.ft}Zt(t,e,l=0){let s=e.length;this.kt.length=s;for(let i=0;s>i;i++){let s=e[i].clone(t,l);s.D=this,this.kt[i]=s}}Bt(){if(this.Vt)for(let[t,e]of this.Vt)e!==t.textContent&&Util.N(t,this.qt().root)}_t(root,shell,pathOffset=0){let rootEl=this.ft.root;if(rootEl){let options=this.ft.options;if(!1!==options?.Jt)for(let t of shell.Jt){pathOffset&&(t=t.slice(0,-pathOffset));let e=Path.resolve(root,t);Util.A(rootEl,e)}if(!1!==options?.Vt){shell.Vt.length&&(this.Vt=new Map);for(let t of shell.Vt){pathOffset&&(t=t.slice(0,-pathOffset));let e=Path.resolve(root,t);1===rootEl.nodeType&&(Util.N(e,rootEl),this.Vt.set(e,e.textContent))}}if(!1!==options?.scripts)for(let path of shell.scripts){pathOffset&&(path=path.slice(0,-pathOffset));let script=Path.resolve(root,path);eval(script.textContent)}}}}function getSingleEl(t){let e=[];for(let l of t.childNodes)if(1===l.nodeType||3===l.nodeType&&l.textContent.trim().length){if(e.length)return null;e.push(l)}return e[0]}function isReplaceEl(t,e){return 1===t.children.length&&e.includes("-")&&t.children[0].tagName.replace("-SOLARITE-PLACEHOLDER","")===e}class RootNodeGroup extends NodeGroup{Xt}class Template{exprs=[];html=[];Yt;jt;constructor(t=[""],e=[]){this.html=t,this.exprs=e}toJSON(){return void 0===this.Yt&&(this.Yt=[getObjectId(this.html),this.exprs]),this.Yt}render(t=null,e={}){let l=t&&Globals$1.p.get(t);if(l||(l=new RootNodeGroup(this,null,t,e),t||(t=l.getRootNode()),Globals$1.p.set(t,l)),1!==this.html?.length||this.html[0]){let t=l.Lt,e=this.Ut();l.Ot(this.exprs,t!==e),l.Lt=e}else t.innerHTML="";return l.Xt=new Map,t}Ut(){return void 0===this.Lt&&(this.Lt=this.exprs.length?getObjectHash(this):this.html[0]),this.Lt}Mt(){return void 0===this.It&&(this.It=this.exprs.length?this.toJSON()[0]:this.html[0]),this.It}static Qt(t,e,l){const s=selfClosingTags.has(t.toLowerCase());let i=[],r=[],o="<"+t;if(e&&"object"==typeof e)for(let t in e){let l=e[t];"id"!==t&&"data-id"!==t?(o+=` ${t}=`,i.push(o),r.push(l),o=""):o+=` ${t}="${l}"`}if(!s){i.push(i.length>0?'"'===o?'">':">":o+">");for(let t of l)addChild(t,i,r)}return s?i.push(i.length>0?">":o+">"):i[i.length-1]+=`</${t}>`,new Template(i,r)}}const selfClosingTags=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),addChild=(t,e,l)=>{if(Array.isArray(t))for(let s of t)addChild(s,e,l);else{let s=!1;if(t instanceof Template)if(t.exprs.length>0)s=!0;else{const e=(t.html[0]||"").match(/^<([a-zA-Z][\w:-]*)/),l=e?e[1].toLowerCase():"";s=selfClosingTags.has(l)}if(s){e[e.length-1]+=t.html[0];for(let s=0;t.exprs.length>s;s++)l.push(t.exprs[s]),e.push(t.html[s+1]??"")}else l.push(t),e.push("")}};function toEl(t){if("string"==typeof t){let e=t;(e.match(/^\s^<\S+/)||e.match(/\S+>\s+$/))&&(e=e.trim());let l=Globals$1.i.createElement("template");l.innerHTML=e;let s=Util.F(l.content.childNodes);return 1===s.length?s[0]:l.content}if(t instanceof Template)return t.render();if(t&&"object"==typeof t){let e=t;if("Object"!==e.constructor.name)throw Error(`Solarate Web Component class ${e.constructor?.name} must extend HTMLElement.`);if(!Globals$1.m.has(e)){Globals$1.m.set(e,null),e[renderF]();let t=Globals$1.m.get(e);Globals$1.m.delete(e);for(let l in e)t[l]="function"==typeof e[l]?e[l].bind(t):e[l];return t}}throw Error("toEl() does not support argument of type: "+(t?typeof t:t))}let renderF="render";function h(t=void 0,...e){if(Array.isArray(arguments[0]))return new Template(arguments[0],e);if("string"==typeof arguments[0]||arguments[0]instanceof String){let t=arguments[0];if(!e.length||"object"!=typeof e[0]&&null!==e[0]){let e=t;return e.match(/^\s^</)&&(e=e.trim()),new Template([e],[])}{let l=t+"",s=e[0]||{},i=e.slice(1);return Template.Qt(l,s,i)}}if(arguments[0]instanceof HTMLElement||arguments[0]instanceof DocumentFragment){if(!(arguments[1]instanceof Template)){let t=arguments[0],e=arguments[1];t.shadowRoot&&(t.innerHTML="");let l=(l,...s)=>(Globals$1.$.add(t),new Template(l,s).render(t,e));return l}arguments[1].render(arguments[0],arguments[2])}else{if(!arguments.length)return(t,...e)=>toEl(h(t,...e));if("object"!=typeof arguments[0]||!Globals$1.m.has(arguments[0])){if(Util.L(arguments[0]))return new Template;throw Error("h() does not support argument of type: "+(arguments[0]?typeof arguments[0]:arguments[0]))}{let t=arguments[0];if("Object"!==t.constructor.name)throw Error(`Solarate Web Component class ${t.constructor?.name} must extend HTMLElement.`);if(!(arguments[1]instanceof Template))return((...e)=>{let l=h(...e).render();Globals$1.m.set(t,l)}).bind(t);{let e=arguments[1].render();Globals$1.m.set(t,e)}}}}function getArg(el,attributeName,defaultValue=void 0,type=ArgType.String){let val=defaultValue,attrVal=el.getAttribute(attributeName)||el.getAttribute(Util.O(attributeName));if(null!==attrVal&&(val=attrVal),Array.isArray(type))return type.includes(val)?val:void 0;if("function"==typeof type)return type.constructor?new type(val):type(val);if(type===ArgType.te){let t="string"==typeof val?val.toLowerCase():val;return!["false","0",!1,0,null,void 0,NaN].includes(t)&&(!(!["true",!0].includes(t)&&0===parseFloat(t))||void 0)}switch(type){case ArgType.ee:return parseInt(val);case ArgType.le:return parseFloat(val);case ArgType.String:return[void 0,null,!1].includes(val)?"":val+"";case ArgType.se:case ArgType.ie:if("string"!=typeof val||!val.length)return val;try{return type===ArgType.se?JSON.parse(val):eval(`(${val})`)}catch(t){return val}default:return val}}function setArgs(t,e,l){for(let s in e)this[s]=getArg(t,s,e[s],l[s]||ArgType.String)}var ArgType={te:"Bool",ee:"Int",le:"Float",String:"String",JSON:"Json",se:"Json",ie:"Eval"};function t(t){return new Template([t],[])}let HTMLElementAutoDefine=new Proxy(HTMLElement,{construct:(t,e,l)=>(Util.H(l),Reflect.construct(t,e,l))});class Solarite extends HTMLElementAutoDefine{constructor(t=null){if(super(),t){if("object"!=typeof t)throw Error("First argument to custom element constructor must be an object.");if(t&&!Object.keys(t).length){let e=Solarite.getAttribs(this);for(let l in e)t[l]=e[l]}}}render(){throw Error("render() is not defined for "+this.constructor.name)}renderFirstTime(){if(!Globals$1.$.has(this)){let t=Solarite.getAttribs(this);this.render(t)}}connectedCallback(){this.renderFirstTime()}static define(t=null){Util.H(this,t)}static getAttribs(t){let e=Util.P(t);for(let t in e){let l=e[t];l.startsWith("${")&&l.endsWith("}")&&(e[t]=JSON.parse(l.slice(2,-1)))}return e}}export default h;export{ArgType,Globals$1 as Globals,HtmlParser,NodeGroup,Shell,Solarite,Util as SolariteUtil,Template,delve,getArg,h,h as r,setArgs,t,toEl};
4
+ function assert(t){}let lastObjectId=1,objectIds=new WeakMap;function getObjectId(t){let e=objectIds.get(t);return void 0===e&&(e="~@"+lastObjectId++,objectIds.set(t,e)),e}let isHashing=!0;function toJSON(){return isHashing?getObjectId(this):this}function getObjectHash(t){Node.prototype.toJSON!==toJSON&&(Node.prototype.toJSON=toJSON,(()=>{}).toJSON!==toJSON&&(Function.prototype.toJSON=toJSON)),isHashing=!0;try{return JSON.stringify(t)}catch(e){return getObjectHashCircular(t)}finally{isHashing=!1}}function getObjectHashCircular(t){const e=new Set;return JSON.stringify(t,((t,l)=>{if("object"==typeof l&&null!==l){if(e.has(l))return getObjectId(l);e.add(l)}return l}))}var Globals;function reset(){Globals={connected:new WeakSet,t:null,l:null,div:document.createElement("div"),i:document,o:{},h:{},u:new WeakMap,p:new WeakMap,m:new WeakMap,$:new WeakSet,v:new WeakMap,reset}}reset();var Globals$1=Globals;function delve(t,e,l=d){let s=l!==d,i=e.length;if(!t&&!s&&i)return;let r=0;for(let o of e){if(void 0===t[o]){if(!s)return;i-1>r&&(t[o]=(e[r+1]+"").match(/^\d+$/)?[]:{})}s&&r===i-1&&(t[o]=l),t=t[o],r++}return t}let d={},Util={T(t,e){let l=t.length;if(l!==e.length)return!1;for(let s=0;l>s;s++)if(t[s]!==e[s])return!1;return!0},P(t,e=null){let l={};for(let s of t.attributes)s.name!==e&&(l[Util.G(s.name)]=s.value);return l},A(t,e){let l=e.getAttribute("data-id")||e.getAttribute("id");if(l){if(t[l]&&!t[l]?.nodeType)throw Error(`${t.constructor.name}.${l} already has a value. Can't set it as a reference to <${e.tagName.toLowerCase()} id="${l}">`);delve(t,l.split(/\./g),e)}},N(t,e){let l,s,i=e.tagName.toLowerCase();if(t.hasAttribute("global")||t.hasAttribute("data-global")){l=i,s="";let r=Globals$1.i||e.ownerDocument||document;r.head.querySelector(`style[data-style="${l}"]`)?t.remove():(r.head.append(t),t.setAttribute("data-style",l))}else{let t=e.getAttribute("data-style");t||(e.constructor.S||(e.constructor.S=1),t=e.constructor.S++,e.setAttribute("data-style",t)),s=`[data-style="${t}"]`}for(let e of t.childNodes)if(3===e.nodeType){let t=e.textContent,l=t.replace(/:host(?=[^a-z0-9_])/gi,`${i}${s}`);t!==l&&(e.textContent=l)}},O:t=>(t=(t=(t=t.replace(/([a-z0-9])([A-Z])/g,"$1-$2")).replace(/([A-Z])([A-Z][a-z])/g,"$1-$2")).replace(/([a-zA-Z])([0-9])/g,"$1-$2")).toLowerCase(),G:t=>t.replace(/-([a-z])/g,(t=>t[1].toUpperCase())),C(t,e){customElements[getName](t)||((e=e||Util.O(t.name)).includes("-")||(e+="-element"),customElements[define](e,t))},H:t=>"checkbox"===t.type||"radio"===t.type?t.checked:"file"===t.type?[...t.files]:"number"===t.type||"range"===t.type?t.valueAsNumber:"date"===t.type||"time"===t.type||"datetime-local"===t.type?t.valueAsDate:"select-multiple"===t.type?[...t.selectedOptions].map((t=>t.value)):t.hasAttribute("contenteditable")?t.innerHTML:t.value,j:t=>t.startsWith("on")&&t in Globals$1.div,U(t,e){let l=t.tagName+"."+e,s=Globals$1.h[l];if(void 0===s){let i=Object.getPrototypeOf(t);for(;i;){const t=i.constructor.name;if(t.startsWith("HTML")&&t.endsWith("Element"))break;i=Object.getPrototypeOf(i)}Globals$1.h[l]=s=!!i&&!!Object.getOwnPropertyDescriptor(i,e)?.set}return s},M:t=>Array.isArray(t)&&t.length>=2&&("object"==typeof t[0]||void 0===t[0])&&!t.slice(1).find((t=>"string"!=typeof t&&"number"!=typeof t)),L:t=>void 0===t||!1===t||null===t,I:t=>"function"==typeof t?Util.I(t()):t instanceof Date?t.toISOString().replace(/T/," "):Array.isArray(t)||"object"==typeof t?"":t,R(t,e,l){let s=t.get(e);s?s.push(l):(s=[l],t.set(e,s))},k(t){Globals$1.i.createDocumentFragment().append(...t)},F(t){const e=t=>t.nodeType!==Node.ELEMENT_NODE&&(t.nodeType!==Node.TEXT_NODE||""===t.textContent.trim()),l=[...t];for(;l.length>0&&e(l[0]);)l.shift();for(;l.length>0&&e(l[l.length-1]);)l.pop();return l}},define="define",getName="getName";class Path{V;J;D;W=[];K;Z;_;B;constructor(t,e){this.V=t,this.J=e}apply(t,e=!0){}q(){return 1}X(t,e){let l=t,s=this._,i=s.length-e;for(let t=i-1;t>0;t--)l=l.childNodes[s[t]];return i?l.childNodes[s[0]]:t}clone(t,e=0){let l,s,i=t,r=this._,o=r.length-e;for(let t=o-1;t>0;t--)i=i.childNodes[r[t]];let n=i.childNodes;l=o?n[r[0]]:t,this.V&&(s=n[this.Z]);let a=new this.constructor(s,l,this.attrName,this.Y);return a.tt=this.tt,a.et=this.et,a}lt(){return[this.J]}static get(t){let e=[];for(;;){let l=t.parentNode;if(!l)break;e.push([].indexOf.call(t.parentNode.childNodes,t)),t=l}return e}static resolve(t,e){for(let l=e.length-1;l>=0;l--)t=t.childNodes[e[l]];return t}}class HtmlParser{constructor(){this.st={context:HtmlParser.Text,quote:null,buffer:"",it:null},this.state={...this.st}}reset(){return this.state={...this.st},this.state.context}parse(t,e=null){if(null===t)return this.reset();for(let l=0;t.length>l;l++){const s=t[l];switch(this.state.context){case HtmlParser.Text:"<"===s&&t[l+1].match(/[/a-z!]/i)&&(e?.(t,l,this.state.context,HtmlParser.rt),this.state.context=HtmlParser.rt,this.state.buffer="");break;case HtmlParser.rt:if(">"===s)e?.(t,l+1,this.state.context,HtmlParser.Text),this.state.context=HtmlParser.Text,this.state.quote=null,this.state.buffer="";else{if(" "===s&&!this.state.buffer)continue;" "===s||"/"===s||"?"===s?this.state.buffer="":'"'===s||"'"===s||"="===s?(e?.(t,l,this.state.context,HtmlParser.ot),this.state.context=HtmlParser.ot,this.state.quote="="===s?null:s,this.state.buffer=""):this.state.buffer+=s}break;case HtmlParser.ot:this.state.quote||this.state.buffer.length||'"'!==s&&"'"!==s?s===this.state.quote||!this.state.quote&&this.state.buffer.length?(e?.(t,l,this.state.context,HtmlParser.rt),this.state.context=HtmlParser.rt,this.state.quote=null,this.state.buffer=""):this.state.quote||">"!==s?" "!==s&&(this.state.buffer+=s):(e?.(t,l+1,this.state.context,HtmlParser.Text),this.state.context=HtmlParser.Text,this.state.quote=null,this.state.buffer=""):this.state.quote=s}}return e?.(t,t.length,this.state.context,null),this.state.context}}HtmlParser.ot="Attribute",HtmlParser.Text="Text",HtmlParser.rt="Tag";class PathToAttribValue extends Path{attrName;Y;nt;et;constructor(t,e,l=null,s=null){super(null,e),this.attrName=l,this.Y=s}apply(t){let e=this.J,l=t[0],s=this.Y;if(!s&&Util.M(l)){if(this.tt&&e.tagName.endsWith("-SOLARITE-PLACEHOLDER"))return;let[t,s]=[l[0],l.slice(1)];if(!t)throw Error(`Solarite cannot bind to <${e.tagName.toLowerCase()} ${this.attrName}=\${[${l.map((t=>t?`'${t}'`:t+"")).join(", ")}]}>.`);let i=delve(t,s);if("value"===this.attrName&&"select-multiple"===e.type&&Array.isArray(i)){let t=i.map((t=>t+""));for(let l of e.options)l.selected=t.includes(l.value)}else{const t=Util.L(i)?"":i;"value"===this.attrName&&e.hasAttribute("contenteditable")?t!==e.innerHTML&&(e.innerHTML=t):t!==e[this.attrName]&&(e[this.attrName]=t)}let r=()=>{let l="value"===this.attrName?Util.H(e):e[this.attrName];delve(t,s,l)};this.ht(e,this.D.getRootNode(),this.attrName,"input",r,[],!0)}else{let i=this.et;if(!s){if(Globals$1.t=this,"function"==typeof l){if(this.tt)return;this.B=l,l=l()}else l=Util.I(l);Globals$1.t=null}if(s||void 0!==l&&!1!==l&&null!==l)if(s||!0!==l){let r=s?this.ft(t):l;(i?e[this.attrName]:e.getAttribute(this.attrName))!==r&&(i?e[this.attrName]=r:"value"===this.attrName&&e.hasAttribute("contenteditable")&&(e.innerHTML=r),e.setAttribute(this.attrName,r))}else i&&(e[this.attrName]=!0),e.setAttribute(this.attrName,"");else i&&(e[this.attrName]=!1),e.removeAttribute(this.attrName)}}q(){return this.Y?this.Y.length-1:1}ft(t){if(!this.Y)return t[0];let e=[],l=this.Y;for(let s=0;l.length>s;s++)if(e.push(l[s]),l.length-1>s){Globals$1.t=this;let l=Util.I(t[s]);Globals$1.t=null,Util.L(l)||e.push(l)}return e.join("")}ht(t,e,l,s,i,r,o=!1){let n=Globals$1.u.get(t);n||(n={[l]:[,,,]},Globals$1.u.set(t,n));let a=n[l];if(a||(n[l]=a=[,,,]),"function"!=typeof i)throw Error(`Solarite cannot bind to <${t.tagName.toLowerCase()} ${this.attrName}=\${${i}}> because it's not a function.`);if(a[0]!==i){let[l,r,n]=a;l&&t.removeEventListener(s,r,o);let h=i,f=l=>h.call(e,...a[2],l,t);a[0]=h,a[1]=f,t.addEventListener(s,f,o)}n[l][2]=r}}class PathToEvent extends PathToAttribValue{constructor(t,e,l=null,s=null){super(null,e,l,s)}apply(t){if(this.Y?.length>1)return void super.apply(t);if(this.tt&&this.J.tagName.endsWith("-SOLARITE-PLACEHOLDER"))return;let e,l=t[0],s=this.D.ut.root,i=this.J,r=this.attrName.slice(2),o=[];if(Array.isArray(l)&&"function"==typeof l[0])e=l[0],o=l.slice(1);else{if("function"!=typeof l)throw Error(`Invalid event binding: <${i.tagName.toLowerCase()} ${this.attrName}=\${${JSON.stringify(l)}}>`);e=l}this.ht(i,s,r,r,e,o)}}class PathToAttribs extends Path{ct;nt;constructor(t,e){super(null,null),this.J=e,this.ct=new Set}apply(t,e){let l=t[0],s=this.J;Array.isArray(l)&&(l=l.flat().join(" "));let i=this.ct;if(this.ct=new Set,l)if("function"==typeof l&&(Globals$1.t=this,this.B=l,l=l(),Globals$1.t=null),"object"==typeof l)for(let t in l){let e=l[t];void 0!==e&&!1!==e&&null!==e&&(s.setAttribute(t,e),this.ct.add(t))}else{let t=(l+"").split(/([\w-]+\s*=\s*(?:"[^"]*"|'[^']*'|\S+))/g).map((t=>t.trim())).filter((t=>t.length));for(let e of t){let[t,l]=e.split(/\s*=\s*/);l=(l||"").replace(/^(['"])(.*)\1$/,"$2"),s.setAttribute(t,l),this.ct.add(t)}}for(let t of i)this.ct.has(t)||s.removeAttribute(t)}q(){return 1}ft(t){return t[0]}}const udomdiff=(t,e,l,s)=>{const i=l.length;let r=e.length,o=i,n=0,a=0,h=null;for(;r>n||o>a;)if(r===n){const e=i>o?a?l[a-1].nextSibling:l[o-a]:s;for(;o>a;){let s=l[a++];t.insertBefore(s,e)}}else if(o===a)for(;r>n;){let l=e[n];h&&h.has(l)||t.removeChild(l),n++}else if(e[n]===l[a])n++,a++;else if(e[r-1]===l[o-1])r--,o--;else if(e[n]===l[o-1]&&l[a]===e[r-1]){const s=e[--r].nextSibling;let i=l[a++],h=e[n++];t.insertBefore(i,h.nextSibling);let f=l[--o];t.insertBefore(f,s),e[r]=l[o]}else{if(!h){h=new Map;let t=a;for(;o>t;)h.set(l[t],t++)}if(h.has(e[n])){const s=h.get(e[n]);if(s>a&&o>s){let i=n,f=1;for(;++i<r&&o>i&&h.get(e[i])===s+f;)f++;if(f>s-a){const i=e[n];for(;s>a;){let e=l[a++];t.insertBefore(e,i)}}else{let s=e[n++],i=l[a++];t.replaceChild(i,s)}}else n++}else{let l=e[n++];t.removeChild(l)}}return l};class MultiValueMap{data={};add(t,e){let l=this.data,s=l[t];s||(s=new Set,l[t]=s),s.add(e)}dt(){for(let t in this.data)return!0;return!1}getAll(t){return this.data[t]||[]}delete(t,e=void 0){let l,s=this.data,i=s[t];if(i)return void 0===e?([l]=i,i.delete(l)):(i.delete(e),l=e),0===i.size&&delete s[t],l}bt(t){let e,l=this.data,s=l[t];if(s)return[e]=s,s.delete(e),0===s.size&&delete l[t],e}yt(t,e){let l,s=this.data,i=s[t];if(i)return i.delete(e),l=e,0===i.size&&delete s[t],l}gt(t){let e=this.data,l=[];for(let s in e)e[s].has(t)&&l.push(s);return l}}class PathToNodes extends Path{$t;Et=[];vt=new MultiValueMap;Tt=new MultiValueMap;constructor(t,e){super(t,e)}apply(t,e=!0){let l=this,s=t[0];e&&l.Pt();let i=[],r=l.W,o=[];l.W=[],l.wt(s,i,o);let n=!1;if(o.length){for(let[t,e]of o){let s=l.Gt(i[t],!1),r=s.lt();1===r.length?i[t]=r[0]:(i[t]=r,n=!0),l.W[e]=s}n&&(i=i.flat())}let a=l.lt();if(!Util.T(a,i)){l.K=i,this.D.At&&this.D.At.Nt(),a.length&&!i.length&&l.St()||udomdiff(l.J.parentNode,a,i,l.J);for(let t of r)t.Ot.parentNode||Util.k(t.lt())}}wt(t,e,l){if(t instanceof Template){let s=this.Gt(t,!0);if(s){let l=s.lt();return e.push(...l),s.Ct(t.exprs,!1,!1),this.W.push(s),s}l.push([e.length,this.W.length]),e.push(t),this.W.push(null)}else t instanceof NodeList?e.push(...t):t?.nodeType?11===t?.nodeType?e.push(...t.childNodes):e.push(t):this.Ht(t,(t=>{this.wt(t,e,l)}))}xt(t){let e=Math.min(t.jt,t.items.length),l=t.jt-e;for(let l=0;e>l;l++){let e=this.W[t.index+l],s=(this.$t||this.B)(t.items[l]);this.Ht(s,(s=>{let i=this.Gt(s,!0);if(i&&i===e);else{i||(i=this.Gt(s,!1)),this.W[t.index+l]=i;let r=e.Ot;for(let t of i.lt())r.parentNode.insertBefore(t,r);i!==e&&Util.k(e.lt())}}))}if(l>0){for(let s=0;l>s;s++)Util.k(this.W[t.index+e+s].lt());this.W.splice(t.index+e,l)}else{let l=t.items.slice(e),s=this.W[t.index+e]?.Ot||this.J;for(let t=0;l.length>t;t++){let e=this.$t(l[t]),i=this.Gt(e,!0);i||(i=this.Gt(e,!1)),this.W.push(i);for(let t of i.lt())s.parentNode.insertBefore(t,s)}}this.K=null}Nt(){let t=this,e=this.J.parentNode;for(;t&&t.J.parentNode===e;)t.K=null,t=t.D?.At}St(){let t=this.V.parentNode;return this.V===t.firstChild&&this.J===t.lastChild&&(t.innerHTML="",t.append(this.V,this.J),!0)}Ht(t,e){if(Array.isArray(t))for(let l of t)this.Ht(l,e);else if("function"==typeof t)Globals$1.t=this,this.B=t,t=t(),Globals$1.t=null,this.Ht(t,e);else if(t instanceof Template||t?.nodeType)e(t);else{void 0===t||!1===t||null===t?t="":"string"!=typeof t&&(t+="");let l=new Template([t],[]);l.Ut=!0,this.Ht(l,e)}}Gt(t,e=!0){let l,s=this.vt;if(e){if(l=s.bt(t.Mt()),l||(s=this.Tt,l=s.bt(t.Mt())),!l)return null;s.yt(t.Lt(),l)}else t.exprs.length&&(l=s.bt(t.Lt()),l||(s=this.Tt,l=s.bt(t.Lt())),l&&(s.yt(l.It,l),l.Ct(t.exprs),l.It=t.Mt()));return l||(l=new NodeGroup(t,this),l.Ct(t.exprs),l.It=t.Mt()),this.Et.push(l),l}Pt(){let t=this.vt.data,e=this.Tt.data;for(let l in t){let s=e[l];if(s)for(let e of t[l])s.add(e);else e[l]=t[l]}this.vt=new MultiValueMap;let l=this.vt;for(let t of this.Et)l.add(t.It,t),l.add(t.Rt,t);this.Et=[]}lt(){let t;if(t=this.K,t)return t;t=[];let e=this.V.nextSibling,l=this.J;for(;e&&e!==l;)t.push(e),e=e.nextSibling;return this.K=t,t}}class PathToComponent extends Path{kt;constructor(t,e){super(null,e)}apply(t,e=!0,l=!0){let s=this.J,i=Util.P(s,"_is");for(let e,l=0;e=this.kt[l];l++)if(e instanceof PathToAttribValue)i[Util.G(e.attrName)]=e.ft(t[l]);else{let s=e.ft(t[l]);if("object"==typeof s)for(let t in s)i[Util.G(t)]=s[t];else if("string"==typeof s){let t=s.split(/([\w-]+\s*=\s*(?:"[^"]*"|'[^']*'|\S+))/g).map((t=>t.trim())).filter((t=>t.length));for(let e of t){let[t,l]=e.split(/\s*=\s*/);l=(l||"").replace(/^(['"])(.*)\1$/,"$2"),i[Util.G(t)]=l}}}let r=s.getAttribute("_is");if(s.tagName.endsWith("-SOLARITE-PLACEHOLDER")||r){let e=(r||s.tagName.slice(0,-21)).toLowerCase(),o=customElements.get(e);if(!o)throw Error(`Must call customElements.define('${e}', Class) before using it.`);Globals$1.l=[...s.childNodes];let n=new o(i);r&&n.setAttribute("is",r);for(let t of s.attributes)"_is"!==t.name&&n.setAttribute(t.name,t.value);for(let t in i){let e=i[t],l=typeof e;"boolean"===l?!1!==e&&null!=e&&n.setAttribute(t,""):"string"!==l&&"number"!==l&&"bigint"!==l||n.setAttribute(t,e)}let a=n.getAttribute("data-id")||n.getAttribute("id");a&&delve(this.D.getRootNode(),a.split(/\./g),n);let h=this.D;this.J=n;for(let t of h.Ft)t.J===s&&(t.J=n),t.V===s&&(t.V=n);h.Ot===s&&(h.Ot=n),h.Vt===s&&(h.Vt=n),"function"!=typeof n.render||Globals$1.$.has(n)||n.render(i,l);for(let e,l=0;e=this.kt[l];l++)e.D=this.D,e.J=n,e.apply(t[l]);s.replaceWith(n)}else"function"==typeof s.render&&s.render(i,l);Globals$1.l=null}clone(t,e=0){let l=this.X(t,e),s=new PathToComponent(null,l);return s.kt=this.kt.map((l=>l.clone(t,e))),s}q(){return 0}}class Shell{fragment;Ft=[];Jt=[];scripts=[];Dt=[];constructor(t=null){if(!t)return;if(1===t.length&&!t[0].match(/[<&]/))return void(this.fragment=Globals$1.i.createTextNode(t[0]));let e,l=Shell.zt(t),s=Globals$1.i.createElement("template");l?s.innerHTML=l:s.content.append(Globals$1.i.createTextNode("")),this.fragment=s.content;let i=[],r=0;const o=Globals$1.i.createTreeWalker(this.fragment,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT|NodeFilter.SHOW_TEXT);for(;e=o.nextNode();)if(i.map((t=>t.remove())),i=[],1===e.nodeType){const t=e.hasAttribute("is"),l=t||e.tagName.includes("-"),s=[];for(let t of[...e.attributes]){let i=t.name.match(/^[\ue000-\uf8ff]$/);if(i){let t=new PathToAttribs(null,e);this.Ft.push(t),l&&(t.tt=!0,s.push(t)),r++,e.removeAttribute(i[0])}else{let i=t.value.split(/[\ue000-\uf8ff]/g);if(i.length>1){let o=2!==i.length||i[0].length||i[1].length?i:null,n=Util.j(t.name)?new PathToEvent(null,e,t.name,o):new PathToAttribValue(null,e,t.name,o);n.et=Util.U(e,t.name),this.Ft.push(n),l&&(n.tt=!0,s.push(n)),r+=i.length-1;try{e.setAttribute(t.name,i.join(""))}catch(l){throw Error(`Error setting attribute "${t.name}" on node <${e.tagName}>: ${l.message}`)}}}}if(l){let l=new PathToComponent(null,e);l.kt=s,this.Ft.splice(this.Ft.length-s.length,0,l),t&&(e.setAttribute("_is",e.getAttribute("is")),e.removeAttribute("is"))}}else if(8===e.nodeType&&"!✨!"===e.nodeValue){if(e?.parentNode?.closest&&e?.parentNode?.closest("[contenteditable]"))throw Error('Contenteditable can\'t have expressions inside them. Use <div contenteditable value="${...}"> instead.');let t,l=e.previousSibling;l||(l=Globals$1.i.createComment("Path:"+this.Ft.length),e.parentNode.insertBefore(l,e)),!e.nextSibling||8===e.nextSibling.nodeType&&"!✨!"===e.nextSibling.textContent?(t=e,t.textContent="PathEnd:"+this.Ft.length):(t=e.nextSibling,i.push(e));let s=new PathToNodes(l,t);this.Ft.push(s),r++}else{if(3===e.nodeType&&"TEXTAREA"===e.parentNode?.tagName&&e.textContent.includes("\x3c!--!✨!--\x3e"))throw Error('Textarea can\'t have expressions inside them. Use <textarea value="${...}"> instead.');if(8===e.nodeType){let t=e.textContent.split(/[\ue000-\uf8ff]/g);for(let l=0;t.length-1>l;l++){let t=new Path(e.previousSibling,e);this.Ft.push(t),r++}}else if(3===e.nodeType&&["SCRIPT","STYLE"].includes(e.parentNode?.nodeName)){let t=e.textContent.split(commentPlaceholder);if(t.length>1){let l=[];for(let s=0;t.length>s;s++){let i=Globals$1.i.createTextNode(t[s]);e.parentNode.insertBefore(i,e),s>0&&l.push(i)}for(let t,e=0;t=l[e];e++){let e=new PathToNodes(t.previousSibling,t);this.Ft.push(e),r++}i.push(e)}}}if(i.map((t=>t.remove())),r!==t.length-1)throw Error("Could not parse expressions in template. Check for duplicate attributes or malformed html: "+t.join("${...}"));for(let t of this.Ft)t.V&&(t.Z=[].indexOf.call(t.V.parentNode.childNodes,t.V)),t._=Path.get(t.J);this.Wt()}static zt(t){let e=[],l=new HtmlParser;for(let s=0;t.length>s;s++){let i=0,r=l.parse(t[s],((t,l,s)=>{if(i!==l){let r=t.slice(i,l);s===HtmlParser.rt&&(r=r.replace(/^<\/?[a-z][a-z0-9]*-[a-z0-9-]+/i,(t=>t+"-SOLARITE-PLACEHOLDER"))),e.push(r)}i=l}));t.length-1>s&&e.push(r===HtmlParser.Text?commentPlaceholder:String.fromCharCode(attribPlaceholder+s))}return e.join("")}Wt(){this.scripts=[].map.call(this.fragment.querySelectorAll("scripts"),(t=>Path.get(t))),this.Dt=[].map.call(this.fragment.querySelectorAll("style"),(t=>Path.get(t)));let t=this.fragment.querySelectorAll("[id],[data-id]");for(let e of t){let t=e.getAttribute("data-id")||e.getAttribute("id");if(Globals$1.div.hasOwnProperty(t))throw Error(`<${e.tagName.toLowerCase()} id="${t}"> can't override existing HTMLElement id property.`)}this.Jt=[].map.call(t,(t=>Path.get(t)))}static get(t){let e=Globals$1.v.get(t);return e||(e=new Shell(t),Globals$1.v.set(t,e)),e}}const commentPlaceholder="\x3c!--!✨!--\x3e",attribPlaceholder=57344;class NodeGroup{ut;At;Ot;Vt;Ft=[];It;Rt;K;Dt;Kt;root;constructor(t,e=null,l=null,s=null){if(this.ut=e?.D?.ut||this,this.At=e,this.Kt=t,this.Rt=t.Lt(),t.Ut)this.Ot=this.Vt=Globals$1.i.createTextNode(t.html[0]);else{const e=Shell.get(t.html),i=e.fragment.cloneNode(!0);if(11===i.nodeType?(this.Ot=i.firstChild,this.Vt=i.lastChild):this.Ot=this.Vt=i,this instanceof RootNodeGroup){let t=0;if(this.options=s,i instanceof Text){if(!l)throw Error("Cannot create a standalone text node");this.root=l,i.nodeValue.length&&this.root.append(i)}else{if(l){let e;if(this.root=l,(Globals$1.l||l.childNodes.length)&&(e=Globals$1.i.createDocumentFragment(),e.append(...Globals$1.l||l.childNodes)),isReplaceEl(i,this.root.tagName)){this.root.append(...i.children[0].childNodes);for(let t of i.children[0].attributes)this.root.hasAttribute(t.name)||this.root.setAttribute(t.name,t.value);t=1}else 1===i.childNodes.length&&3===i.childNodes[0].nodeType&&""===i.childNodes[0].textContent||this.root.append(...i.childNodes);if(e){for(let t of l.querySelectorAll("slot[name]")){let l=t.getAttribute("name");if(l){let s=e.querySelectorAll(`[slot='${l}']`);t.append(...s)}}let t=l.querySelector("slot:not([name])");t?t.append(e):l.append(e)}}else{let e=getSingleEl(i);this.root=e||i,e&&(t=1)}this.Zt(this.root,e.Ft,t),this._t(this.root,e,t)}this.Ot=this.Vt=this.root,Globals$1.p.set(this.root,this)}else e&&(e.Ft.length&&this.Zt(i,e.Ft),this._t(i,e))}}Ct(t,e=!0,l=!0){let s=this.Ft,i=t.length,r=Array(s.length);for(let o,n=s.length-1;o=s[n];n--){if(0===n&&o instanceof PathToComponent&&o.J===this.getRootNode())continue;let s=o.q();if(r[n]=t.slice(i-s,i),i-=s,o instanceof PathToComponent){let t=r.slice(n+1,n+1+o.kt.length);o.apply(t,!0,e)}else l&&o.apply(r[n])}l&&(this.Bt(),this.K=null)}qt(t){}lt(){let t=this.K;if(t)return t;t=[];let e=this.Ot,l=this.Vt?.nextSibling;for(;e&&e!==l;)t.push(e),e=e.nextSibling;return this.K=t,t}getRootNode(){return this.ut.root}Xt(){return this.ut}Zt(t,e,l=0){let s=e.length;this.Ft.length=s;for(let i=0;s>i;i++){let s=e[i].clone(t,l);s.D=this,this.Ft[i]=s}}Bt(){if(this.Dt)for(let[t,e]of this.Dt)e!==t.textContent&&Util.N(t,this.Xt().root)}_t(root,shell,pathOffset=0){let rootEl=this.ut.root;if(rootEl){let options=this.ut.options;if(!1!==options?.Jt)for(let t of shell.Jt){pathOffset&&(t=t.slice(0,-pathOffset));let e=Path.resolve(root,t);Util.A(rootEl,e)}if(!1!==options?.Dt){shell.Dt.length&&(this.Dt=new Map);for(let t of shell.Dt){pathOffset&&(t=t.slice(0,-pathOffset));let e=Path.resolve(root,t);1===rootEl.nodeType&&(Util.N(e,rootEl),this.Dt.set(e,e.textContent))}}if(!1!==options?.scripts)for(let path of shell.scripts){pathOffset&&(path=path.slice(0,-pathOffset));let script=Path.resolve(root,path);eval(script.textContent)}}}}function getSingleEl(t){let e=[];for(let l of t.childNodes)if(1===l.nodeType||3===l.nodeType&&l.textContent.trim().length){if(e.length)return null;e.push(l)}return e[0]}function isReplaceEl(t,e){return 1===t.children.length&&e.includes("-")&&t.children[0].tagName.replace("-SOLARITE-PLACEHOLDER","")===e}class RootNodeGroup extends NodeGroup{Yt}class Template{exprs=[];html=[];Qt;Rt;It;Ut;constructor(t=[""],e=[]){this.html=t,this.exprs=e}toJSON(){return void 0===this.Qt&&(this.Qt=[getObjectId(this.html),this.exprs]),this.Qt}render(t=null,e={}){let l=t&&Globals$1.p.get(t);if(l||(l=new RootNodeGroup(this,null,t,e),t||(t=l.getRootNode()),Globals$1.p.set(t,l)),1!==this.html?.length||this.html[0]){let t=l.It,e=this.Mt();l.Ct(this.exprs,t!==e),l.It=e}else t.innerHTML="";return l.Yt=new Map,t}Mt(){return void 0===this.It&&(this.It=this.exprs.length?getObjectHash(this):this.html[0]),this.It}Lt(){return void 0===this.Rt&&(this.Rt=this.exprs.length?this.toJSON()[0]:this.html[0]),this.Rt}static te(t,e,l){const s=selfClosingTags.has(t.toLowerCase());let i=[],r=[],o="<"+t;if(e&&"object"==typeof e)for(let t in e){let l=e[t];"id"!==t&&"data-id"!==t?(o+=` ${t}=`,i.push(o),r.push(l),o=""):o+=` ${t}="${l}"`}if(!s){i.push(i.length>0?'"'===o?'">':">":o+">");for(let t of l)addChild(t,i,r)}return s?i.push(i.length>0?">":o+">"):i[i.length-1]+=`</${t}>`,new Template(i,r)}}const selfClosingTags=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),addChild=(t,e,l)=>{if(Array.isArray(t))for(let s of t)addChild(s,e,l);else{let s=!1;if(t instanceof Template)if(t.exprs.length>0)s=!0;else{const e=(t.html[0]||"").match(/^<([a-zA-Z][\w:-]*)/),l=e?e[1].toLowerCase():"";s=selfClosingTags.has(l)}if(s){e[e.length-1]+=t.html[0];for(let s=0;t.exprs.length>s;s++)l.push(t.exprs[s]),e.push(t.html[s+1]??"")}else l.push(t),e.push("")}};function toEl(t){if("string"==typeof t){let e=t;(e.match(/^\s^<\S+/)||e.match(/\S+>\s+$/))&&(e=e.trim());let l=Globals$1.i.createElement("template");l.innerHTML=e;let s=Util.F(l.content.childNodes);return 1===s.length?s[0]:l.content}if(t instanceof Template)return t.render();if(t&&"object"==typeof t){let e=t;if("Object"!==e.constructor.name)throw Error(`Solarate Web Component class ${e.constructor?.name} must extend HTMLElement.`);if(!Globals$1.m.has(e)){Globals$1.m.set(e,null),e[renderF]();let t=Globals$1.m.get(e);Globals$1.m.delete(e);for(let l in e)t[l]="function"==typeof e[l]?e[l].bind(t):e[l];return t}}throw Error("toEl() does not support argument of type: "+(t?typeof t:t))}let renderF="render";function h(t=void 0,...e){if(Array.isArray(arguments[0]))return new Template(arguments[0],e);if("string"==typeof arguments[0]||arguments[0]instanceof String){let t=arguments[0];if(!e.length||"object"!=typeof e[0]&&null!==e[0]){let e=t;return e.match(/^\s^</)&&(e=e.trim()),new Template([e],[])}{let l=t+"",s=e[0]||{},i=e.slice(1);return Template.te(l,s,i)}}if(arguments[0]instanceof HTMLElement||arguments[0]instanceof DocumentFragment){if(!(arguments[1]instanceof Template)){let t=arguments[0],e=arguments[1];t.shadowRoot&&(t.innerHTML="");let l=(l,...s)=>(Globals$1.$.add(t),new Template(l,s).render(t,e));return l}arguments[1].render(arguments[0],arguments[2])}else{if(!arguments.length)return(t,...e)=>toEl(h(t,...e));if("object"!=typeof arguments[0]||!Globals$1.m.has(arguments[0])){if(Util.L(arguments[0]))return new Template;throw Error("h() does not support argument of type: "+(arguments[0]?typeof arguments[0]:arguments[0]))}{let t=arguments[0];if("Object"!==t.constructor.name)throw Error(`Solarate Web Component class ${t.constructor?.name} must extend HTMLElement.`);if(!(arguments[1]instanceof Template))return((...e)=>{let l=h(...e).render();Globals$1.m.set(t,l)}).bind(t);{let e=arguments[1].render();Globals$1.m.set(t,e)}}}}function getArg(el,attributeName,defaultValue=void 0,type=ArgType.String){let val=defaultValue,attrVal=el.getAttribute(attributeName)||el.getAttribute(Util.O(attributeName));if(null!==attrVal&&(val=attrVal),Array.isArray(type))return type.includes(val)?val:void 0;if("function"==typeof type)return type.constructor?new type(val):type(val);if(type===ArgType.ee){let t="string"==typeof val?val.toLowerCase():val;return!["false","0",!1,0,null,void 0,NaN].includes(t)&&(!(!["true",!0].includes(t)&&0===parseFloat(t))||void 0)}switch(type){case ArgType.le:return parseInt(val);case ArgType.se:return parseFloat(val);case ArgType.String:return[void 0,null,!1].includes(val)?"":val+"";case ArgType.ie:case ArgType.re:if("string"!=typeof val||!val.length)return val;try{return type===ArgType.ie?JSON.parse(val):eval(`(${val})`)}catch(t){return val}default:return val}}function setArgs(t,e,l){for(let s in e)this[s]=getArg(t,s,e[s],l[s]||ArgType.String)}var ArgType={ee:"Bool",le:"Int",se:"Float",String:"String",JSON:"Json",ie:"Json",re:"Eval"};function t(t){return new Template([t],[])}let HTMLElementAutoDefine=new Proxy(HTMLElement,{construct:(t,e,l)=>(Util.C(l),Reflect.construct(t,e,l))});class Solarite extends HTMLElementAutoDefine{constructor(t=null){if(super(),t){if("object"!=typeof t)throw Error("First argument to custom element constructor must be an object.");if(t&&!Object.keys(t).length){let e=Solarite.getAttribs(this);for(let l in e)t[l]=e[l]}}}render(){throw Error("render() is not defined for "+this.constructor.name)}renderFirstTime(){if(!Globals$1.$.has(this)){let t=Solarite.getAttribs(this);this.render(t)}}connectedCallback(){this.renderFirstTime()}static define(t=null){Util.C(this,t)}static getAttribs(t){let e=Util.P(t);for(let t in e){let l=e[t];l.startsWith("${")&&l.endsWith("}")&&(e[t]=JSON.parse(l.slice(2,-1)))}return e}}function assignFields(t,e,l=[]){for(let s in e||{})if(s in t&&!l.includes(s)){const l=Object.getOwnPropertyDescriptor(t,s)||Object.getOwnPropertyDescriptor(Object.getPrototypeOf(t),s);if(!l||l.writable||l.set){let l=e[s],i=t[s];t[s]="string"==typeof e[s]?"boolean"==typeof i?![!1,"false",0,"0"].includes(l):"number"==typeof i?+l:i instanceof Date?new Date(l):l:l}}}export default h;export{ArgType,Globals$1 as Globals,HtmlParser,NodeGroup,Shell,Solarite,Util as SolariteUtil,Template,assignFields,delve,getArg,h,h as r,setArgs,t,toEl};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solarite",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Solarite is a small (9KB min+gzip), fast, compilation-free JavaScript library for adding reactivity to native web components, so that updates require minimal re-rendering.",
5
5
  "type": "module",
6
6
  "main": "dist/Solarite.js",
@@ -13,6 +13,9 @@ export default class PathToAttribValue extends Path {
13
13
  * @type {?string[]} Used only if type=AttribType.Value. If null, use one expr to set the whole attribute value. */
14
14
  attrValue;
15
15
 
16
+ /** @type {boolean} Provides value for attribute on a component. */
17
+ isComponent;
18
+
16
19
  isHtmlProperty;
17
20
 
18
21
  constructor(nodeBefore, nodeMarker, attrName=null, attrValue=null) {
@@ -8,6 +8,9 @@ export default class PathToAttribs extends Path {
8
8
  * @type {Set<string>} Used for type=AttribType.Multiple to remember the attributes that were added. */
9
9
  attrNames;
10
10
 
11
+ /** @type {boolean} Provides one or more attributes on a component. */
12
+ isComponent;
13
+
11
14
  constructor(nodeBefore, nodeMarker) {
12
15
  super(null, null);
13
16
  this.nodeMarker = nodeMarker;
@@ -74,4 +77,5 @@ export default class PathToAttribs extends Path {
74
77
 
75
78
 
76
79
  getExpressionCount() { return 1 }
80
+ getValue(exprs) { return exprs[0]; }
77
81
  }
@@ -2,6 +2,7 @@ import Path from "./Path.js";
2
2
  import Util from "./Util.js";
3
3
  import delve from "./delve.js";
4
4
  import assert from "./assert.js";
5
+ import PathToAttribValue from "./PathToAttribValue.js";
5
6
  import Globals from "./Globals.js";
6
7
 
7
8
  export default class PathToComponent extends Path {
@@ -36,8 +37,27 @@ export default class PathToComponent extends Path {
36
37
  // 1. Attributes
37
38
  let attribs = Util.attribsToObject(el, '_is');
38
39
  for (let i=0, attribPath; attribPath = this.attribPaths[i]; i++) {
39
- let name = Util.dashesToCamel(attribPath.attrName);
40
- attribs[name] = attribPath.getValue(exprs[i]);
40
+ if (attribPath instanceof PathToAttribValue) {
41
+ let name = Util.dashesToCamel(attribPath.attrName);
42
+ attribs[name] = attribPath.getValue(exprs[i]);
43
+ }
44
+ else { // PathToAttribs
45
+ let val = attribPath.getValue(exprs[i]);
46
+ if (typeof val === 'object')
47
+ for (let name in val)
48
+ attribs[Util.dashesToCamel(name)] = val[name];
49
+ else if (typeof val === 'string') {
50
+ let attrs = val.split(/([\w-]+\s*=\s*(?:"[^"]*"|'[^']*'|\S+))/g)
51
+ .map(text => text.trim())
52
+ .filter(text => text.length);
53
+
54
+ for (let attr of attrs) {
55
+ let [name, value] = attr.split(/\s*=\s*/); // split on first equals.
56
+ value = (value || '').replace(/^(['"])(.*)\1$/, '$2'); // trim value quotes if they match.
57
+ attribs[Util.dashesToCamel(name)] = value;
58
+ }
59
+ }
60
+ }
41
61
  }
42
62
 
43
63
  // 2. Instantiate component on first time.
@@ -20,6 +20,14 @@ export default class PathToEvent extends PathToAttribValue {
20
20
  assert(Array.isArray(exprs));
21
21
  //#ENDIF
22
22
 
23
+ // Tested by Solariate.events.classicWithExpr
24
+ // We have expressions within a string attribute value that's not a Solarite event. E.g.
25
+ // <div onclick="alert(${1});"
26
+ if (this.attrValue?.length > 1) {
27
+ super.apply(exprs);
28
+ return;
29
+ }
30
+
23
31
  // Don't bind events to component placeholders.
24
32
  // PathToComponent will do the binding later when it instantiates the component.
25
33
  if (this.isComponentAttrib && this.nodeMarker.tagName.endsWith('-SOLARITE-PLACEHOLDER'))
package/src/Shell.js CHANGED
@@ -85,13 +85,15 @@ export default class Shell {
85
85
 
86
86
  for (let attr of [...node.attributes]) { // Copy the attributes array b/c we remove attributes with placeholders as we go.
87
87
 
88
- // Whole attribute
88
+ // One or more whole attributes
89
89
  let matches = attr.name.match(/^[\ue000-\uf8ff]$/)
90
90
  if (matches) {
91
91
  let path = new PathToAttribs(null, node);
92
92
  this.paths.push(path);
93
- if (isComponent)
93
+ if (isComponent) {
94
+ path.isComponentAttrib = true;
94
95
  componentAttribPaths.push(path);
96
+ }
95
97
 
96
98
  placeholdersUsed ++;
97
99
  node.removeAttribute(matches[0]); // TODO: Is this necessary?
@@ -114,7 +116,12 @@ export default class Shell {
114
116
  }
115
117
 
116
118
  placeholdersUsed += parts.length - 1;
117
- node.setAttribute(attr.name, parts.join(''));
119
+ try {
120
+ node.setAttribute(attr.name, parts.join(''));
121
+ }
122
+ catch (e) {
123
+ throw new Error(`Error setting attribute "${attr.name}" on node <${node.tagName}>: ${e.message}`);
124
+ }
118
125
  }
119
126
  }
120
127
  }
package/src/Solarite.d.ts CHANGED
@@ -19,10 +19,11 @@ declare function h(el: HTMLElement | DocumentFragment, options?: RenderOptions):
19
19
  declare function h(el: HTMLElement | DocumentFragment, template: Template, options?: RenderOptions): void;
20
20
  declare function h(tag: string, props: object, ...children: any[]): Template; // JSX
21
21
  declare function h(obj: {render: Function}): (htmlStrings: TemplateStringsArray, ...exprs: any[]) => void; // Rebound render
22
+ declare function h(): (htmlStrings: TemplateStringsArray, ...exprs: any[]) => Node|DocumentFragment;
22
23
 
23
24
  export default h;
24
25
  export {h};
25
- export {h as r};
26
+ export {h as r}; // deprecated
26
27
 
27
28
  /**
28
29
  * Solarite provides more features if your web component extends Solarite instead of HTMLElement. */
@@ -40,6 +41,12 @@ export class Solarite extends HTMLElement {
40
41
  * Convert a template, string, or object into a DOM Node or Element. */
41
42
  export function toEl(arg: string | Template | {render: () => void}): Node | HTMLElement | DocumentFragment;
42
43
 
44
+ /**
45
+ * Assign fields from `src` to `dest` if they exist in `dest` and don't exist in `ignore`.
46
+ * When a value in `src` is a string and the existing value in `dest` is a boolean, number, or Date,
47
+ * it will be converted to that type. */
48
+ export function assignFields(dest: object, src: object|null, ignore?: string[]): void;
49
+
43
50
  /**
44
51
  * @deprecated
45
52
  * Retrieve and cast an attribute value from an HTMLElement. */
package/src/Solarite.js CHANGED
@@ -145,4 +145,142 @@ export class Solarite extends HTMLElementAutoDefine {
145
145
  }
146
146
  return result;
147
147
  }
148
+
149
+
150
+ // TODO: Do we want to use this to get the tag name from the render() function, instead of having the user define it?
151
+ /**
152
+ * Get the tag name for a class, as defined by the tag used in render().
153
+ *
154
+ * This will parse the JavaScript code of the render() function to find the tag name.
155
+ * It will itarage every character, keeping track of quotes and comments so it can
156
+ * skip them until it finds the tag name passed to h(this)`<tagname>` inside the render() function.
157
+ *
158
+ * */
159
+ /*
160
+ static getTagName(Class) {
161
+ let code = Class.prototype.render.toString();
162
+ let i = 0;
163
+ while (i < code.length) {
164
+ let char = code[i];
165
+ let next = code[i + 1];
166
+
167
+ // Skip single line comments
168
+ if (char === '/' && next === '/') {
169
+ i = code.indexOf('\n', i);
170
+ if (i === -1) break;
171
+ continue;
172
+ }
173
+ // Skip multi-line comments
174
+ if (char === '/' && next === '*') {
175
+ i = code.indexOf('*'+'/', i + 2);
176
+ if (i === -1) break;
177
+ i += 2;
178
+ continue;
179
+ }
180
+ // Skip strings and template literals
181
+ if (char === "'" || char === '"' || char === '`') {
182
+ let quote = char;
183
+ i++;
184
+ while (i < code.length) {
185
+ if (code[i] === '\\') i += 2;
186
+ else if (code[i] === quote) { i++; break; }
187
+ else i++;
188
+ }
189
+ continue;
190
+ }
191
+ // Skip regex literals (simple heuristic)
192
+ if (char === '/') {
193
+ let prev = code.slice(Math.max(0, i - 10), i).trim();
194
+ // If / is preceded by something that indicates an operator or start of expression
195
+ if (/[=(,;:[!&|?]$|return$|yield$|case$/.test(prev)) {
196
+ i++;
197
+ while (i < code.length) {
198
+ if (code[i] === '\\') i += 2;
199
+ else if (code[i] === '[') { // Skip character classes
200
+ i++;
201
+ while (i < code.length && code[i] !== ']') {
202
+ if (code[i] === '\\') i += 2;
203
+ else i++;
204
+ }
205
+ i++;
206
+ }
207
+ else if (code[i] === '/') { i++; break; }
208
+ else i++;
209
+ }
210
+ continue;
211
+ }
212
+ }
213
+ // Check for h(this)`
214
+ if (char === 'h' && code.slice(i, i + 8) === 'h(this)`') {
215
+ i += 8;
216
+ // We are now inside the template literal.
217
+ // Skip whitespace and HTML comments
218
+ while (i < code.length) {
219
+ // Skip JS template literal end (shouldn't happen before tag, but for safety)
220
+ if (code[i] === '`') return null;
221
+
222
+ // Skip whitespace
223
+ if (/\s/.test(code[i])) { i++; continue; }
224
+
225
+ // Skip HTML comments <!-- ... -->
226
+ if (code.slice(i, i + 4) === '<!--') {
227
+ i = code.indexOf('-->', i + 4);
228
+ if (i === -1) return null;
229
+ i += 3;
230
+ continue;
231
+ }
232
+
233
+ // Find the first tag
234
+ if (code[i] === '<') {
235
+ let start = ++i;
236
+ while (i < code.length && /[a-zA-Z0-9-]/.test(code[i])) i++;
237
+ return code.slice(start, i);
238
+ }
239
+
240
+ // If we encounter anything else (like text before a tag),
241
+ // we can keep looking or return null depending on how strict we want to be.
242
+ // For now, let's just skip non-tag characters.
243
+ i++;
244
+ }
245
+ }
246
+ i++;
247
+ }
248
+ return null;
249
+ }
250
+ */
251
+ }
252
+
253
+
254
+ /**
255
+ * Assign fields from `src` to `dest` if they exist in `dest` and their names are not in the `ignore` list.
256
+ * When a value in `src` is a string and the existing value in `dest` is a boolean, number, or Date,
257
+ * it will be converted to that type.
258
+ * This is often used in class constructors that accept an object of arguments.
259
+ * @param {object} dest
260
+ * @param {?object} src
261
+ * @param {string[]} [ignore=[]] */
262
+ export function assignFields(dest, src, ignore=[]) {
263
+ for (let name in src || {}) {
264
+ if (name in dest && !ignore.includes(name)) {
265
+ const descriptor = Object.getOwnPropertyDescriptor(dest, name)
266
+ || Object.getOwnPropertyDescriptor(Object.getPrototypeOf(dest), name); // Also find (parent?) setters. Is this necssary?
267
+ if (!descriptor || descriptor.writable || descriptor.set) {
268
+ let srcVal = src[name];
269
+ let destVal = dest[name];
270
+ if (typeof src[name] === 'string') {
271
+ if (typeof destVal === 'boolean') // empty string (when an attribute is present with no value) is true
272
+ dest[name] = ![false, 'false', 0, '0'].includes(srcVal);
273
+ else if (typeof destVal === 'number')
274
+ dest[name] = Number(srcVal);
275
+ else if (destVal instanceof Date) {
276
+ dest[name] = new Date(srcVal); // TODO: read it as UTC 0 by default.
277
+ }
278
+ else
279
+ dest[name] = srcVal;
280
+ }
281
+ else
282
+ dest[name] = srcVal;
283
+ }
284
+ }
285
+ }
148
286
  }
package/src/Template.js CHANGED
@@ -18,6 +18,9 @@ export default class Template {
18
18
  /** @type {Array} Used for toJSON() and getObjectHash(). Stores values used to quickly create a string hash of this template. */
19
19
  hashedFields;
20
20
 
21
+ closeKey;
22
+ exactKey;
23
+
21
24
  isText;
22
25
 
23
26
  /**