@mintjamsinc/ichigojs 0.1.40 → 0.1.42

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/ichigo.cjs CHANGED
@@ -7816,6 +7816,13 @@
7816
7816
  * This allows retrieving the source path of an object for computed property mapping.
7817
7817
  */
7818
7818
  static proxyPaths = new WeakMap();
7819
+ /**
7820
+ * A Map to store path aliases.
7821
+ * Key: alias path (e.g., "editingNestedStep.steps")
7822
+ * Value: source path (e.g., "routes[0].steps[0].steps")
7823
+ * This allows mapping variable names to their actual source paths for dependency tracking.
7824
+ */
7825
+ static pathAliases = new Map();
7819
7826
  /**
7820
7827
  * Creates a reactive proxy for the given object.
7821
7828
  * The proxy will call the onChange callback whenever a property is modified.
@@ -7982,6 +7989,84 @@
7982
7989
  }
7983
7990
  return this.proxyPaths.get(obj);
7984
7991
  }
7992
+ /**
7993
+ * Registers a path alias.
7994
+ * This is used when a variable is assigned to reference an existing reactive object.
7995
+ * For example, when `editingNestedStep = routes[0].steps[0]`, this creates an alias
7996
+ * so that changes to "routes[0].steps[0].steps" also match "editingNestedStep.steps".
7997
+ *
7998
+ * @param aliasPath The alias path (e.g., "editingNestedStep")
7999
+ * @param sourcePath The source path (e.g., "routes[0].steps[0]")
8000
+ */
8001
+ static registerPathAlias(aliasPath, sourcePath) {
8002
+ if (aliasPath && sourcePath && aliasPath !== sourcePath) {
8003
+ this.pathAliases.set(aliasPath, sourcePath);
8004
+ }
8005
+ }
8006
+ /**
8007
+ * Unregisters a path alias.
8008
+ *
8009
+ * @param aliasPath The alias path to remove
8010
+ */
8011
+ static unregisterPathAlias(aliasPath) {
8012
+ // Remove all aliases that start with the given path
8013
+ for (const key of this.pathAliases.keys()) {
8014
+ if (key === aliasPath || key.startsWith(aliasPath + '.') || key.startsWith(aliasPath + '[')) {
8015
+ this.pathAliases.delete(key);
8016
+ }
8017
+ }
8018
+ }
8019
+ /**
8020
+ * Resolves an alias path to its source path.
8021
+ * Also handles nested paths (e.g., "editingNestedStep.steps" -> "routes[0].steps[0].steps").
8022
+ *
8023
+ * @param aliasPath The alias path to resolve
8024
+ * @returns The source path, or undefined if no alias exists
8025
+ */
8026
+ static resolvePathAlias(aliasPath) {
8027
+ // Direct match
8028
+ if (this.pathAliases.has(aliasPath)) {
8029
+ return this.pathAliases.get(aliasPath);
8030
+ }
8031
+ // Check if this is a nested path of an aliased variable
8032
+ // e.g., "editingNestedStep.steps" when "editingNestedStep" is aliased
8033
+ for (const [alias, source] of this.pathAliases.entries()) {
8034
+ if (aliasPath.startsWith(alias + '.') || aliasPath.startsWith(alias + '[')) {
8035
+ const suffix = aliasPath.substring(alias.length);
8036
+ return source + suffix;
8037
+ }
8038
+ }
8039
+ return undefined;
8040
+ }
8041
+ /**
8042
+ * Checks if a change path matches an identifier, considering path aliases.
8043
+ * For example, if "editingNestedStep" is aliased to "routes[0].steps[0]",
8044
+ * then a change to "routes[0].steps[0].steps" should match "editingNestedStep.steps".
8045
+ *
8046
+ * @param changePath The path that was changed (e.g., "routes[0].steps[0].steps")
8047
+ * @param identifier The identifier to check (e.g., "editingNestedStep.steps")
8048
+ * @returns True if the change path matches the identifier
8049
+ */
8050
+ static doesChangeMatchIdentifier(changePath, identifier) {
8051
+ // Direct match
8052
+ if (changePath === identifier) {
8053
+ return true;
8054
+ }
8055
+ // Check if the identifier has an alias that matches
8056
+ const resolvedIdentifier = this.resolvePathAlias(identifier);
8057
+ if (resolvedIdentifier && changePath === resolvedIdentifier) {
8058
+ return true;
8059
+ }
8060
+ // Check if change path starts with the resolved identifier
8061
+ // (handles cases like array item changes)
8062
+ if (resolvedIdentifier) {
8063
+ if (changePath.startsWith(resolvedIdentifier + '.') ||
8064
+ changePath.startsWith(resolvedIdentifier + '[')) {
8065
+ return true;
8066
+ }
8067
+ }
8068
+ return false;
8069
+ }
7985
8070
  }
7986
8071
 
7987
8072
  // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
@@ -8049,18 +8134,48 @@
8049
8134
  }
8050
8135
  let newValue = value;
8051
8136
  if (typeof value === 'object' && value !== null) {
8052
- // Wrap objects/arrays with reactive proxy, tracking the root key
8053
- newValue = ReactiveProxy.create(value, (changedPath) => {
8054
- let path = '';
8055
- for (const part of changedPath?.split('.') || []) {
8056
- path = path ? `${path}.${part}` : part;
8057
- this.#logger?.debug(`Binding changed: ${path}`);
8058
- this.#changes.add(path);
8059
- }
8060
- if (!this.#suppressOnChange) {
8061
- this.#onChange?.(changedPath);
8137
+ // Check if the value already has a path (it's an existing reactive proxy reference)
8138
+ const existingPath = ReactiveProxy.getPath(value);
8139
+ if (existingPath) {
8140
+ // Register a path alias so changes to the source path will match this identifier
8141
+ ReactiveProxy.registerPathAlias(key, existingPath);
8142
+ this.#logger?.debug(`Path alias registered: ${key} -> ${existingPath}`);
8143
+ // Keep the existing proxy as-is to preserve reactivity chain
8144
+ newValue = value;
8145
+ }
8146
+ else {
8147
+ // Before wrapping, check if any properties are existing ReactiveProxies
8148
+ // and register path aliases for them
8149
+ if (!Array.isArray(value)) {
8150
+ for (const propKey of Object.keys(value)) {
8151
+ const propValue = value[propKey];
8152
+ if (typeof propValue === 'object' && propValue !== null) {
8153
+ const propPath = ReactiveProxy.getPath(propValue);
8154
+ if (propPath) {
8155
+ // Register alias: key.propKey -> propPath
8156
+ ReactiveProxy.registerPathAlias(`${key}.${propKey}`, propPath);
8157
+ this.#logger?.debug(`Property path alias registered: ${key}.${propKey} -> ${propPath}`);
8158
+ }
8159
+ }
8160
+ }
8062
8161
  }
8063
- }, key);
8162
+ // Wrap objects/arrays with reactive proxy, tracking the root key
8163
+ newValue = ReactiveProxy.create(value, (changedPath) => {
8164
+ let path = '';
8165
+ for (const part of changedPath?.split('.') || []) {
8166
+ path = path ? `${path}.${part}` : part;
8167
+ this.#logger?.debug(`Binding changed: ${path}`);
8168
+ this.#changes.add(path);
8169
+ }
8170
+ if (!this.#suppressOnChange) {
8171
+ this.#onChange?.(changedPath);
8172
+ }
8173
+ }, key);
8174
+ }
8175
+ }
8176
+ else if (value === null || value === undefined) {
8177
+ // When setting to null/undefined, unregister any path alias
8178
+ ReactiveProxy.unregisterPathAlias(key);
8064
8179
  }
8065
8180
  const oldValue = Reflect.get(target, key);
8066
8181
  const result = Reflect.set(target, key, newValue);
@@ -8910,8 +9025,8 @@
8910
9025
  const changes = this.bindings?.changes || [];
8911
9026
  if (this.#nodeType === Node.TEXT_NODE && this.#textEvaluator) {
8912
9027
  // If this is a text node with a text evaluator, update its content if needed
8913
- // Check if any of the identifiers are in the changed identifiers
8914
- const changed = this.#textEvaluator.identifiers.some(id => changes.includes(id));
9028
+ // Check if any of the identifiers are in the changed identifiers (considering path aliases)
9029
+ const changed = this.#textEvaluator.identifiers.some(id => changes.some(change => ReactiveProxy.doesChangeMatchIdentifier(change, id)));
8915
9030
  // If the text node has changed, update its content
8916
9031
  if (changed) {
8917
9032
  const text = this.#node;
@@ -8934,7 +9049,7 @@
8934
9049
  }
8935
9050
  // Prepare bindings for each preparer if relevant identifiers have changed
8936
9051
  for (const preparer of this.#directiveManager.bindingsPreparers) {
8937
- const changed = preparer.dependentIdentifiers.some(id => changes.includes(id));
9052
+ const changed = preparer.dependentIdentifiers.some(id => changes.some(change => ReactiveProxy.doesChangeMatchIdentifier(change, id)));
8938
9053
  if (changed) {
8939
9054
  preparer.prepareBindings();
8940
9055
  }
@@ -8943,7 +9058,7 @@
8943
9058
  // Apply DOM updaters from directives, if any
8944
9059
  if (this.#directiveManager?.domUpdaters) {
8945
9060
  for (const updater of this.#directiveManager.domUpdaters) {
8946
- const changed = updater.dependentIdentifiers.some(id => changes.includes(id));
9061
+ const changed = updater.dependentIdentifiers.some(id => changes.some(change => ReactiveProxy.doesChangeMatchIdentifier(change, id)));
8947
9062
  if (changed) {
8948
9063
  updater.applyToDOM();
8949
9064
  }
@@ -8951,7 +9066,7 @@
8951
9066
  }
8952
9067
  // Recursively update dependent virtual nodes
8953
9068
  this.#dependents?.forEach(dependentNode => {
8954
- const changed = dependentNode.dependentIdentifiers.some(id => changes.includes(id));
9069
+ const changed = dependentNode.dependentIdentifiers.some(id => changes.some(change => ReactiveProxy.doesChangeMatchIdentifier(change, id)));
8955
9070
  if (changed) {
8956
9071
  dependentNode.update();
8957
9072
  }
@@ -12210,6 +12325,13 @@
12210
12325
  });
12211
12326
  // Initial rendering
12212
12327
  this.#vNode.update();
12328
+ // Remove v-cloak attributes after mounting
12329
+ // v-cloak is used to hide un-compiled template until the app is ready
12330
+ // Usage: Add CSS rule "[v-cloak] { display: none; }" to hide elements with v-cloak
12331
+ element.querySelectorAll('[v-cloak]').forEach(el => {
12332
+ el.removeAttribute('v-cloak');
12333
+ });
12334
+ element.removeAttribute('v-cloak');
12213
12335
  this.#logger.info('Application mounted.');
12214
12336
  }
12215
12337
  /**