snice 3.10.1 → 3.10.3

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/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v3.10.0
2
+ * snice v3.10.2
3
3
  * Imperative TypeScript framework for building vanilla web components with decorators, differential rendering, routing, and controllers. No virtual DOM, no build complexity.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -1492,10 +1492,12 @@ function matchesKeyboardFilter(event, filter) {
1492
1492
  * ConditionalIfPart handles <if> conditional rendering
1493
1493
  * Removes/inserts DOM nodes based on condition
1494
1494
  */
1495
+ // Sentinel value to distinguish "not yet set" from undefined
1496
+ const NOT_SET = Symbol('not-set');
1495
1497
  class ConditionalIfPart extends Part {
1496
1498
  constructor(ifElement) {
1497
1499
  super();
1498
- this.value = undefined;
1500
+ this.value = NOT_SET;
1499
1501
  this.fragment = null;
1500
1502
  this.ifElement = ifElement;
1501
1503
  this.ifElement.style.display = 'contents';
@@ -1537,7 +1539,7 @@ class ConditionalIfPart extends Part {
1537
1539
  class ConditionalCasePart extends Part {
1538
1540
  constructor(caseElement) {
1539
1541
  super();
1540
- this.value = undefined;
1542
+ this.value = NOT_SET;
1541
1543
  this.childrenMap = new Map();
1542
1544
  this.fragments = new Map();
1543
1545
  this.defaultChild = null;
@@ -3012,17 +3014,19 @@ function applyElementFunctionality(constructor) {
3012
3014
  }
3013
3015
  }
3014
3016
  }
3015
- // Apply any properties that were set before element was connected
3016
- // BUT only if they don't have an HTML attribute (don't override HTML attributes)
3017
+ // Clear pre-init values for properties that have HTML attributes
3018
+ // This prevents field initializers from overwriting HTML attributes later
3017
3019
  if (this[PRE_INIT_PROPERTY_VALUES]) {
3018
- for (const [propName, propValue] of this[PRE_INIT_PROPERTY_VALUES]) {
3019
- // Remove from map first so getter doesn't return it during setter call
3020
- this[PRE_INIT_PROPERTY_VALUES].delete(propName);
3021
- // Only apply pre-init value if NO HTML attribute exists
3022
- // This prevents field initializers from overwriting HTML attributes
3020
+ for (const [propName, propValue] of Array.from(this[PRE_INIT_PROPERTY_VALUES].entries())) {
3023
3021
  const propOptions = properties?.get(propName);
3024
3022
  const attributeName = typeof propOptions?.attribute === 'string' ? propOptions.attribute : propName.toLowerCase();
3025
- if (!this.hasAttribute(attributeName)) {
3023
+ if (this.hasAttribute(attributeName)) {
3024
+ // Attribute exists - remove from PRE_INIT to prevent overwriting
3025
+ this[PRE_INIT_PROPERTY_VALUES].delete(propName);
3026
+ }
3027
+ else {
3028
+ // No attribute - apply the pre-init value
3029
+ this[PRE_INIT_PROPERTY_VALUES].delete(propName);
3026
3030
  this[propName] = propValue;
3027
3031
  }
3028
3032
  }
@@ -3282,16 +3286,18 @@ function property(options) {
3282
3286
  context.metadata[PROPERTIES].set(propertyKey, options || {});
3283
3287
  // Return a field initializer function for new decorators
3284
3288
  return function (initialValue) {
3289
+ // Ensure constructor[PROPERTIES] exists
3290
+ const constructor = this.constructor;
3291
+ if (!constructor[PROPERTIES]) {
3292
+ constructor[PROPERTIES] = new Map();
3293
+ }
3285
3294
  // Detect type from initial value if not explicitly provided
3286
3295
  const finalOptions = { ...options };
3287
3296
  if (!finalOptions.type && initialValue !== undefined) {
3288
3297
  finalOptions.type = detectType(initialValue);
3289
- // Update the metadata with the detected type
3290
- const constructor = this.constructor;
3291
- if (constructor[PROPERTIES]) {
3292
- constructor[PROPERTIES].set(propertyKey, finalOptions);
3293
- }
3294
3298
  }
3299
+ // Always store property options on constructor for runtime access
3300
+ constructor[PROPERTIES].set(propertyKey, finalOptions);
3295
3301
  // Set up the property descriptor on first access
3296
3302
  if (!Object.hasOwnProperty.call(this.constructor.prototype, propertyKey)) {
3297
3303
  const descriptor = {
@@ -3320,8 +3326,9 @@ function property(options) {
3320
3326
  // Get old value by calling the getter (which reads from attribute)
3321
3327
  const oldValue = this[propertyKey];
3322
3328
  // Check if value actually changed
3323
- if (oldValue === newValue)
3329
+ if (oldValue === newValue) {
3324
3330
  return;
3331
+ }
3325
3332
  // Don't reflect to DOM until connectedCallback has started
3326
3333
  // This prevents field initializers from overwriting HTML attributes
3327
3334
  if (!this[PROPERTIES_INITIALIZED]) {