leanweb 3.0.7 → 3.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leanweb",
3
- "version": "3.0.7",
3
+ "version": "3.0.8",
4
4
  "description": "Builds framework agnostic web components.",
5
5
  "bin": {
6
6
  "leanweb": "leanweb.js",
@@ -111,10 +111,14 @@ export default class LWElement extends HTMLElement {
111
111
 
112
112
  this._bindMethods();
113
113
  setTimeout(() => {
114
- this.update(this.shadowRoot);
115
- setTimeout(() => {
116
- this.domReady?.call(this);
117
- });
114
+ const result = this.domReady?.call(this);
115
+ if (result && typeof result.then === 'function') {
116
+ // domReady is async
117
+ result.then(() => this.update());
118
+ } else {
119
+ // domReady is sync
120
+ this.update();
121
+ }
118
122
  });
119
123
 
120
124
  if (this.urlHashChanged && typeof this.urlHashChanged === 'function') {
@@ -286,7 +290,9 @@ export default class LWElement extends HTMLElement {
286
290
  } else if (modelNode.type === 'checkbox') {
287
291
  if (Array.isArray(object[propertyExpr])) {
288
292
  if (modelNode.checked) {
289
- object[propertyExpr].push(modelNode.value);
293
+ if (!object[propertyExpr].includes(modelNode.value)) {
294
+ object[propertyExpr].push(modelNode.value);
295
+ }
290
296
  } else {
291
297
  const index = object[propertyExpr].indexOf(modelNode.value);
292
298
  if (index > -1) {
@@ -335,9 +341,14 @@ export default class LWElement extends HTMLElement {
335
341
  } else if (modelNode.type === 'radio') {
336
342
  modelNode.checked = parsed[0] === modelNode.value;
337
343
  } else if (modelNode.type === 'select-multiple') {
344
+ // First, clear all selections
338
345
  for (let i = 0; i < modelNode.options.length; ++i) {
339
- const option = modelNode.options[i];
340
- if (parsed[0]) {
346
+ modelNode.options[i].selected = false;
347
+ }
348
+ // Then, set selected options
349
+ if (parsed[0]) {
350
+ for (let i = 0; i < modelNode.options.length; ++i) {
351
+ const option = modelNode.options[i];
341
352
  option.selected = parsed[0].includes(option.value);
342
353
  }
343
354
  }
@@ -419,11 +430,20 @@ export default class LWElement extends HTMLElement {
419
430
  const parsed = parser.evaluate(interpolation.ast, context, interpolation.loc);
420
431
 
421
432
  if (interpolation.lwValue === 'class') {
422
- const initClass = bindNode.getAttribute('lw-init-class');
423
- if (!parsed[0]) {
424
- bindNode.classList.remove(parsed[0]);
425
- } else {
426
- bindNode.classList = initClass + ' ' + parsed[0];
433
+ const dynamicClass = parsed[0];
434
+ const initClass = bindNode.getAttribute('lw-init-class') || '';
435
+ // Ensure initial classes are present
436
+ if (initClass) {
437
+ initClass.split(' ').forEach(cls => {
438
+ if (cls) bindNode.classList.add(cls);
439
+ });
440
+ }
441
+ // Add or remove the dynamic class
442
+ if (dynamicClass) {
443
+ bindNode.classList.add(dynamicClass);
444
+ } else if (dynamicClass !== undefined) {
445
+ // Only remove if not undefined (so we don't remove all classes accidentally)
446
+ bindNode.classList.remove(dynamicClass);
427
447
  }
428
448
  } else {
429
449
  if (parsed[0] !== false && parsed[0] !== undefined && parsed[0] !== null) {
@@ -96,14 +96,35 @@ const nodeHandlers = {
96
96
  'ExpressionStatement': (node, context) => evalNode(node.expression, context),
97
97
  'BinaryExpression': (node, context) => binaryOperations[node.operator](evalNode(node.left, context), evalNode(node.right, context)),
98
98
  'AssignmentExpression': (node, context) => {
99
- const immediateCtx = immediateContext(node.left, context);
100
- assignmentOperations[node.operator](immediateCtx, node.left.name, evalNode(node.right, context));
99
+ // Support complex left-hand sides (e.g., obj.prop = 1, obj[expr] = 1)
100
+ let obj, prop;
101
+ if (node.left.type === 'MemberExpression' || node.left.type === 'OptionalMemberExpression') {
102
+ obj = evalNode(node.left.object, context);
103
+ prop = node.left.computed ? evalNode(node.left.property, context) : node.left.property.name;
104
+ } else if (node.left.type === 'Identifier') {
105
+ // Simple variable assignment
106
+ obj = immediateContext(node.left, context);
107
+ prop = node.left.name;
108
+ } else {
109
+ throw new Error('Unsupported assignment left-hand side');
110
+ }
111
+ assignmentOperations[node.operator](obj, prop, evalNode(node.right, context));
101
112
  },
102
113
  'LogicalExpression': (node, context) => logicalOperators[node.operator](evalNode(node.left, context), evalNode(node.right, context)),
103
114
  'UnaryExpression': (node, context) => unaryOperators[node.operator](evalNode(node.argument, context)),
104
115
  'UpdateExpression': (node, context) => {
105
- const immediateCtx = immediateContext(node.argument, context);
106
- updateOperators(node.operator, node.prefix)(immediateCtx, node.argument.name, evalNode(node.argument, context));
116
+ // Support complex left-hand sides (e.g., ++obj.prop, ++obj[expr])
117
+ let obj, prop;
118
+ if (node.argument.type === 'MemberExpression' || node.argument.type === 'OptionalMemberExpression') {
119
+ obj = evalNode(node.argument.object, context);
120
+ prop = node.argument.computed ? evalNode(node.argument.property, context) : node.argument.property.name;
121
+ } else if (node.argument.type === 'Identifier') {
122
+ obj = immediateContext(node.argument, context);
123
+ prop = node.argument.name;
124
+ } else {
125
+ throw new Error('Unsupported update left-hand side');
126
+ }
127
+ return updateOperators(node.operator, node.prefix)(obj, prop);
107
128
  },
108
129
  'ConditionalExpression': (node, context) => {
109
130
  const test = evalNode(node.test, context);