snice 3.10.2 → 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.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v3.10.1
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.
@@ -3012,17 +3012,19 @@ function applyElementFunctionality(constructor) {
3012
3012
  }
3013
3013
  }
3014
3014
  }
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)
3015
+ // Clear pre-init values for properties that have HTML attributes
3016
+ // This prevents field initializers from overwriting HTML attributes later
3017
3017
  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
3018
+ for (const [propName, propValue] of Array.from(this[PRE_INIT_PROPERTY_VALUES].entries())) {
3023
3019
  const propOptions = properties?.get(propName);
3024
3020
  const attributeName = typeof propOptions?.attribute === 'string' ? propOptions.attribute : propName.toLowerCase();
3025
- if (!this.hasAttribute(attributeName)) {
3021
+ if (this.hasAttribute(attributeName)) {
3022
+ // Attribute exists - remove from PRE_INIT to prevent overwriting
3023
+ this[PRE_INIT_PROPERTY_VALUES].delete(propName);
3024
+ }
3025
+ else {
3026
+ // No attribute - apply the pre-init value
3027
+ this[PRE_INIT_PROPERTY_VALUES].delete(propName);
3026
3028
  this[propName] = propValue;
3027
3029
  }
3028
3030
  }
@@ -3282,16 +3284,18 @@ function property(options) {
3282
3284
  context.metadata[PROPERTIES].set(propertyKey, options || {});
3283
3285
  // Return a field initializer function for new decorators
3284
3286
  return function (initialValue) {
3287
+ // Ensure constructor[PROPERTIES] exists
3288
+ const constructor = this.constructor;
3289
+ if (!constructor[PROPERTIES]) {
3290
+ constructor[PROPERTIES] = new Map();
3291
+ }
3285
3292
  // Detect type from initial value if not explicitly provided
3286
3293
  const finalOptions = { ...options };
3287
3294
  if (!finalOptions.type && initialValue !== undefined) {
3288
3295
  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
3296
  }
3297
+ // Always store property options on constructor for runtime access
3298
+ constructor[PROPERTIES].set(propertyKey, finalOptions);
3295
3299
  // Set up the property descriptor on first access
3296
3300
  if (!Object.hasOwnProperty.call(this.constructor.prototype, propertyKey)) {
3297
3301
  const descriptor = {
@@ -3320,8 +3324,9 @@ function property(options) {
3320
3324
  // Get old value by calling the getter (which reads from attribute)
3321
3325
  const oldValue = this[propertyKey];
3322
3326
  // Check if value actually changed
3323
- if (oldValue === newValue)
3327
+ if (oldValue === newValue) {
3324
3328
  return;
3329
+ }
3325
3330
  // Don't reflect to DOM until connectedCallback has started
3326
3331
  // This prevents field initializers from overwriting HTML attributes
3327
3332
  if (!this[PROPERTIES_INITIALIZED]) {