resonantjs 1.1.3 → 1.1.4

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.
@@ -102,8 +102,8 @@
102
102
  <section class="grid">
103
103
  <div>
104
104
  <h2>Project Members</h2>
105
- <ul res="projectTeam">
106
- <li>
105
+ <ul>
106
+ <li res="projectTeam">
107
107
  <span res-prop="name"></span> - <span res-prop="role"></span>
108
108
  </li>
109
109
  </ul>
@@ -207,6 +207,8 @@
207
207
  ]
208
208
  });
209
209
 
210
+
211
+
210
212
  // Chain together callbacks
211
213
  resonantJs.addCallback("user", (user) => {
212
214
  console.log(`User updated: ${user.firstname} ${user.lastname}`);
@@ -0,0 +1,452 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>Resonant.js Practical Demo</title>
5
+ <link
6
+ rel="stylesheet"
7
+ href="https://cdn.jsdelivr.net/npm/@picocss/pico@2.0.6/css/pico.min.css"
8
+ />
9
+ <script src="../resonant.js"></script>
10
+ <style>
11
+ .success {
12
+ background-color: #0172ad;
13
+ }
14
+ .fail {
15
+ background-color: #883935;
16
+ }
17
+ section.grid {
18
+ padding: 1rem;
19
+ margin-bottom: 2rem;
20
+ border: 1px solid #e0e0e0;
21
+ border-radius: 0.5rem;
22
+ }
23
+ </style>
24
+ </head>
25
+ <body>
26
+
27
+ <main class="container">
28
+ <h1>Variable/Object/Array update tests</h1>
29
+ <section class="grid">
30
+ <div>
31
+ <h2>Basic Variable: <span res="basicVariable"></span></h2>
32
+ <div res-display="basicVariable == 'Initial'">
33
+ Has not been updated yet
34
+ </div>
35
+ <div res-display="basicVariable != 'Initial'">
36
+ Has been updated
37
+ </div>
38
+ </div>
39
+ <div>
40
+ <button class="runTest" data-type="basicVariable">Run Test</button>
41
+ </div>
42
+ </section>
43
+ <section class="grid">
44
+ <div res="simpleObject">
45
+ <h2>Simple Object: </h2>
46
+ First Name: <span res-prop="firstName"></span>
47
+ Last Name: <span res-prop="lastName"></span>
48
+
49
+ <div res-display="firstName == 'John'">
50
+ Has not been updated yet
51
+ </div>
52
+ <div res-display="firstName != 'John'">
53
+ Has been updated
54
+ </div>
55
+ </div>
56
+ <div>
57
+ <button class="runTest" data-type="simpleObject">Run Test</button>
58
+ </div>
59
+ </section>
60
+ <section class="grid">
61
+ <div>
62
+ <h2>Simple Array Update: </h2>
63
+ <ul>
64
+ <li res="simpleArrayUpdate">
65
+ <span res-prop="firstName"></span> <span res-prop="lastName"></span>
66
+ </li>
67
+ </ul>
68
+
69
+ <div res-display="simpleArrayUpdate[0].firstName == 'John'">
70
+ Has not been updated yet
71
+ </div>
72
+ <div res-display="simpleArrayUpdate[0].firstName != 'John'">
73
+ Has been updated
74
+ </div>
75
+ </div>
76
+ <div>
77
+ <button class="runTest" data-type="simpleArrayUpdate">Run Test</button>
78
+ </div>
79
+ </section>
80
+ <section class="grid">
81
+ <div>
82
+ <h2>Simple Array Add: </h2>
83
+ <ul>
84
+ <li res="simpleArrayAdd">
85
+ <span res-prop="firstName"></span> <span res-prop="lastName"></span>
86
+ </li>
87
+ </ul>
88
+
89
+ <div res-display="simpleArrayAdd[2] === undefined">
90
+ Has not been updated yet
91
+ </div>
92
+ <div res-display="simpleArrayAdd[2] !== undefined">
93
+ Has been updated
94
+ </div>
95
+ </div>
96
+ <div>
97
+ <button class="runTest" data-type="simpleArrayAdd">Run Test</button>
98
+ </div>
99
+ </section>
100
+ <section class="grid">
101
+ <div>
102
+ <h2>Simple Array Remove: </h2>
103
+ <ul>
104
+ <li res="simpleArrayRemove">
105
+ <span res-prop="firstName"></span> <span res-prop="lastName"></span>
106
+ </li>
107
+ </ul>
108
+
109
+ <div res-display="simpleArrayRemove[0].firstName == 'John'">
110
+ Has not been updated yet
111
+ </div>
112
+ <div res-display="simpleArrayRemove[0].firstName != 'John'">
113
+ Has been updated
114
+ </div>
115
+ </div>
116
+ <div>
117
+ <button class="runTest" data-type="simpleArrayRemove">Run Test</button>
118
+ </div>
119
+ </section>
120
+ <section class="grid">
121
+ <div>
122
+ <h2>Complex Array With Children Update: </h2>
123
+ <hr>
124
+ <div>
125
+ <div res="complexArrayWithChildrenUpdate">
126
+ <h3><span res-prop="firstName"></span> <span res-prop="lastName"></span></h3>
127
+
128
+ Phone Numbers:
129
+ <ul>
130
+ <li res-prop="phoneNumbers">
131
+ </li>
132
+ </ul>
133
+ Addresses
134
+ <ul>
135
+ <li res-prop="addresses">
136
+ <span res-prop="city"></span>,
137
+ <span res-prop="state"></span>
138
+ </li>
139
+ </ul>
140
+ <hr>
141
+ </div>
142
+ </div>
143
+
144
+
145
+ <div res-display="complexArrayWithChildrenUpdate[0].firstName == 'John'">
146
+ Has not been updated yet
147
+ </div>
148
+ <div res-display="complexArrayWithChildrenUpdate[0].firstName != 'John'">
149
+ Has been updated
150
+ </div>
151
+ </div>
152
+ <div>
153
+ <button class="runTest" data-type="complexArrayWithChildrenUpdate">Run Test</button>
154
+ </div>
155
+ </section>
156
+ <section class="grid">
157
+ <div>
158
+ <h2>Complex Array With Children Display Update: </h2>
159
+ <hr>
160
+ <div>
161
+ <div res="complexArrayWithChildrenDisplayUpdate">
162
+ <h3><span res-prop="firstName"></span> <span res-prop="lastName"></span></h3>
163
+
164
+ <div res-display="attributes.showOnPage">
165
+ Show on page
166
+ </div>
167
+ <hr>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ <div>
172
+ <button class="runTest" data-type="complexArrayWithChildrenDisplayUpdate">Run Test</button>
173
+ </div>
174
+ </section>
175
+ <section class="grid">
176
+ <div>
177
+ <h2>Complex Array With Arrays Display Test: </h2>
178
+ <hr>
179
+ <div>
180
+ <div res="complexArrayWithArrayDisplayUpdate">
181
+ <h3>
182
+ <span res-prop="firstName"></span>
183
+ <span res-prop="lastName"></span>
184
+ </h3>
185
+
186
+ <div res-prop="attributes">
187
+ <div res-prop="name">
188
+ </div>
189
+ <div res-display="showOnPage">
190
+ Show on page
191
+ </div>
192
+ </div>
193
+ <hr>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ <div>
198
+ <button class="runTest" data-type="complexArrayWithArrayDisplayUpdate">Run Test</button>
199
+ </div>
200
+ </section>
201
+ <button onclick="runAllTests()">Run All Tests</button>
202
+ </main>
203
+
204
+ <script>
205
+ const resonantJs = new Resonant();
206
+ resonantJs.add("basicVariable", "Initial");
207
+ resonantJs.add("simpleObject", {
208
+ firstName: "John",
209
+ lastName: "Doe"
210
+ });
211
+ resonantJs.add("simpleArrayUpdate", [
212
+ {
213
+ firstName: "John",
214
+ lastName: "Doe"
215
+ },
216
+ {
217
+ firstName: "Jane",
218
+ lastName: "Doe"
219
+ }
220
+ ]);
221
+ resonantJs.add("simpleArrayAdd", [
222
+ {
223
+ firstName: "John",
224
+ lastName: "Doe"
225
+ },
226
+ {
227
+ firstName: "Jane",
228
+ lastName: "Doe"
229
+ }
230
+ ]);
231
+ resonantJs.add("simpleArrayRemove", [
232
+ {
233
+ firstName: "John",
234
+ lastName: "Doe"
235
+ },
236
+ {
237
+ firstName: "Jane",
238
+ lastName: "Doe"
239
+ }
240
+ ]);
241
+ resonantJs.add("complexArrayWithChildrenUpdate", [
242
+ {
243
+ firstName: "Michael",
244
+ lastName: "Smith",
245
+ phoneNumbers: [
246
+ "555-123-4567",
247
+ "555-987-6543"
248
+ ],
249
+ addresses: [
250
+ {
251
+ city: "Chicago",
252
+ state: "IL"
253
+ },
254
+ {
255
+ city: "Seattle",
256
+ state: "WA"
257
+ },
258
+ {
259
+ city: "New York",
260
+ state: "NY"
261
+ }
262
+ ]
263
+ },
264
+ {
265
+ firstName: "Sarah",
266
+ lastName: "Johnson",
267
+ phoneNumbers: [
268
+ "555-234-5678",
269
+ "555-876-5432",
270
+ "555-345-6789"
271
+ ],
272
+ addresses: [
273
+ {
274
+ city: "Boston",
275
+ state: "MA"
276
+ },
277
+ {
278
+ city: "Austin",
279
+ state: "TX"
280
+ }
281
+ ]
282
+ }
283
+ ]);
284
+ resonantJs.add("complexArrayWithChildrenDisplayUpdate", [
285
+ {
286
+ firstName: "Michael",
287
+ lastName: "Smith",
288
+ attributes:
289
+ {
290
+ showOnPage: true
291
+ }
292
+ },
293
+ {
294
+ firstName: "Sarah",
295
+ lastName: "Johnson",
296
+ attributes:
297
+ {
298
+ showOnPage: true
299
+ }
300
+ }
301
+ ]);
302
+ resonantJs.add("complexArrayWithArrayDisplayUpdate", [
303
+ {
304
+ firstName: "Michael",
305
+ lastName: "Smith",
306
+ attributes: [
307
+ {
308
+ name: "Personal",
309
+ showOnPage: true
310
+ },
311
+ {
312
+ name: "Not Personal",
313
+ showOnPage: true
314
+ }]
315
+ }
316
+ ]);
317
+
318
+ function runAllTests() {
319
+ let tests = document.querySelectorAll(".runTest");
320
+ tests.forEach(test => {
321
+ test.click();
322
+ });
323
+ }
324
+
325
+ function runTest() {
326
+
327
+ //hide button
328
+ this.style.display = "none";
329
+
330
+ let parentElement = this.parentElement.parentElement;
331
+ let dataAttribute = this.getAttribute("data-type");
332
+ let expectedText = "";
333
+
334
+ console.log("Parent element inner text: ", parentElement.innerText);
335
+
336
+ if(dataAttribute === "basicVariable") {
337
+ basicVariable = "Updated";
338
+
339
+ expectedText = `Basic Variable: Updated
340
+ Has been updated`;
341
+ }
342
+
343
+ if(dataAttribute === "simpleObject") {
344
+ simpleObject.firstName = "Jane";
345
+ simpleObject.lastName = "Doe";
346
+
347
+ expectedText = `Simple Object:
348
+ First Name: Jane
349
+ Last Name: Doe
350
+ Has been updated`;
351
+ }
352
+
353
+ if(dataAttribute === "simpleArrayUpdate") {
354
+ simpleArrayUpdate[0].firstName = "Josh";
355
+ simpleArrayUpdate[0].lastName = "Forger";
356
+ simpleArrayUpdate[1].firstName = "Matilda";
357
+ simpleArrayUpdate[1].lastName = "Swinson";
358
+
359
+ expectedText = `Simple Array Update:
360
+ Josh Forger
361
+ Matilda Swinson
362
+ Has been updated`;
363
+ }
364
+
365
+ if(dataAttribute === "simpleArrayAdd") {
366
+ simpleArrayAdd.push({
367
+ firstName: "Josh",
368
+ lastName: "Forger"
369
+ });
370
+
371
+ expectedText = `Simple Array Add:
372
+ John Doe
373
+ Jane Doe
374
+ Josh Forger
375
+ Has been updated`;
376
+ }
377
+
378
+ if(dataAttribute === "simpleArrayRemove") {
379
+ simpleArrayRemove.splice(0, 1);
380
+
381
+ expectedText = `Simple Array Remove:
382
+ Jane Doe
383
+ Has been updated`;
384
+ }
385
+
386
+ if(dataAttribute === "complexArrayWithChildrenUpdate") {
387
+ complexArrayWithChildrenUpdate[0].firstName = "Josh";
388
+ complexArrayWithChildrenUpdate[0].lastName = "Forger";
389
+ complexArrayWithChildrenUpdate[0].phoneNumbers[0] = "123-123-1234";
390
+ complexArrayWithChildrenUpdate[0].addresses[1].city = "Hudson";
391
+ complexArrayWithChildrenUpdate[0].addresses[1].state = "OH";
392
+
393
+ expectedText = `Complex Array With Children Update:
394
+ Josh Forger
395
+ Phone Numbers:
396
+ 123-123-1234
397
+ 555-987-6543
398
+ Addresses
399
+ Chicago, IL
400
+ Hudson, OH
401
+ New York, NY
402
+ Sarah Johnson
403
+ Phone Numbers:
404
+ 555-234-5678
405
+ 555-876-5432
406
+ 555-345-6789
407
+ Addresses
408
+ Boston, MA
409
+ Austin, TX
410
+ Has been updated
411
+ `;
412
+ }
413
+
414
+ if(dataAttribute === "complexArrayWithChildrenDisplayUpdate") {
415
+ complexArrayWithChildrenDisplayUpdate[0].attributes.showOnPage = false;
416
+ // requires a force update unfortunately
417
+ complexArrayWithChildrenDisplayUpdate.forceUpdate();
418
+
419
+ expectedText = `Complex Array With Children Display Update:
420
+ Michael Smith
421
+ Sarah Johnson
422
+ Show on page
423
+ `;
424
+ }
425
+
426
+ setTimeout(() => {
427
+ visibleTextCompare(parentElement,expectedText);
428
+ }, 1000)
429
+ }
430
+
431
+ document.querySelectorAll(".runTest").forEach(test => {
432
+ test.addEventListener("click", runTest);
433
+ });
434
+
435
+ function visibleTextCompare(element, expectedText) {
436
+ let visibleText = element.innerText;
437
+
438
+ visibleText = visibleText.replace(/\s/g, "").replace("RunTest", "");
439
+ expectedText = expectedText.replace(/\s/g, "").replace("RunTest", "");
440
+
441
+ let result = visibleText === expectedText;
442
+
443
+ if(!result) {
444
+ console.log("Visible text: ", visibleText);
445
+ console.log("Expected text: ", expectedText);
446
+ }
447
+
448
+ element.classList.add(result ? "success" : "fail");
449
+ }
450
+ </script>
451
+ </body>
452
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "resonantjs",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "description": "A lightweight JavaScript framework that enables reactive data-binding for building dynamic and responsive web applications. It simplifies creating interactive UIs by automatically updating the DOM when your data changes.",
5
5
  "main": "resonant.js",
6
6
  "repository": {
package/resonant.js CHANGED
@@ -79,7 +79,6 @@ class ObservableArray extends Array {
79
79
 
80
80
  forceUpdate() {
81
81
  this.forEach((item, index) => {
82
- console.log('forceUpdate', item, index);
83
82
  this._setKeyForObjectAndChildObjects(item, index);
84
83
  });
85
84
  this.resonantInstance.arrayDataChangeDetection[this.variableName] = this.slice();
@@ -259,10 +258,60 @@ class Resonant {
259
258
  });
260
259
  }
261
260
 
262
- _evaluateDisplayCondition(element, item, condition) {
261
+ _evaluateDisplayCondition(element, instance, condition) {
263
262
  try {
264
- const show = new Function('item', `return ${condition}`)(item);
265
- element.style.display = show ? '' : 'none';
263
+ let parent = element.parentElement;
264
+ let parentResName = null;
265
+ let arrayIndex = null;
266
+
267
+ while (parent && !parentResName) {
268
+ parentResName = parent.getAttribute('res');
269
+ if (!arrayIndex) {
270
+ arrayIndex = parent.getAttribute('res-index');
271
+ }
272
+ parent = parent.parentElement;
273
+ }
274
+
275
+ // For array items, use the specific array element as instance
276
+ if (parentResName && arrayIndex !== null && Array.isArray(this.data[parentResName])) {
277
+ instance = this.data[parentResName][arrayIndex];
278
+ }
279
+
280
+ // For object properties without parent reference
281
+ if (parentResName && !condition.includes(parentResName + '.')) {
282
+ const propNames = condition.match(/\b[a-zA-Z_][a-zA-Z0-9_]*\b/g) || [];
283
+ propNames.forEach(prop => {
284
+ if (prop === '==' || prop === '!=' || !(prop in instance)) return;
285
+
286
+ const regex = new RegExp(`\\b${prop}\\b`, 'g');
287
+ const propValue = instance[prop];
288
+
289
+ if (propValue === undefined) {
290
+ // Keep as is - property doesn't exist
291
+ return;
292
+ }
293
+
294
+ // Determine correct property access path
295
+ if (instance['item.' + prop] !== undefined) {
296
+ condition = condition.replace(regex, `item.${prop}`);
297
+ } else if (typeof propValue === 'object') {
298
+ condition = condition.replace(regex, `${parentResName}.${prop}`);
299
+ }
300
+ });
301
+ }
302
+
303
+ let show = false;
304
+ try{
305
+ show = new Function('item', `return ${condition}`)(instance);
306
+ } catch(e) {
307
+
308
+ const firstPeriodIndex = condition.indexOf('.');
309
+ const conditionAfterFirstPeriod = condition.substring(firstPeriodIndex + 1);
310
+ show = new Function('item', `return item.${conditionAfterFirstPeriod}`)(instance);
311
+
312
+ }
313
+
314
+ element.style.display = show ? 'inherit' : 'none';
266
315
  } catch (e) {
267
316
  console.error(`Error evaluating display condition: ${condition}`, e);
268
317
  }
@@ -361,9 +410,9 @@ class Resonant {
361
410
  }
362
411
 
363
412
  updateElement(variableName) {
413
+
364
414
  const elements = document.querySelectorAll(`[res="${variableName}"]`);
365
415
  const value = this.data[variableName];
366
-
367
416
  elements.forEach(element => {
368
417
  if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
369
418
  this._handleInputElement(element, value, (newValue) => {
@@ -402,7 +451,8 @@ class Resonant {
402
451
  });
403
452
  }
404
453
  else if (Array.isArray(propValue)) {
405
- this._renderNestedArray(subEl, propValue);
454
+ let parentKey = this.data[parentVarName].key;
455
+ this._renderNestedArray(subEl, propValue, parentKey);
406
456
  }
407
457
  else if (typeof propValue === 'object' && propValue !== null) {
408
458
  const nestedElements = subEl.querySelectorAll('[res-prop]');
@@ -480,7 +530,8 @@ class Resonant {
480
530
  );
481
531
  }
482
532
  else if (Array.isArray(value)) {
483
- this._renderNestedArray(subEl, value);
533
+ let parentKey = this.data[variableName][index].key;
534
+ this._renderNestedArray(subEl, value, parentKey);
484
535
  }
485
536
  else if (typeof value === 'object' && value !== null) {
486
537
  const nestedElements = subEl.querySelectorAll('[res-prop]');
@@ -504,7 +555,7 @@ class Resonant {
504
555
  container.appendChild(elementToUse);
505
556
  });
506
557
  }
507
- _renderNestedArray(subEl, arrayValue) {
558
+ _renderNestedArray(subEl, arrayValue, parentKey) {
508
559
  const template = subEl.cloneNode(true);
509
560
  subEl.innerHTML = '';
510
561
 
@@ -514,26 +565,42 @@ class Resonant {
514
565
  const cloned = template.cloneNode(true);
515
566
  cloned.setAttribute('res-rendered', 'true');
516
567
 
517
- const nestedEls = cloned.querySelectorAll('[res-prop]');
518
- nestedEls.forEach(nestedEl => {
519
- const nestedKey = nestedEl.getAttribute('res-prop');
520
- if (nestedKey && nestedKey in item) {
521
- this._renderObjectProperty(nestedEl, item[nestedKey], null, nestedKey);
522
- }
523
- });
568
+ if (item !== null && typeof item !== 'object') {
569
+ cloned.innerHTML = item;
570
+ } else {
571
+ const nestedEls = cloned.querySelectorAll('[res-prop]');
572
+ nestedEls.forEach(nestedEl => {
573
+ const nestedKey = nestedEl.getAttribute('res-prop');
574
+ if (nestedKey && nestedKey in item) {
575
+ nestedEl.setAttribute('res-child', item.key + '-' + nestedKey + '--' + parentKey);
576
+ this._renderObjectProperty(nestedEl, item[nestedKey], null, nestedKey);
577
+ }
578
+ });
524
579
 
525
- this._handleDisplayElements(cloned, item);
526
- this._bindClickEvents(cloned, item, arrayValue);
580
+ this._handleDisplayElements(cloned, item);
581
+ this._bindClickEvents(cloned, item, arrayValue);
527
582
 
583
+ const displayCondition = cloned.getAttribute('res-display');
584
+ if (displayCondition) {
585
+ this._evaluateDisplayCondition(cloned, item, displayCondition);
586
+ }
587
+ }
528
588
  subEl.appendChild(cloned);
529
589
  });
530
590
  }
591
+
531
592
  updateDisplayConditionalsFor(variableName) {
532
593
  const conditionalElements = document.querySelectorAll(`[res-display*="${variableName}"]`);
533
594
  conditionalElements.forEach(conditionalElement => {
534
595
  const condition = conditionalElement.getAttribute('res-display');
535
596
  this._evaluateDisplayCondition(conditionalElement, this.data[variableName], condition);
536
597
  });
598
+
599
+ const contextElements = document.querySelectorAll(`[res="${variableName}"] [res-display]`);
600
+ contextElements.forEach(conditionalElement => {
601
+ const condition = conditionalElement.getAttribute('res-display');
602
+ this._evaluateDisplayCondition(conditionalElement, this.data[variableName], condition);
603
+ });
537
604
  }
538
605
 
539
606
  updateStylesFor(variableName) {
package/resonant.min.js CHANGED
@@ -1 +1 @@
1
- class ObservableArray extends Array{constructor(e,t,...r){if(void 0===t)return super(...r);super(...r);var s=void 0===t.data[e];this.variableName=e,this.resonantInstance=t,this.isDeleting=!1,this.forEach((e,t)=>{"object"==typeof e&&(this._setKeyForObjectAndChildObjects(e,t),this[t]=this._createProxy(e,t))}),s||this.forceUpdate()}_setKeyForObjectAndChildObjects(e,t){"object"==typeof e&&(e.key=t+"-"+this._generateKeyByContentCheckSum(e),Object.keys(e).forEach(r=>{this._setKeyForObjectAndChildObjects(e[r],t)}))}_generateKeyByContentCheckSum(e){let t=e=>{if(!e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(e=>t(e));let r={...e};return delete r.key,Object.keys(r).forEach(e=>{"object"==typeof r[e]&&null!==r[e]&&(r[e]=t(r[e]))}),r},r=t(e),s=JSON.stringify(r),a=0;for(let i=0;i<s.length;i++){let n=s.charCodeAt(i);a=(a<<5)-a+n,a&=a}return Math.abs(a).toString(36)}_createProxy(e,t){return new Proxy(e,{set:(r,s,a)=>{if(r[s]!==a){let i=r[s];r[s]=a,this._setKeyForObjectAndChildObjects(e,t),this.resonantInstance._queueUpdate(this.variableName,"modified",r,s,i,t)}return!0}})}forceUpdate(){this.forEach((e,t)=>{console.log("forceUpdate",e,t),this._setKeyForObjectAndChildObjects(e,t)}),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),this.resonantInstance._queueUpdate(this.variableName,"modified",this.slice())}update(e){window[this.variableName]=e,this.resonantInstance._queueUpdate(this.variableName,"updated",e)}push(...e){e=e.map((e,t)=>"object"==typeof e?(this._setKeyForObjectAndChildObjects(e,this.length+t),this._createProxy(e,this.length+t)):e);let t=super.push(...e);return this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),e.forEach((e,t)=>{this.resonantInstance._queueUpdate(this.variableName,"added",e,this.length-1-t)}),t}splice(e,t,...r){r=r.map((t,r)=>"object"==typeof t?this._createProxy(t,e+r):t);let s=super.splice(e,t,...r);return this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),t>0&&s.forEach((t,r)=>{this.resonantInstance._queueUpdate(this.variableName,"removed",t,e+r)}),r.length>0&&r.forEach((t,r)=>{this.resonantInstance._queueUpdate(this.variableName,"added",t,e+r)}),s}set(e,t){if(this[e]!==t){if(this.isDeleting)return!0;let r=this.resonantInstance.arrayDataChangeDetection[this.variableName],s="modified";e>=r.length?s="added":void 0===r[e]&&(s="added"),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice();let a=this[e];this[e]=t,this.resonantInstance._queueUpdate(this.variableName,s,this[e],e,a)}return!0}delete(e){let t=this[e];return this.isDeleting=!0,this.splice(e,1),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),this.resonantInstance._queueUpdate(this.variableName,"removed",null,e,t),this.isDeleting=!1,!0}filter(e,t=!0){if(void 0===this.resonantInstance||!1===t)return super.filter(e);let r=super.filter(e);return this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),this.resonantInstance._queueUpdate(this.variableName,"filtered"),r}}class Resonant{constructor(){this.data={},this.callbacks={},this.pendingUpdates=new Map,this.arrayDataChangeDetection={}}_handleInputElement(e,t,r){"checkbox"===e.type?(e.checked=t,e.hasAttribute("data-resonant-bound")||(e.onchange=()=>r(e.checked),e.setAttribute("data-resonant-bound","true"))):(e.value=t,e.hasAttribute("data-resonant-bound")||(e.oninput=()=>r(e.value),e.setAttribute("data-resonant-bound","true")))}add(e,t,r){Array.isArray(t=this.persist(e,t,r))?(this.data[e]=new ObservableArray(e,this,...t),this.arrayDataChangeDetection[e]=this.data[e].slice()):"object"==typeof t&&null!==t?this.data[e]=this._createObject(e,t):this.data[e]=t,this._defineProperty(e),this.updateElement(e)}persist(e,t,r){if(void 0===r||!r)return t;var s=localStorage.getItem("res_"+e);return null!=s?JSON.parse(s):(localStorage.setItem("res_"+e,JSON.stringify(t)),t)}updatePersistantData(e){localStorage.getItem("res_"+e)&&localStorage.setItem("res_"+e,JSON.stringify(this.data[e]))}addAll(e){Object.entries(e).forEach(([e,t])=>{this.add(e,t)})}_resolveValue(e,t,r=null){return r??e[t]}_createObject(e,t){return t[Symbol("isProxy")]=!0,new Proxy(t,{set:(t,r,s)=>{if(t[r]!==s){let a=t[r];t[r]=s,this._queueUpdate(e,"modified",t,r,a)}return!0}})}_evaluateDisplayCondition(e,t,r){try{let s=Function("item",`return ${r}`)(t);e.style.display=s?"":"none"}catch(a){console.error(`Error evaluating display condition: ${r}`,a)}}_handleDisplayElements(e,t){let r=e.querySelectorAll("[res-display]");r.forEach(e=>{let r=e.getAttribute("res-display")||"";this._evaluateDisplayCondition(e,t,r)})}_bindClickEvents(e,t,r){let s=e.querySelectorAll("[res-onclick], [res-onclick-remove]");s.forEach(e=>{let s=e.getAttribute("res-onclick"),a=e.getAttribute("res-onclick-remove");s&&(e.onclick=()=>{let e=Function("item",`return ${s}(item)`);e(t)}),a&&(e.onclick=()=>{if(r){let e=r.findIndex(e=>e[a]===t[a]);-1!==e&&r.splice(e,1)}})})}_defineProperty(e){Object.defineProperty(window,e,{get:()=>this.data[e],set:t=>{Array.isArray(t)?(this.data[e]=new ObservableArray(e,this,...t),this.arrayDataChangeDetection[e]=this.data[e].slice()):"object"==typeof t&&null!==t?this.data[e]=this._createObject(e,t):this.data[e]=t,this.updateElement(e),this.updateDisplayConditionalsFor(e),this.updateStylesFor(e),Array.isArray(t)||"object"==typeof t&&null!==t||this._queueUpdate(e,"modified",this.data[e])}})}_queueUpdate(e,t,r,s,a){this.pendingUpdates.has(e)||this.pendingUpdates.set(e,[]),this.pendingUpdates.get(e).push({action:t,item:r,property:s,oldValue:a}),1===this.pendingUpdates.get(e).length&&setTimeout(()=>{let t=this.pendingUpdates.get(e);this.updatePersistantData(e),this.pendingUpdates.delete(e),(t=t.filter((e,t,r)=>r.findIndex(t=>t.property===e.property&&t.action===e.action)===t)).forEach(t=>{this._triggerCallbacks(e,t)}),this.updateElement(e),this.updateDisplayConditionalsFor(e),this.updateStylesFor(e)},0)}_triggerCallbacks(e,t){this.callbacks[e]&&this.callbacks[e].forEach(r=>{let s=t.item||t.oldValue;r(this.data[e],s,t.action)})}updateElement(e){let t=document.querySelectorAll(`[res="${e}"]`),r=this.data[e];t.forEach(t=>{if("INPUT"===t.tagName||"TEXTAREA"===t.tagName)this._handleInputElement(t,r,t=>{this.data[e]=t,this._queueUpdate(e,"modified",this.data[e])});else if(Array.isArray(r))t.querySelectorAll(`[res="${e}"][res-rendered="true"]`).forEach(e=>e.remove()),this._renderArray(e,t);else if("object"==typeof r&&null!==r){let s=t.querySelectorAll("[res-prop]");s.forEach(t=>{let s=t.getAttribute("res-prop");s&&s in r&&this._renderObjectProperty(t,r[s],e,s)})}else t.innerHTML=r??""}),this.updateDisplayConditionalsFor(e),this.updateStylesFor(e)}_renderObjectProperty(e,t,r,s){if("INPUT"!==e.tagName&&"TEXTAREA"!==e.tagName||Array.isArray(t)||"object"==typeof t){if(Array.isArray(t))this._renderNestedArray(e,t);else if("object"==typeof t&&null!==t){let a=e.querySelectorAll("[res-prop]");a.forEach(e=>{let s=e.getAttribute("res-prop");s&&s in t&&this._renderObjectProperty(e,t[s],r,s)})}else e.innerHTML=t??""}else this._handleInputElement(e,t,e=>{window[r][s]=e})}_renderArray(e,t){let r=t.hasAttribute("res")&&t.parentElement?t.parentElement:t,s;window[e+"_template"]?s=window[e+"_template"]:(s=t.cloneNode(!0),window[e+"_template"]=s,t.style.display="none",t.setAttribute("res-template","true"));let a=new Map;r.querySelectorAll(`[res="${e}"][res-rendered="true"]`).forEach(e=>{let t=e.getAttribute("res-key");t&&a.set(t,e)}),r.querySelectorAll(`[res="${e}"][res-rendered="true"]`).forEach(e=>e.remove()),this.data[e].forEach((t,i)=>{let n=t.key,l;if(a.has(n))l=a.get(n),a.delete(n),l.setAttribute("res-index",i);else for(let o in(l=s.cloneNode(!0)).removeAttribute("res-template"),l.style.display="",l.setAttribute("res-rendered","true"),l.setAttribute("res-key",n),l.setAttribute("res-index",i),t){let h=null,d=l.querySelector(`[res-prop="${o}"]`);if(d||(d=l.querySelector('[res-prop=""]'),h=t),d){let c=this._resolveValue(t,o,h);if("INPUT"!==d.tagName&&"TEXTAREA"!==d.tagName||Array.isArray(c)||"object"==typeof c){if(Array.isArray(c))this._renderNestedArray(d,c);else if("object"==typeof c&&null!==c){let u=d.querySelectorAll("[res-prop]");u.forEach(t=>{let r=t.getAttribute("res-prop");r&&r in c&&this._renderObjectProperty(t,c[r],e,r)})}else d.innerHTML=c??""}else this._handleInputElement(d,c,r=>{t[o]=r,this._queueUpdate(e,"modified",t,o,c)})}}this._handleDisplayElements(l,t),this._bindClickEvents(l,t,this.data[e]),r.appendChild(l)})}_renderNestedArray(e,t){let r=e.cloneNode(!0);e.innerHTML="",e.removeAttribute("res-prop"),t.forEach((s,a)=>{let i=r.cloneNode(!0);i.setAttribute("res-rendered","true");let n=i.querySelectorAll("[res-prop]");n.forEach(e=>{let t=e.getAttribute("res-prop");t&&t in s&&this._renderObjectProperty(e,s[t],null,t)}),this._handleDisplayElements(i,s),this._bindClickEvents(i,s,t),e.appendChild(i)})}updateDisplayConditionalsFor(e){let t=document.querySelectorAll(`[res-display*="${e}"]`);t.forEach(t=>{let r=t.getAttribute("res-display");this._evaluateDisplayCondition(t,this.data[e],r)})}updateStylesFor(variableName){let styleElements=document.querySelectorAll(`[res-style*="${variableName}"]`);styleElements.forEach(styleElement=>{let styleCondition=styleElement.getAttribute("res-style");try{let parent=styleElement,index=null;for(;parent&&!index;)index=parent.getAttribute("res-index"),parent=parent.parentElement;let resStyles=styleElement.getAttribute("res-styles");if(resStyles&&resStyles.split(" ").forEach(e=>{styleElement.classList.remove(e)}),null!==index){let item=this.data[variableName][index];styleCondition=styleCondition.replace(RegExp(`\\b${variableName}\\b`,"g"),"item");let styleClass=Function("item",`return ${styleCondition}`)(item);if(styleClass)styleElement.classList.add(styleClass);else{let elementHasStyle=styleElement.classList.contains(styleClass);elementHasStyle&&styleElement.classList.remove(styleClass)}}else{let styleClass=eval(styleCondition);if(styleClass)styleElement.classList.add(styleClass),styleElement.setAttribute("res-styles",styleClass);else{let elementHasStyle=styleElement.classList.contains(styleClass);elementHasStyle&&styleElement.classList.remove(styleClass)}}}catch(e){console.error(`Error evaluating style for ${variableName}: ${styleCondition}`,e)}})}addCallback(e,t){this.callbacks[e]||(this.callbacks[e]=[]),this.callbacks[e].push(t)}}
1
+ class ObservableArray extends Array{constructor(e,t,...r){if(void 0===t)return super(...r);super(...r);var s=void 0===t.data[e];this.variableName=e,this.resonantInstance=t,this.isDeleting=!1,this.forEach((e,t)=>{"object"==typeof e&&(this._setKeyForObjectAndChildObjects(e,t),this[t]=this._createProxy(e,t))}),s||this.forceUpdate()}_setKeyForObjectAndChildObjects(e,t){"object"==typeof e&&(e.key=t+"-"+this._generateKeyByContentCheckSum(e),Object.keys(e).forEach(r=>{this._setKeyForObjectAndChildObjects(e[r],t)}))}_generateKeyByContentCheckSum(e){let t=e=>{if(!e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(e=>t(e));let r={...e};return delete r.key,Object.keys(r).forEach(e=>{"object"==typeof r[e]&&null!==r[e]&&(r[e]=t(r[e]))}),r},r=t(e),s=JSON.stringify(r),a=0;for(let i=0;i<s.length;i++){let l=s.charCodeAt(i);a=(a<<5)-a+l,a&=a}return Math.abs(a).toString(36)}_createProxy(e,t){return new Proxy(e,{set:(r,s,a)=>{if(r[s]!==a){let i=r[s];r[s]=a,this._setKeyForObjectAndChildObjects(e,t),this.resonantInstance._queueUpdate(this.variableName,"modified",r,s,i,t)}return!0}})}forceUpdate(){this.forEach((e,t)=>{this._setKeyForObjectAndChildObjects(e,t)}),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),this.resonantInstance._queueUpdate(this.variableName,"modified",this.slice())}update(e){window[this.variableName]=e,this.resonantInstance._queueUpdate(this.variableName,"updated",e)}push(...e){e=e.map((e,t)=>"object"==typeof e?(this._setKeyForObjectAndChildObjects(e,this.length+t),this._createProxy(e,this.length+t)):e);let t=super.push(...e);return this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),e.forEach((e,t)=>{this.resonantInstance._queueUpdate(this.variableName,"added",e,this.length-1-t)}),t}splice(e,t,...r){r=r.map((t,r)=>"object"==typeof t?this._createProxy(t,e+r):t);let s=super.splice(e,t,...r);return this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),t>0&&s.forEach((t,r)=>{this.resonantInstance._queueUpdate(this.variableName,"removed",t,e+r)}),r.length>0&&r.forEach((t,r)=>{this.resonantInstance._queueUpdate(this.variableName,"added",t,e+r)}),s}set(e,t){if(this[e]!==t){if(this.isDeleting)return!0;let r=this.resonantInstance.arrayDataChangeDetection[this.variableName],s="modified";e>=r.length?s="added":void 0===r[e]&&(s="added"),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice();let a=this[e];this[e]=t,this.resonantInstance._queueUpdate(this.variableName,s,this[e],e,a)}return!0}delete(e){let t=this[e];return this.isDeleting=!0,this.splice(e,1),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),this.resonantInstance._queueUpdate(this.variableName,"removed",null,e,t),this.isDeleting=!1,!0}filter(e,t=!0){if(void 0===this.resonantInstance||!1===t)return super.filter(e);let r=super.filter(e);return this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),this.resonantInstance._queueUpdate(this.variableName,"filtered"),r}}class Resonant{constructor(){this.data={},this.callbacks={},this.pendingUpdates=new Map,this.arrayDataChangeDetection={}}_handleInputElement(e,t,r){"checkbox"===e.type?(e.checked=t,e.hasAttribute("data-resonant-bound")||(e.onchange=()=>r(e.checked),e.setAttribute("data-resonant-bound","true"))):(e.value=t,e.hasAttribute("data-resonant-bound")||(e.oninput=()=>r(e.value),e.setAttribute("data-resonant-bound","true")))}add(e,t,r){Array.isArray(t=this.persist(e,t,r))?(this.data[e]=new ObservableArray(e,this,...t),this.arrayDataChangeDetection[e]=this.data[e].slice()):"object"==typeof t&&null!==t?this.data[e]=this._createObject(e,t):this.data[e]=t,this._defineProperty(e),this.updateElement(e)}persist(e,t,r){if(void 0===r||!r)return t;var s=localStorage.getItem("res_"+e);return null!=s?JSON.parse(s):(localStorage.setItem("res_"+e,JSON.stringify(t)),t)}updatePersistantData(e){localStorage.getItem("res_"+e)&&localStorage.setItem("res_"+e,JSON.stringify(this.data[e]))}addAll(e){Object.entries(e).forEach(([e,t])=>{this.add(e,t)})}_resolveValue(e,t,r=null){return r??e[t]}_createObject(e,t){return t[Symbol("isProxy")]=!0,new Proxy(t,{set:(t,r,s)=>{if(t[r]!==s){let a=t[r];t[r]=s,this._queueUpdate(e,"modified",t,r,a)}return!0}})}_evaluateDisplayCondition(e,t,r){try{let s=e.parentElement,a=null,i=null;for(;s&&!a;)a=s.getAttribute("res"),i||(i=s.getAttribute("res-index")),s=s.parentElement;if(a&&null!==i&&Array.isArray(this.data[a])&&(t=this.data[a][i]),a&&!r.includes(a+".")){let l=r.match(/\b[a-zA-Z_][a-zA-Z0-9_]*\b/g)||[];l.forEach(e=>{if("=="===e||"!="===e||!(e in t))return;let s=RegExp(`\\b${e}\\b`,"g"),i=t[e];void 0!==i&&(void 0!==t["item."+e]?r=r.replace(s,`item.${e}`):"object"==typeof i&&(r=r.replace(s,`${a}.${e}`)))})}let n=!1;try{n=Function("item",`return ${r}`)(t)}catch(o){let h=r.indexOf("."),d=r.substring(h+1);n=Function("item",`return item.${d}`)(t)}e.style.display=n?"inherit":"none"}catch(c){console.error(`Error evaluating display condition: ${r}`,c)}}_handleDisplayElements(e,t){let r=e.querySelectorAll("[res-display]");r.forEach(e=>{let r=e.getAttribute("res-display")||"";this._evaluateDisplayCondition(e,t,r)})}_bindClickEvents(e,t,r){let s=e.querySelectorAll("[res-onclick], [res-onclick-remove]");s.forEach(e=>{let s=e.getAttribute("res-onclick"),a=e.getAttribute("res-onclick-remove");s&&(e.onclick=()=>{let e=Function("item",`return ${s}(item)`);e(t)}),a&&(e.onclick=()=>{if(r){let e=r.findIndex(e=>e[a]===t[a]);-1!==e&&r.splice(e,1)}})})}_defineProperty(e){Object.defineProperty(window,e,{get:()=>this.data[e],set:t=>{Array.isArray(t)?(this.data[e]=new ObservableArray(e,this,...t),this.arrayDataChangeDetection[e]=this.data[e].slice()):"object"==typeof t&&null!==t?this.data[e]=this._createObject(e,t):this.data[e]=t,this.updateElement(e),this.updateDisplayConditionalsFor(e),this.updateStylesFor(e),Array.isArray(t)||"object"==typeof t&&null!==t||this._queueUpdate(e,"modified",this.data[e])}})}_queueUpdate(e,t,r,s,a){this.pendingUpdates.has(e)||this.pendingUpdates.set(e,[]),this.pendingUpdates.get(e).push({action:t,item:r,property:s,oldValue:a}),1===this.pendingUpdates.get(e).length&&setTimeout(()=>{let t=this.pendingUpdates.get(e);this.updatePersistantData(e),this.pendingUpdates.delete(e),(t=t.filter((e,t,r)=>r.findIndex(t=>t.property===e.property&&t.action===e.action)===t)).forEach(t=>{this._triggerCallbacks(e,t)}),this.updateElement(e),this.updateDisplayConditionalsFor(e),this.updateStylesFor(e)},0)}_triggerCallbacks(e,t){this.callbacks[e]&&this.callbacks[e].forEach(r=>{let s=t.item||t.oldValue;r(this.data[e],s,t.action)})}updateElement(e){let t=document.querySelectorAll(`[res="${e}"]`),r=this.data[e];t.forEach(t=>{if("INPUT"===t.tagName||"TEXTAREA"===t.tagName)this._handleInputElement(t,r,t=>{this.data[e]=t,this._queueUpdate(e,"modified",this.data[e])});else if(Array.isArray(r))t.querySelectorAll(`[res="${e}"][res-rendered="true"]`).forEach(e=>e.remove()),this._renderArray(e,t);else if("object"==typeof r&&null!==r){let s=t.querySelectorAll("[res-prop]");s.forEach(t=>{let s=t.getAttribute("res-prop");s&&s in r&&this._renderObjectProperty(t,r[s],e,s)})}else t.innerHTML=r??""}),this.updateDisplayConditionalsFor(e),this.updateStylesFor(e)}_renderObjectProperty(e,t,r,s){if("INPUT"!==e.tagName&&"TEXTAREA"!==e.tagName||Array.isArray(t)||"object"==typeof t){if(Array.isArray(t)){let a=this.data[r].key;this._renderNestedArray(e,t,a)}else if("object"==typeof t&&null!==t){let i=e.querySelectorAll("[res-prop]");i.forEach(e=>{let s=e.getAttribute("res-prop");s&&s in t&&this._renderObjectProperty(e,t[s],r,s)})}else e.innerHTML=t??""}else this._handleInputElement(e,t,e=>{window[r][s]=e})}_renderArray(e,t){let r=t.hasAttribute("res")&&t.parentElement?t.parentElement:t,s;window[e+"_template"]?s=window[e+"_template"]:(s=t.cloneNode(!0),window[e+"_template"]=s,t.style.display="none",t.setAttribute("res-template","true"));let a=new Map;r.querySelectorAll(`[res="${e}"][res-rendered="true"]`).forEach(e=>{let t=e.getAttribute("res-key");t&&a.set(t,e)}),r.querySelectorAll(`[res="${e}"][res-rendered="true"]`).forEach(e=>e.remove()),this.data[e].forEach((t,i)=>{let l=t.key,n;if(a.has(l))n=a.get(l),a.delete(l),n.setAttribute("res-index",i);else for(let o in(n=s.cloneNode(!0)).removeAttribute("res-template"),n.style.display="",n.setAttribute("res-rendered","true"),n.setAttribute("res-key",l),n.setAttribute("res-index",i),t){let h=null,d=n.querySelector(`[res-prop="${o}"]`);if(d||(d=n.querySelector('[res-prop=""]'),h=t),d){let c=this._resolveValue(t,o,h);if("INPUT"!==d.tagName&&"TEXTAREA"!==d.tagName||Array.isArray(c)||"object"==typeof c){if(Array.isArray(c)){let u=this.data[e][i].key;this._renderNestedArray(d,c,u)}else if("object"==typeof c&&null!==c){let p=d.querySelectorAll("[res-prop]");p.forEach(t=>{let r=t.getAttribute("res-prop");r&&r in c&&this._renderObjectProperty(t,c[r],e,r)})}else d.innerHTML=c??""}else this._handleInputElement(d,c,r=>{t[o]=r,this._queueUpdate(e,"modified",t,o,c)})}}this._handleDisplayElements(n,t),this._bindClickEvents(n,t,this.data[e]),r.appendChild(n)})}_renderNestedArray(e,t,r){let s=e.cloneNode(!0);e.innerHTML="",e.removeAttribute("res-prop"),t.forEach((a,i)=>{let l=s.cloneNode(!0);if(l.setAttribute("res-rendered","true"),null!==a&&"object"!=typeof a)l.innerHTML=a;else{let n=l.querySelectorAll("[res-prop]");n.forEach(e=>{let t=e.getAttribute("res-prop");t&&t in a&&(e.setAttribute("res-child",a.key+"-"+t+"--"+r),this._renderObjectProperty(e,a[t],null,t))}),this._handleDisplayElements(l,a),this._bindClickEvents(l,a,t);let o=l.getAttribute("res-display");o&&this._evaluateDisplayCondition(l,a,o)}e.appendChild(l)})}updateDisplayConditionalsFor(e){let t=document.querySelectorAll(`[res-display*="${e}"]`);t.forEach(t=>{let r=t.getAttribute("res-display");this._evaluateDisplayCondition(t,this.data[e],r)});let r=document.querySelectorAll(`[res="${e}"] [res-display]`);r.forEach(t=>{let r=t.getAttribute("res-display");this._evaluateDisplayCondition(t,this.data[e],r)})}updateStylesFor(variableName){let styleElements=document.querySelectorAll(`[res-style*="${variableName}"]`);styleElements.forEach(styleElement=>{let styleCondition=styleElement.getAttribute("res-style");try{let parent=styleElement,index=null;for(;parent&&!index;)index=parent.getAttribute("res-index"),parent=parent.parentElement;let resStyles=styleElement.getAttribute("res-styles");if(resStyles&&resStyles.split(" ").forEach(e=>{styleElement.classList.remove(e)}),null!==index){let item=this.data[variableName][index];styleCondition=styleCondition.replace(RegExp(`\\b${variableName}\\b`,"g"),"item");let styleClass=Function("item",`return ${styleCondition}`)(item);if(styleClass)styleElement.classList.add(styleClass);else{let elementHasStyle=styleElement.classList.contains(styleClass);elementHasStyle&&styleElement.classList.remove(styleClass)}}else{let styleClass=eval(styleCondition);if(styleClass)styleElement.classList.add(styleClass),styleElement.setAttribute("res-styles",styleClass);else{let elementHasStyle=styleElement.classList.contains(styleClass);elementHasStyle&&styleElement.classList.remove(styleClass)}}}catch(e){console.error(`Error evaluating style for ${variableName}: ${styleCondition}`,e)}})}addCallback(e,t){this.callbacks[e]||(this.callbacks[e]=[]),this.callbacks[e].push(t)}}